From 3e76dd4a4586edbe988401a06025e3a231e9651b Mon Sep 17 00:00:00 2001 From: Steven Newbury Date: Thu, 29 Jun 2017 23:01:14 +0100 Subject: [PATCH 1/2] Clone SDL into SDL2 Prepare for before commiting changes needed for SDL2 --- src/SDL2/Comparison.h | 121 + src/SDL2/Comparison.m | 88 + src/SDL2/GameController+SDLFullScreen.m | 165 ++ src/SDL2/MyOpenGLView.h | 331 +++ src/SDL2/MyOpenGLView.m | 2731 +++++++++++++++++++++++ src/SDL2/OOSDLJoystickManager.h | 57 + src/SDL2/OOSDLJoystickManager.m | 113 + src/SDL2/main.m | 124 + 8 files changed, 3730 insertions(+) create mode 100644 src/SDL2/Comparison.h create mode 100644 src/SDL2/Comparison.m create mode 100644 src/SDL2/GameController+SDLFullScreen.m create mode 100644 src/SDL2/MyOpenGLView.h create mode 100644 src/SDL2/MyOpenGLView.m create mode 100644 src/SDL2/OOSDLJoystickManager.h create mode 100644 src/SDL2/OOSDLJoystickManager.m create mode 100644 src/SDL2/main.m diff --git a/src/SDL2/Comparison.h b/src/SDL2/Comparison.h new file mode 100644 index 000000000..55e55aacc --- /dev/null +++ b/src/SDL2/Comparison.h @@ -0,0 +1,121 @@ +// +// $Id: Comparison.h,v 1.3 2004/12/12 20:17:24 will_mason Exp $ +// +// vi: set ft=objc: + +/* + * ObjectiveLib - a library of containers and algorithms for Objective-C + * + * Copyright (c) 2004 + * Will Mason + * + * Portions: + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Copyright (c) 1996,1997 + * Silicon Graphics Computer Systems, Inc. + * + * Copyright (c) 1997 + * Moscow Center for SPARC Technology + * + * Copyright (c) 1999 + * Boris Fomitchev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * You may contact the author at will_mason@users.sourceforge.net. + */ + +#if defined(GNUSTEP) + +#if !defined(__COMPARISON_OL_GUARD) +#define __COMPARISON_OL_GUARD + +#include + +/** + * @category NSObject(OLComparisonMethods) Comparison.h Objectivelib/Comparison.h + * + * Comparison methods used in @ref Functors "function objects". These comparison + * methods are only required to be included when GNUstep is the platform, as + * Cocoa already defines them. Under Cocoa they are declared in the + * intuitively-named file @c NSScriptWhoseTests.h. All of these methods send + * the message @c compare: to the receiving object. + * + * @pre The receiving object must implement the method @c compare:. + */ +@interface NSObject (OLComparisonMethods) + +/** + * Return whether another object is equal to this one. This message returns YES if + * and only if the message @c compare: returns @c NSOrderedSame. + * + * @param object the object to which to compare this one + * @return YES if @a object is equal to this one, NO otherwise + */ +- (BOOL) isEqualTo: (id)object; + +/** + * Return whether this object is greater than another one. This message returns + * YES if and only if @c compare: returns @c NSOrderedDescending. + * + * @param object the object to which to compare this one + * @return YES if this object is greater than @a object, NO otherwise + */ +- (BOOL) isGreaterThan: (id)object; + +/** + * Return whether this object is greater than or equal to another one. This message returns + * YES if and only if @c compare: does not return @c NSOrderedAscending. + * + * @param object the object to which to compare this one + * @return YES if this object is greater than or equal to @a object, NO otherwise + */ +- (BOOL) isGreaterThanOrEqualTo: (id)object; + +/** + * Return whether this object is less than another one. This message returns + * YES if and only if @c compare: returns @c NSOrderedAscending. + * + * @param object the object to which to compare this one + * @return YES if this object is less than @a object, NO otherwise + */ +- (BOOL) isLessThan: (id)object; + +/** + * Return whether this object is less than or equal to another one. This message returns + * YES if and only if @c compare: does not return @c NSOrderedDescending. + * + * @param object the object to which to compare this one + * @return YES if this object is less than or equal to @a object, NO otherwise + */ +- (BOOL) isLessThanOrEqualTo: (id)object; + +/** + * Return whether another object is not equal to this one. This message returns YES if + * and only if the message @c compare: does not return @c NSOrderedSame. + * + * @param object the object to which to compare this one + * @return YES if @a object is not equal to this one, NO otherwise + */ +- (BOOL) isNotEqualTo: (id)object; + +@end + +#endif + +#endif diff --git a/src/SDL2/Comparison.m b/src/SDL2/Comparison.m new file mode 100644 index 000000000..8bcca0c82 --- /dev/null +++ b/src/SDL2/Comparison.m @@ -0,0 +1,88 @@ +// +// $Id: Comparison.m,v 1.3 2004/11/29 23:35:50 will_mason Exp $ +// +// vi: set ft=objc: + +/* + * ObjectiveLib - a library of containers and algorithms for Objective-C + * + * Copyright (c) 2004 + * Will Mason + * + * Portions: + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Copyright (c) 1996,1997 + * Silicon Graphics Computer Systems, Inc. + * + * Copyright (c) 1997 + * Moscow Center for SPARC Technology + * + * Copyright (c) 1999 + * Boris Fomitchev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * You may contact the author at will_mason@users.sourceforge.net. + */ + +#if defined(GNUSTEP) + +#include "Comparison.h" +#include + +@implementation NSObject (OLComparison) + +- (BOOL) isEqualTo: (id)object +{ + return (object != nil && [self compare: object] == NSOrderedSame) ? + YES : NO; +} + +- (BOOL) isGreaterThan: (id)object +{ + return (object != nil && [self compare: object] == NSOrderedDescending) ? + YES : NO; +} + +- (BOOL) isGreaterThanOrEqualTo: (id)object +{ + return (object != nil && [self compare: object] != NSOrderedAscending) ? + YES : NO; +} + +- (BOOL) isLessThan: (id)object +{ + return (object != nil && [self compare: object] == NSOrderedAscending) ? + YES : NO; +} + +- (BOOL) isLessThanOrEqualTo: (id)object +{ + return (object != nil && [self compare: object] != NSOrderedDescending) ? + YES : NO; +} + +- (BOOL) isNotEqualTo: (id)object +{ + return (object != nil && [self compare: object] != NSOrderedSame) ? + YES : NO; +} + +@end + +#endif diff --git a/src/SDL2/GameController+SDLFullScreen.m b/src/SDL2/GameController+SDLFullScreen.m new file mode 100644 index 000000000..175e0b458 --- /dev/null +++ b/src/SDL2/GameController+SDLFullScreen.m @@ -0,0 +1,165 @@ +/* + +GameController+SDLFullScreen.m + +Full-screen rendering support for SDL targets. + + +Oolite +Copyright (C) 2004-2013 Giles C Williams and contributors + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +MA 02110-1301, USA. + +*/ + + +#import "GameController.h" + +#if OOLITE_SDL + +#import "MyOpenGLView.h" +#import "Universe.h" +#import "OOFullScreenController.h" + + +@implementation GameController (FullScreen) + +- (void) setUpDisplayModes +{ + NSArray *modes = [gameView getScreenSizeArray]; + NSDictionary *mode = nil; + unsigned int modeIndex, modeCount; + unsigned int modeWidth, modeHeight; + + displayModes = [[NSMutableArray alloc] init]; + modeCount = [modes count]; + for (modeIndex = 0; modeIndex < modeCount; modeIndex++) + { + mode = [modes objectAtIndex: modeIndex]; + modeWidth = [[mode objectForKey: kOODisplayWidth] intValue]; + modeHeight = [[mode objectForKey: kOODisplayHeight] intValue]; + + if (modeWidth < DISPLAY_MIN_WIDTH || + modeWidth > DISPLAY_MAX_WIDTH || + modeHeight < DISPLAY_MIN_HEIGHT || + modeHeight > DISPLAY_MAX_HEIGHT) + continue; + [displayModes addObject: mode]; + } + + NSSize fsmSize = [gameView currentScreenSize]; + width = fsmSize.width; + height = fsmSize.height; +} + + +- (void) setFullScreenMode:(BOOL)fsm +{ + fullscreen = fsm; +} + + +- (void) exitFullScreenMode +{ + [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"fullscreen"]; + stayInFullScreenMode = NO; +} + + +- (BOOL) inFullScreenMode +{ + return [gameView inFullScreenMode]; +} + + +- (BOOL) setDisplayWidth:(unsigned int) d_width Height:(unsigned int) d_height Refresh:(unsigned int) d_refresh +{ + NSDictionary *d_mode = [self findDisplayModeForWidth: d_width Height: d_height Refresh: d_refresh]; + if (d_mode) + { + width = d_width; + height = d_height; + refresh = d_refresh; + fullscreenDisplayMode = d_mode; + + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + + [userDefaults setInteger:width forKey:@"display_width"]; + [userDefaults setInteger:height forKey:@"display_height"]; + [userDefaults setInteger:refresh forKey:@"display_refresh"]; + + // Manual synchronization is required for SDL And doesn't hurt much for OS X. + [userDefaults synchronize]; + + return YES; + } + return NO; +} + + +- (NSDictionary *) findDisplayModeForWidth:(unsigned int) d_width Height:(unsigned int) d_height Refresh:(unsigned int) d_refresh +{ + int i, modeCount; + NSDictionary *mode; + unsigned int modeWidth, modeHeight, modeRefresh; + + modeCount = [displayModes count]; + + for (i = 0; i < modeCount; i++) + { + mode = [displayModes objectAtIndex: i]; + modeWidth = [[mode objectForKey:kOODisplayWidth] intValue]; + modeHeight = [[mode objectForKey:kOODisplayHeight] intValue]; + modeRefresh = [[mode objectForKey:kOODisplayRefreshRate] intValue]; + if ((modeWidth == d_width)&&(modeHeight == d_height)&&(modeRefresh == d_refresh)) + { + return mode; + } + } + return nil; +} + + +- (NSArray *) displayModes +{ + return [NSArray arrayWithArray:displayModes]; +} + + +- (NSUInteger) indexOfCurrentDisplayMode +{ + NSDictionary *mode; + + mode = [self findDisplayModeForWidth: width Height: height Refresh: refresh]; + if (mode == nil) + return NSNotFound; + else + return [displayModes indexOfObject:mode]; + + return NSNotFound; +} + + +- (void) pauseFullScreenModeToPerform:(SEL) selector onTarget:(id) target +{ + pauseSelector = selector; + pauseTarget = target; + stayInFullScreenMode = NO; +} + +@end + +#endif diff --git a/src/SDL2/MyOpenGLView.h b/src/SDL2/MyOpenGLView.h new file mode 100644 index 000000000..ecfb6dadd --- /dev/null +++ b/src/SDL2/MyOpenGLView.h @@ -0,0 +1,331 @@ +/* + +MyOpenGLView.h + +Oolite +Copyright (C) 2004-2013 Giles C Williams and contributors + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +MA 02110-1301, USA. + +*/ + +#import "OOCocoa.h" +#import "OOOpenGL.h" +#import "OOMouseInteractionMode.h" +#import "OOOpenGLMatrixManager.h" + + +#include + +#define MIN_FOV_DEG 30.0f +#define MAX_FOV_DEG 80.0f +#define MIN_FOV (tan((MIN_FOV_DEG / 2) * M_PI / 180.0f)) +#define MAX_FOV (tan((MAX_FOV_DEG / 2) * M_PI / 180.0f)) + +#define MOUSEVIRTUALSTICKSENSITIVITYFACTOR 0.95f +#define MOUSEX_MAXIMUM 0.6 +#define MOUSEY_MAXIMUM 0.6 + +#define MAX_CLEAR_DEPTH 10000000000.0 +// 10 000 000 km. +#define INTERMEDIATE_CLEAR_DEPTH 100.0 +// 100 m. + + +#define NUM_KEYS 320 +#define MOUSE_DOUBLE_CLICK_INTERVAL 0.40 +#define OOMOUSEWHEEL_EVENTS_DELAY_INTERVAL 0.05 + +#define SNAPSHOTS_PNG_FORMAT 1 + +@class Entity, GameController, OpenGLSprite; + +enum GameViewKeys +{ + gvFunctionKey1 = 241, + gvFunctionKey2, + gvFunctionKey3, + gvFunctionKey4, + gvFunctionKey5, + gvFunctionKey6, + gvFunctionKey7, + gvFunctionKey8, + gvFunctionKey9, + gvFunctionKey10, + gvFunctionKey11, + gvArrowKeyRight, + gvArrowKeyLeft, + gvArrowKeyDown, + gvArrowKeyUp, // 255 + gvMouseLeftButton = 301, + gvMouseDoubleClick, + gvHomeKey, + gvEndKey, + gvInsertKey, + gvDeleteKey, + gvPageUpKey, + gvPageDownKey, // 308 + gvNumberKey0 = 48, + gvNumberKey1, + gvNumberKey2, + gvNumberKey3, + gvNumberKey4, + gvNumberKey5, + gvNumberKey6, + gvNumberKey7, + gvNumberKey8, + gvNumberKey9, //57 + gvNumberPadKey0 = 310, + gvNumberPadKey1, + gvNumberPadKey2, + gvNumberPadKey3, + gvNumberPadKey4, + gvNumberPadKey5, + gvNumberPadKey6, + gvNumberPadKey7, + gvNumberPadKey8, + gvNumberPadKey9 //319 +}; + +enum MouseWheelStatus +{ + gvMouseWheelDown = -1, + gvMouseWheelNeutral, + gvMouseWheelUp +}; + +enum StringInput +{ + gvStringInputNo = 0, + gvStringInputAlpha = 1, + gvStringInputLoadSave = 2, + gvStringInputAll = 3 +}; + +enum KeyboardType +{ + gvKeyboardAuto, + gvKeyboardUS, + gvKeyboardUK +}; + +extern int debug; + +@interface MyOpenGLView : NSObject +{ + GameController *gameController; + BOOL keys[NUM_KEYS]; + BOOL supressKeys; // DJS + + BOOL opt, ctrl, command, shift; + BOOL allowingStringInput; + BOOL isAlphabetKeyDown; + + int keycodetrans[255]; + + BOOL m_glContextInitialized; + NSPoint mouseDragStartPoint; + + BOOL mouseWarped; + + NSTimeInterval timeIntervalAtLastClick; + NSTimeInterval timeSinceLastMouseWheel; + BOOL doubleClick; + + NSMutableString *typedString; + + NSPoint virtualJoystickPosition; + + NSSize viewSize; + GLfloat display_z; + GLfloat x_offset, y_offset; + + double squareX,squareY; + NSRect bounds; + + float _gamma; + float _fov; + + // Full screen sizes + NSMutableArray *screenSizes; + int currentSize; //we need an int! + BOOL fullScreen; + + // Windowed mode + NSSize currentWindowSize; + SDL_Surface *surface; + + BOOL showSplashScreen; + +#if OOLITE_WINDOWS + + BOOL wasFullScreen; + BOOL updateContext; + BOOL saveSize; + unsigned keyboardMap; + HWND SDL_Window; + MONITORINFOEX monitorInfo; + RECT lastGoodRect; + +#endif + + BOOL grabMouseStatus; + + NSSize firstScreen; + + OOOpenGLMatrixManager *matrixManager; + + // Mouse mode indicator (for mouse movement model) + BOOL mouseInDeltaMode; + + int _mouseWheelState; +} + +- (void) initSplashScreen; +- (void) endSplashScreen; +- (void) autoShowMouse; + +- (void) setStringInput: (enum StringInput) value; +- (void) allowStringInput: (BOOL) value; +- (enum StringInput) allowingStringInput; +- (NSString *) typedString; +- (void) resetTypedString; +- (void) setTypedString:(NSString*) value; + +- (NSSize) viewSize; +- (NSSize) backingViewSize; +- (GLfloat) display_z; +- (GLfloat) x_offset; +- (GLfloat) y_offset; + +- (GameController *) gameController; +- (void) setGameController:(GameController *) controller; + +- (void) noteMouseInteractionModeChangedFrom:(OOMouseInteractionMode)oldMode to:(OOMouseInteractionMode)newMode; + +- (void) initialiseGLWithSize:(NSSize) v_size; +- (void) initialiseGLWithSize:(NSSize) v_size useVideoMode:(BOOL) v_mode; +- (BOOL) isRunningOnPrimaryDisplayDevice; +- (BOOL) enableDPIAwareness; +#if OOLITE_WINDOWS +- (BOOL) getCurrentMonitorInfo:(MONITORINFOEX *)mInfo; +- (MONITORINFOEX) currentMonitorInfo; +#endif + +- (void) grabMouseInsideGameWindow:(BOOL) value; + +- (void) stringToClipboard:(NSString *)stringToCopy; + +- (void) drawRect:(NSRect)rect; +- (void) updateScreen; +- (void) updateScreenWithVideoMode:(BOOL) v_mode; +- (void) display; + +- (BOOL) snapShot:(NSString *)filename; +#if SNAPSHOTS_PNG_FORMAT +- (BOOL) pngSaveSurface:(NSString *)fileName withSurface:(SDL_Surface *)surf; +#endif + +- (NSRect) bounds; ++ (NSMutableDictionary *) getNativeSize; + +- (void) setFullScreenMode:(BOOL)fsm; +- (BOOL) inFullScreenMode; +- (void) toggleScreenMode; +- (void) setDisplayMode:(int)mode fullScreen:(BOOL)fsm; + +- (int) indexOfCurrentSize; +- (void) setScreenSize: (int)sizeIndex; +- (NSMutableArray *)getScreenSizeArray; +- (void) populateFullScreenModelist; +- (NSSize) modeAsSize: (int)sizeIndex; +- (void) saveWindowSize: (NSSize) windowSize; +- (NSSize) loadWindowSize; +- (int) loadFullscreenSettings; +- (int) findDisplayModeForWidth: (unsigned int) d_width Height:(unsigned int) d_height + Refresh: (unsigned int)d_refresh; +- (NSSize) currentScreenSize; + +- (void) pollControls; + +- (void) setVirtualJoystick:(double) vmx :(double) vmy; +- (NSPoint) virtualJoystickPosition; + +- (void) clearKeys; +- (void) clearMouse; +- (void) clearKey: (int)theKey; +- (void) resetMouse; +- (BOOL) isAlphabetKeyDown; +- (void) supressKeysUntilKeyUp; // DJS +- (BOOL) isDown: (int) key; +- (BOOL) isOptDown; // opt == alt key +- (BOOL) isCtrlDown; +- (BOOL) isCommandDown; +- (BOOL) isShiftDown; +- (BOOL) isCapsLockOn; +- (int) numKeys; +- (int) mouseWheelState; + +// Command-key combinations need special handling. SDL stubs for these mac functions. +- (BOOL) isCommandQDown; +- (BOOL) isCommandFDown; +- (void) clearCommandF; + +- (void) setKeyboardTo: (NSString *) value; +- (void) setMouseInDeltaMode: (BOOL) inDelta; + +- (void) setGammaValue: (float) value; +- (float) gammaValue; + +- (void) setFov:(float)value fromFraction:(BOOL)fromFraction; +- (float) fov:(BOOL)inFraction; + +// Check current state of shift key rather than relying on last event. ++ (BOOL)pollShiftKey; + +- (OOOpenGLMatrixManager *) getOpenGLMatrixManager; + +#ifndef NDEBUG +// General image-dumping method. +- (void) dumpRGBAToFileNamed:(NSString *)name + bytes:(uint8_t *)bytes + width:(NSUInteger)width + height:(NSUInteger)height + rowBytes:(NSUInteger)rowBytes; +- (void) dumpRGBToFileNamed:(NSString *)name + bytes:(uint8_t *)bytes + width:(NSUInteger)width + height:(NSUInteger)height + rowBytes:(NSUInteger)rowBytes; +- (void) dumpGrayToFileNamed:(NSString *)name + bytes:(uint8_t *)bytes + width:(NSUInteger)width + height:(NSUInteger)height + rowBytes:(NSUInteger)rowBytes; +- (void) dumpGrayAlphaToFileNamed:(NSString *)name + bytes:(uint8_t *)bytes + width:(NSUInteger)width + height:(NSUInteger)height + rowBytes:(NSUInteger)rowBytes; +- (void) dumpRGBAToRGBFileNamed:(NSString *)rgbName + andGrayFileNamed:(NSString *)grayName + bytes:(uint8_t *)bytes + width:(NSUInteger)width + height:(NSUInteger)height + rowBytes:(NSUInteger)rowBytes; +#endif + +@end diff --git a/src/SDL2/MyOpenGLView.m b/src/SDL2/MyOpenGLView.m new file mode 100644 index 000000000..e7933155e --- /dev/null +++ b/src/SDL2/MyOpenGLView.m @@ -0,0 +1,2731 @@ +/* + +MyOpenGLView.m + +Oolite +Copyright (C) 2004-2013 Giles C Williams and contributors + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +MA 02110-1301, USA. + +*/ + +#import "png.h" +#import "MyOpenGLView.h" + +#import "GameController.h" +#import "Universe.h" +#import "OOSDLJoystickManager.h" +#import "SDL_syswm.h" +#import "OOSound.h" +#import "NSFileManagerOOExtensions.h" // to find savedir +#import "PlayerEntity.h" +#import "GuiDisplayGen.h" +#import "PlanetEntity.h" +#import "OOGraphicsResetManager.h" +#import "OOCollectionExtractors.h" // for splash screen settings +#import "OOFullScreenController.h" + +#define kOOLogUnconvertedNSLog @"unclassified.MyOpenGLView" + +#include + +@interface MyOpenGLView (OOPrivate) + +- (void) resetSDLKeyModifiers; +- (void) setWindowBorderless:(BOOL)borderless; +- (void) handleStringInput: (SDL_KeyboardEvent *) kbd_event; // DJS +@end + +@implementation MyOpenGLView + ++ (NSMutableDictionary *) getNativeSize +{ + NSMutableDictionary *mode=[[NSMutableDictionary alloc] init]; + int nativeDisplayWidth = 1024; + int nativeDisplayHeight = 768; + +#if OOLITE_LINUX + SDL_SysWMinfo dpyInfo; + SDL_VERSION(&dpyInfo.version); + if(SDL_GetWMInfo(&dpyInfo)) + { + nativeDisplayWidth = DisplayWidth(dpyInfo.info.x11.display, 0); + nativeDisplayHeight = DisplayHeight(dpyInfo.info.x11.display, 0); + OOLog(@"display.mode.list.native", @"X11 native resolution detected: %d x %d", nativeDisplayWidth, nativeDisplayHeight); + } + else + { + OOLog(@"display.mode.list.native.failed", @"%@", @"SDL_GetWMInfo failed, defaulting to 1024x768 for native size"); + } +#elif OOLITE_WINDOWS + nativeDisplayWidth = GetSystemMetrics(SM_CXSCREEN); + nativeDisplayHeight = GetSystemMetrics(SM_CYSCREEN); + OOLog(@"display.mode.list.native", @"Windows native resolution detected: %d x %d", nativeDisplayWidth, nativeDisplayHeight); +#else + OOLog(@"display.mode.list.native.unknown", @"Unknown architecture, defaulting to 1024x768"); +#endif + [mode setValue: [NSNumber numberWithInt: nativeDisplayWidth] forKey:kOODisplayWidth]; + [mode setValue: [NSNumber numberWithInt: nativeDisplayHeight] forKey: kOODisplayHeight]; + [mode setValue: [NSNumber numberWithInt: 0] forKey: kOODisplayRefreshRate]; + + return [mode autorelease]; +} + + +- (void) createSurface +{ + // Changing these flags can trigger texture bugs. + const int videoModeFlags = SDL_HWSURFACE | SDL_OPENGL | SDL_RESIZABLE; + + if (showSplashScreen) + { +#if OOLITE_WINDOWS + // Pre setVideoMode adjustments. + NSSize tmp = currentWindowSize; + ShowWindow(SDL_Window,SW_SHOWMINIMIZED); + updateContext = NO; //don't update the (splash screen) window yet! + + // Initialise the SDL surface. (need custom SDL.dll) + surface = SDL_SetVideoMode(firstScreen.width, firstScreen.height, 32, videoModeFlags); + + // Post setVideoMode adjustments. + currentWindowSize=tmp; +#else + // Changing the flags can trigger texture bugs. + surface = SDL_SetVideoMode(8, 8, 32, videoModeFlags); + if (!surface) { + return; + } +#endif + } + else + { +#if OOLITE_WINDOWS + updateContext = YES; +#endif + surface = SDL_SetVideoMode(firstScreen.width, firstScreen.height, 32, videoModeFlags); + if (!surface) { + return; + } + // blank the surface / go to fullscreen + [self initialiseGLWithSize: firstScreen]; + } + + _gamma = 1.0f; + if (SDL_SetGamma(_gamma, _gamma, _gamma) < 0 ) + { + char * errStr = SDL_GetError(); + OOLogWARN(@"gamma.set.failed", @"Could not set gamma: %s", errStr); + // CIM: this doesn't seem to necessarily be fatal. Gamma settings + // mostly work on mine despite this function failing. + // exit(1); + } + SDL_EnableUNICODE(1); +} + + +- (id) init +{ + self = [super init]; + + Uint32 colorkey; + SDL_Surface *icon=NULL; + NSString *imagesDir; + + // SDL splash screen settings + + NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; + showSplashScreen = [prefs oo_boolForKey:@"splash-screen" defaultValue:YES]; + BOOL vSyncPreference = [prefs oo_boolForKey:@"v-sync" defaultValue:YES]; + int vSyncValue; + + NSArray *arguments = nil; + NSEnumerator *argEnum = nil; + NSString *arg = nil; + BOOL noSplashArgFound = NO; + + arguments = [[NSProcessInfo processInfo] arguments]; + + // scan for splash screen overrides: -nosplash || --nosplash , -splash || --splash + // scan for V-sync disabling overrides: -novsync || --novsync + for (argEnum = [arguments objectEnumerator]; (arg = [argEnum nextObject]); ) + { + if ([arg isEqual:@"-nosplash"] || [arg isEqual:@"--nosplash"]) + { + showSplashScreen = NO; + noSplashArgFound = YES; // -nosplash always trumps -splash + } + else if (([arg isEqual:@"-splash"] || [arg isEqual:@"--splash"]) && !noSplashArgFound) + { + showSplashScreen = YES; + } + + // if V-sync is disabled at the command line, override the defaults file + if ([arg isEqual:@"-novsync"] || [arg isEqual:@"--novsync"]) vSyncPreference = NO; + } + + // high-DPI awareness; must be done before any SDL initialization + if (![self enableDPIAwareness]) + { + OOLogWARN(@"display.initGL.dpiAwareness", @"Could not declare application as DPI-aware."); + } + + matrixManager = [[OOOpenGLMatrixManager alloc] init]; + + // TODO: This code up to and including stickHandler really ought + // not to be in this class. + OOLog(@"sdl.init", @"%@", @"initialising SDL"); + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) + { + OOLog(@"sdl.init.failed", @"Unable to init SDL: %s\n", SDL_GetError()); + [self dealloc]; + return nil; + } + + SDL_putenv ("SDL_VIDEO_WINDOW_POS=center"); + + [OOJoystickManager setStickHandlerClass:[OOSDLJoystickManager class]]; + // end TODO + + [OOSound setUp]; + if (![OOSound isSoundOK]) OOLog(@"sound.init", @"Sound system disabled."); + + // Generate the window caption, containing the version number and the date the executable was compiled. + static char windowCaption[128]; + NSString *versionString = [NSString stringWithFormat:@"Oolite v%@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]; + + strcpy (windowCaption, [versionString UTF8String]); + strcat (windowCaption, " - "__DATE__); + SDL_WM_SetCaption (windowCaption, "Oolite"); // Set window title. + +#if OOLITE_WINDOWS + // needed for enabling system window manager events, which is needed for handling window movement messages + SDL_EventState (SDL_SYSWMEVENT, SDL_ENABLE); + + //capture the window handle for later + static SDL_SysWMinfo wInfo; + SDL_VERSION(&wInfo.version); + SDL_GetWMInfo(&wInfo); + SDL_Window = wInfo.window; + + // This must be inited after SDL_Window has been set - we need the main window handle in order to get monitor info + if (![self getCurrentMonitorInfo:&monitorInfo]) + { + OOLogWARN(@"display.initGL.monitorInfoWarning", @"Could not get current monitor information."); + } +#endif + + grabMouseStatus = NO; + + imagesDir = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Images"]; + icon = SDL_LoadBMP([[imagesDir stringByAppendingPathComponent:@"WMicon.bmp"] UTF8String]); + + if (icon != NULL) + { + colorkey = SDL_MapRGB(icon->format, 128, 0, 128); + SDL_SetColorKey(icon, SDL_SRCCOLORKEY, colorkey); + SDL_WM_SetIcon(icon, NULL); + } + SDL_FreeSurface(icon); + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 32); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + // V-sync settings - we set here, but can only verify after SDL_SetVideoMode has been called. + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, vSyncPreference); // V-sync on by default. + OOLog(@"display.initGL", @"V-Sync %@requested.", vSyncPreference ? @"" : @"not "); + + /* Multisampling significantly improves graphics quality with + * basically no extra programming effort on our part, especially + * for curved surfaces like the planet, but is also expensive - in + * the worst case the entire scene must be rendered four + * times. For now it can be a hidden setting. If early testing + * doesn't give any problems (other than speed on low-end graphics + * cards) a game options entry might be useful. - CIM, 24 Aug 2013*/ + if ([prefs oo_boolForKey:@"anti-aliasing" defaultValue:NO]) + { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); + } + + OOLog(@"display.mode.list", @"%@", @"CREATING MODE LIST"); + [self populateFullScreenModelist]; + currentSize = 0; + + // Find what the full screen and windowed settings are. + fullScreen = NO; + [self loadFullscreenSettings]; + [self loadWindowSize]; + + // Set up the drawing surface's dimensions. + firstScreen= (fullScreen) ? [self modeAsSize: currentSize] : currentWindowSize; + viewSize = firstScreen; // viewSize must be set prior to splash screen initialization + + OOLog(@"display.initGL", @"%@", @"Trying 32-bit depth buffer"); + [self createSurface]; + if (surface == NULL) + { + // Retry with a 24-bit depth buffer + OOLog(@"display.initGL", @"%@", @"Trying 24-bit depth buffer"); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + [self createSurface]; + if (surface == NULL) + { + // Still not working? One last go... + // Retry, allowing 16-bit contexts. + OOLog(@"display.initGL", @"%@", @"Trying 16-bit depth buffer"); + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); + // and if it's this bad, forget even trying to multisample! + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); + + [self createSurface]; + + if (surface == NULL) + { + char * errStr = SDL_GetError(); + OOLogERR(@"display.mode.error", @"Could not create display surface: %s", errStr); +#if OOLITE_WINDOWS + if (showSplashScreen) + { + [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"splash-screen"]; + OOLogWARN(@"display.mode.conflict",@"Possible incompatibility between the splash screen and video drivers detected."); + OOLogWARN(@"display.mode.conflict",@"Oolite will start without showing the splash screen from now on. Override with 'oolite.exe -splash'"); + } +#endif + exit(1); + } + } + } + + // Verify V-sync successfully set - report it if not + if (vSyncPreference && SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL, &vSyncValue) == -1) + { + OOLogWARN(@"display.initGL", @"Could not enable V-Sync. Please check that your graphics driver supports the %@_swap_control extension.", + OOLITE_WINDOWS ? @"WGL_EXT" : @"[GLX_SGI/GLX_MESA]"); + } + + bounds.size.width = surface->w; + bounds.size.height = surface->h; + + [self autoShowMouse]; + + virtualJoystickPosition = NSMakePoint(0.0,0.0); + mouseWarped = NO; + + typedString = [[NSMutableString alloc] initWithString:@""]; + allowingStringInput = gvStringInputNo; + isAlphabetKeyDown = NO; + + timeIntervalAtLastClick = timeSinceLastMouseWheel = [NSDate timeIntervalSinceReferenceDate]; + + _mouseWheelState = gvMouseWheelNeutral; + + m_glContextInitialized = NO; + + return self; +} + +- (void) endSplashScreen +{ + if (!showSplashScreen) return; + +#if OOLITE_WINDOWS + + wasFullScreen = !fullScreen; + updateContext = YES; + ShowWindow(SDL_Window,SW_RESTORE); + [self initialiseGLWithSize: firstScreen]; + +#else + + int videoModeFlags = SDL_HWSURFACE | SDL_OPENGL; + + videoModeFlags |= (fullScreen) ? SDL_FULLSCREEN : SDL_RESIZABLE; + surface = SDL_SetVideoMode(firstScreen.width, firstScreen.height, 32, videoModeFlags); + + if (!surface && fullScreen == YES) + { + [self setFullScreenMode: NO]; + videoModeFlags &= ~SDL_FULLSCREEN; + videoModeFlags |= SDL_RESIZABLE; + surface = SDL_SetVideoMode(currentWindowSize.width, currentWindowSize.height, 32, videoModeFlags); + } + + SDL_putenv ("SDL_VIDEO_WINDOW_POS=none"); //stop linux from auto centering on resize + + /* MKW 2011.11.11 + * Eat all SDL events to gobble up any resize events while the + * splash-screen was visible. They affected the main window after 1.74. + * TODO: should really process SDL events while showing the splash-screen + + int numEvents = 0; + */ + SDL_Event dummyEvent; + while (SDL_PollEvent(&dummyEvent)) + { + /* Do nothing; the below is for development info + numEvents++; + OOLog(@"display.splash", @"Suppressed splash-screen event %d: %d ", numEvents, dummyEvent.type); + */ + } + + +#endif + + [self updateScreen]; + [self autoShowMouse]; +} + +- (void) dealloc +{ + if (typedString) + [typedString release]; + + if (screenSizes) + [screenSizes release]; + + if (surface != 0) + { + SDL_FreeSurface(surface); + surface = 0; + } + + SDL_Quit(); + + if (matrixManager) + { + [matrixManager release]; + } + + [super dealloc]; +} + +- (void) autoShowMouse +{ + //don't touch the 'please wait...' cursor. + if (fullScreen) + { + if (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE) + SDL_ShowCursor(SDL_DISABLE); + } + else + { + if (SDL_ShowCursor(SDL_QUERY) == SDL_DISABLE) + SDL_ShowCursor(SDL_ENABLE); + } +} + +- (void) setStringInput: (enum StringInput) value +{ + allowingStringInput = value; +} + + +- (void) allowStringInput: (BOOL) value +{ + if (value) + allowingStringInput = gvStringInputAlpha; + else + allowingStringInput = gvStringInputNo; +} + +-(enum StringInput) allowingStringInput +{ + return allowingStringInput; +} + + +- (NSString *) typedString +{ + return typedString; +} + + +- (void) resetTypedString +{ + [typedString setString:@""]; +} + + +- (void) setTypedString:(NSString*) value +{ + [typedString setString:value]; +} + + +- (NSRect) bounds +{ + return bounds; +} + + +- (NSSize) viewSize +{ + return viewSize; +} + + +- (NSSize) backingViewSize +{ + return viewSize; +} + + +- (GLfloat) display_z +{ + return display_z; +} + + +- (GLfloat) x_offset +{ + return x_offset; +} + + +- (GLfloat) y_offset +{ + return y_offset; +} + + +- (GameController *) gameController +{ + return gameController; +} + + +- (void) setGameController:(GameController *) controller +{ + gameController = controller; +} + + +- (void) noteMouseInteractionModeChangedFrom:(OOMouseInteractionMode)oldMode to:(OOMouseInteractionMode)newMode +{ + [self autoShowMouse]; + [self setMouseInDeltaMode:OOMouseInteractionModeIsFlightMode(newMode)]; +} + + +- (BOOL) inFullScreenMode +{ + return fullScreen; +} + +#ifdef GNUSTEP +- (void) setFullScreenMode:(BOOL)fsm +{ + fullScreen = fsm; + + // Save the settings for later. + [[NSUserDefaults standardUserDefaults] + setBool: fullScreen forKey:@"fullscreen"]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + + +- (void) toggleScreenMode +{ + [self setFullScreenMode: !fullScreen]; +#if OOLITE_WINDOWS + [self getCurrentMonitorInfo:&monitorInfo]; +#endif + if(fullScreen) + { +#if OOLITE_WINDOWS + if(![self isRunningOnPrimaryDisplayDevice]) + { + [self initialiseGLWithSize:NSMakeSize(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left, + monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top)]; + } + else [self initialiseGLWithSize:[self modeAsSize: currentSize]]; +#else + [self initialiseGLWithSize:[self modeAsSize: currentSize]]; +#endif + } + else + [self initialiseGLWithSize: currentWindowSize]; + + + // do screen resizing updates + if ([PlayerEntity sharedPlayer]) + { + [[PlayerEntity sharedPlayer] doGuiScreenResizeUpdates]; + } +} + + +- (void) setDisplayMode:(int)mode fullScreen:(BOOL)fsm +{ + [self setFullScreenMode: fsm]; + currentSize=mode; + if(fullScreen) + [self initialiseGLWithSize: [self modeAsSize: mode]]; +} + + +- (int) indexOfCurrentSize +{ + return currentSize; +} + + +- (void) setScreenSize: (int)sizeIndex +{ + currentSize=sizeIndex; + if(fullScreen) + [self initialiseGLWithSize: [self modeAsSize: currentSize]]; +} + + +- (NSMutableArray *)getScreenSizeArray +{ + return screenSizes; +} + + +- (NSSize) modeAsSize:(int)sizeIndex +{ + NSDictionary *mode=[screenSizes objectAtIndex: sizeIndex]; + return NSMakeSize([[mode objectForKey: kOODisplayWidth] intValue], + [[mode objectForKey: kOODisplayHeight] intValue]); +} + +#endif + +- (void) display +{ + [self updateScreen]; +} + +- (void) updateScreen +{ + [self drawRect: NSMakeRect(0, 0, viewSize.width, viewSize.height)]; +} + +- (void) drawRect:(NSRect)rect +{ + [self updateScreenWithVideoMode:YES]; +} + +- (void) updateScreenWithVideoMode:(BOOL) v_mode +{ + if ((viewSize.width != surface->w)||(viewSize.height != surface->h)) // resized + { +#if OOLITE_LINUX + m_glContextInitialized = NO; //probably not needed +#endif + viewSize.width = surface->w; + viewSize.height = surface->h; + } + + if (m_glContextInitialized == NO) + { + [self initialiseGLWithSize:viewSize useVideoMode:v_mode]; + } + + if (surface == 0) + return; + + // do all the drawing! + // + if (UNIVERSE) [UNIVERSE drawUniverse]; + else + { + // not set up yet, draw a black screen + glClearColor( 0.0, 0.0, 0.0, 0.0); + glClear( GL_COLOR_BUFFER_BIT); + } + + SDL_GL_SwapBuffers(); +} + +- (void) initSplashScreen +{ + if (!showSplashScreen) return; + + //too early for OOTexture! + SDL_Surface *image=NULL; + SDL_Rect dest; + + NSString *imagesDir = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Images"]; + + image = SDL_LoadBMP([[imagesDir stringByAppendingPathComponent:@"splash.bmp"] UTF8String]); + + if (image == NULL) + { + SDL_FreeSurface(image); + OOLogWARN(@"sdl.gameStart", @"%@", @"image 'splash.bmp' not found!"); + [self endSplashScreen]; + return; + } + + dest.x = 0; + dest.y = 0; + dest.w = image->w; + dest.h = image->h; + + #if OOLITE_WINDOWS + + dest.x = (GetSystemMetrics(SM_CXSCREEN)- dest.w)/2; + dest.y = (GetSystemMetrics(SM_CYSCREEN)-dest.h)/2; + SetWindowLong(SDL_Window,GWL_STYLE,GetWindowLong(SDL_Window,GWL_STYLE) & ~WS_CAPTION & ~WS_THICKFRAME); + ShowWindow(SDL_Window,SW_RESTORE); + MoveWindow(SDL_Window,dest.x,dest.y,dest.w,dest.h,TRUE); + + #else + + /* MKW 2011.11.11 + * According to Marc using the NOFRAME flag causes trouble under Ubuntu 8.04. + * + * The current Ubuntu LTS is 10.04, which doesn't seem to have that problem. + * 12.04 LTS is going to be released soon, also without apparent problems. + * Changed to SDL_NOFRAME, throwing caution to the wind - Kaks 2012.03.23 + * Took SDL_NOFRAME out, since it still causes strange problems here - cim 2012.04.09 + */ + surface = SDL_SetVideoMode(dest.w, dest.h, 32, SDL_HWSURFACE | SDL_OPENGL); + + #endif + + OOSetOpenGLState(OPENGL_STATE_OVERLAY); + + glViewport( 0, 0, dest.w, dest.h); + + glEnable( GL_TEXTURE_2D ); + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); + glClear( GL_COLOR_BUFFER_BIT ); + + [matrixManager resetProjection]; + [matrixManager orthoLeft: 0.0f right: dest.w bottom: dest.h top: 0.0 near: -1.0 far: 1.0]; + [matrixManager syncProjection]; + + [matrixManager resetModelView]; + [matrixManager syncModelView]; + + GLuint texture; + GLenum texture_format; + GLint nOfColors; + + // get the number of channels in the SDL image + nOfColors = image->format->BytesPerPixel; + if (nOfColors == 4) // contains an alpha channel + { + if (image->format->Rmask == 0x000000ff) + texture_format = GL_RGBA; + else + texture_format = GL_BGRA; + } + else if (nOfColors == 3) // no alpha channel + { + if (image->format->Rmask == 0x000000ff) + texture_format = GL_RGB; + else + texture_format = GL_BGR; + } else { + SDL_FreeSurface(image); + OOLog(@"Sdl.GameStart", @"%@", @"----- Encoding error within image 'splash.bmp'"); + [self endSplashScreen]; + return; + } + + glGenTextures( 1, &texture ); + glBindTexture( GL_TEXTURE_2D, texture ); + + // Set the texture's stretching properties + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + // Set the texture image data with the information from SDL_Surface + glTexImage2D( GL_TEXTURE_2D, 0, nOfColors, image->w, image->h, 0, + texture_format, GL_UNSIGNED_BYTE, image->pixels ); + + glBindTexture( GL_TEXTURE_2D, texture ); + glBegin( GL_QUADS ); + + glTexCoord2i( 0, 0 ); + glVertex2i( 0, 0 ); + glTexCoord2i( 1, 0 ); + glVertex2i( dest.w, 0 ); + glTexCoord2i( 1, 1 ); + glVertex2i( dest.w, dest.h ); + glTexCoord2i( 0, 1 ); + glVertex2i( 0, dest.h ); + + glEnd(); + + SDL_GL_SwapBuffers(); + [matrixManager resetModelView]; + [matrixManager syncModelView]; + + if ( image ) { + SDL_FreeSurface( image ); + } + glDeleteTextures(1, &texture); + + glDisable( GL_TEXTURE_2D ); + OOVerifyOpenGLState(); +} + + +#if OOLITE_WINDOWS +- (BOOL) enableDPIAwareness +{ + /* + Declare the application as DPI-aware, so that Windows Vista and later + versions' automatic DPI virtualization does not kick-in. Attempt to + load the SetProcessDpiAwareness WinAPI function and execute it if available. + If not available (as would be the case in Windows versions prior to 8.1), + attempt to load and execute the older SetProcessDPIAware instead. + */ + BOOL dpiAwarenessSet = NO; + BOOL dpiAwareSet = NO; + // the following enum is supposed to be part of the Windows API headers, + // but it looks like MinGW does not declare it + #ifndef DPI_ENUMS_DECLARED + typedef enum PROCESS_DPI_AWARENESS + { + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2 + } PROCESS_DPI_AWARENESS; + #endif + HRESULT(WINAPI *setProcessDpiAwareness)(PROCESS_DPI_AWARENESS) = NULL; + setProcessDpiAwareness = (HRESULT(WINAPI*)(PROCESS_DPI_AWARENESS)) + (void*)GetProcAddress(GetModuleHandle("shcore.dll"), "SetProcessDpiAwareness"); + if (setProcessDpiAwareness) + { + dpiAwarenessSet = (setProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE) == S_OK); + } + else + { + BOOL(WINAPI *setProcessDPIAware)() = NULL; + setProcessDPIAware = (BOOL(WINAPI*)())(void*)GetProcAddress(GetModuleHandle("user32.dll"), "SetProcessDPIAware"); + if (setProcessDPIAware) + { + dpiAwareSet = setProcessDPIAware(); + } + } + + OOLog(@"display.initGL.dpiAwareness", @"%@ loaded and executed", + dpiAwarenessSet ? @"SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE)" : dpiAwareSet ? + @"SetProcessDPIAware()" : @"No DPI awareness method"); + + return dpiAwarenessSet || dpiAwareSet; +} + + +- (MONITORINFOEX) currentMonitorInfo +{ + return monitorInfo; +} + + +- (BOOL) getCurrentMonitorInfo:(MONITORINFOEX *)mInfo +{ + HMONITOR hMon = MonitorFromWindow(SDL_Window, MONITOR_DEFAULTTOPRIMARY); + ZeroMemory(mInfo, sizeof(MONITORINFOEX)); + mInfo->cbSize = sizeof(MONITORINFOEX); + if (GetMonitorInfo (hMon, (LPMONITORINFO)mInfo)) + { + return YES; + } + return NO; +} + + +- (BOOL) isRunningOnPrimaryDisplayDevice +{ + BOOL result = YES; + [self getCurrentMonitorInfo:&monitorInfo]; + if (!(monitorInfo.dwFlags & MONITORINFOF_PRIMARY)) + { + result = NO; + } + return result; +} + + +- (void) grabMouseInsideGameWindow:(BOOL) value +{ + if(value) + { + RECT gameWindowRect; + GetWindowRect(SDL_Window, &gameWindowRect); + ClipCursor(&gameWindowRect); + } + else + { + ClipCursor(NULL); + } + grabMouseStatus = !!value; +} + + +- (void) stringToClipboard:(NSString *)stringToCopy +{ + if (stringToCopy) + { + const char *clipboardText = [stringToCopy cStringUsingEncoding:NSUTF8StringEncoding]; + const size_t clipboardTextLength = strlen(clipboardText) + 1; + HGLOBAL clipboardMem = GlobalAlloc(GMEM_MOVEABLE, clipboardTextLength); + if (clipboardMem) + { + memcpy(GlobalLock(clipboardMem), clipboardText, clipboardTextLength); + GlobalUnlock(clipboardMem); + OpenClipboard(0); + EmptyClipboard(); + if (!SetClipboardData(CF_TEXT, clipboardMem)) + { + OOLog(@"stringToClipboard.failed", @"Failed to copy string %@ to clipboard", stringToCopy); + // free global allocated memory if clipboard copy failed + // note: no need to free it if copy succeeded; the OS becomes + // the owner of the copied memory once SetClipboardData has + // been executed successfully + GlobalFree(clipboardMem); + } + CloseClipboard(); + } + } +} + + +- (void) resetSDLKeyModifiers +{ + // this is used when we regain focus to ensure that all + // modifier keys are reset to their correct status + SDLMod modState = SDL_GetModState(); + Uint8 *keyState = SDL_GetKeyState(NULL); + BYTE keyboardStatus[256]; + #define OO_RESET_SDLKEY_MODIFIER(vkCode, kModCode, sdlkCode) do {\ + if (keyboardStatus[vkCode] & 0x0080) \ + { \ + modState |= kModCode; \ + keyState[sdlkCode] = SDL_PRESSED; \ + } \ + else \ + { \ + modState &= ~kModCode; \ + keyState[sdlkCode] = SDL_RELEASED; \ + } \ + } while(0) + if (GetKeyboardState(keyboardStatus)) + { + // Alt key + OO_RESET_SDLKEY_MODIFIER(VK_LMENU, KMOD_LALT, SDLK_LALT); + OO_RESET_SDLKEY_MODIFIER(VK_RMENU, KMOD_RALT, SDLK_RALT); + opt = (modState & KMOD_LALT || modState & KMOD_RALT); + + //Ctrl key + OO_RESET_SDLKEY_MODIFIER(VK_LCONTROL, KMOD_LCTRL, SDLK_LCTRL); + OO_RESET_SDLKEY_MODIFIER(VK_RCONTROL, KMOD_RCTRL, SDLK_RCTRL); + ctrl = (modState & KMOD_LCTRL || modState & KMOD_RCTRL); + + // Shift key + OO_RESET_SDLKEY_MODIFIER(VK_LSHIFT, KMOD_LSHIFT, SDLK_LSHIFT); + OO_RESET_SDLKEY_MODIFIER(VK_RSHIFT, KMOD_RSHIFT, SDLK_RSHIFT); + shift = (modState & KMOD_LSHIFT || modState & KMOD_RSHIFT); + + // Caps Lock key state + if (GetKeyState(VK_CAPITAL) & 0x0001) + { + modState |= KMOD_CAPS; + keyState[SDLK_CAPSLOCK] = SDL_PRESSED; + } + else + { + modState &= ~KMOD_CAPS; + keyState[SDLK_CAPSLOCK] = SDL_RELEASED; + } + } + + SDL_SetModState(modState); +} + + +- (void) setWindowBorderless:(BOOL)borderless +{ + LONG currentWindowStyle = GetWindowLong(SDL_Window, GWL_STYLE); + + // window already has the desired style? + if ((!borderless && (currentWindowStyle & WS_CAPTION)) || + (borderless && !(currentWindowStyle & WS_CAPTION))) return; + + if (borderless) + { + SetWindowLong(SDL_Window, GWL_STYLE, currentWindowStyle & ~WS_CAPTION & ~WS_THICKFRAME); + } + else + { + SetWindowLong(SDL_Window, GWL_STYLE, currentWindowStyle | + WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX ); + } + SetWindowPos(SDL_Window, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); +} + + +#else // Linus stub methods + +- (BOOL) enableDPIAwareness +{ + return NO; +} + + +// for Linux we assume we are always on the primary monitor for now +- (BOOL) isRunningOnPrimaryDisplayDevice +{ + return YES; +} + + +- (void) grabMouseInsideGameWindow:(BOOL) value +{ + // do nothing +} + + +- (void) stringToClipboard:(NSString *)stringToCopy +{ + // TODO: implement string clipboard copy for Linux +} + + +- (void) resetSDLKeyModifiers +{ + // probably not needed for Linux +} + + +- (void) setWindowBorderless:(BOOL)borderless +{ + // do nothing on Linux +} + +#endif //OOLITE_WINDOWS + + +- (void) initialiseGLWithSize:(NSSize) v_size +{ + [self initialiseGLWithSize:v_size useVideoMode:YES]; +} + + +- (void) initialiseGLWithSize:(NSSize) v_size useVideoMode:(BOOL) v_mode +{ +#if OOLITE_LINUX + NSSize oldViewSize = viewSize; +#endif + viewSize = v_size; + OOLog(@"display.initGL", @"Requested a new surface of %d x %d, %@.", (int)viewSize.width, (int)viewSize.height,(fullScreen ? @"fullscreen" : @"windowed")); + SDL_GL_SwapBuffers(); // clear the buffer before resize + +#if OOLITE_WINDOWS + if (!updateContext) return; + + DEVMODE settings; + settings.dmSize = sizeof(DEVMODE); + settings.dmDriverExtra = 0; + EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &settings); + + WINDOWPLACEMENT windowPlacement; + windowPlacement.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(SDL_Window, &windowPlacement); + + static BOOL lastWindowPlacementMaximized = NO; + if (fullScreen && (windowPlacement.showCmd == SW_SHOWMAXIMIZED)) + { + if (!wasFullScreen) + { + lastWindowPlacementMaximized = YES; + } + } + + if (lastWindowPlacementMaximized) + { + windowPlacement.showCmd = SW_SHOWMAXIMIZED; + } + + // are we attempting to go to a different screen resolution? Note: this also takes care of secondary monitor situations because + // by design the only resolution available for fullscreen on a secondary display device is its native one - Nikos 20150605 + BOOL changingResolution = [self isRunningOnPrimaryDisplayDevice] && + ((fullScreen && (settings.dmPelsWidth != viewSize.width || settings.dmPelsHeight != viewSize.height)) || + (wasFullScreen && (settings.dmPelsWidth != [[[screenSizes objectAtIndex:0] objectForKey: kOODisplayWidth] intValue] + || settings.dmPelsHeight != [[[screenSizes objectAtIndex:0] objectForKey: kOODisplayHeight] intValue]))); + + RECT wDC; + + if (fullScreen) + { + /*NOTE: If we ever decide to change the default behaviour of launching + always on primary monitor to launching on the monitor the program was + started on, all that needs to be done is comment out the line below, as + well as the identical one in the else branch further down. + Nikos 20141222 + */ + [self getCurrentMonitorInfo: &monitorInfo]; + + settings.dmPelsWidth = viewSize.width; + settings.dmPelsHeight = viewSize.height; + settings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; + + // just before going fullscreen, save the location of the current window. It + // may be needed in case of potential attempts to move our fullscreen window + // in a maximized state (yes, in Windows this is entirely possible). + if(lastWindowPlacementMaximized) + { + CopyRect(&lastGoodRect, &windowPlacement.rcNormalPosition); + // if maximized, switch to normal placement before going full screen + windowPlacement.showCmd = SW_SHOWNORMAL; + SetWindowPlacement(SDL_Window, &windowPlacement); + } + else GetWindowRect(SDL_Window, &lastGoodRect); + + // ok, can go fullscreen now + SetForegroundWindow(SDL_Window); + if (changingResolution) + { + if (ChangeDisplaySettingsEx(monitorInfo.szDevice, &settings, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL) + { + m_glContextInitialized = YES; + OOLogERR(@"displayMode.change.error", @"Could not switch to requested display mode."); + return; + } + } + + MoveWindow(SDL_Window, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, (int)viewSize.width, (int)viewSize.height, TRUE); + if(!wasFullScreen) + { + [self setWindowBorderless:YES]; + } + } + + else if ( wasFullScreen ) + { + if (changingResolution) ChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL); + + /*NOTE: If we ever decide to change the default behaviour of launching + always on primary monitor to launching on the monitor the program was + started on, we need to comment out the line below. + For now, this line is needed for correct positioning of our window in case + we return from a non-native resolution fullscreen and has to come after the + display settings have been reverted. + Nikos 20141222 + */ + [self getCurrentMonitorInfo: &monitorInfo]; + + if (lastWindowPlacementMaximized) CopyRect(&windowPlacement.rcNormalPosition, &lastGoodRect); + SetWindowPlacement(SDL_Window, &windowPlacement); + if (!lastWindowPlacementMaximized) + { + MoveWindow(SDL_Window, (monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left - (int)viewSize.width)/2 + + monitorInfo.rcMonitor.left, + (monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top - (int)viewSize.height)/2 + + monitorInfo.rcMonitor.top, + (int)viewSize.width, (int)viewSize.height, TRUE); + } + + [self setWindowBorderless:NO]; + + lastWindowPlacementMaximized = NO; + ShowWindow(SDL_Window,SW_SHOW); + } + + // stop saveWindowSize from reacting to caption & frame if necessary + saveSize = !wasFullScreen; + + GetClientRect(SDL_Window, &wDC); + + if (!fullScreen && (bounds.size.width != wDC.right - wDC.left + || bounds.size.height != wDC.bottom - wDC.top)) + { + // Resize the game window if needed. When we ask for a W x H + // window, we intend that the client area be W x H. The actual + // window itself must become big enough to accomodate an area + // of such size. + if (wasFullScreen) // this is true when switching from full screen or when starting in windowed mode + //after the splash screen has ended + { + RECT desiredClientRect; + GetWindowRect(SDL_Window, &desiredClientRect); + AdjustWindowRect(&desiredClientRect, WS_CAPTION | WS_THICKFRAME, FALSE); + SetWindowPos(SDL_Window, NULL, desiredClientRect.left, desiredClientRect.top, + desiredClientRect.right - desiredClientRect.left, + desiredClientRect.bottom - desiredClientRect.top, 0); + } + GetClientRect(SDL_Window, &wDC); + viewSize.width = wDC.right - wDC.left; + viewSize.height = wDC.bottom - wDC.top; + } + + // Reset bounds and viewSize to current values + bounds.size.width = viewSize.width = wDC.right - wDC.left; + bounds.size.height = viewSize.height = wDC.bottom - wDC.top; + if (fullScreen) // bounds on fullscreen coincide with client area, since we are borderless + { + bounds.origin.x = monitorInfo.rcMonitor.left; + bounds.origin.y = monitorInfo.rcMonitor.top; + } + wasFullScreen=fullScreen; + +#else //OOLITE_LINUX + + int videoModeFlags = SDL_HWSURFACE | SDL_OPENGL; + + if (v_mode == NO) + videoModeFlags |= SDL_NOFRAME; + if (fullScreen == YES) + { + videoModeFlags |= SDL_FULLSCREEN; + } + else + { + videoModeFlags |= SDL_RESIZABLE; + } + surface = SDL_SetVideoMode((int)viewSize.width, (int)viewSize.height, 32, videoModeFlags); + + if (!surface && fullScreen == YES) + { + [self setFullScreenMode: NO]; + viewSize = oldViewSize; + videoModeFlags &= ~SDL_FULLSCREEN; + videoModeFlags |= SDL_RESIZABLE; + surface = SDL_SetVideoMode((int)viewSize.width, (int)viewSize.height, 32, videoModeFlags); + } + + if (!surface) + { + // we should always have a valid surface, but in case we don't + OOLogERR(@"display.mode.error",@"Unable to change display mode: %s",SDL_GetError()); + exit(1); + } + + bounds.size.width = surface->w; + bounds.size.height = surface->h; + +#endif + OOLog(@"display.initGL", @"Created a new surface of %d x %d, %@.", (int)viewSize.width, (int)viewSize.height,(fullScreen ? @"fullscreen" : @"windowed")); + + if (viewSize.width/viewSize.height > 4.0/3.0) { + display_z = 480.0 * bounds.size.width/bounds.size.height; + x_offset = 240.0 * bounds.size.width/bounds.size.height; + y_offset = 240.0; + } else { + display_z = 640.0; + x_offset = 320.0; + y_offset = 320.0 * bounds.size.height/bounds.size.width; + } + + if (surface != 0) SDL_FreeSurface(surface); + + [self autoShowMouse]; + + [[self gameController] setUpBasicOpenGLStateWithSize:viewSize]; + SDL_GL_SwapBuffers(); + squareX = 0.0f; + + m_glContextInitialized = YES; +} + + +- (BOOL) snapShot:(NSString *)filename +{ + BOOL snapShotOK = YES; + SDL_Surface* tmpSurface; + + // backup the previous directory + NSString* originalDirectory = [[NSFileManager defaultManager] currentDirectoryPath]; + // use the snapshots directory + [[NSFileManager defaultManager] chdirToSnapshotPath]; + + BOOL withFilename = (filename != nil); + static unsigned imageNo = 0; + unsigned tmpImageNo = 0; + NSString *pathToPic = nil; + NSString *baseName = @"oolite"; + +#if SNAPSHOTS_PNG_FORMAT + NSString *extension = @".png"; +#else + NSString *extension = @".bmp"; +#endif + + if (withFilename) + { + baseName = filename; + pathToPic = [filename stringByAppendingString:extension]; + } + else + { + tmpImageNo = imageNo; + } + + if (withFilename && [[NSFileManager defaultManager] fileExistsAtPath:pathToPic]) + { + OOLog(@"screenshot.filenameExists", @"Snapshot \"%@%@\" already exists - adding numerical sequence.", pathToPic, extension); + pathToPic = nil; + } + + if (pathToPic == nil) + { + do + { + tmpImageNo++; + pathToPic = [NSString stringWithFormat:@"%@-%03d%@", baseName, tmpImageNo, extension]; + } while ([[NSFileManager defaultManager] fileExistsAtPath:pathToPic]); + } + + if (!withFilename) + { + imageNo = tmpImageNo; + } + + OOLog(@"screenshot", @"Saved screen shot \"%@\" (%u x %u pixels).", pathToPic, surface->w, surface->h); + + int pitch = surface->w * 3; + unsigned char *pixls = malloc(pitch * surface->h); + int y; + int off; + + if (surface->w % 4) glPixelStorei(GL_PACK_ALIGNMENT,1); + else glPixelStorei(GL_PACK_ALIGNMENT,4); + for (y=surface->h-1, off=0; y>=0; y--, off+=pitch) + { + glReadPixels(0, y, surface->w, 1, GL_RGB, GL_UNSIGNED_BYTE, pixls + off); + } + + tmpSurface=SDL_CreateRGBSurfaceFrom(pixls,surface->w,surface->h,24,surface->w*3,0xFF,0xFF00,0xFF0000,0x0); +#if SNAPSHOTS_PNG_FORMAT + if(![self pngSaveSurface:pathToPic withSurface:tmpSurface]) + { + OOLog(@"screenshotPNG", @"Failed to save %@", pathToPic); + snapShotOK = NO; + } +#else + if (SDL_SaveBMP(tmpSurface, [pathToPic UTF8String]) == -1) + { + OOLog(@"screenshotBMP", @"Failed to save %@", pathToPic); + snapShotOK = NO; + } +#endif + SDL_FreeSurface(tmpSurface); + free(pixls); + + // return to the previous directory + [[NSFileManager defaultManager] changeCurrentDirectoryPath:originalDirectory]; + return snapShotOK; +} + + +#if SNAPSHOTS_PNG_FORMAT +// This method is heavily based on 'Mars, Land of No Mercy' SDL examples, by Angelo "Encelo" Theodorou, see http://encelo.netsons.org/programming/sdl +- (BOOL) pngSaveSurface:(NSString *)fileName withSurface:(SDL_Surface *)surf +{ + FILE *fp; + png_structp pngPtr; + png_infop infoPtr; + int i, colorType; + png_bytep *rowPointers; + + fp = fopen([fileName UTF8String], "wb"); + if (fp == NULL) + { + OOLog(@"pngSaveSurface.fileCreate.failed", @"Failed to create output screenshot file %@", fileName); + return NO; + } + + // initialize png structures (no callbacks) + pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (pngPtr == NULL) + { + return NO; + } + + infoPtr = png_create_info_struct(pngPtr); + if (infoPtr == NULL) { + png_destroy_write_struct(&pngPtr, (png_infopp)NULL); + OOLog(@"pngSaveSurface.info_struct.failed", @"%@", @"png_create_info_struct error"); + exit(-1); + } + + if (setjmp(png_jmpbuf(pngPtr))) + { + png_destroy_write_struct(&pngPtr, &infoPtr); + fclose(fp); + exit(-1); + } + + png_init_io(pngPtr, fp); + + colorType = PNG_COLOR_MASK_COLOR; /* grayscale not supported */ + if (surf->format->palette) + { + colorType |= PNG_COLOR_MASK_PALETTE; + } + else if (surf->format->Amask) + { + colorType |= PNG_COLOR_MASK_ALPHA; + } + + png_set_IHDR(pngPtr, infoPtr, surf->w, surf->h, 8, colorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + // write the image + png_write_info(pngPtr, infoPtr); + png_set_packing(pngPtr); + + rowPointers = (png_bytep*) malloc(sizeof(png_bytep)*surf->h); + for (i = 0; i < surf->h; i++) + { + rowPointers[i] = (png_bytep)(Uint8 *)surf->pixels + i*surf->pitch; + } + png_write_image(pngPtr, rowPointers); + png_write_end(pngPtr, infoPtr); + + free(rowPointers); + png_destroy_write_struct(&pngPtr, &infoPtr); + fclose(fp); + + return YES; +} +#endif // SNAPSHOTS_PNG_FORMAT + + +/* Turn the Cocoa ArrowKeys into our arrow key constants. */ +- (int) translateKeyCode: (int) input +{ + int key = input; + switch ( input ) + { + case NSUpArrowFunctionKey: + key = gvArrowKeyUp; + break; + + case NSDownArrowFunctionKey: + key = gvArrowKeyDown; + break; + + case NSLeftArrowFunctionKey: + key = gvArrowKeyLeft; + break; + + case NSRightArrowFunctionKey: + key = gvArrowKeyRight; + break; + + case NSF1FunctionKey: + key = gvFunctionKey1; + break; + + case NSF2FunctionKey: + key = gvFunctionKey2; + break; + + case NSF3FunctionKey: + key = gvFunctionKey3; + break; + + case NSF4FunctionKey: + key = gvFunctionKey4; + break; + + case NSF5FunctionKey: + key = gvFunctionKey5; + break; + + case NSF6FunctionKey: + key = gvFunctionKey6; + break; + + case NSF7FunctionKey: + key = gvFunctionKey7; + break; + + case NSF8FunctionKey: + key = gvFunctionKey8; + break; + + case NSF9FunctionKey: + key = gvFunctionKey9; + break; + + case NSF10FunctionKey: + key = gvFunctionKey10; + break; + + case NSF11FunctionKey: + key = gvFunctionKey11; + break; + + case NSHomeFunctionKey: + key = gvHomeKey; + break; + + default: + break; + } + return key; +} + + +- (void) setVirtualJoystick:(double) vmx :(double) vmy +{ + virtualJoystickPosition.x = vmx; + virtualJoystickPosition.y = vmy; +} + + +- (NSPoint) virtualJoystickPosition +{ + return virtualJoystickPosition; +} + + +///////////////////////////////////////////////////////////// + +- (void) clearKeys +{ + int i; + for (i = 0; i < [self numKeys]; i++) + keys[i] = NO; +} + + +- (void) clearMouse +{ + keys[gvMouseDoubleClick] = NO; + keys[gvMouseLeftButton] = NO; + doubleClick = NO; +} + + +- (void) clearKey: (int)theKey +{ + if (theKey >= 0 && theKey < [self numKeys]) + { + keys[theKey] = NO; + } +} + + +- (void) resetMouse +{ + [self setVirtualJoystick:0.0 :0.0]; + if ([[PlayerEntity sharedPlayer] isMouseControlOn]) + { + SDL_WarpMouse([self viewSize].width / 2, [self viewSize].height / 2); + mouseWarped = YES; + } +} + + +- (BOOL) isAlphabetKeyDown +{ + return isAlphabetKeyDown = NO;; +} + +// DJS: When entering submenus in the gui, it is not helpful if the +// key down that brought you into the submenu is still registered +// as down when we're in. This makes isDown return NO until a key up +// event has been received from SDL. +- (void) supressKeysUntilKeyUp +{ + if (keys[gvMouseDoubleClick] == NO) + { + supressKeys = YES; + [self clearKeys]; + } + else + { + [self clearMouse]; + } + +} + + +- (BOOL) isDown: (int) key +{ + if ( supressKeys ) + return NO; + if ( key < 0 ) + return NO; + if ( key >= [self numKeys] ) + return NO; + return keys[key]; +} + + +- (BOOL) isOptDown +{ + return opt; +} + + +- (BOOL) isCtrlDown +{ + return ctrl; +} + + +- (BOOL) isCommandDown +{ + return command; +} + + +- (BOOL) isShiftDown +{ + return shift; +} + + +- (BOOL) isCapsLockOn +{ + /* Caps Lock state check - This effectively gives us + an alternate keyboard state to play with and, in + the future, we could assign different behaviours + to existing controls, depending on the state of + Caps Lock. - Nikos 20160304 + */ + return (SDL_GetModState() & KMOD_CAPS) == KMOD_CAPS; +} + + +- (int) numKeys +{ + return NUM_KEYS; +} + + +- (int) mouseWheelState +{ + return _mouseWheelState; +} + + +- (BOOL) isCommandQDown +{ + return NO; +} + + +- (BOOL) isCommandFDown +{ + return NO; +} + + +- (void) clearCommandF +{ + // SDL stub for the mac function. +} + + +- (void) setKeyboardTo: (NSString *) value +{ +#if OOLITE_WINDOWS + keyboardMap=gvKeyboardAuto; + + if ([value isEqual: @"UK"]) + { + keyboardMap=gvKeyboardUK; + } + else if ([value isEqual: @"US"]) + { + keyboardMap=gvKeyboardUS; + } +#endif +} + +- (void)pollControls +{ + SDL_Event event; + SDL_KeyboardEvent *kbd_event; + SDL_MouseButtonEvent *mbtn_event; + SDL_MouseMotionEvent *mmove_event; + int mxdelta, mydelta; + float mouseVirtualStickSensitivityX = viewSize.width * MOUSEVIRTUALSTICKSENSITIVITYFACTOR; + float mouseVirtualStickSensitivityY = viewSize.height * MOUSEVIRTUALSTICKSENSITIVITYFACTOR; + NSTimeInterval timeNow = [NSDate timeIntervalSinceReferenceDate]; + + + while (SDL_PollEvent(&event)) + { + switch (event.type) { + case SDL_JOYAXISMOTION: + case SDL_JOYBUTTONUP: + case SDL_JOYBUTTONDOWN: + case SDL_JOYHATMOTION: + [(OOSDLJoystickManager*)[OOJoystickManager sharedStickHandler] handleSDLEvent: &event]; + break; + + case SDL_MOUSEBUTTONDOWN: + mbtn_event = (SDL_MouseButtonEvent*)&event; + switch(mbtn_event->button) + { + case SDL_BUTTON_LEFT: + keys[gvMouseLeftButton] = YES; + break; + case SDL_BUTTON_RIGHT: + // Cocoa version does this in the GameController + /* + The mouseWarped variable is quite important as far as mouse control is concerned. When we + reset the virtual joystick (mouse) coordinates, we need to send a WarpMouse call because we + must recenter the pointer physically on screen. This goes together with a mouse motion event, + so we use mouseWarped to simply ignore handling of motion events in this case. - Nikos 20110721 + */ + [self resetMouse]; // Will set mouseWarped to YES + break; + // mousewheel stuff + case SDL_BUTTON_WHEELUP: + _mouseWheelState = gvMouseWheelUp; + break; + case SDL_BUTTON_WHEELDOWN: + _mouseWheelState = gvMouseWheelDown; + break; + } + break; + + case SDL_MOUSEBUTTONUP: + mbtn_event = (SDL_MouseButtonEvent*)&event; + NSTimeInterval timeBetweenClicks = timeNow - timeIntervalAtLastClick; + timeIntervalAtLastClick += timeBetweenClicks; + if (mbtn_event->button == SDL_BUTTON_LEFT) + { + if (!doubleClick) + { + doubleClick = (timeBetweenClicks < MOUSE_DOUBLE_CLICK_INTERVAL); // One fifth of a second + keys[gvMouseDoubleClick] = doubleClick; + } + keys[gvMouseLeftButton] = NO; + } + /* + Mousewheel handling - just note time since last use here and mark as inactive, + if needed, at the end of this method. Note that the mousewheel button up event is + kind of special, as in, it is sent at the same time as its corresponding mousewheel + button down one - Nikos 20140809 + */ + if (mbtn_event->button == SDL_BUTTON_WHEELUP || mbtn_event->button == SDL_BUTTON_WHEELDOWN) + { + NSTimeInterval timeBetweenMouseWheels = timeNow - timeSinceLastMouseWheel; + timeSinceLastMouseWheel += timeBetweenMouseWheels; + } + break; + + case SDL_MOUSEMOTION: + { + // Delta mode is set when the game is in 'flight' mode. + // In this mode, the mouse movement delta is used rather + // than absolute position. This is because if the user + // clicks the right button to recentre the virtual joystick, + // if we are using absolute joystick positioning, as soon + // as the player touches the mouse again, the virtual joystick + // will snap back to the absolute position (which can be + // annoyingly fatal in battle). + if(mouseInDeltaMode) + { + // possible TODO - make virtual stick sensitivity configurable + SDL_GetRelativeMouseState(&mxdelta, &mydelta); + double mxd=(double)mxdelta / mouseVirtualStickSensitivityX; + double myd=(double)mydelta / mouseVirtualStickSensitivityY; + + if (!mouseWarped) // Standard event, update coordinates + { + virtualJoystickPosition.x += mxd; + virtualJoystickPosition.y += myd; + + // if we excceed the limits, revert changes + if(fabs(virtualJoystickPosition.x) > MOUSEX_MAXIMUM) + { + virtualJoystickPosition.x -= mxd; + } + if(fabs(virtualJoystickPosition.y) > MOUSEY_MAXIMUM) + { + virtualJoystickPosition.y -= myd; + } + } + else + { + // Motion event generated by WarpMouse is ignored and + // we reset mouseWarped for the next time. + mouseWarped = NO; + } + } + else + { + // Windowed mode. Use the absolute position so the + // Oolite mouse pointer appears under the X Window System + // mouse pointer. + mmove_event = (SDL_MouseMotionEvent*)&event; + + int w=bounds.size.width; + int h=bounds.size.height; + + if (!mouseWarped) // standard event, handle it + { + double mx = mmove_event->x - w/2.0; + double my = mmove_event->y - h/2.0; + if (display_z > 640.0) + { + mx /= w * MAIN_GUI_PIXEL_WIDTH / display_z; + my /= h; + } + else + { + mx /= MAIN_GUI_PIXEL_WIDTH * w / 640.0; + my /= MAIN_GUI_PIXEL_HEIGHT * w / 640.0; + } + + [self setVirtualJoystick:mx :my]; + } + else + { + // event coming from WarpMouse ignored, get ready for the next + mouseWarped = NO; + } + } + break; + } + case SDL_KEYDOWN: + kbd_event = (SDL_KeyboardEvent*)&event; + + if(allowingStringInput) + { + [self handleStringInput: kbd_event]; + } + + // Macro KEYCODE_DOWN_EITHER. Detect the keypress state (with shift or without) and assign appropriate values to the + // keys array. This way Oolite can use more keys, since now key '3', for example is a different keypress to '#'. +#define KEYCODE_DOWN_EITHER(a,b) do { \ +if (shift) { keys[a] = YES; keys[b] = NO; } else { keys[a] = NO; keys[b] = YES; } \ +} while (0) + +#if OOLITE_WINDOWS + /* + Windows locale patch - Enable backslash in win/UK + */ + if (EXPECT_NOT(kbd_event->keysym.scancode==86 && (keyboardMap==gvKeyboardAuto || keyboardMap==gvKeyboardUK))) + { + //non-US scancode. If in autodetect, we'll assume UK keyboard. + KEYCODE_DOWN_EITHER (124, 92); // | or \. + } + else switch (kbd_event->keysym.sym) { + + case SDLK_BACKSLASH: + if (keyboardMap==gvKeyboardUK ) + { + KEYCODE_DOWN_EITHER (126, 35); // ~ or # + } + else if (keyboardMap==gvKeyboardAuto || keyboardMap==gvKeyboardUS) + { + KEYCODE_DOWN_EITHER (124, 92); // | or \. + } + break; +#else + switch (kbd_event->keysym.sym) { + + case SDLK_BACKSLASH: KEYCODE_DOWN_EITHER (124, 92); break; // | or \. +#endif + case SDLK_1: KEYCODE_DOWN_EITHER (33, gvNumberKey1); break; // ! or 1 +#if OOLITE_WINDOWS + /* + Windows locale patch - fix shift-2 & shift-3 + */ + case SDLK_2: + if (keyboardMap==gvKeyboardUK) + { + KEYCODE_DOWN_EITHER (34, gvNumberKey2); // " or 2 + } + else + { + KEYCODE_DOWN_EITHER (64, gvNumberKey2); // @ or 2 + } + break; + case SDLK_3: + if (keyboardMap==gvKeyboardUK) + { + KEYCODE_DOWN_EITHER (156, gvNumberKey3); // � or 3 + } + else + { + KEYCODE_DOWN_EITHER (35, gvNumberKey3); // # or 3 + } + break; +#else + case SDLK_2: KEYCODE_DOWN_EITHER (64, gvNumberKey2); break; // @ or 2 + case SDLK_3: KEYCODE_DOWN_EITHER (35, gvNumberKey3); break; // # or 3 +#endif + case SDLK_4: KEYCODE_DOWN_EITHER (36, gvNumberKey4); break; // $ or 4 + case SDLK_5: KEYCODE_DOWN_EITHER (37, gvNumberKey5); break; // % or 5 + case SDLK_6: KEYCODE_DOWN_EITHER (94, gvNumberKey6); break; // ^ or 6 + case SDLK_7: KEYCODE_DOWN_EITHER (38, gvNumberKey7); break; // & or 7 + case SDLK_8: KEYCODE_DOWN_EITHER (42, gvNumberKey8); break; // * or 8 + case SDLK_9: KEYCODE_DOWN_EITHER (40, gvNumberKey9); break; // ( or 9 + case SDLK_0: KEYCODE_DOWN_EITHER (41, gvNumberKey0); break; // ) or 0 + case SDLK_MINUS: KEYCODE_DOWN_EITHER (95, 45); break; // _ or - + case SDLK_COMMA: KEYCODE_DOWN_EITHER (60, 44); break; // < or , + case SDLK_EQUALS: KEYCODE_DOWN_EITHER (43, 61); break; // + or = + case SDLK_PERIOD: KEYCODE_DOWN_EITHER (62, 46); break; // > or . + case SDLK_SLASH: KEYCODE_DOWN_EITHER (63, 47); break; // ? or / + case SDLK_a: KEYCODE_DOWN_EITHER (65, 97); break; // A or a + case SDLK_b: KEYCODE_DOWN_EITHER (66, 98); break; // B or b + case SDLK_c: KEYCODE_DOWN_EITHER (67, 99); break; // C or c + case SDLK_d: KEYCODE_DOWN_EITHER (68, 100); break; // D or d + case SDLK_e: KEYCODE_DOWN_EITHER (69, 101); break; // E or e + case SDLK_f: KEYCODE_DOWN_EITHER (70, 102); break; // F or f + case SDLK_g: KEYCODE_DOWN_EITHER (71, 103); break; // G or g + case SDLK_h: KEYCODE_DOWN_EITHER (72, 104); break; // H or h + case SDLK_i: KEYCODE_DOWN_EITHER (73, 105); break; // I or i + case SDLK_j: KEYCODE_DOWN_EITHER (74, 106); break; // J or j + case SDLK_k: KEYCODE_DOWN_EITHER (75, 107); break; // K or k + case SDLK_l: KEYCODE_DOWN_EITHER (76, 108); break; // L or l + case SDLK_m: KEYCODE_DOWN_EITHER (77, 109); break; // M or m + case SDLK_n: KEYCODE_DOWN_EITHER (78, 110); break; // N or n + case SDLK_o: KEYCODE_DOWN_EITHER (79, 111); break; // O or o + case SDLK_p: KEYCODE_DOWN_EITHER (80, 112); break; // P or p + case SDLK_q: KEYCODE_DOWN_EITHER (81, 113); break; // Q or q + case SDLK_r: KEYCODE_DOWN_EITHER (82, 114); break; // R or r + case SDLK_s: KEYCODE_DOWN_EITHER (83, 115); break; // S or s + case SDLK_t: KEYCODE_DOWN_EITHER (84, 116); break; // T or t + case SDLK_u: KEYCODE_DOWN_EITHER (85, 117); break; // U or u + case SDLK_v: KEYCODE_DOWN_EITHER (86, 118); break; // V or v + case SDLK_w: KEYCODE_DOWN_EITHER (87, 119); break; // W or w + case SDLK_x: KEYCODE_DOWN_EITHER (88, 120); break; // X or x + case SDLK_y: KEYCODE_DOWN_EITHER (89, 121); break; // Y or y + case SDLK_z: KEYCODE_DOWN_EITHER (90, 122); break; // Z or z + case SDLK_SEMICOLON: KEYCODE_DOWN_EITHER(58, 59); break; // : or ; + //SDLK_BACKQUOTE and SDLK_HASH are special cases. No SDLK_ with code 126 exists. + case SDLK_HASH: if (!shift) keys[126] = YES; break; // ~ (really #) + case SDLK_BACKQUOTE: if (!shift) keys[96] = YES; break; // ` + case SDLK_QUOTE: keys[39] = YES; break; // ' + case SDLK_LEFTBRACKET: keys[91] = YES; break; // [ + case SDLK_RIGHTBRACKET: keys[93] = YES; break; // ] + case SDLK_HOME: keys[gvHomeKey] = YES; break; + case SDLK_END: keys[gvEndKey] = YES; break; + case SDLK_INSERT: keys[gvInsertKey] = YES; break; + case SDLK_PAGEUP: keys[gvPageUpKey] = YES; break; + case SDLK_PAGEDOWN: keys[gvPageDownKey] = YES; break; + case SDLK_SPACE: keys[32] = YES; break; + case SDLK_RETURN: keys[13] = YES; break; + case SDLK_TAB: keys[9] = YES; break; + case SDLK_UP: keys[gvArrowKeyUp] = YES; break; + case SDLK_DOWN: keys[gvArrowKeyDown] = YES; break; + case SDLK_LEFT: keys[gvArrowKeyLeft] = YES; break; + case SDLK_RIGHT: keys[gvArrowKeyRight] = YES; break; + + case SDLK_KP_MINUS: keys[45] = YES; break; // numeric keypad - key + case SDLK_KP_PLUS: keys[43] = YES; break; // numeric keypad + key + case SDLK_KP_ENTER: keys[13] = YES; break; + + case SDLK_KP_MULTIPLY: keys[42] = YES; break; // * + + case SDLK_KP1: keys[gvNumberPadKey1] = YES; break; + case SDLK_KP2: keys[gvNumberPadKey2] = YES; break; + case SDLK_KP3: keys[gvNumberPadKey3] = YES; break; + case SDLK_KP4: keys[gvNumberPadKey4] = YES; break; + case SDLK_KP5: keys[gvNumberPadKey5] = YES; break; + case SDLK_KP6: keys[gvNumberPadKey6] = YES; break; + case SDLK_KP7: keys[gvNumberPadKey7] = YES; break; + case SDLK_KP8: keys[gvNumberPadKey8] = YES; break; + case SDLK_KP9: keys[gvNumberPadKey9] = YES; break; + case SDLK_KP0: keys[gvNumberPadKey0] = YES; break; + + case SDLK_F1: keys[gvFunctionKey1] = YES; break; + case SDLK_F2: keys[gvFunctionKey2] = YES; break; + case SDLK_F3: keys[gvFunctionKey3] = YES; break; + case SDLK_F4: keys[gvFunctionKey4] = YES; break; + case SDLK_F5: keys[gvFunctionKey5] = YES; break; + case SDLK_F6: keys[gvFunctionKey6] = YES; break; + case SDLK_F7: keys[gvFunctionKey7] = YES; break; + case SDLK_F8: keys[gvFunctionKey8] = YES; break; + case SDLK_F9: keys[gvFunctionKey9] = YES; break; + case SDLK_F10: keys[gvFunctionKey10] = YES; break; + + case SDLK_BACKSPACE: + case SDLK_DELETE: + keys[gvDeleteKey] = YES; + break; + + case SDLK_LSHIFT: + case SDLK_RSHIFT: + shift = YES; + break; + + case SDLK_LCTRL: + case SDLK_RCTRL: + ctrl = YES; + break; + + case SDLK_LALT: + case SDLK_RALT: + opt = YES; + break; + + case SDLK_F12: + [self toggleScreenMode]; + break; + + case SDLK_ESCAPE: + if (shift) + { + SDL_FreeSurface(surface); + [gameController exitAppWithContext:@"Shift-escape pressed"]; + } + else + keys[27] = YES; + break; + default: + // Numerous cases not handled. + //OOLog(@"keys.test", @"Keydown scancode: %d", kbd_event->keysym.scancode); + ; + } + break; + + case SDL_KEYUP: + supressKeys = NO; // DJS + kbd_event = (SDL_KeyboardEvent*)&event; + +#define KEYCODE_UP_BOTH(a,b) do { \ +keys[a] = NO; keys[b] = NO; \ +} while (0) + +#if OOLITE_WINDOWS + /* + Windows locale patch - Enable backslash in win/UK + */ + if (EXPECT_NOT(kbd_event->keysym.scancode==86 && (keyboardMap==gvKeyboardAuto || keyboardMap==gvKeyboardUK))) + { + //non-US scancode. If in autodetect, we'll assume UK keyboard. + KEYCODE_UP_BOTH (124, 92); // | or \. + } + else switch (kbd_event->keysym.sym) { + + case SDLK_BACKSLASH: + if (keyboardMap==gvKeyboardUK ) + { + KEYCODE_UP_BOTH (126, 35); // ~ or # + } + else if (keyboardMap==gvKeyboardAuto || keyboardMap==gvKeyboardUS) + { + KEYCODE_UP_BOTH (124, 92); // | or \. + } + break; +#else + switch (kbd_event->keysym.sym) { + + case SDLK_BACKSLASH: KEYCODE_UP_BOTH (124, 92); break; // | or \. +#endif + + case SDLK_1: KEYCODE_UP_BOTH (33, gvNumberKey1); break; // ! and 1 +#if OOLITE_WINDOWS + /* + Windows locale patch - fix shift-2 & shift-3 + */ + case SDLK_2: + if (keyboardMap==gvKeyboardUK) + { + KEYCODE_UP_BOTH (34, gvNumberKey2); // " or 2 + } + else + { + KEYCODE_UP_BOTH (64, gvNumberKey2); // @ or 2 + } + break; + case SDLK_3: + if (keyboardMap==gvKeyboardUK) + { + KEYCODE_UP_BOTH (156, gvNumberKey3); // � or 3 + } + else + { + KEYCODE_UP_BOTH (35, gvNumberKey3); // # or 3 + } + break; +#else + case SDLK_2: KEYCODE_UP_BOTH (64, gvNumberKey2); break; // @ or 2 + case SDLK_3: KEYCODE_UP_BOTH (35, gvNumberKey3); break; // # or 3 +#endif + case SDLK_4: KEYCODE_UP_BOTH (36, gvNumberKey4); break; // $ or 4 + case SDLK_5: KEYCODE_UP_BOTH (37, gvNumberKey5); break; // % or 5 + case SDLK_6: KEYCODE_UP_BOTH (94, gvNumberKey6); break; // ^ or 6 + case SDLK_7: KEYCODE_UP_BOTH (38, gvNumberKey7); break; // & or 7 + case SDLK_8: KEYCODE_UP_BOTH (42, gvNumberKey8); break; // * or 8 + case SDLK_9: KEYCODE_UP_BOTH (40, gvNumberKey9); break; // ( or 9 + case SDLK_0: KEYCODE_UP_BOTH (41, gvNumberKey0); break; // ) or 0 + case SDLK_MINUS: KEYCODE_UP_BOTH (95, 45); break; // _ and - + case SDLK_COMMA: KEYCODE_UP_BOTH (60, 44); break; // < and , + case SDLK_EQUALS: KEYCODE_UP_BOTH (43, 61); break; // + and = + case SDLK_PERIOD: KEYCODE_UP_BOTH (62, 46); break; // > and . + case SDLK_SLASH: KEYCODE_UP_BOTH (63, 47); break; // ? and / + case SDLK_a: KEYCODE_UP_BOTH (65, 97); break; // A and a + case SDLK_b: KEYCODE_UP_BOTH (66, 98); break; // B and b + case SDLK_c: KEYCODE_UP_BOTH (67, 99); break; // C and c + case SDLK_d: KEYCODE_UP_BOTH (68, 100); break; // D and d + case SDLK_e: KEYCODE_UP_BOTH (69, 101); break; // E and e + case SDLK_f: KEYCODE_UP_BOTH (70, 102); break; // F and f + case SDLK_g: KEYCODE_UP_BOTH (71, 103); break; // G and g + case SDLK_h: KEYCODE_UP_BOTH (72, 104); break; // H and h + case SDLK_i: KEYCODE_UP_BOTH (73, 105); break; // I and i + case SDLK_j: KEYCODE_UP_BOTH (74, 106); break; // J and j + case SDLK_k: KEYCODE_UP_BOTH (75, 107); break; // K and k + case SDLK_l: KEYCODE_UP_BOTH (76, 108); break; // L and l + case SDLK_m: KEYCODE_UP_BOTH (77, 109); break; // M and m + case SDLK_n: KEYCODE_UP_BOTH (78, 110); break; // N and n + case SDLK_o: KEYCODE_UP_BOTH (79, 111); break; // O and o + case SDLK_p: KEYCODE_UP_BOTH (80, 112); break; // P and p + case SDLK_q: KEYCODE_UP_BOTH (81, 113); break; // Q and q + case SDLK_r: KEYCODE_UP_BOTH (82, 114); break; // R and r + case SDLK_s: KEYCODE_UP_BOTH (83, 115); break; // S and s + case SDLK_t: KEYCODE_UP_BOTH (84, 116); break; // T and t + case SDLK_u: KEYCODE_UP_BOTH (85, 117); break; // U and u + case SDLK_v: KEYCODE_UP_BOTH (86, 118); break; // V and v + case SDLK_w: KEYCODE_UP_BOTH (87, 119); break; // W and w + case SDLK_x: KEYCODE_UP_BOTH (88, 120); break; // X and x + case SDLK_y: KEYCODE_UP_BOTH (89, 121); break; // Y and y + case SDLK_z: KEYCODE_UP_BOTH (90, 122); break; // Z and z + case SDLK_SEMICOLON: KEYCODE_UP_BOTH(58, 59); break; // : and ; + //SDLK_BACKQUOTE and SDLK_HASH are special cases. No SDLK_ with code 126 exists. + case SDLK_HASH: if (!shift) keys[126] = NO; break; // ~ (really #) + case SDLK_BACKQUOTE: keys[96] = NO; break; // ` + case SDLK_QUOTE: keys[39] = NO; break; // ' + case SDLK_LEFTBRACKET: keys[91] = NO; break; // [ + case SDLK_RIGHTBRACKET: keys[93] = NO; break; // ] + case SDLK_HOME: keys[gvHomeKey] = NO; break; + case SDLK_END: keys[gvEndKey] = NO; break; + case SDLK_INSERT: keys[gvInsertKey] = NO; break; + case SDLK_PAGEUP: keys[gvPageUpKey] = NO; break; + case SDLK_PAGEDOWN: keys[gvPageDownKey] = NO; break; + case SDLK_SPACE: keys[32] = NO; break; + case SDLK_RETURN: keys[13] = NO; break; + case SDLK_TAB: keys[9] = NO; break; + case SDLK_UP: keys[gvArrowKeyUp] = NO; break; + case SDLK_DOWN: keys[gvArrowKeyDown] = NO; break; + case SDLK_LEFT: keys[gvArrowKeyLeft] = NO; break; + case SDLK_RIGHT: keys[gvArrowKeyRight] = NO; break; + + case SDLK_KP_MINUS: keys[45] = NO; break; // numeric keypad - key + case SDLK_KP_PLUS: keys[43] = NO; break; // numeric keypad + key + case SDLK_KP_ENTER: keys[13] = NO; break; + + case SDLK_KP_MULTIPLY: keys[42] = NO; break; // * + + case SDLK_KP1: keys[gvNumberPadKey1] = NO; break; + case SDLK_KP2: keys[gvNumberPadKey2] = NO; break; + case SDLK_KP3: keys[gvNumberPadKey3] = NO; break; + case SDLK_KP4: keys[gvNumberPadKey4] = NO; break; + case SDLK_KP5: keys[gvNumberPadKey5] = NO; break; + case SDLK_KP6: keys[gvNumberPadKey6] = NO; break; + case SDLK_KP7: keys[gvNumberPadKey7] = NO; break; + case SDLK_KP8: keys[gvNumberPadKey8] = NO; break; + case SDLK_KP9: keys[gvNumberPadKey9] = NO; break; + case SDLK_KP0: keys[gvNumberPadKey0] = NO; break; + + case SDLK_F1: keys[gvFunctionKey1] = NO; break; + case SDLK_F2: keys[gvFunctionKey2] = NO; break; + case SDLK_F3: keys[gvFunctionKey3] = NO; break; + case SDLK_F4: keys[gvFunctionKey4] = NO; break; + case SDLK_F5: keys[gvFunctionKey5] = NO; break; + case SDLK_F6: keys[gvFunctionKey6] = NO; break; + case SDLK_F7: keys[gvFunctionKey7] = NO; break; + case SDLK_F8: keys[gvFunctionKey8] = NO; break; + case SDLK_F9: keys[gvFunctionKey9] = NO; break; + case SDLK_F10: keys[gvFunctionKey10] = NO; break; + + case SDLK_BACKSPACE: + case SDLK_DELETE: + keys[gvDeleteKey] = NO; + break; + + case SDLK_LSHIFT: + case SDLK_RSHIFT: + shift = NO; + break; + + case SDLK_LCTRL: + case SDLK_RCTRL: + ctrl = NO; + break; + + case SDLK_LALT: + case SDLK_RALT: + opt = NO; + break; + + case SDLK_ESCAPE: + keys[27] = NO; + break; + + default: + // Numerous cases not handled. + //OOLog(@"keys.test", @"Keyup scancode: %d", kbd_event->keysym.scancode); + ; + } + break; + + case SDL_VIDEORESIZE: + { + SDL_ResizeEvent *rsevt=(SDL_ResizeEvent *)&event; + NSSize newSize=NSMakeSize(rsevt->w, rsevt->h); +#if OOLITE_WINDOWS + if (!fullScreen && updateContext) + { + if (saveSize == NO) + { + // event triggered by caption & frame + // next event will be a real resize. + saveSize = YES; + } + else + { + [self initialiseGLWithSize: newSize]; + [self saveWindowSize: newSize]; + } + } +#else + [self initialiseGLWithSize: newSize]; + [self saveWindowSize: newSize]; +#endif + // certain gui screens will require an immediate redraw after + // a resize event - Nikos 20140129 + if ([PlayerEntity sharedPlayer]) + { + [[PlayerEntity sharedPlayer] doGuiScreenResizeUpdates]; + } + break; + } + +#if OOLITE_WINDOWS + // if we minimize the window while in fullscreen (e.g. via + // Win+M or Win+DownArrow), restore the non-borderless window + // style before minimuzing and reset it when we return, otherwise + // there might be issues with the game window remaining stuck on + // top in some cases (seen with some Intel gfx chips). + // N.B. active event gain of zero means app is iconified + case SDL_ACTIVEEVENT: + { + if ((event.active.state & SDL_APPACTIVE) && fullScreen) + { + [self setWindowBorderless:event.active.gain]; + } + break; + } + + // need to track this because the user may move the game window + // to a secondary monitor, in which case we must potentially + // refresh the information displayed (e.g. Game Options screen) + // Nikos - 20140920 + case SDL_SYSWMEVENT: + { + switch (event.syswm.msg->msg) + { + case WM_WINDOWPOSCHANGING: + /* if we are in fullscreen mode we normally don't worry about having the window moved. + However, when using multiple monitors, one can use hotkey combinations to make the + window "jump" from one monitor to the next. We don't want this to happen, so if we + detect that our (fullscreen) window has moved, we immediately bring it back to its + original position. Nikos - 20140922 + */ + if (fullScreen) + { + RECT rDC; + + /* attempting to move our fullscreen window while in maximized state can freak + Windows out and the window may not return to its original position properly. + Solution: if such a move takes place, first change the window placement to + normal, move it normally, then restore its placement to maximized again. + Additionally, the last good known window position seems to be lost in such + a case. While at it, update also the coordinates of the non-maximized window + so that it can return to its original position - this is why we need lastGoodRect. + */ + WINDOWPLACEMENT wp; + wp.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(SDL_Window, &wp); + + GetWindowRect(SDL_Window, &rDC); + if (rDC.left != monitorInfo.rcMonitor.left || rDC.top != monitorInfo.rcMonitor.top) + { + BOOL fullScreenMaximized = NO; + if (wp.showCmd == SW_SHOWMAXIMIZED && !fullScreenMaximized) + { + fullScreenMaximized = YES; + wp.showCmd = SW_SHOWNORMAL; + SetWindowPlacement(SDL_Window, &wp); + } + + if (wp.showCmd != SW_SHOWMINIMIZED && wp.showCmd != SW_MINIMIZE) + { + MoveWindow(SDL_Window, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, + (int)viewSize.width, (int)viewSize.height, TRUE); + } + + if (fullScreenMaximized) + { + GetWindowPlacement(SDL_Window, &wp); + wp.showCmd = SW_SHOWMAXIMIZED; + CopyRect(&wp.rcNormalPosition, &lastGoodRect); + SetWindowPlacement(SDL_Window, &wp); + } + } + else if (wp.showCmd == SW_SHOWMAXIMIZED) + { + CopyRect(&wp.rcNormalPosition, &lastGoodRect); + SetWindowPlacement(SDL_Window, &wp); + } + } + // it is important that this gets done after we've dealt with possible fullscreen movements, + // because -doGuiScreenResizeUpdates does itself an update on current monitor + if ([PlayerEntity sharedPlayer]) + { + [[PlayerEntity sharedPlayer] doGuiScreenResizeUpdates]; + } + /* + deliberately no break statement here - moving or resizing the window changes its bounds + rectangle. Therefore we must check whether to clip the mouse or not inside the newly + updated rectangle, so just let it fall through + */ + + case WM_ACTIVATEAPP: + if(grabMouseStatus) [self grabMouseInsideGameWindow:YES]; + break; + + case WM_SETFOCUS: + /* + ` make sure that all modifier keys like Shift, Alt, Ctrl and Caps Lock + ` are set correctly to what they should be when we get focus. We have + ` to do it ourselves because SDL on Windows has problems with this + ` when focus change events occur, like e.g. Alt-Tab in/out of the + application + ` */ + [self resetSDLKeyModifiers]; + break; + + default: + ; + } + break; + } +#endif + + // caused by INTR or someone hitting close + case SDL_QUIT: + { + SDL_FreeSurface(surface); + [gameController exitAppWithContext:@"SDL_QUIT event received"]; + } + } + } + // check if enough time has passed since last use of the mousewheel and act + // if needed + if (timeNow >= timeSinceLastMouseWheel + OOMOUSEWHEEL_EVENTS_DELAY_INTERVAL) + { + _mouseWheelState = gvMouseWheelNeutral; + } +} + + +// DJS: String input handler. Since for SDL versions we're also handling +// freeform typing this has necessarily got more complex than the non-SDL +// versions. +- (void) handleStringInput: (SDL_KeyboardEvent *) kbd_event; +{ + SDLKey key=kbd_event->keysym.sym; + + // Del, Backspace + if((key == SDLK_BACKSPACE || key == SDLK_DELETE) && [typedString length] > 0) + { + // delete + [typedString deleteCharactersInRange:NSMakeRange([typedString length]-1, 1)]; + } + + isAlphabetKeyDown=NO; + + // TODO: a more flexible mechanism for max. string length ? + if([typedString length] < 40) + { + if (allowingStringInput == gvStringInputAlpha) + { + // inputAlpha - limited input for planet find screen + if(key >= SDLK_a && key <= SDLK_z) + { + isAlphabetKeyDown=YES; + [typedString appendFormat:@"%c", key]; + // if in inputAlpha, keep in lower case. + } + } + else + { + Uint16 unicode = kbd_event->keysym.unicode; + // printable range + if (unicode >= 32 && unicode <= 126) + { + if ((char)unicode != '/' || allowingStringInput == gvStringInputAll) + { + isAlphabetKeyDown=YES; + [typedString appendFormat:@"%c", unicode]; + } + } + } + } +} + + +// Full screen mode enumerator. +- (void) populateFullScreenModelist +{ + int i; + SDL_Rect **modes; + NSMutableDictionary *mode; + + screenSizes=[[NSMutableArray alloc] init]; + + // The default resolution (slot 0) is the resolution we are + // already in since this is guaranteed to work. + mode=[MyOpenGLView getNativeSize]; + [screenSizes addObject: mode]; + + modes=SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE); + if(modes == (SDL_Rect **)NULL) + { + OOLog(@"display.mode.list.none", @"%@", @"SDL didn't return any screen modes"); + return; + } + + if(modes == (SDL_Rect **)-1) + { + OOLog(@"display.mode.list.none", @"%@", @"SDL claims 'all resolutions available' which is unhelpful in the extreme"); + return; + } + + int lastw=[[mode objectForKey: kOODisplayWidth] intValue]; + int lasth=[[mode objectForKey: kOODisplayHeight] intValue]; + for(i=0; modes[i]; i++) + { + // SDL_ListModes often lists a mode several times, + // presumably because each mode has several refresh rates. + // But the modes pointer is an SDL_Rect which can't represent + // refresh rates. WHY!? + if(modes[i]->w != lastw || modes[i]->h != lasth) + { + // new resolution, save it + mode=[NSMutableDictionary dictionary]; + [mode setValue: [NSNumber numberWithInt: (int)modes[i]->w] + forKey: kOODisplayWidth]; + [mode setValue: [NSNumber numberWithInt: (int)modes[i]->h] + forKey: kOODisplayHeight]; + [mode setValue: [NSNumber numberWithInt: 0] + forKey: kOODisplayRefreshRate]; + if (![screenSizes containsObject:mode]) + { + [screenSizes addObject: mode]; + OOLog(@"display.mode.list", @"Added res %d x %d", modes[i]->w, modes[i]->h); + lastw=modes[i]->w; + lasth=modes[i]->h; + } + } + } +} + + +// Save and restore window sizes to/from defaults. +- (void) saveWindowSize: (NSSize) windowSize +{ + NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults]; + [defaults setInteger: (int)windowSize.width forKey: @"window_width"]; + [defaults setInteger: (int)windowSize.height forKey: @"window_height"]; + currentWindowSize=windowSize; +} + + +- (NSSize) loadWindowSize +{ + NSSize windowSize; + NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults]; + if([defaults objectForKey:@"window_width"] && [defaults objectForKey:@"window_height"]) + { + windowSize=NSMakeSize([defaults integerForKey: @"window_width"], + [defaults integerForKey: @"window_height"]); + } + else + { + windowSize=NSMakeSize(800, 600); + } + currentWindowSize=windowSize; + return windowSize; +} + + +- (int) loadFullscreenSettings +{ + currentSize=0; + int width=0, height=0, refresh=0; + unsigned i; + + NSArray* cmdline_arguments = [[NSProcessInfo processInfo] arguments]; + + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + if ([userDefaults objectForKey:@"display_width"]) + width = [userDefaults integerForKey:@"display_width"]; + if ([userDefaults objectForKey:@"display_height"]) + height = [userDefaults integerForKey:@"display_height"]; + if ([userDefaults objectForKey:@"display_refresh"]) + refresh = [userDefaults integerForKey:@"display_refresh"]; + if([userDefaults objectForKey:@"fullscreen"]) + fullScreen=[userDefaults boolForKey:@"fullscreen"]; + + // Check if -fullscreen or -windowed has been passed on the command line. If yes, + // set it regardless of what is set by .GNUstepDefaults. If both are found in the + // arguments list, the one that comes last wins. + for (i = 0; i < [cmdline_arguments count]; i++) + { + if ([[cmdline_arguments objectAtIndex:i] isEqual:@"-fullscreen"]) fullScreen = YES; + if ([[cmdline_arguments objectAtIndex:i] isEqual:@"-windowed"]) fullScreen = NO; + } + + if(width && height) + { + currentSize=[self findDisplayModeForWidth: width Height: height Refresh: refresh]; + return currentSize; + } + return currentSize; +} + + +- (int) findDisplayModeForWidth:(unsigned int) d_width Height:(unsigned int) d_height Refresh:(unsigned int) d_refresh +{ + int i, modeCount; + NSDictionary *mode; + unsigned int modeWidth, modeHeight, modeRefresh; + + modeCount = [screenSizes count]; + + for (i = 0; i < modeCount; i++) + { + mode = [screenSizes objectAtIndex: i]; + modeWidth = [[mode objectForKey: kOODisplayWidth] intValue]; + modeHeight = [[mode objectForKey: kOODisplayHeight] intValue]; + modeRefresh = [[mode objectForKey: kOODisplayRefreshRate] intValue]; + if ((modeWidth == d_width)&&(modeHeight == d_height)&&(modeRefresh == d_refresh)) + { + OOLog(@"display.mode.found", @"Found mode %@", mode); + return i; + } + } + + OOLog(@"display.mode.found.failed", @"Failed to find mode: width=%d height=%d refresh=%d", d_width, d_height, d_refresh); + OOLog(@"display.mode.found.failed.list", @"Contents of list: %@", screenSizes); + return 0; +} + + +- (NSSize) currentScreenSize +{ + NSDictionary *mode=[screenSizes objectAtIndex: currentSize]; + + if(mode) + { + return NSMakeSize([[mode objectForKey: kOODisplayWidth] intValue], + [[mode objectForKey: kOODisplayHeight] intValue]); + } + OOLog(@"display.mode.unknown", @"%@", @"Screen size unknown!"); + return NSMakeSize(800, 600); +} + + +- (void) setMouseInDeltaMode: (BOOL) inDelta +{ + mouseInDeltaMode=inDelta; +} + + +- (void) setGammaValue: (float) value +{ + if (value < 0.2f) value = 0.2f; + if (value > 4.0f) value = 4.0f; + + _gamma = value; + SDL_SetGamma(_gamma, _gamma, _gamma); + + [[NSUserDefaults standardUserDefaults] setFloat:_gamma forKey:@"gamma-value"]; +} + + +- (float) gammaValue +{ + return _gamma; +} + + +- (void) setFov:(float)value fromFraction:(BOOL)fromFraction +{ + _fov = fromFraction ? value : tan((value / 2) * M_PI / 180); +} + + +- (float) fov:(BOOL)inFraction +{ + return inFraction ? _fov : 2 * atan(_fov) * 180 / M_PI; +} + + +- (OOOpenGLMatrixManager *) getOpenGLMatrixManager +{ + return matrixManager; +} + + ++ (BOOL)pollShiftKey +{ + return 0 != (SDL_GetModState() & (KMOD_LSHIFT | KMOD_RSHIFT)); +} + + +#ifndef NDEBUG +- (void) dumpRGBAToFileNamed:(NSString *)name + bytes:(uint8_t *)bytes + width:(NSUInteger)width + height:(NSUInteger)height + rowBytes:(NSUInteger)rowBytes +{ + if (name == nil || bytes == NULL || width == 0 || height == 0 || rowBytes < width * 4) return; + + // use the snapshots directory + NSString *dumpFile = [[NSHomeDirectory() stringByAppendingPathComponent:@SAVEDIR] stringByAppendingPathComponent:@SNAPSHOTDIR]; + dumpFile = [dumpFile stringByAppendingPathComponent: [NSString stringWithFormat:@"%@.bmp", name]]; + + // convert transparency to black before saving to bmp + SDL_Surface* tmpSurface = SDL_CreateRGBSurfaceFrom(bytes, width, height, 32, rowBytes, 0xFF, 0xFF00, 0xFF0000, 0xFF000000); + SDL_SaveBMP(tmpSurface, [dumpFile UTF8String]); + SDL_FreeSurface(tmpSurface); +} + + +- (void) dumpRGBToFileNamed:(NSString *)name + bytes:(uint8_t *)bytes + width:(NSUInteger)width + height:(NSUInteger)height + rowBytes:(NSUInteger)rowBytes +{ + if (name == nil || bytes == NULL || width == 0 || height == 0 || rowBytes < width * 3) return; + + // use the snapshots directory + NSString *dumpFile = [[NSHomeDirectory() stringByAppendingPathComponent:@SAVEDIR] stringByAppendingPathComponent:@SNAPSHOTDIR]; + dumpFile = [dumpFile stringByAppendingPathComponent: [NSString stringWithFormat:@"%@.bmp", name]]; + + SDL_Surface* tmpSurface = SDL_CreateRGBSurfaceFrom(bytes, width, height, 24, rowBytes, 0xFF, 0xFF00, 0xFF0000, 0x0); + SDL_SaveBMP(tmpSurface, [dumpFile UTF8String]); + SDL_FreeSurface(tmpSurface); +} + + +- (void) dumpGrayToFileNamed:(NSString *)name + bytes:(uint8_t *)bytes + width:(NSUInteger)width + height:(NSUInteger)height + rowBytes:(NSUInteger)rowBytes +{ + if (name == nil || bytes == NULL || width == 0 || height == 0 || rowBytes < width) return; + + // use the snapshots directory + NSString *dumpFile = [[NSHomeDirectory() stringByAppendingPathComponent:@SAVEDIR] stringByAppendingPathComponent:@SNAPSHOTDIR]; + dumpFile = [dumpFile stringByAppendingPathComponent: [NSString stringWithFormat:@"%@.bmp", name]]; + + SDL_Surface* tmpSurface = SDL_CreateRGBSurfaceFrom(bytes, width, height, 8, rowBytes, 0xFF, 0xFF, 0xFF, 0x0); + SDL_SaveBMP(tmpSurface, [dumpFile UTF8String]); + SDL_FreeSurface(tmpSurface); +} + + +- (void) dumpGrayAlphaToFileNamed:(NSString *)name + bytes:(uint8_t *)bytes + width:(NSUInteger)width + height:(NSUInteger)height + rowBytes:(NSUInteger)rowBytes +{ + if (name == nil || bytes == NULL || width == 0 || height == 0 || rowBytes < width * 2) return; + + // use the snapshots directory + NSString *dumpFile = [[NSHomeDirectory() stringByAppendingPathComponent:@SAVEDIR] stringByAppendingPathComponent:@SNAPSHOTDIR]; + dumpFile = [dumpFile stringByAppendingPathComponent: [NSString stringWithFormat:@"%@.bmp", name]]; + + SDL_Surface* tmpSurface = SDL_CreateRGBSurfaceFrom(bytes, width, height, 16, rowBytes, 0xFF, 0xFF, 0xFF, 0xFF); + SDL_SaveBMP(tmpSurface, [dumpFile UTF8String]); + SDL_FreeSurface(tmpSurface); +} + + +- (void) dumpRGBAToRGBFileNamed:(NSString *)rgbName + andGrayFileNamed:(NSString *)grayName + bytes:(uint8_t *)bytes + width:(NSUInteger)width + height:(NSUInteger)height + rowBytes:(NSUInteger)rowBytes +{ + if ((rgbName == nil && grayName == nil) || bytes == NULL || width == 0 || height == 0 || rowBytes < width * 4) return; + + uint8_t *rgbBytes, *rgbPx, *grayBytes, *grayPx, *srcPx; + NSUInteger x, y; + BOOL trivalAlpha = YES; + + rgbPx = rgbBytes = malloc(width * height * 3); + if (rgbBytes == NULL) return; + + grayPx = grayBytes = malloc(width * height); + if (grayBytes == NULL) + { + free(rgbBytes); + return; + } + + for (y = 0; y < height; y++) + { + srcPx = bytes + rowBytes * y; + + for (x = 0; x < width; x++) + { + *rgbPx++ = *srcPx++; + *rgbPx++ = *srcPx++; + *rgbPx++ = *srcPx++; + trivalAlpha = trivalAlpha && ((*srcPx == 0xFF) || (*srcPx == 0x00)); // Look for any "interesting" pixels in alpha. + *grayPx++ = *srcPx++; + } + } + + [self dumpRGBToFileNamed:rgbName + bytes:rgbBytes + width:width + height:height + rowBytes:width * 3]; + free(rgbBytes); + + if (!trivalAlpha) + { + [self dumpGrayToFileNamed:grayName + bytes:grayBytes + width:width + height:height + rowBytes:width]; + } + free(grayBytes); +} +#endif + +@end diff --git a/src/SDL2/OOSDLJoystickManager.h b/src/SDL2/OOSDLJoystickManager.h new file mode 100644 index 000000000..1acb1f3bd --- /dev/null +++ b/src/SDL2/OOSDLJoystickManager.h @@ -0,0 +1,57 @@ +/* + +OOSDLJoystickManager.h +By Dylan Smith + +JoystickHandler handles joystick events from SDL, and translates them +into the appropriate action via a lookup table. The lookup table is +stored as a simple array rather than an ObjC dictionary since this +will be examined fairly often (once per frame during gameplay). + +Conversion methods are provided to convert between the internal +representation and an NSDictionary (for loading/saving user defaults +and for use in areas where portability/ease of coding are more important +than performance such as the GUI) + +Oolite +Copyright (C) 2004-2013 Giles C Williams and contributors + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +MA 02110-1301, USA. + +*/ + + + +#import +#import +#import "OOJoystickManager.h" + + + + +@interface OOSDLJoystickManager: OOJoystickManager +{ +@private + SDL_Joystick *stick[MAX_STICKS]; + NSUInteger stickCount; +} + +- (id) init; +- (BOOL) handleSDLEvent: (SDL_Event *)evt; +- (NSString *) nameOfJoystick:(NSUInteger)stickNumber; +- (int16_t) getAxisWithStick:(NSUInteger) stickNum axis:(NSUInteger) axisNum ; + +@end diff --git a/src/SDL2/OOSDLJoystickManager.m b/src/SDL2/OOSDLJoystickManager.m new file mode 100644 index 000000000..0f56d108b --- /dev/null +++ b/src/SDL2/OOSDLJoystickManager.m @@ -0,0 +1,113 @@ +/* + +OOSDLJoystickManager.m +By Dylan Smith + +Oolite +Copyright (C) 2004-2013 Giles C Williams and contributors + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +MA 02110-1301, USA. + +*/ + +#import "OOSDLJoystickManager.h" +#import "OOLogging.h" + +#define kOOLogUnconvertedNSLog @"unclassified.OOSDLJoystickManager" + + +@implementation OOSDLJoystickManager + +- (id) init +{ + int i; + + // Find and open the sticks. Make sure that we don't fail if more joysticks than MAX_STICKS are detected. + stickCount = SDL_NumJoysticks(); + OOLog(@"joystick.init", @"Number of joysticks detected: %ld", (long)stickCount); + if (stickCount > MAX_STICKS) + { + stickCount = MAX_STICKS; + OOLog(@"joystick.init", @"Number of joysticks detected exceeds maximum number of joysticks allowed. Setting number of active joysticks to %d.", MAX_STICKS); + } + if(stickCount) + { + for(i = 0; i < stickCount; i++) + { + // it's doubtful MAX_STICKS will ever get exceeded, but + // we need to be defensive. + if(i > MAX_STICKS) + break; + + stick[i]=SDL_JoystickOpen(i); + if(!stick[i]) + { + OOLog(@"joystick.init", @"Failed to open joystick #%d", i); + } + } + SDL_JoystickEventState(SDL_ENABLE); + } + return [super init]; +} + + +- (BOOL) handleSDLEvent: (SDL_Event *)evt +{ + BOOL rc=NO; + switch(evt->type) + { + case SDL_JOYAXISMOTION: + [self decodeAxisEvent: (JoyAxisEvent *)evt]; + rc=YES; + break; + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + [self decodeButtonEvent: (JoyButtonEvent *)evt]; + rc=YES; + break; + case SDL_JOYHATMOTION: + [self decodeHatEvent: (JoyHatEvent *)evt]; + rc=YES; + break; + default: + OOLog(@"handleSDLEvent.unknownEvent", @"%@", @"JoystickHandler was sent an event it doesn't know"); + } + return rc; +} + + +// Overrides + +- (NSUInteger) joystickCount +{ + return stickCount; +} + + +- (NSString *) nameOfJoystick:(NSUInteger)stickNumber +{ + return [NSString stringWithUTF8String:SDL_JoystickName((int)stickNumber)]; +} + + +- (int16_t) getAxisWithStick:(NSUInteger) stickNum axis:(NSUInteger) axisNum +{ + return SDL_JoystickGetAxis(stick[stickNum], axisNum); +} + + + +@end diff --git a/src/SDL2/main.m b/src/SDL2/main.m new file mode 100644 index 000000000..2fcf01bca --- /dev/null +++ b/src/SDL2/main.m @@ -0,0 +1,124 @@ +/* + +main.m + +Oolite +Copyright (C) 2004-2013 Giles C Williams and contributors + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +MA 02110-1301, USA. + +*/ + + +#ifdef GNUSTEP +#import +#if (GNUSTEP_BASE_MAJOR_VERSION == 1 && (GNUSTEP_BASE_MINOR_VERSION == 24 && GNUSTEP_BASE_SUBMINOR_VERSION >= 9) || (GNUSTEP_BASE_MINOR_VERSION > 24)) || (GNUSTEP_BASE_MAJOR_VERSION > 1) +#import +#endif +#import + +#import "GameController.h" +#import "OOLoggingExtended.h" + +#if OOLITE_WINDOWS +#include +#include +#endif +GameController* controller; +#endif + + +#ifndef NDEBUG +uint32_t gDebugFlags = 0; +#endif + + +int main(int argc, char *argv[]) +{ +#ifdef GNUSTEP + int i; + +#if (GNUSTEP_BASE_MAJOR_VERSION == 1 && (GNUSTEP_BASE_MINOR_VERSION == 24 && GNUSTEP_BASE_SUBMINOR_VERSION >= 9) || (GNUSTEP_BASE_MINOR_VERSION > 24)) || (GNUSTEP_BASE_MAJOR_VERSION > 1) + [NSDate class]; // See github issue #202 +#endif + +#if OOLITE_WINDOWS + + // Detect current working directory and set up GNUstep environment variables + #define MAX_PATH_LEN 256 + char currentWorkingDir[MAX_PATH_LEN]; + char envVarString[2 * MAX_PATH_LEN]; + GetCurrentDirectory(MAX_PATH_LEN - 1, currentWorkingDir); + + #define SETENVVAR(var, value) do {\ + sprintf(envVarString, "%s=%s", (var), (value));\ + SDL_putenv (envVarString);\ + } while (0); + + SETENVVAR("GNUSTEP_PATH_HANDLING", "windows"); + SETENVVAR("GNUSTEP_SYSTEM_ROOT", currentWorkingDir); + SETENVVAR("GNUSTEP_LOCAL_ROOT", currentWorkingDir); + SETENVVAR("GNUSTEP_NETWORK_ROOT", currentWorkingDir); + SETENVVAR("GNUSTEP_USERS_ROOT", currentWorkingDir); + SETENVVAR("HOMEPATH", currentWorkingDir); + + /* Windows amibtiously starts apps with the C library locale set to the + system locale rather than the "C" locale as per spec. Fixing here so + numbers don't behave strangely. + */ + setlocale(LC_ALL, "C"); +#endif + + // Need this because we're not using the default run loop's autorelease + // pool. + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + OOLoggingInit(); + + @try + { + // dajt: allocate and set the NSApplication delegate manually because not + // using NIB to do this + controller = [[GameController alloc] init]; + + // Release anything allocated during the controller initialisation that + // is no longer required. + + for (i = 1; i < argc; i++) + { + if (strcmp("-load", argv[i]) == 0) + { + i++; + if (i < argc) + [controller setPlayerFileToLoad: [NSString stringWithCString: argv[i]]]; + } + } + + DESTROY(pool); + + // Call applicationDidFinishLaunching because NSApp is not running in + // GNUstep port. + [controller applicationDidFinishLaunching: nil]; + } + @catch (NSException *exception) + { + OOLogERR(kOOLogException, @"Root exception handler hit - terminating. This is an internal error, please report it. Exception name: %@, reason: %@", [exception name], [exception reason]); + return EXIT_FAILURE; + } +#endif + + // never reached + return 0; +} From 9d2392e7793085c1f8c8a57150d3a24e880ff75c Mon Sep 17 00:00:00 2001 From: Steven Newbury Date: Thu, 29 Jun 2017 22:36:24 +0100 Subject: [PATCH 2/2] This is an initial (mostly working) port to SDL2. By default SDL1.2 is still used, but by chaning the config.make option, SDL2 is used instead as a build-time option. What works, what doesn't? Working fine: Joystick input Mouse input Keyboard input Sound Fullscreen mode-switching - now mostly working Issues: Fullscreen *mostly* (there is often some flickering sometimes, switching back and forth fixes it. Okay, I think this is might be related to the problems with the splash screen. There's a problem with the GL bounds I think. I'm not an OpenGL expert by any means, so I'm not sure what the problem is exactly. A bigger issue is changing fullscreen resolutions from the in game menu only properly resizes going down, going up leaves the "window" at the previous size but like the flickering, switching to windowed and back fixes it. Splash screen - code is there and no longer prevents startup. It works sometimes. I tried writing a test outside the game and it worked fine. Something is strange, under X the window doesn't get painted or contains random video memory, once the game starts rendering it's fine. It always works under wayland (with the Wayland SDL video backend), see below. Windows support is untested. I tried not to break it, or even change it where possible. Wayland - it works, even the splash screen! There were some issues resizing under Weston, possibly fixed now, lack of Server Side Decorations makes it tricky anyway! Worked fine under Enlightenment/Wayland. Android/iPhone, obscure devices ... Probably needs OpenGL ES ... maybe it just works like Wayland. There is a lot of code that could be simplified, in particular it's possible the SDL2 Windows support works...? Testers/reviewers more than welcome! Especially help with the GL issues mentioned above. --- GNUmakefile | 34 +- config.make | 1 + src/Core/OOJoystickManager.h | 1 - src/Core/OOOpenGLOnly.h | 4 + src/SDL2/MyOpenGLView.h | 5 +- src/SDL2/MyOpenGLView.m | 534 +++++++++++++++++--------------- src/SDL2/OOSDLJoystickManager.m | 2 +- 7 files changed, 324 insertions(+), 257 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 95b4b28e3..70969c206 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,9 +1,21 @@ include $(GNUSTEP_MAKEFILES)/common.make include config.make -vpath %.m src/SDL:src/Core:src/Core/Entities:src/Core/Materials:src/Core/Scripting:src/Core/OXPVerifier:src/Core/Debug -vpath %.h src/SDL:src/Core:src/Core/Entities:src/Core/Materials:src/Core/Scripting:src/Core/OXPVerifier:src/Core/Debug:src/Core/MiniZip -vpath %.c src/SDL:src/Core:src/BSDCompat:src/Core/Debug:src/Core/MiniZip +ifeq ($(OO_SDL2_ENABLED),yes) + OO_SDL_DIR = src/SDL2 + SDL_CFLAGS = `sdl2-config --cflags` -DOO_ENABLE_SDL2 + SDL_OBJCFLAGS = `sdl2-config --cflags` -DOO_ENABLE_SDL2 + SDL_OBJC_LIBS = -lSDL2main -lSDL2 +else + OO_SDL_DIR = src/SDL + SDL_CFLAGS = `sdl-config --cflags` + SDL_OBJCFLAGS = `sdl-config --cflags` + SDL_OBJC_LIBS = -lSDLmain -lSDL +endif + +vpath %.m $(OO_SDL_DIR):src/Core:src/Core/Entities:src/Core/Materials:src/Core/Scripting:src/Core/OXPVerifier:src/Core/Debug +vpath %.h $(OO_SDL_DIR):src/Core:src/Core/Entities:src/Core/Materials:src/Core/Scripting:src/Core/OXPVerifier:src/Core/Debug:src/Core/MiniZip +vpath %.c $(OO_SDL_DIR):src/Core:src/BSDCompat:src/Core/Debug:src/Core/MiniZip GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_USER_ROOT) ifeq ($(GNUSTEP_HOST_OS),mingw32) GNUSTEP_OBJ_DIR_NAME := $(GNUSTEP_OBJ_DIR_NAME).win @@ -23,11 +35,11 @@ ifeq ($(GNUSTEP_HOST_OS),mingw32) else JS_IMPORT_LIBRARY = js32ECMAv5 endif - ADDITIONAL_INCLUDE_DIRS = -I$(WIN_DEPS_DIR)/include -I$(JS_INC_DIR) -Isrc/SDL -Isrc/Core -Isrc/BSDCompat -Isrc/Core/Scripting -Isrc/Core/Materials -Isrc/Core/Entities -Isrc/Core/OXPVerifier -Isrc/Core/Debug -Isrc/Core/Tables -Isrc/Core/MiniZip - ADDITIONAL_OBJC_LIBS = -lglu32 -lopengl32 -lopenal32.dll -lpng14.dll -lmingw32 -lSDLmain -lSDL -lvorbisfile.dll -lvorbis.dll -lz -lgnustep-base -l$(JS_IMPORT_LIBRARY) -lwinmm -mwindows - ADDITIONAL_CFLAGS = -DWIN32 -DNEED_STRLCPY `sdl-config --cflags` -mtune=generic + ADDITIONAL_INCLUDE_DIRS = -I$(WIN_DEPS_DIR)/include -I$(JS_INC_DIR) -I$(OO_SDL_DIR) -Isrc/Core -Isrc/BSDCompat -Isrc/Core/Scripting -Isrc/Core/Materials -Isrc/Core/Entities -Isrc/Core/OXPVerifier -Isrc/Core/Debug -Isrc/Core/Tables -Isrc/Core/MiniZip + ADDITIONAL_OBJC_LIBS = -lglu32 -lopengl32 -lopenal32.dll -lpng14.dll -lmingw32 $(SDL_OBJC_LIBS) -lvorbisfile.dll -lvorbis.dll -lz -lgnustep-base -l$(JS_IMPORT_LIBRARY) -lwinmm -mwindows + ADDITIONAL_CFLAGS = -DWIN32 -DNEED_STRLCPY $(SDL_CFLAGS) -mtune=generic # note the vpath stuff above isn't working for me, so adding src/SDL and src/Core explicitly - ADDITIONAL_OBJCFLAGS = -DLOADSAVEGUI -DWIN32 -DXP_WIN -Wno-import -std=gnu99 `sdl-config --cflags` -mtune=generic + ADDITIONAL_OBJCFLAGS = -DLOADSAVEGUI -DWIN32 -DXP_WIN -Wno-import -std=gnu99 $(SDL_OBJCFLAGS) -mtune=generic ifneq ($(GNUSTEP_HOST_CPU),x86_64) ADDITIONAL_LDFLAGS += -Wl,--large-address-aware else @@ -49,10 +61,10 @@ else LIBJS_LIB_DIR = $(LIBJS_ROOT)/dist/lib LIBJS = js_static - ADDITIONAL_INCLUDE_DIRS = -I$(LIBJS_INC_DIR) -Isrc/SDL -Isrc/Core -Isrc/BSDCompat -Isrc/Core/Scripting -Isrc/Core/Materials -Isrc/Core/Entities -Isrc/Core/OXPVerifier -Isrc/Core/Debug -Isrc/Core/Tables -Isrc/Core/MiniZip - ADDITIONAL_OBJC_LIBS = -lGLU -lGL -lX11 -lSDL -lgnustep-base -l$(LIBJS) `nspr-config --libs` -lstdc++ -lopenal -lz -lvorbisfile - ADDITIONAL_CFLAGS = -Wall -DLINUX -DNEED_STRLCPY `sdl-config --cflags` `nspr-config --cflags` - ADDITIONAL_OBJCFLAGS = -Wall -std=gnu99 -DLOADSAVEGUI -DLINUX -DXP_UNIX -Wno-import `sdl-config --cflags` `nspr-config --cflags` + ADDITIONAL_INCLUDE_DIRS = -I$(LIBJS_INC_DIR) -I$(OO_SDL_DIR) -Isrc/Core -Isrc/BSDCompat -Isrc/Core/Scripting -Isrc/Core/Materials -Isrc/Core/Entities -Isrc/Core/OXPVerifier -Isrc/Core/Debug -Isrc/Core/Tables -Isrc/Core/MiniZip + ADDITIONAL_OBJC_LIBS = -lGLU -lGL -lX11 $(SDL_OBJC_LIBS) -lgnustep-base -l$(LIBJS) `nspr-config --libs` -lstdc++ -lopenal -lz -lvorbisfile + ADDITIONAL_CFLAGS = -Wall -DLINUX -DNEED_STRLCPY $(SDL_CFLAGS) `nspr-config --cflags` + ADDITIONAL_OBJCFLAGS = -Wall -std=gnu99 -DLOADSAVEGUI -DLINUX -DXP_UNIX -Wno-import $(SDL_OBJCFLAGS) `nspr-config --cflags` oolite_LIB_DIRS += -L$(LIBJS_LIB_DIR) -L/usr/X11R6/lib/ ifeq ($(use_deps),yes) diff --git a/config.make b/config.make index 297e7c3df..9d17c73c8 100644 --- a/config.make +++ b/config.make @@ -22,3 +22,4 @@ OO_LOCALIZATION_TOOLS = yes DEBUG_GRAPHVIZ = yes OO_JAVASCRIPT_TRACE = yes OO_FOV_INFLIGHT_CONTROL_ENABLED = no +OO_SDL2_ENABLED = no diff --git a/src/Core/OOJoystickManager.h b/src/Core/OOJoystickManager.h index 530783ed4..71cf285c5 100644 --- a/src/Core/OOJoystickManager.h +++ b/src/Core/OOJoystickManager.h @@ -151,7 +151,6 @@ enum { //SDL Abstracted constants #if OOLITE_SDL - #import enum diff --git a/src/Core/OOOpenGLOnly.h b/src/Core/OOOpenGLOnly.h index 367b4fbc7..f7f77fc50 100644 --- a/src/Core/OOOpenGLOnly.h +++ b/src/Core/OOOpenGLOnly.h @@ -57,6 +57,10 @@ MA 02110-1301, USA. // the standard SDL_opengl.h #include +#if OO_ENABLE_SDL2 +#include +#endif + // include an up-to-date version of glext.h #include diff --git a/src/SDL2/MyOpenGLView.h b/src/SDL2/MyOpenGLView.h index ecfb6dadd..19f1918ad 100644 --- a/src/SDL2/MyOpenGLView.h +++ b/src/SDL2/MyOpenGLView.h @@ -166,7 +166,8 @@ extern int debug; // Windowed mode NSSize currentWindowSize; - SDL_Surface *surface; + SDL_Window *mainWindow; + SDL_GLContext *glContext; BOOL showSplashScreen; @@ -176,7 +177,7 @@ extern int debug; BOOL updateContext; BOOL saveSize; unsigned keyboardMap; - HWND SDL_Window; + HWND Main_Window; MONITORINFOEX monitorInfo; RECT lastGoodRect; diff --git a/src/SDL2/MyOpenGLView.m b/src/SDL2/MyOpenGLView.m index e7933155e..903cb4d5a 100644 --- a/src/SDL2/MyOpenGLView.m +++ b/src/SDL2/MyOpenGLView.m @@ -58,17 +58,18 @@ + (NSMutableDictionary *) getNativeSize int nativeDisplayHeight = 768; #if OOLITE_LINUX - SDL_SysWMinfo dpyInfo; - SDL_VERSION(&dpyInfo.version); - if(SDL_GetWMInfo(&dpyInfo)) - { - nativeDisplayWidth = DisplayWidth(dpyInfo.info.x11.display, 0); - nativeDisplayHeight = DisplayHeight(dpyInfo.info.x11.display, 0); - OOLog(@"display.mode.list.native", @"X11 native resolution detected: %d x %d", nativeDisplayWidth, nativeDisplayHeight); - } - else - { - OOLog(@"display.mode.list.native.failed", @"%@", @"SDL_GetWMInfo failed, defaulting to 1024x768 for native size"); + SDL_DisplayMode dpyMode; + // This gets the native resolution of the primary display, there may be SDL_GetNumVideoDisplays() + // (TODO?) Support multiple outputs + if(SDL_GetDesktopDisplayMode(0, &dpyMode) == 0) + { + nativeDisplayWidth = dpyMode.w; + nativeDisplayHeight = dpyMode.h; + OOLog(@"display.mode.list.native", @"Native resolution detected: %d x %d", nativeDisplayWidth, nativeDisplayHeight); + } + else + { + OOLog(@"display.mode.list.native.failed", @"%@", @"SDL_GetDesktopDisplayMode failed, defaulting to 1024x768 for native size"); } #elif OOLITE_WINDOWS nativeDisplayWidth = GetSystemMetrics(SM_CXSCREEN); @@ -87,28 +88,28 @@ + (NSMutableDictionary *) getNativeSize - (void) createSurface { - // Changing these flags can trigger texture bugs. - const int videoModeFlags = SDL_HWSURFACE | SDL_OPENGL | SDL_RESIZABLE; + if (glContext == NULL) + glContext = SDL_GL_CreateContext(mainWindow); + if (glContext == NULL) + { + // we should have a valid GL context, but in case we don't + OOLogERR(@"display.mode.error",@"Unable to create GL context: %s",SDL_GetError()); + return; + } if (showSplashScreen) { #if OOLITE_WINDOWS // Pre setVideoMode adjustments. NSSize tmp = currentWindowSize; - ShowWindow(SDL_Window,SW_SHOWMINIMIZED); + ShowWindow(Main_Window,SW_SHOWMINIMIZED); updateContext = NO; //don't update the (splash screen) window yet! - // Initialise the SDL surface. (need custom SDL.dll) - surface = SDL_SetVideoMode(firstScreen.width, firstScreen.height, 32, videoModeFlags); + // Resize the SDL surface? + //SDL_SetWindowSize(mainWindow, (int)firstScreen.width, (int)firstScreen.height); // Post setVideoMode adjustments. currentWindowSize=tmp; -#else - // Changing the flags can trigger texture bugs. - surface = SDL_SetVideoMode(8, 8, 32, videoModeFlags); - if (!surface) { - return; - } #endif } else @@ -116,24 +117,22 @@ - (void) createSurface #if OOLITE_WINDOWS updateContext = YES; #endif - surface = SDL_SetVideoMode(firstScreen.width, firstScreen.height, 32, videoModeFlags); - if (!surface) { - return; - } - // blank the surface / go to fullscreen + // blank the output / go to fullscreen [self initialiseGLWithSize: firstScreen]; } + Uint16* gamma_ramp = (Uint16 *)SDL_malloc(256 * sizeof(Uint16)); _gamma = 1.0f; - if (SDL_SetGamma(_gamma, _gamma, _gamma) < 0 ) + SDL_CalculateGammaRamp(_gamma, gamma_ramp); + + if (SDL_SetWindowGammaRamp(mainWindow, gamma_ramp, gamma_ramp, gamma_ramp) < 0 ) { - char * errStr = SDL_GetError(); + const char * errStr = SDL_GetError(); OOLogWARN(@"gamma.set.failed", @"Could not set gamma: %s", errStr); // CIM: this doesn't seem to necessarily be fatal. Gamma settings // mostly work on mine despite this function failing. // exit(1); } - SDL_EnableUNICODE(1); } @@ -150,13 +149,14 @@ - (id) init NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; showSplashScreen = [prefs oo_boolForKey:@"splash-screen" defaultValue:YES]; BOOL vSyncPreference = [prefs oo_boolForKey:@"v-sync" defaultValue:YES]; - int vSyncValue; NSArray *arguments = nil; NSEnumerator *argEnum = nil; NSString *arg = nil; BOOL noSplashArgFound = NO; + SDL_Rect drawable; + arguments = [[NSProcessInfo processInfo] arguments]; // scan for splash screen overrides: -nosplash || --nosplash , -splash || --splash @@ -195,7 +195,18 @@ - (id) init return nil; } - SDL_putenv ("SDL_VIDEO_WINDOW_POS=center"); + // Generate the window caption, containing the version number and the date the executable was compiled. + static char windowCaption[128]; + NSString *versionString = [NSString stringWithFormat:@"Oolite v%@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]; + + strcpy (windowCaption, [versionString UTF8String]); + strcat (windowCaption, " - "__DATE__); + + mainWindow = SDL_CreateWindow(windowCaption, + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + 8, 8, + SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI); [OOJoystickManager setStickHandlerClass:[OOSDLJoystickManager class]]; // end TODO @@ -203,13 +214,6 @@ - (id) init [OOSound setUp]; if (![OOSound isSoundOK]) OOLog(@"sound.init", @"Sound system disabled."); - // Generate the window caption, containing the version number and the date the executable was compiled. - static char windowCaption[128]; - NSString *versionString = [NSString stringWithFormat:@"Oolite v%@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]; - - strcpy (windowCaption, [versionString UTF8String]); - strcat (windowCaption, " - "__DATE__); - SDL_WM_SetCaption (windowCaption, "Oolite"); // Set window title. #if OOLITE_WINDOWS // needed for enabling system window manager events, which is needed for handling window movement messages @@ -218,10 +222,10 @@ - (id) init //capture the window handle for later static SDL_SysWMinfo wInfo; SDL_VERSION(&wInfo.version); - SDL_GetWMInfo(&wInfo); - SDL_Window = wInfo.window; + SDL_GetWindowWMInfo(mainWindow, &wInfo); + Main_Window = wInfo.window; - // This must be inited after SDL_Window has been set - we need the main window handle in order to get monitor info + // This must be inited after Main_Window has been set - we need the main window handle in order to get monitor info if (![self getCurrentMonitorInfo:&monitorInfo]) { OOLogWARN(@"display.initGL.monitorInfoWarning", @"Could not get current monitor information."); @@ -236,8 +240,8 @@ - (id) init if (icon != NULL) { colorkey = SDL_MapRGB(icon->format, 128, 0, 128); - SDL_SetColorKey(icon, SDL_SRCCOLORKEY, colorkey); - SDL_WM_SetIcon(icon, NULL); + SDL_SetColorKey(icon, SDL_TRUE, colorkey); + SDL_SetWindowIcon(mainWindow, icon); } SDL_FreeSurface(icon); @@ -247,10 +251,6 @@ - (id) init SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 32); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - // V-sync settings - we set here, but can only verify after SDL_SetVideoMode has been called. - SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, vSyncPreference); // V-sync on by default. - OOLog(@"display.initGL", @"V-Sync %@requested.", vSyncPreference ? @"" : @"not "); - /* Multisampling significantly improves graphics quality with * basically no extra programming effort on our part, especially * for curved surfaces like the planet, but is also expensive - in @@ -279,13 +279,13 @@ - (id) init OOLog(@"display.initGL", @"%@", @"Trying 32-bit depth buffer"); [self createSurface]; - if (surface == NULL) + if (glContext == NULL) { // Retry with a 24-bit depth buffer OOLog(@"display.initGL", @"%@", @"Trying 24-bit depth buffer"); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); [self createSurface]; - if (surface == NULL) + if (glContext == NULL) { // Still not working? One last go... // Retry, allowing 16-bit contexts. @@ -300,10 +300,10 @@ - (id) init [self createSurface]; - if (surface == NULL) + if (glContext == NULL) { - char * errStr = SDL_GetError(); - OOLogERR(@"display.mode.error", @"Could not create display surface: %s", errStr); + const char * errStr = SDL_GetError(); + OOLogERR(@"display.mode.error", @"Could not create display GL context: %s", errStr); #if OOLITE_WINDOWS if (showSplashScreen) { @@ -316,16 +316,22 @@ - (id) init } } } + + SDL_GL_SetSwapInterval(vSyncPreference); // V-sync on by default. + OOLog(@"display.initGL", @"V-Sync %@requested.", vSyncPreference ? @"" : @"not "); + // Verify V-sync successfully set - report it if not - if (vSyncPreference && SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL, &vSyncValue) == -1) + if (vSyncPreference && SDL_GL_GetSwapInterval() == -1) { OOLogWARN(@"display.initGL", @"Could not enable V-Sync. Please check that your graphics driver supports the %@_swap_control extension.", OOLITE_WINDOWS ? @"WGL_EXT" : @"[GLX_SGI/GLX_MESA]"); } - bounds.size.width = surface->w; - bounds.size.height = surface->h; + SDL_GL_GetDrawableSize(mainWindow, &drawable.w, &drawable.h); + + bounds.size.width = drawable.w; + bounds.size.height = drawable.h; [self autoShowMouse]; @@ -353,25 +359,23 @@ - (void) endSplashScreen wasFullScreen = !fullScreen; updateContext = YES; - ShowWindow(SDL_Window,SW_RESTORE); + ShowWindow(Main_Window,SW_RESTORE); [self initialiseGLWithSize: firstScreen]; #else + [self setWindowBorderless:NO]; - int videoModeFlags = SDL_HWSURFACE | SDL_OPENGL; + SDL_SetWindowSize(mainWindow, (int)firstScreen.width, (int)firstScreen.height); + SDL_SetWindowResizable(mainWindow, SDL_TRUE); + SDL_SetWindowPosition(mainWindow, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED); //stop linux from auto centering on resize - videoModeFlags |= (fullScreen) ? SDL_FULLSCREEN : SDL_RESIZABLE; - surface = SDL_SetVideoMode(firstScreen.width, firstScreen.height, 32, videoModeFlags); + [self initialiseGLWithSize: firstScreen]; - if (!surface && fullScreen == YES) + if (!(SDL_GetWindowFlags(mainWindow) & SDL_WINDOW_FULLSCREEN) && fullScreen == YES) { [self setFullScreenMode: NO]; - videoModeFlags &= ~SDL_FULLSCREEN; - videoModeFlags |= SDL_RESIZABLE; - surface = SDL_SetVideoMode(currentWindowSize.width, currentWindowSize.height, 32, videoModeFlags); } - SDL_putenv ("SDL_VIDEO_WINDOW_POS=none"); //stop linux from auto centering on resize /* MKW 2011.11.11 * Eat all SDL events to gobble up any resize events while the @@ -404,10 +408,10 @@ - (void) dealloc if (screenSizes) [screenSizes release]; - if (surface != 0) + if (glContext != NULL) { - SDL_FreeSurface(surface); - surface = 0; + SDL_GL_DeleteContext(glContext); + glContext = NULL; } SDL_Quit(); @@ -631,13 +635,16 @@ - (void) drawRect:(NSRect)rect - (void) updateScreenWithVideoMode:(BOOL) v_mode { - if ((viewSize.width != surface->w)||(viewSize.height != surface->h)) // resized + int v_width, v_height; + + SDL_GetWindowSize(mainWindow, &v_width, &v_height); + if ((viewSize.width != v_width)||(viewSize.height != v_height)) // resized { #if OOLITE_LINUX m_glContextInitialized = NO; //probably not needed #endif - viewSize.width = surface->w; - viewSize.height = surface->h; + viewSize.width = v_width; + viewSize.height = v_height; } if (m_glContextInitialized == NO) @@ -645,7 +652,7 @@ - (void) updateScreenWithVideoMode:(BOOL) v_mode [self initialiseGLWithSize:viewSize useVideoMode:v_mode]; } - if (surface == 0) + if (glContext == NULL) return; // do all the drawing! @@ -658,7 +665,7 @@ - (void) updateScreenWithVideoMode:(BOOL) v_mode glClear( GL_COLOR_BUFFER_BIT); } - SDL_GL_SwapBuffers(); + SDL_GL_SwapWindow(mainWindow); } - (void) initSplashScreen @@ -668,6 +675,7 @@ - (void) initSplashScreen //too early for OOTexture! SDL_Surface *image=NULL; SDL_Rect dest; + SDL_Rect drawable; NSString *imagesDir = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Images"]; @@ -690,9 +698,9 @@ - (void) initSplashScreen dest.x = (GetSystemMetrics(SM_CXSCREEN)- dest.w)/2; dest.y = (GetSystemMetrics(SM_CYSCREEN)-dest.h)/2; - SetWindowLong(SDL_Window,GWL_STYLE,GetWindowLong(SDL_Window,GWL_STYLE) & ~WS_CAPTION & ~WS_THICKFRAME); - ShowWindow(SDL_Window,SW_RESTORE); - MoveWindow(SDL_Window,dest.x,dest.y,dest.w,dest.h,TRUE); + SetWindowLong(Main_Window,GWL_STYLE,GetWindowLong(Main_Window,GWL_STYLE) & ~WS_CAPTION & ~WS_THICKFRAME); + ShowWindow(Main_Window,SW_RESTORE); + MoveWindow(Main_Window,dest.x,dest.y,dest.w,dest.h,TRUE); #else @@ -704,20 +712,31 @@ - (void) initSplashScreen * Changed to SDL_NOFRAME, throwing caution to the wind - Kaks 2012.03.23 * Took SDL_NOFRAME out, since it still causes strange problems here - cim 2012.04.09 */ - surface = SDL_SetVideoMode(dest.w, dest.h, 32, SDL_HWSURFACE | SDL_OPENGL); + [self setWindowBorderless:YES]; + + SDL_SetWindowResizable(mainWindow, SDL_FALSE); + SDL_SetWindowSize(mainWindow, dest.w, dest.h); + SDL_SetWindowPosition(mainWindow, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); #endif + if(SDL_GL_MakeCurrent(mainWindow, glContext)) + { + OOLogERR(@"display.mode.error",@"Unable to make GL context current: %s",SDL_GetError()); + exit(1); + } + SDL_GL_GetDrawableSize(mainWindow, &drawable.w, &drawable.h); + OOSetOpenGLState(OPENGL_STATE_OVERLAY); - glViewport( 0, 0, dest.w, dest.h); + glViewport( 0, 0, drawable.w, drawable.h); glEnable( GL_TEXTURE_2D ); glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); glClear( GL_COLOR_BUFFER_BIT ); [matrixManager resetProjection]; - [matrixManager orthoLeft: 0.0f right: dest.w bottom: dest.h top: 0.0 near: -1.0 far: 1.0]; + [matrixManager orthoLeft: 0.0f right: drawable.w bottom: drawable.h top: 0.0 near: -1.0 far: 1.0]; [matrixManager syncProjection]; [matrixManager resetModelView]; @@ -766,15 +785,16 @@ - (void) initSplashScreen glTexCoord2i( 0, 0 ); glVertex2i( 0, 0 ); glTexCoord2i( 1, 0 ); - glVertex2i( dest.w, 0 ); + glVertex2i( drawable.w, 0 ); glTexCoord2i( 1, 1 ); - glVertex2i( dest.w, dest.h ); + glVertex2i( drawable.w, drawable.h ); glTexCoord2i( 0, 1 ); - glVertex2i( 0, dest.h ); + glVertex2i( 0, drawable.h ); glEnd(); - SDL_GL_SwapBuffers(); + SDL_GL_SwapWindow(mainWindow); + [matrixManager resetModelView]; [matrixManager syncModelView]; @@ -843,7 +863,7 @@ - (MONITORINFOEX) currentMonitorInfo - (BOOL) getCurrentMonitorInfo:(MONITORINFOEX *)mInfo { - HMONITOR hMon = MonitorFromWindow(SDL_Window, MONITOR_DEFAULTTOPRIMARY); + HMONITOR hMon = MonitorFromWindow(Main_Window, MONITOR_DEFAULTTOPRIMARY); ZeroMemory(mInfo, sizeof(MONITORINFOEX)); mInfo->cbSize = sizeof(MONITORINFOEX); if (GetMonitorInfo (hMon, (LPMONITORINFO)mInfo)) @@ -871,7 +891,7 @@ - (void) grabMouseInsideGameWindow:(BOOL) value if(value) { RECT gameWindowRect; - GetWindowRect(SDL_Window, &gameWindowRect); + GetWindowRect(Main_Window, &gameWindowRect); ClipCursor(&gameWindowRect); } else @@ -965,7 +985,7 @@ - (void) resetSDLKeyModifiers - (void) setWindowBorderless:(BOOL)borderless { - LONG currentWindowStyle = GetWindowLong(SDL_Window, GWL_STYLE); + LONG currentWindowStyle = GetWindowLong(Main_Window, GWL_STYLE); // window already has the desired style? if ((!borderless && (currentWindowStyle & WS_CAPTION)) || @@ -973,14 +993,14 @@ - (void) setWindowBorderless:(BOOL)borderless if (borderless) { - SetWindowLong(SDL_Window, GWL_STYLE, currentWindowStyle & ~WS_CAPTION & ~WS_THICKFRAME); + SetWindowLong(Main_Window, GWL_STYLE, currentWindowStyle & ~WS_CAPTION & ~WS_THICKFRAME); } else { - SetWindowLong(SDL_Window, GWL_STYLE, currentWindowStyle | + SetWindowLong(Main_Window, GWL_STYLE, currentWindowStyle | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX ); } - SetWindowPos(SDL_Window, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + SetWindowPos(Main_Window, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); } @@ -1019,7 +1039,18 @@ - (void) resetSDLKeyModifiers - (void) setWindowBorderless:(BOOL)borderless { - // do nothing on Linux + // window already has the desired style? + if ((!borderless && !(SDL_GetWindowFlags(mainWindow) & SDL_WINDOW_BORDERLESS)) || + (borderless && (SDL_GetWindowFlags(mainWindow) & SDL_WINDOW_BORDERLESS))) return; + + if (borderless) + { + SDL_SetWindowBordered(mainWindow, SDL_FALSE); + } + else + { + SDL_SetWindowBordered(mainWindow, SDL_TRUE); + } } #endif //OOLITE_WINDOWS @@ -1035,11 +1066,12 @@ - (void) initialiseGLWithSize:(NSSize) v_size useVideoMode:(BOOL) v_mode { #if OOLITE_LINUX NSSize oldViewSize = viewSize; + int width, height; #endif viewSize = v_size; - OOLog(@"display.initGL", @"Requested a new surface of %d x %d, %@.", (int)viewSize.width, (int)viewSize.height,(fullScreen ? @"fullscreen" : @"windowed")); - SDL_GL_SwapBuffers(); // clear the buffer before resize - + OOLog(@"display.initGL", @"Requested a new output of %d x %d, %@.", (int)viewSize.width, (int)viewSize.height,(fullScreen ? @"fullscreen" : @"windowed")); + SDL_GL_SwapWindow(mainWindow); // clear the buffer before resize + #if OOLITE_WINDOWS if (!updateContext) return; @@ -1050,7 +1082,7 @@ - (void) initialiseGLWithSize:(NSSize) v_size useVideoMode:(BOOL) v_mode WINDOWPLACEMENT windowPlacement; windowPlacement.length = sizeof(WINDOWPLACEMENT); - GetWindowPlacement(SDL_Window, &windowPlacement); + GetWindowPlacement(Main_Window, &windowPlacement); static BOOL lastWindowPlacementMaximized = NO; if (fullScreen && (windowPlacement.showCmd == SW_SHOWMAXIMIZED)) @@ -1097,12 +1129,12 @@ - (void) initialiseGLWithSize:(NSSize) v_size useVideoMode:(BOOL) v_mode CopyRect(&lastGoodRect, &windowPlacement.rcNormalPosition); // if maximized, switch to normal placement before going full screen windowPlacement.showCmd = SW_SHOWNORMAL; - SetWindowPlacement(SDL_Window, &windowPlacement); + SetWindowPlacement(Main_Window, &windowPlacement); } - else GetWindowRect(SDL_Window, &lastGoodRect); + else GetWindowRect(Main_Window, &lastGoodRect); // ok, can go fullscreen now - SetForegroundWindow(SDL_Window); + SetForegroundWindow(Main_Window); if (changingResolution) { if (ChangeDisplaySettingsEx(monitorInfo.szDevice, &settings, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL) @@ -1113,7 +1145,7 @@ - (void) initialiseGLWithSize:(NSSize) v_size useVideoMode:(BOOL) v_mode } } - MoveWindow(SDL_Window, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, (int)viewSize.width, (int)viewSize.height, TRUE); + MoveWindow(Main_Window, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, (int)viewSize.width, (int)viewSize.height, TRUE); if(!wasFullScreen) { [self setWindowBorderless:YES]; @@ -1135,10 +1167,10 @@ - (void) initialiseGLWithSize:(NSSize) v_size useVideoMode:(BOOL) v_mode [self getCurrentMonitorInfo: &monitorInfo]; if (lastWindowPlacementMaximized) CopyRect(&windowPlacement.rcNormalPosition, &lastGoodRect); - SetWindowPlacement(SDL_Window, &windowPlacement); + SetWindowPlacement(Main_Window, &windowPlacement); if (!lastWindowPlacementMaximized) { - MoveWindow(SDL_Window, (monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left - (int)viewSize.width)/2 + + MoveWindow(Main_Window, (monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left - (int)viewSize.width)/2 + monitorInfo.rcMonitor.left, (monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top - (int)viewSize.height)/2 + monitorInfo.rcMonitor.top, @@ -1148,13 +1180,13 @@ - (void) initialiseGLWithSize:(NSSize) v_size useVideoMode:(BOOL) v_mode [self setWindowBorderless:NO]; lastWindowPlacementMaximized = NO; - ShowWindow(SDL_Window,SW_SHOW); + ShowWindow(Main_Window,SW_SHOW); } // stop saveWindowSize from reacting to caption & frame if necessary saveSize = !wasFullScreen; - GetClientRect(SDL_Window, &wDC); + GetClientRect(Main_Window, &wDC); if (!fullScreen && (bounds.size.width != wDC.right - wDC.left || bounds.size.height != wDC.bottom - wDC.top)) @@ -1167,13 +1199,13 @@ - (void) initialiseGLWithSize:(NSSize) v_size useVideoMode:(BOOL) v_mode //after the splash screen has ended { RECT desiredClientRect; - GetWindowRect(SDL_Window, &desiredClientRect); + GetWindowRect(Main_Window, &desiredClientRect); AdjustWindowRect(&desiredClientRect, WS_CAPTION | WS_THICKFRAME, FALSE); - SetWindowPos(SDL_Window, NULL, desiredClientRect.left, desiredClientRect.top, + SetWindowPos(Main_Window, NULL, desiredClientRect.left, desiredClientRect.top, desiredClientRect.right - desiredClientRect.left, desiredClientRect.bottom - desiredClientRect.top, 0); } - GetClientRect(SDL_Window, &wDC); + GetClientRect(Main_Window, &wDC); viewSize.width = wDC.right - wDC.left; viewSize.height = wDC.bottom - wDC.top; } @@ -1189,42 +1221,47 @@ - (void) initialiseGLWithSize:(NSSize) v_size useVideoMode:(BOOL) v_mode wasFullScreen=fullScreen; #else //OOLITE_LINUX - - int videoModeFlags = SDL_HWSURFACE | SDL_OPENGL; - if (v_mode == NO) - videoModeFlags |= SDL_NOFRAME; + [self setWindowBorderless:YES]; if (fullScreen == YES) { - videoModeFlags |= SDL_FULLSCREEN; + SDL_DisplayMode target, closest; + SDL_SetWindowResizable(mainWindow, SDL_FALSE); + target.w = (int)viewSize.width; + target.h = (int)viewSize.height; + target.format = 0; + target.refresh_rate = 0; //FIXME: maybe replace viewSize with SDL_DisplayMode? + target.driverdata = 0; + if (SDL_GetClosestDisplayMode(0, &target, &closest) != NULL) + { + if(SDL_SetWindowDisplayMode(mainWindow, &closest) == 0) + { + OOLog(@"display.initGL", @"Fullscreen resolution set to %d x %d.", (int)viewSize.width, (int)viewSize.height); + if (SDL_SetWindowFullscreen(mainWindow, SDL_WINDOW_FULLSCREEN)) + { + [self setFullScreenMode: NO]; + viewSize = oldViewSize; + } + else + { + SDL_GL_GetDrawableSize(mainWindow, &width, &height); + bounds.size.width = viewSize.width = width; + bounds.size.height = viewSize.height = height; + } + } + } + } else { - videoModeFlags |= SDL_RESIZABLE; + SDL_SetWindowFullscreen(mainWindow, 0); + SDL_SetWindowResizable(mainWindow, SDL_TRUE); + SDL_GL_GetDrawableSize(mainWindow, &width, &height); + bounds.size.width = width; + bounds.size.height = height; } - surface = SDL_SetVideoMode((int)viewSize.width, (int)viewSize.height, 32, videoModeFlags); - - if (!surface && fullScreen == YES) - { - [self setFullScreenMode: NO]; - viewSize = oldViewSize; - videoModeFlags &= ~SDL_FULLSCREEN; - videoModeFlags |= SDL_RESIZABLE; - surface = SDL_SetVideoMode((int)viewSize.width, (int)viewSize.height, 32, videoModeFlags); - } - - if (!surface) - { - // we should always have a valid surface, but in case we don't - OOLogERR(@"display.mode.error",@"Unable to change display mode: %s",SDL_GetError()); - exit(1); - } - - bounds.size.width = surface->w; - bounds.size.height = surface->h; - #endif - OOLog(@"display.initGL", @"Created a new surface of %d x %d, %@.", (int)viewSize.width, (int)viewSize.height,(fullScreen ? @"fullscreen" : @"windowed")); + OOLog(@"display.initGL", @"Created a new output of %d x %d, %@.", (int)viewSize.width, (int)viewSize.height,(fullScreen ? @"fullscreen" : @"windowed")); if (viewSize.width/viewSize.height > 4.0/3.0) { display_z = 480.0 * bounds.size.width/bounds.size.height; @@ -1236,12 +1273,10 @@ - (void) initialiseGLWithSize:(NSSize) v_size useVideoMode:(BOOL) v_mode y_offset = 320.0 * bounds.size.height/bounds.size.width; } - if (surface != 0) SDL_FreeSurface(surface); - [self autoShowMouse]; [[self gameController] setUpBasicOpenGLStateWithSize:viewSize]; - SDL_GL_SwapBuffers(); + SDL_GL_SwapWindow(mainWindow); squareX = 0.0f; m_glContextInitialized = YES; @@ -1251,7 +1286,9 @@ - (void) initialiseGLWithSize:(NSSize) v_size useVideoMode:(BOOL) v_mode - (BOOL) snapShot:(NSString *)filename { BOOL snapShotOK = YES; - SDL_Surface* tmpSurface; + SDL_Surface *surface, *tmpSurface; + + surface = SDL_GetWindowSurface(mainWindow); // backup the previous directory NSString* originalDirectory = [[NSFileManager defaultManager] currentDirectoryPath]; @@ -1329,6 +1366,7 @@ - (BOOL) snapShot:(NSString *)filename } #endif SDL_FreeSurface(tmpSurface); + SDL_FreeSurface(surface); free(pixls); // return to the previous directory @@ -1532,7 +1570,7 @@ - (void) resetMouse [self setVirtualJoystick:0.0 :0.0]; if ([[PlayerEntity sharedPlayer] isMouseControlOn]) { - SDL_WarpMouse([self viewSize].width / 2, [self viewSize].height / 2); + SDL_WarpMouseInWindow(mainWindow, [self viewSize].width / 2, [self viewSize].height / 2); mouseWarped = YES; } } @@ -1659,13 +1697,15 @@ - (void) setKeyboardTo: (NSString *) value - (void)pollControls { SDL_Event event; - SDL_KeyboardEvent *kbd_event; - SDL_MouseButtonEvent *mbtn_event; - SDL_MouseMotionEvent *mmove_event; - int mxdelta, mydelta; + SDL_KeyboardEvent *kbd_event; + SDL_MouseButtonEvent *mbtn_event; + SDL_MouseWheelEvent *mwheel_event; + SDL_WindowEvent *window_event; + SDL_MouseMotionEvent *mmove_event; + int mxdelta, mydelta; float mouseVirtualStickSensitivityX = viewSize.width * MOUSEVIRTUALSTICKSENSITIVITYFACTOR; float mouseVirtualStickSensitivityY = viewSize.height * MOUSEVIRTUALSTICKSENSITIVITYFACTOR; - NSTimeInterval timeNow = [NSDate timeIntervalSinceReferenceDate]; + NSTimeInterval timeNow = [NSDate timeIntervalSinceReferenceDate]; while (SDL_PollEvent(&event)) @@ -1695,13 +1735,6 @@ reset the virtual joystick (mouse) coordinates, we need to send a WarpMouse call */ [self resetMouse]; // Will set mouseWarped to YES break; - // mousewheel stuff - case SDL_BUTTON_WHEELUP: - _mouseWheelState = gvMouseWheelUp; - break; - case SDL_BUTTON_WHEELDOWN: - _mouseWheelState = gvMouseWheelDown; - break; } break; @@ -1718,17 +1751,23 @@ reset the virtual joystick (mouse) coordinates, we need to send a WarpMouse call } keys[gvMouseLeftButton] = NO; } + break; + + case SDL_MOUSEWHEEL: + mwheel_event = (SDL_MouseWheelEvent*)&event; /* - Mousewheel handling - just note time since last use here and mark as inactive, - if needed, at the end of this method. Note that the mousewheel button up event is - kind of special, as in, it is sent at the same time as its corresponding mousewheel - button down one - Nikos 20140809 + Mousewheel handling - SDL2 Supports delta movement of mouse wheel. + For now just emulate the old behaviour. */ - if (mbtn_event->button == SDL_BUTTON_WHEELUP || mbtn_event->button == SDL_BUTTON_WHEELDOWN) + if (mwheel_event->y != 0) { NSTimeInterval timeBetweenMouseWheels = timeNow - timeSinceLastMouseWheel; timeSinceLastMouseWheel += timeBetweenMouseWheels; } + if (mwheel_event->y <0) + _mouseWheelState = gvMouseWheelDown; + else + _mouseWheelState = gvMouseWheelUp; break; case SDL_MOUSEMOTION: @@ -1938,16 +1977,16 @@ reset the virtual joystick (mouse) coordinates, we need to send a WarpMouse call case SDLK_KP_MULTIPLY: keys[42] = YES; break; // * - case SDLK_KP1: keys[gvNumberPadKey1] = YES; break; - case SDLK_KP2: keys[gvNumberPadKey2] = YES; break; - case SDLK_KP3: keys[gvNumberPadKey3] = YES; break; - case SDLK_KP4: keys[gvNumberPadKey4] = YES; break; - case SDLK_KP5: keys[gvNumberPadKey5] = YES; break; - case SDLK_KP6: keys[gvNumberPadKey6] = YES; break; - case SDLK_KP7: keys[gvNumberPadKey7] = YES; break; - case SDLK_KP8: keys[gvNumberPadKey8] = YES; break; - case SDLK_KP9: keys[gvNumberPadKey9] = YES; break; - case SDLK_KP0: keys[gvNumberPadKey0] = YES; break; + case SDLK_KP_1: keys[gvNumberPadKey1] = YES; break; + case SDLK_KP_2: keys[gvNumberPadKey2] = YES; break; + case SDLK_KP_3: keys[gvNumberPadKey3] = YES; break; + case SDLK_KP_4: keys[gvNumberPadKey4] = YES; break; + case SDLK_KP_5: keys[gvNumberPadKey5] = YES; break; + case SDLK_KP_6: keys[gvNumberPadKey6] = YES; break; + case SDLK_KP_7: keys[gvNumberPadKey7] = YES; break; + case SDLK_KP_8: keys[gvNumberPadKey8] = YES; break; + case SDLK_KP_9: keys[gvNumberPadKey9] = YES; break; + case SDLK_KP_0: keys[gvNumberPadKey0] = YES; break; case SDLK_F1: keys[gvFunctionKey1] = YES; break; case SDLK_F2: keys[gvFunctionKey2] = YES; break; @@ -1987,7 +2026,7 @@ reset the virtual joystick (mouse) coordinates, we need to send a WarpMouse call case SDLK_ESCAPE: if (shift) { - SDL_FreeSurface(surface); + if (glContext != NULL) SDL_GL_DeleteContext(glContext); [gameController exitAppWithContext:@"Shift-escape pressed"]; } else @@ -2128,16 +2167,16 @@ reset the virtual joystick (mouse) coordinates, we need to send a WarpMouse call case SDLK_KP_MULTIPLY: keys[42] = NO; break; // * - case SDLK_KP1: keys[gvNumberPadKey1] = NO; break; - case SDLK_KP2: keys[gvNumberPadKey2] = NO; break; - case SDLK_KP3: keys[gvNumberPadKey3] = NO; break; - case SDLK_KP4: keys[gvNumberPadKey4] = NO; break; - case SDLK_KP5: keys[gvNumberPadKey5] = NO; break; - case SDLK_KP6: keys[gvNumberPadKey6] = NO; break; - case SDLK_KP7: keys[gvNumberPadKey7] = NO; break; - case SDLK_KP8: keys[gvNumberPadKey8] = NO; break; - case SDLK_KP9: keys[gvNumberPadKey9] = NO; break; - case SDLK_KP0: keys[gvNumberPadKey0] = NO; break; + case SDLK_KP_1: keys[gvNumberPadKey1] = NO; break; + case SDLK_KP_2: keys[gvNumberPadKey2] = NO; break; + case SDLK_KP_3: keys[gvNumberPadKey3] = NO; break; + case SDLK_KP_4: keys[gvNumberPadKey4] = NO; break; + case SDLK_KP_5: keys[gvNumberPadKey5] = NO; break; + case SDLK_KP_6: keys[gvNumberPadKey6] = NO; break; + case SDLK_KP_7: keys[gvNumberPadKey7] = NO; break; + case SDLK_KP_8: keys[gvNumberPadKey8] = NO; break; + case SDLK_KP_9: keys[gvNumberPadKey9] = NO; break; + case SDLK_KP_0: keys[gvNumberPadKey0] = NO; break; case SDLK_F1: keys[gvFunctionKey1] = NO; break; case SDLK_F2: keys[gvFunctionKey2] = NO; break; @@ -2181,34 +2220,43 @@ reset the virtual joystick (mouse) coordinates, we need to send a WarpMouse call } break; - case SDL_VIDEORESIZE: + case SDL_WINDOWEVENT: { - SDL_ResizeEvent *rsevt=(SDL_ResizeEvent *)&event; - NSSize newSize=NSMakeSize(rsevt->w, rsevt->h); -#if OOLITE_WINDOWS - if (!fullScreen && updateContext) - { - if (saveSize == NO) - { - // event triggered by caption & frame - // next event will be a real resize. - saveSize = YES; - } - else + window_event = (SDL_WindowEvent*)&event; + switch (window_event->event) { + case SDL_WINDOWEVENT_RESIZED: + case SDL_WINDOWEVENT_SIZE_CHANGED: { - [self initialiseGLWithSize: newSize]; - [self saveWindowSize: newSize]; - } - } + NSSize newSize=NSMakeSize(window_event->data1, window_event->data2); +#if OOLITE_WINDOWS + if (!fullScreen && updateContext)( { + if (saveSize == NO) + { + // event triggered by caption & frame + // next event will be a real resize. + saveSize = YES; + } + else + { + [self initialiseGLWithSize: newSize]; + [self saveWindowSize: newSize]; + } + } #else - [self initialiseGLWithSize: newSize]; - [self saveWindowSize: newSize]; + if (SDL_GetWindowFlags(mainWindow) & SDL_WINDOW_RESIZABLE) + { + [self initialiseGLWithSize: newSize]; + [self saveWindowSize: newSize]; + } #endif - // certain gui screens will require an immediate redraw after - // a resize event - Nikos 20140129 - if ([PlayerEntity sharedPlayer]) - { - [[PlayerEntity sharedPlayer] doGuiScreenResizeUpdates]; + // certain gui screens will require an immediate redraw after + // a resize event - Nikos 20140129 + if ([PlayerEntity sharedPlayer]) + { + [[PlayerEntity sharedPlayer] doGuiScreenResizeUpdates]; + } + } + break; } break; } @@ -2258,9 +2306,9 @@ detect that our (fullscreen) window has moved, we immediately bring it back to i */ WINDOWPLACEMENT wp; wp.length = sizeof(WINDOWPLACEMENT); - GetWindowPlacement(SDL_Window, &wp); + GetWindowPlacement(Main_Window, &wp); - GetWindowRect(SDL_Window, &rDC); + GetWindowRect(Main_Window, &rDC); if (rDC.left != monitorInfo.rcMonitor.left || rDC.top != monitorInfo.rcMonitor.top) { BOOL fullScreenMaximized = NO; @@ -2268,27 +2316,27 @@ detect that our (fullscreen) window has moved, we immediately bring it back to i { fullScreenMaximized = YES; wp.showCmd = SW_SHOWNORMAL; - SetWindowPlacement(SDL_Window, &wp); + SetWindowPlacement(Main_Window, &wp); } if (wp.showCmd != SW_SHOWMINIMIZED && wp.showCmd != SW_MINIMIZE) { - MoveWindow(SDL_Window, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, + MoveWindow(Main_Window, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, (int)viewSize.width, (int)viewSize.height, TRUE); } if (fullScreenMaximized) { - GetWindowPlacement(SDL_Window, &wp); + GetWindowPlacement(Main_Window, &wp); wp.showCmd = SW_SHOWMAXIMIZED; CopyRect(&wp.rcNormalPosition, &lastGoodRect); - SetWindowPlacement(SDL_Window, &wp); + SetWindowPlacement(Main_Window, &wp); } } else if (wp.showCmd == SW_SHOWMAXIMIZED) { CopyRect(&wp.rcNormalPosition, &lastGoodRect); - SetWindowPlacement(SDL_Window, &wp); + SetWindowPlacement(Main_Window, &wp); } } // it is important that this gets done after we've dealt with possible fullscreen movements, @@ -2328,7 +2376,7 @@ detect that our (fullscreen) window has moved, we immediately bring it back to i // caused by INTR or someone hitting close case SDL_QUIT: { - SDL_FreeSurface(surface); + if (glContext != NULL) SDL_GL_DeleteContext(glContext); [gameController exitAppWithContext:@"SDL_QUIT event received"]; } } @@ -2347,7 +2395,7 @@ detect that our (fullscreen) window has moved, we immediately bring it back to i // versions. - (void) handleStringInput: (SDL_KeyboardEvent *) kbd_event; { - SDLKey key=kbd_event->keysym.sym; + SDL_Keycode key=kbd_event->keysym.sym; // Del, Backspace if((key == SDLK_BACKSPACE || key == SDLK_DELETE) && [typedString length] > 0) @@ -2373,7 +2421,7 @@ - (void) handleStringInput: (SDL_KeyboardEvent *) kbd_event; } else { - Uint16 unicode = kbd_event->keysym.unicode; + Uint16 unicode = kbd_event->keysym.sym; // printable range if (unicode >= 32 && unicode <= 126) { @@ -2392,7 +2440,9 @@ - (void) handleStringInput: (SDL_KeyboardEvent *) kbd_event; - (void) populateFullScreenModelist { int i; - SDL_Rect **modes; + static int display_num = 0; // TODO: Support multiple displays? + SDL_DisplayMode display_mode; + int mode_count; NSMutableDictionary *mode; screenSizes=[[NSMutableArray alloc] init]; @@ -2402,49 +2452,45 @@ - (void) populateFullScreenModelist mode=[MyOpenGLView getNativeSize]; [screenSizes addObject: mode]; - modes=SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE); - if(modes == (SDL_Rect **)NULL) + mode_count = SDL_GetNumDisplayModes(display_num); + if (mode_count < 1) { - OOLog(@"display.mode.list.none", @"%@", @"SDL didn't return any screen modes"); - return; - } - - if(modes == (SDL_Rect **)-1) - { - OOLog(@"display.mode.list.none", @"%@", @"SDL claims 'all resolutions available' which is unhelpful in the extreme"); + OOLog(@"display.mode.list.none", @"SDL didn't return any screen modes"); return; } + // SDL_GetDisplayMode often lists a mode several times, + // because each mode has several refresh rates. + // SDL2 uses SDL_DisplayMode which does support + // refresh rates unlike SDL1 which didn't. This needs + // quite a few code adjustments. TODO. int lastw=[[mode objectForKey: kOODisplayWidth] intValue]; int lasth=[[mode objectForKey: kOODisplayHeight] intValue]; - for(i=0; modes[i]; i++) - { - // SDL_ListModes often lists a mode several times, - // presumably because each mode has several refresh rates. - // But the modes pointer is an SDL_Rect which can't represent - // refresh rates. WHY!? - if(modes[i]->w != lastw || modes[i]->h != lasth) + for (i = 0; i < mode_count; ++i) { + if (SDL_GetDisplayMode(display_num, i, &display_mode) == 0) { - // new resolution, save it - mode=[NSMutableDictionary dictionary]; - [mode setValue: [NSNumber numberWithInt: (int)modes[i]->w] - forKey: kOODisplayWidth]; - [mode setValue: [NSNumber numberWithInt: (int)modes[i]->h] - forKey: kOODisplayHeight]; - [mode setValue: [NSNumber numberWithInt: 0] - forKey: kOODisplayRefreshRate]; - if (![screenSizes containsObject:mode]) + if(display_mode.w != lastw || display_mode.h != lasth) { - [screenSizes addObject: mode]; - OOLog(@"display.mode.list", @"Added res %d x %d", modes[i]->w, modes[i]->h); - lastw=modes[i]->w; - lasth=modes[i]->h; + // new resolution, save it + mode=[NSMutableDictionary dictionary]; + [mode setValue: [NSNumber numberWithInt: display_mode.w] + forKey: kOODisplayWidth]; + [mode setValue: [NSNumber numberWithInt: display_mode.h] + forKey: kOODisplayHeight]; + [mode setValue: [NSNumber numberWithInt: 0] + forKey: kOODisplayRefreshRate]; + if (![screenSizes containsObject:mode]) + { + [screenSizes addObject: mode]; + OOLog(@"display.mode.list", @"Added res %d x %d", display_mode.w, display_mode.h); + lastw=display_mode.w; + lasth=display_mode.h; + } } } } } - // Save and restore window sizes to/from defaults. - (void) saveWindowSize: (NSSize) windowSize { @@ -2558,11 +2604,15 @@ - (void) setMouseInDeltaMode: (BOOL) inDelta - (void) setGammaValue: (float) value { + Uint16* gamma_ramp; + if (value < 0.2f) value = 0.2f; if (value > 4.0f) value = 4.0f; + gamma_ramp = (Uint16 *)SDL_malloc(256 * sizeof(Uint16)); _gamma = value; - SDL_SetGamma(_gamma, _gamma, _gamma); + SDL_CalculateGammaRamp(_gamma, gamma_ramp); + SDL_SetWindowGammaRamp(mainWindow, gamma_ramp, gamma_ramp, gamma_ramp); [[NSUserDefaults standardUserDefaults] setFloat:_gamma forKey:@"gamma-value"]; } diff --git a/src/SDL2/OOSDLJoystickManager.m b/src/SDL2/OOSDLJoystickManager.m index 0f56d108b..1fc8216af 100644 --- a/src/SDL2/OOSDLJoystickManager.m +++ b/src/SDL2/OOSDLJoystickManager.m @@ -99,7 +99,7 @@ - (NSUInteger) joystickCount - (NSString *) nameOfJoystick:(NSUInteger)stickNumber { - return [NSString stringWithUTF8String:SDL_JoystickName((int)stickNumber)]; + return [NSString stringWithUTF8String:SDL_JoystickNameForIndex((int)stickNumber)]; }