From 638dc113f8c05f121d50e68f68c4e86c130756a4 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Fri, 4 Dec 2015 18:20:09 +0100 Subject: IOS: Create two targets for old iPhone (iOS <= 6) and new one (iOS >= 7) The "iphone" backend is the support for the old iPhones. The "ios7" backend is for the new iPhones. --- backends/platform/ios7/README.md | 66 +++ backends/platform/ios7/iphone_common.h | 111 ++++ backends/platform/ios7/iphone_keyboard.h | 44 ++ backends/platform/ios7/iphone_keyboard.mm | 98 ++++ backends/platform/ios7/iphone_main.mm | 154 ++++++ backends/platform/ios7/iphone_video.h | 109 ++++ backends/platform/ios7/iphone_video.mm | 821 ++++++++++++++++++++++++++++++ backends/platform/ios7/module.mk | 15 + backends/platform/ios7/osys_events.cpp | 562 ++++++++++++++++++++ backends/platform/ios7/osys_main.cpp | 344 +++++++++++++ backends/platform/ios7/osys_main.h | 224 ++++++++ backends/platform/ios7/osys_sound.cpp | 105 ++++ backends/platform/ios7/osys_video.mm | 503 ++++++++++++++++++ 13 files changed, 3156 insertions(+) create mode 100644 backends/platform/ios7/README.md create mode 100644 backends/platform/ios7/iphone_common.h create mode 100644 backends/platform/ios7/iphone_keyboard.h create mode 100644 backends/platform/ios7/iphone_keyboard.mm create mode 100644 backends/platform/ios7/iphone_main.mm create mode 100644 backends/platform/ios7/iphone_video.h create mode 100644 backends/platform/ios7/iphone_video.mm create mode 100644 backends/platform/ios7/module.mk create mode 100644 backends/platform/ios7/osys_events.cpp create mode 100644 backends/platform/ios7/osys_main.cpp create mode 100644 backends/platform/ios7/osys_main.h create mode 100644 backends/platform/ios7/osys_sound.cpp create mode 100644 backends/platform/ios7/osys_video.mm (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/README.md b/backends/platform/ios7/README.md new file mode 100644 index 0000000000..0e22e6d2bd --- /dev/null +++ b/backends/platform/ios7/README.md @@ -0,0 +1,66 @@ +# ScummVM for iOS 7.1+ # + +This is a quick fix of the latest ScummVM (1.8.0) for iOS 7.1. It has been tested on real iPhone 6S+, and iPad Pro, and also on all the available Xcode simulators. + +I tried to use all the latest iOS features to replace the old code. For instance, it uses gesture recognizers most of the time, it supports the new iPhones 6 / 6+ / 6s / 6s+ resolution, and you can copy your game files using iTunes. + +## Compilation ## + +First, clone the repository: +``` +$ git clone -b ios-fix --recursive https://github.com/bSr43/scummvm.git +``` + +### Compilation from Xcode ### + +This is the recommended way to compile ScummVM, and the only one which makes it possible to run ScummVM on a non-jailbroken device! + +The next step is to compile the **create_project** tool. Open the Xcode project you'll found in the **devtools/create\_project/xcode/** directory. Once compiled, copy the binary somewhere in your *PATH*, and create a **build** directory somewhere on your harddisk. It is recommended to create this directory next to the cloned repository (they share the same parent). + +Execute the following commands in a terminal: +``` +$ cd path_to_the_build_directory +$ create_project path_to_scummvm_repository --xcode --disable-mad --disable-jpeg --disable-bink --disable-scalers --disable-hqscalers --disable-16bit --disable-mt32emu --disable-nasm --disable-opengl --disable-theora --disable-taskbar +``` + +This will create an Xcode project for ScummVM, for both the OS X, and the iOS target. + +Now, download the external libraries from http://bsr43.free.fr/scummvm/ScummVM-iOS-libraries.zip. Unzip the archive in your **build** directory. Please make sure that the **lib**, and **include** directories are at the root of the **build** directory, not in a subdirectory. + +Now, your **build** directory should contain: +* a generated **engines** directory, +* a generated **scummvm.xcodeproj** project, +* an **include** directory, +* a **lib** directory. + +You are ready to compile ScummVM: open the **scummvm.xcodeproj** project, and build it. + +### Compilation from command line ### + +For jailbroken devices, it is also possible to compile the project from command line. You'll need some tools, like **ldid**, to fake the code signature. + +Open a terminal, and execute the following commands: +``` +$ cd path_to_the_scummvm_sources +$ SDKROOT=$(xcrun --sdk iphoneos --show-sdk-path) CC=clang CXX=clang++ ./configure --host=iphone --disable-scalers --disable-mt32emu --enable-release +$ make iphone +$ make iphonebundle +``` + +At the end of the compilation, you'll find a **ScummVM.app** application: copy it over SSH, and reboot your device. + +## Usage ## + +The game data files can be copied on the iOS device using iTunes. Once done, add your games in ScummVM as usual. + +Here is a list of the in-game gestures: + +|Gesture|Description| +|-------|-----------| +|Two fingers swipe down|Display the ScummVM menu for loading, saving, etc.| +|Two fingers swipe right|Enable / disable the touchpad mode| +|Two fingers swipe up|Enable / disable the mouse-click-and-drag mode| +|Two fingers tap|Simulate a right click. You should tap with one finger, and then tap with another while keeping your first finger on the screen.| +|Two fingers double-tap|Skip the cinematic / video| + +The iOS keyboard is visible when the device is in portrait mode, and hidden in landscape mode. diff --git a/backends/platform/ios7/iphone_common.h b/backends/platform/ios7/iphone_common.h new file mode 100644 index 0000000000..94836dabcd --- /dev/null +++ b/backends/platform/ios7/iphone_common.h @@ -0,0 +1,111 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#ifndef BACKENDS_PLATFORM_IPHONE_IPHONE_COMMON_H +#define BACKENDS_PLATFORM_IPHONE_IPHONE_COMMON_H + +#include "graphics/surface.h" + +enum InputEvent { + kInputMouseDown, + kInputMouseUp, + kInputMouseDragged, + kInputMouseSecondDragged, + kInputMouseSecondDown, + kInputMouseSecondUp, + kInputOrientationChanged, + kInputKeyPressed, + kInputApplicationSuspended, + kInputApplicationResumed, + kInputSwipe, + kInputTap +}; + +enum ScreenOrientation { + kScreenOrientationPortrait, + kScreenOrientationLandscape, + kScreenOrientationFlippedLandscape +}; + +enum UIViewSwipeDirection { + kUIViewSwipeUp = 1, + kUIViewSwipeDown = 2, + kUIViewSwipeLeft = 4, + kUIViewSwipeRight = 8 +}; + +enum UIViewTapDescription { + kUIViewTapSingle = 1, + kUIViewTapDouble = 2 +}; + +enum GraphicsModes { + kGraphicsModeLinear = 0, + kGraphicsModeNone = 1 +}; + +struct VideoContext { + VideoContext() : asprectRatioCorrection(), screenWidth(), screenHeight(), overlayVisible(false), + overlayWidth(), overlayHeight(), mouseX(), mouseY(), + mouseHotspotX(), mouseHotspotY(), mouseWidth(), mouseHeight(), + mouseIsVisible(), graphicsMode(kGraphicsModeLinear), shakeOffsetY() { + } + + // Game screen state + bool asprectRatioCorrection; + uint screenWidth, screenHeight; + Graphics::Surface screenTexture; + + // Overlay state + bool overlayVisible; + uint overlayWidth, overlayHeight; + Graphics::Surface overlayTexture; + + // Mouse cursor state + uint mouseX, mouseY; + int mouseHotspotX, mouseHotspotY; + uint mouseWidth, mouseHeight; + bool mouseIsVisible; + Graphics::Surface mouseTexture; + + // Misc state + GraphicsModes graphicsMode; + int shakeOffsetY; +}; + +struct InternalEvent { + InternalEvent() : type(), value1(), value2() {} + InternalEvent(InputEvent t, int v1, int v2) : type(t), value1(v1), value2(v2) {} + + InputEvent type; + int value1, value2; +}; + +// On the ObjC side +void iPhone_updateScreen(); +bool iPhone_fetchEvent(InternalEvent *event); +const char *iPhone_getDocumentsDir(); +bool iPhone_isHighResDevice(); + +uint getSizeNextPOT(uint size); + +#endif diff --git a/backends/platform/ios7/iphone_keyboard.h b/backends/platform/ios7/iphone_keyboard.h new file mode 100644 index 0000000000..ddd8f436e5 --- /dev/null +++ b/backends/platform/ios7/iphone_keyboard.h @@ -0,0 +1,44 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#ifndef BACKENDS_PLATFORM_IPHONE_IPHONE_KEYBOARD_H +#define BACKENDS_PLATFORM_IPHONE_IPHONE_KEYBOARD_H + +#include +#include + +@interface SoftKeyboard : UIView { + id inputDelegate; + UITextView *inputView; +} + +- (id)initWithFrame:(CGRect)frame; +- (UITextView *)inputView; +- (void)setInputDelegate:(id)delegate; +- (void)handleKeyPress:(unichar)c; + +- (void)showKeyboard; +- (void)hideKeyboard; + +@end + +#endif diff --git a/backends/platform/ios7/iphone_keyboard.mm b/backends/platform/ios7/iphone_keyboard.mm new file mode 100644 index 0000000000..0588aac8ab --- /dev/null +++ b/backends/platform/ios7/iphone_keyboard.mm @@ -0,0 +1,98 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#include "iphone_keyboard.h" + +@interface UITextInputTraits +- (void)setAutocorrectionType:(int)type; +- (void)setAutocapitalizationType:(int)type; +- (void)setEnablesReturnKeyAutomatically:(BOOL)val; +@end + +@interface TextInputHandler : UITextView { + SoftKeyboard *softKeyboard; +} + +- (id)initWithKeyboard:(SoftKeyboard *)keyboard; + +@end + + +@implementation TextInputHandler + +- (id)initWithKeyboard:(SoftKeyboard *)keyboard { + self = [super initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.0f)]; + softKeyboard = keyboard; + + [self setAutocorrectionType:UITextAutocorrectionTypeNo]; + [self setAutocapitalizationType:UITextAutocapitalizationTypeNone]; + [self setEnablesReturnKeyAutomatically:NO]; + + return self; +} + +@end + + +@implementation SoftKeyboard + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + inputDelegate = nil; + inputView = [[TextInputHandler alloc] initWithKeyboard:self]; + inputView.delegate = self; + return self; +} + +- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { + unichar c; + if (text.length) { + c = [text characterAtIndex:0]; + } + else { + c = '\b'; + } + [inputDelegate handleKeyPress:c]; + return YES; +} + +- (UITextView *)inputView { + return inputView; +} + +- (void)setInputDelegate:(id)delegate { + inputDelegate = delegate; +} + +- (void)handleKeyPress:(unichar)c { + [inputDelegate handleKeyPress:c]; +} + +- (void)showKeyboard { + [inputView becomeFirstResponder]; +} + +- (void)hideKeyboard { + [inputView endEditing:YES]; +} + +@end diff --git a/backends/platform/ios7/iphone_main.mm b/backends/platform/ios7/iphone_main.mm new file mode 100644 index 0000000000..02d46c1995 --- /dev/null +++ b/backends/platform/ios7/iphone_main.mm @@ -0,0 +1,154 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include +#include + +#include "iphone_video.h" + +void iphone_main(int argc, char *argv[]); + +@interface ScummVMViewController : UIViewController + +@end + +@implementation ScummVMViewController + +- (BOOL)prefersStatusBarHidden { + return YES; +} + +@end + +@interface iPhoneMain : UIApplication { + UIWindow *_window; + ScummVMViewController *_controller; + iPhoneView *_view; +} + +- (void)mainLoop:(id)param; +- (iPhoneView *)getView; +- (UIWindow *)getWindow; +- (void)didRotate:(NSNotification *)notification; +@end + +static int g_argc; +static char **g_argv; + +int main(int argc, char **argv) { + g_argc = argc; + g_argv = argv; + + NSAutoreleasePool *autoreleasePool = [ + [NSAutoreleasePool alloc] init + ]; + + int returnCode = UIApplicationMain(argc, argv, @"iPhoneMain", @"iPhoneMain"); + [autoreleasePool release]; + return returnCode; +} + +@implementation iPhoneMain + +-(id) init { + [super init]; + _window = nil; + _view = nil; + return self; +} + +- (void)mainLoop:(id)param { + [[NSAutoreleasePool alloc] init]; + + iphone_main(g_argc, g_argv); + exit(0); +} + +- (iPhoneView *)getView { + return _view; +} + +- (void)applicationDidFinishLaunching:(UIApplication *)application { + CGRect rect = [[UIScreen mainScreen] bounds]; + + // Create the directory for savegames +#ifdef IPHONE_OFFICIAL + NSFileManager *fm = [NSFileManager defaultManager]; + NSString *documentPath = [NSString stringWithUTF8String:iPhone_getDocumentsDir()]; + NSString *savePath = [documentPath stringByAppendingPathComponent:@"Savegames"]; + if (![fm fileExistsAtPath:savePath]) { + [fm createDirectoryAtPath:savePath withIntermediateDirectories:YES attributes:nil error:nil]; + } +#endif + + _window = [[UIWindow alloc] initWithFrame:rect]; + [_window retain]; + + _controller = [[ScummVMViewController alloc] init]; + + _view = [[iPhoneView alloc] initWithFrame:rect]; + _view.multipleTouchEnabled = YES; + _controller.view = _view; + + [_window setRootViewController:_controller]; + [_window makeKeyAndVisible]; + + [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didRotate:) + name:@"UIDeviceOrientationDidChangeNotification" + object:nil]; + + [NSThread detachNewThreadSelector:@selector(mainLoop:) toTarget:self withObject:nil]; +} + +- (void)applicationDidResume { +} + +- (void)applicationWillSuspend { +} + +- (void)applicationWillTerminate { +} + +- (void)applicationSuspend:(struct __GSEvent *)event { + //[self setApplicationBadge:NSLocalizedString(@"ON", nil)]; + [_view applicationSuspend]; +} + +- (void)applicationResume:(struct __GSEvent *)event { + [_view applicationResume]; +} + +- (void)didRotate:(NSNotification *)notification { + UIDeviceOrientation screenOrientation = [[UIDevice currentDevice] orientation]; + [_view deviceOrientationChanged:screenOrientation]; +} + +- (UIWindow*) getWindow { + return _window; +} + +@end diff --git a/backends/platform/ios7/iphone_video.h b/backends/platform/ios7/iphone_video.h new file mode 100644 index 0000000000..5c9766a116 --- /dev/null +++ b/backends/platform/ios7/iphone_video.h @@ -0,0 +1,109 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#ifndef BACKENDS_PLATFORM_IPHONE_IPHONE_VIDEO_H +#define BACKENDS_PLATFORM_IPHONE_IPHONE_VIDEO_H + +#include +#include +#include + +#include +#include +#include + +#include "iphone_keyboard.h" +#include "iphone_common.h" + +#include "common/list.h" + +@interface iPhoneView : UIView { + VideoContext _videoContext; + + Common::List _events; + NSLock *_eventLock; + SoftKeyboard *_keyboardView; + + EAGLContext *_context; + GLuint _viewRenderbuffer; + GLuint _viewFramebuffer; + GLuint _screenTexture; + GLuint _overlayTexture; + GLuint _mouseCursorTexture; + + GLint _renderBufferWidth; + GLint _renderBufferHeight; + + GLfloat _gameScreenVertCoords[4 * 2]; + GLfloat _gameScreenTexCoords[4 * 2]; + CGRect _gameScreenRect; + + GLfloat _overlayVertCoords[4 * 2]; + GLfloat _overlayTexCoords[4 * 2]; + CGRect _overlayRect; + + GLfloat _mouseVertCoords[4 * 2]; + GLfloat _mouseTexCoords[4 * 2]; + GLint _mouseHotspotX, _mouseHotspotY; + GLint _mouseWidth, _mouseHeight; + GLfloat _mouseScaleX, _mouseScaleY; + + int _scaledShakeOffsetY; + CGFloat _contentScaleFactor; + + UITouch *_firstTouch; + UITouch *_secondTouch; +} + +- (id)initWithFrame:(struct CGRect)frame; + +- (VideoContext *)getVideoContext; + +- (void)createScreenTexture; +- (void)initSurface; +- (void)setViewTransformation; + +- (void)setGraphicsMode; + +- (void)updateSurface; +- (void)updateMainSurface; +- (void)updateOverlaySurface; +- (void)updateMouseSurface; +- (void)clearColorBuffer; + +- (void)notifyMouseMove; +- (void)updateMouseCursorScaling; +- (void)updateMouseCursor; + +- (void)deviceOrientationChanged:(UIDeviceOrientation)orientation; + +- (void)applicationSuspend; + +- (void)applicationResume; + +- (bool)fetchEvent:(InternalEvent *)event; + +@end + +extern iPhoneView *g_iPhoneViewInstance; + +#endif diff --git a/backends/platform/ios7/iphone_video.mm b/backends/platform/ios7/iphone_video.mm new file mode 100644 index 0000000000..efd8ea3acf --- /dev/null +++ b/backends/platform/ios7/iphone_video.mm @@ -0,0 +1,821 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "iphone_video.h" + +#include "graphics/colormasks.h" +#include "common/system.h" + +iPhoneView *g_iPhoneViewInstance = nil; +static int g_fullWidth; +static int g_fullHeight; + +static int g_needsScreenUpdate = 0; + +#if 0 +static long g_lastTick = 0; +static int g_frames = 0; +#endif + +extern bool iphone_touchpadModeEnabled(); + +#define printOpenGLError() printOglError(__FILE__, __LINE__) + +int printOglError(const char *file, int line) { + int retCode = 0; + + // returns 1 if an OpenGL error occurred, 0 otherwise. + GLenum glErr = glGetError(); + while (glErr != GL_NO_ERROR) { + fprintf(stderr, "glError: %u (%s: %d)\n", glErr, file, line); + retCode = 1; + glErr = glGetError(); + } + return retCode; +} + +bool iPhone_isHighResDevice() { + return g_fullHeight > 480; +} + +void iPhone_updateScreen() { + //printf("Mouse: (%i, %i)\n", mouseX, mouseY); + if (!g_needsScreenUpdate) { + g_needsScreenUpdate = 1; + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateSurface) withObject:nil waitUntilDone: NO]; + } +} + +bool iPhone_fetchEvent(InternalEvent *event) { + return [g_iPhoneViewInstance fetchEvent:event]; +} + +uint getSizeNextPOT(uint size) { + if ((size & (size - 1)) || !size) { + int log = 0; + + while (size >>= 1) + ++log; + + size = (2 << log); + } + + return size; +} + +const char *iPhone_getDocumentsDir() { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + return [documentsDirectory UTF8String]; +} + +@implementation iPhoneView + ++ (Class)layerClass { + return [CAEAGLLayer class]; +} + +- (VideoContext *)getVideoContext { + return &_videoContext; +} + +- (void)createContext { + CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; + + eaglLayer.opaque = YES; + eaglLayer.drawableProperties = @{ + kEAGLDrawablePropertyRetainedBacking: @NO, + kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGB565 + }; + + _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; + + // In case creating the OpenGL ES context failed, we will error out here. + if (_context == nil) { + fprintf(stderr, "Could not create OpenGL ES context\n"); + exit(-1); + } + + if ([EAGLContext setCurrentContext:_context]) { + glGenFramebuffersOES(1, &_viewFramebuffer); printOpenGLError(); + glGenRenderbuffersOES(1, &_viewRenderbuffer); printOpenGLError(); + + glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); printOpenGLError(); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); + [_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id)self.layer]; + + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); + + // Retrieve the render buffer size. This *should* match the frame size, + // i.e. g_fullWidth and g_fullHeight. + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &_renderBufferWidth); printOpenGLError(); + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &_renderBufferHeight); printOpenGLError(); + + if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { + NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); + return; + } + uint maxValue = MAX(_renderBufferWidth, _renderBufferHeight), maxValuePOT = getSizeNextPOT(maxValue); + uint minValue = MIN(_renderBufferWidth, _renderBufferHeight), minValuePOT = getSizeNextPOT(minValue); + + _videoContext.overlayWidth = maxValue; + _videoContext.overlayHeight = minValue; + + uint overlayTextureWidth = maxValuePOT; + uint overlayTextureHeight = minValuePOT; + + // Since the overlay size won't change the whole run, we can + // precalculate the texture coordinates for the overlay texture here + // and just use it later on. + _overlayTexCoords[2] = _overlayTexCoords[6] = _videoContext.overlayWidth / (GLfloat)overlayTextureWidth; + _overlayTexCoords[5] = _overlayTexCoords[7] = _videoContext.overlayHeight / (GLfloat)overlayTextureHeight; + + _videoContext.overlayTexture.create(overlayTextureWidth, overlayTextureHeight, Graphics::createPixelFormat<5551>()); + + glViewport(0, 0, _renderBufferWidth, _renderBufferHeight); printOpenGLError(); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); printOpenGLError(); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_TEXTURE_2D); printOpenGLError(); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); printOpenGLError(); + glEnableClientState(GL_VERTEX_ARRAY); printOpenGLError(); + } +} + +- (void)setupGestureRecognizers { + UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeRight:)]; + swipeRight.direction = UISwipeGestureRecognizerDirectionRight; + swipeRight.numberOfTouchesRequired = 2; + + UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeLeft:)]; + swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft; + swipeLeft.numberOfTouchesRequired = 2; + + UISwipeGestureRecognizer *swipeUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeUp:)]; + swipeUp.direction = UISwipeGestureRecognizerDirectionUp; + swipeUp.numberOfTouchesRequired = 2; + + UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeDown:)]; + swipeDown.direction = UISwipeGestureRecognizerDirectionDown; + swipeDown.numberOfTouchesRequired = 2; + + UITapGestureRecognizer *doubleTapTwoFingers = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersDoubleTap:)]; + doubleTapTwoFingers.numberOfTapsRequired = 2; + doubleTapTwoFingers.numberOfTouchesRequired = 2; + + [self addGestureRecognizer:swipeRight]; + [self addGestureRecognizer:swipeLeft]; + [self addGestureRecognizer:swipeUp]; + [self addGestureRecognizer:swipeDown]; + [self addGestureRecognizer:doubleTapTwoFingers]; +} + +- (CGFloat)optimalScale { + CGFloat screenScale = [[UIScreen mainScreen] scale]; + if (screenScale < 2) return screenScale; + + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + return 1; + } + + CGSize screenSize; + UIScreen *mainScreen = [UIScreen mainScreen]; + if ([mainScreen respondsToSelector:@selector(nativeBounds)]) { + screenSize = [mainScreen nativeBounds].size; + } + else { + screenSize = [mainScreen bounds].size; + screenSize.width *= screenScale; + screenSize.height *= screenScale; + } + CGFloat mxSize = MAX(screenSize.width, screenSize.height); + + if (mxSize <= 1136) { + // iPhone 4S / 5 / 5S / 5C + return 1; + } + else { + // iPhone 6 / 6S / 6+ / 6S+ + return 2; + } +} + +- (id)initWithFrame:(struct CGRect)frame { + self = [super initWithFrame: frame]; + + [self setupGestureRecognizers]; + + g_fullWidth = (int)MAX(frame.size.width, frame.size.height); + g_fullHeight = (int)MIN(frame.size.width, frame.size.height); + + _contentScaleFactor = [self optimalScale]; + [self setContentScaleFactor:_contentScaleFactor]; + + g_iPhoneViewInstance = self; + + _keyboardView = nil; + _screenTexture = 0; + _overlayTexture = 0; + _mouseCursorTexture = 0; + + _scaledShakeOffsetY = 0; + + _firstTouch = NULL; + _secondTouch = NULL; + + _eventLock = [[NSLock alloc] init]; + + _gameScreenVertCoords[0] = _gameScreenVertCoords[1] = + _gameScreenVertCoords[2] = _gameScreenVertCoords[3] = + _gameScreenVertCoords[4] = _gameScreenVertCoords[5] = + _gameScreenVertCoords[6] = _gameScreenVertCoords[7] = 0; + + _gameScreenTexCoords[0] = _gameScreenTexCoords[1] = + _gameScreenTexCoords[2] = _gameScreenTexCoords[3] = + _gameScreenTexCoords[4] = _gameScreenTexCoords[5] = + _gameScreenTexCoords[6] = _gameScreenTexCoords[7] = 0; + + _overlayVertCoords[0] = _overlayVertCoords[1] = + _overlayVertCoords[2] = _overlayVertCoords[3] = + _overlayVertCoords[4] = _overlayVertCoords[5] = + _overlayVertCoords[6] = _overlayVertCoords[7] = 0; + + _overlayTexCoords[0] = _overlayTexCoords[1] = + _overlayTexCoords[2] = _overlayTexCoords[3] = + _overlayTexCoords[4] = _overlayTexCoords[5] = + _overlayTexCoords[6] = _overlayTexCoords[7] = 0; + + _mouseVertCoords[0] = _mouseVertCoords[1] = + _mouseVertCoords[2] = _mouseVertCoords[3] = + _mouseVertCoords[4] = _mouseVertCoords[5] = + _mouseVertCoords[6] = _mouseVertCoords[7] = 0; + + _mouseTexCoords[0] = _mouseTexCoords[1] = + _mouseTexCoords[2] = _mouseTexCoords[3] = + _mouseTexCoords[4] = _mouseTexCoords[5] = + _mouseTexCoords[6] = _mouseTexCoords[7] = 0; + + // Initialize the OpenGL ES context + [self createContext]; + + return self; +} + +- (void)dealloc { + if (_keyboardView != nil) { + [_keyboardView dealloc]; + } + + _videoContext.screenTexture.free(); + _videoContext.overlayTexture.free(); + _videoContext.mouseTexture.free(); + + [_eventLock dealloc]; + [super dealloc]; +} + +#if 0 +- (void)drawRect:(CGRect)frame { + if (g_lastTick == 0) { + g_lastTick = time(0); + } + + g_frames++; + if (time(0) > g_lastTick) { + g_lastTick = time(0); + printf("FPS: %i\n", g_frames); + g_frames = 0; + } +} +#endif + +- (void)setFilterModeForTexture:(GLuint)tex { + if (!tex) + return; + + glBindTexture(GL_TEXTURE_2D, tex); printOpenGLError(); + + GLint filter = GL_LINEAR; + + switch (_videoContext.graphicsMode) { + case kGraphicsModeLinear: + filter = GL_LINEAR; + break; + + case kGraphicsModeNone: + filter = GL_NEAREST; + break; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); printOpenGLError(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); printOpenGLError(); + // We use GL_CLAMP_TO_EDGE here to avoid artifacts when linear filtering + // is used. If we would not use this for example the cursor in Loom would + // have a line/border artifact on the right side of the covered rect. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); printOpenGLError(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); printOpenGLError(); +} + +- (void)setGraphicsMode { + [self setFilterModeForTexture:_screenTexture]; + [self setFilterModeForTexture:_overlayTexture]; + [self setFilterModeForTexture:_mouseCursorTexture]; +} + +- (void)updateSurface { + if (!g_needsScreenUpdate) { + return; + } + g_needsScreenUpdate = 0; + + glClear(GL_COLOR_BUFFER_BIT); printOpenGLError(); + + [self updateMainSurface]; + + if (_videoContext.overlayVisible) + [self updateOverlaySurface]; + + if (_videoContext.mouseIsVisible) + [self updateMouseSurface]; + + glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); + [_context presentRenderbuffer:GL_RENDERBUFFER_OES]; + +} + +- (void)notifyMouseMove { + const GLint mouseX = (GLint)(_videoContext.mouseX * _mouseScaleX) - _mouseHotspotX; + const GLint mouseY = (GLint)(_videoContext.mouseY * _mouseScaleY) - _mouseHotspotY; + + _mouseVertCoords[0] = _mouseVertCoords[4] = mouseX; + _mouseVertCoords[1] = _mouseVertCoords[3] = mouseY; + _mouseVertCoords[2] = _mouseVertCoords[6] = mouseX + _mouseWidth; + _mouseVertCoords[5] = _mouseVertCoords[7] = mouseY + _mouseHeight; +} + +- (void)updateMouseCursorScaling { + CGRect *rect; + int maxWidth, maxHeight; + + if (!_videoContext.overlayVisible) { + rect = &_gameScreenRect; + maxWidth = _videoContext.screenWidth; + maxHeight = _videoContext.screenHeight; + } else { + rect = &_overlayRect; + maxWidth = _videoContext.overlayWidth; + maxHeight = _videoContext.overlayHeight; + } + + if (!maxWidth || !maxHeight) { + printf("WARNING: updateMouseCursorScaling called when screen was not ready (%d)!\n", _videoContext.overlayVisible); + return; + } + + _mouseScaleX = CGRectGetWidth(*rect) / (GLfloat)maxWidth; + _mouseScaleY = CGRectGetHeight(*rect) / (GLfloat)maxHeight; + + _mouseWidth = (GLint)(_videoContext.mouseWidth * _mouseScaleX); + _mouseHeight = (GLint)(_videoContext.mouseHeight * _mouseScaleY); + + _mouseHotspotX = (GLint)(_videoContext.mouseHotspotX * _mouseScaleX); + _mouseHotspotY = (GLint)(_videoContext.mouseHotspotY * _mouseScaleY); + + // We subtract the screen offset to the hotspot here to simplify the + // screen offset handling in the mouse code. Note the subtraction here + // makes sure that the offset actually gets added to the mouse position, + // since the hotspot offset is substracted from the position. + _mouseHotspotX -= (GLint)CGRectGetMinX(*rect); + _mouseHotspotY -= (GLint)CGRectGetMinY(*rect); + + // FIXME: For now we also adapt the mouse position here. In reality we + // would be better off to also adjust the event position when switching + // from overlay to game screen or vica versa. + [self notifyMouseMove]; +} + +- (void)updateMouseCursor { + if (_mouseCursorTexture == 0) { + glGenTextures(1, &_mouseCursorTexture); printOpenGLError(); + [self setFilterModeForTexture:_mouseCursorTexture]; + } + + [self updateMouseCursorScaling]; + + _mouseTexCoords[2] = _mouseTexCoords[6] = _videoContext.mouseWidth / (GLfloat)_videoContext.mouseTexture.w; + _mouseTexCoords[5] = _mouseTexCoords[7] = _videoContext.mouseHeight / (GLfloat)_videoContext.mouseTexture.h; + + glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.mouseTexture.w, _videoContext.mouseTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.mouseTexture.getPixels()); printOpenGLError(); +} + +- (void)updateMainSurface { + glVertexPointer(2, GL_FLOAT, 0, _gameScreenVertCoords); printOpenGLError(); + glTexCoordPointer(2, GL_FLOAT, 0, _gameScreenTexCoords); printOpenGLError(); + + glBindTexture(GL_TEXTURE_2D, _screenTexture); printOpenGLError(); + + // Unfortunately we have to update the whole texture every frame, since glTexSubImage2D is actually slower in all cases + // due to the iPhone internals having to convert the whole texture back from its internal format when used. + // In the future we could use several tiled textures instead. + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w, _videoContext.screenTexture.h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _videoContext.screenTexture.getPixels()); printOpenGLError(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); +} + +- (void)updateOverlaySurface { + glVertexPointer(2, GL_FLOAT, 0, _overlayVertCoords); printOpenGLError(); + glTexCoordPointer(2, GL_FLOAT, 0, _overlayTexCoords); printOpenGLError(); + + glBindTexture(GL_TEXTURE_2D, _overlayTexture); printOpenGLError(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.overlayTexture.w, _videoContext.overlayTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.overlayTexture.getPixels()); printOpenGLError(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); +} + +- (void)updateMouseSurface { + glVertexPointer(2, GL_FLOAT, 0, _mouseVertCoords); printOpenGLError(); + glTexCoordPointer(2, GL_FLOAT, 0, _mouseTexCoords); printOpenGLError(); + + glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); +} + +- (void)createScreenTexture { + const uint screenTexWidth = getSizeNextPOT(_videoContext.screenWidth); + const uint screenTexHeight = getSizeNextPOT(_videoContext.screenHeight); + + _gameScreenTexCoords[2] = _gameScreenTexCoords[6] = _videoContext.screenWidth / (GLfloat)screenTexWidth; + _gameScreenTexCoords[5] = _gameScreenTexCoords[7] = _videoContext.screenHeight / (GLfloat)screenTexHeight; + + _videoContext.screenTexture.create(screenTexWidth, screenTexHeight, Graphics::createPixelFormat<565>()); +} + +- (void)initSurface { + if (_context) { + glDeleteTextures(1, &_screenTexture); printOpenGLError(); + glDeleteTextures(1, &_overlayTexture); printOpenGLError(); + + glDeleteRenderbuffersOES(1, &_viewRenderbuffer); + glDeleteFramebuffersOES(1, &_viewFramebuffer); + + glGenFramebuffersOES(1, &_viewFramebuffer); printOpenGLError(); + glGenRenderbuffersOES(1, &_viewRenderbuffer); printOpenGLError(); + + glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); printOpenGLError(); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); + [_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id)self.layer]; + + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); + + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &_renderBufferWidth); printOpenGLError(); + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &_renderBufferHeight); printOpenGLError(); + + if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { + NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); + return; + } + + glViewport(0, 0, _renderBufferWidth, _renderBufferHeight); printOpenGLError(); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); printOpenGLError(); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_TEXTURE_2D); printOpenGLError(); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); printOpenGLError(); + glEnableClientState(GL_VERTEX_ARRAY); printOpenGLError(); + } + + BOOL isLandscape = (self.bounds.size.width > self.bounds.size.height); // UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]); + +// glMatrixMode(GL_PROJECTION); +// glLoadIdentity(); + + int screenWidth, screenHeight; + if (isLandscape) { + screenWidth = MAX(_renderBufferWidth, _renderBufferHeight); + screenHeight = MIN(_renderBufferWidth, _renderBufferHeight); +// glOrthof(0, screenWidth, screenHeight, 0, 0, 1); printOpenGLError(); + } + else { + screenWidth = MIN(_renderBufferWidth, _renderBufferHeight); + screenHeight = MAX(_renderBufferWidth, _renderBufferHeight); +// glOrthof(0, screenHeight, screenWidth, 0, 0, 1); printOpenGLError(); + } + + glGenTextures(1, &_screenTexture); printOpenGLError(); + [self setFilterModeForTexture:_screenTexture]; + + glGenTextures(1, &_overlayTexture); printOpenGLError(); + [self setFilterModeForTexture:_overlayTexture]; + + glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); + + [self clearColorBuffer]; + +// if (_keyboardView != nil) { +// [_keyboardView removeFromSuperview]; +// [[_keyboardView inputView] removeFromSuperview]; +// } + + GLfloat adjustedWidth = _videoContext.screenWidth; + GLfloat adjustedHeight = _videoContext.screenHeight; + if (_videoContext.asprectRatioCorrection) { + if (_videoContext.screenWidth == 320 && _videoContext.screenHeight == 200) + adjustedHeight = 240; + else if (_videoContext.screenWidth == 640 && _videoContext.screenHeight == 400) + adjustedHeight = 480; + } + + float overlayPortraitRatio; + + if (isLandscape) { + GLfloat gameScreenRatio = adjustedWidth / adjustedHeight; + GLfloat screenRatio = (GLfloat)screenWidth / (GLfloat)screenHeight; + + // These are the width/height according to the portrait layout! + int rectWidth, rectHeight; + int xOffset, yOffset; + + if (gameScreenRatio < screenRatio) { + // When the game screen ratio is less than the screen ratio + // we need to scale the width, since the game screen was higher + // compared to the width than our output screen is. + rectWidth = (int)(screenHeight * gameScreenRatio); + rectHeight = screenHeight; + xOffset = (screenWidth - rectWidth) / 2; + yOffset = 0; + } else { + // When the game screen ratio is bigger than the screen ratio + // we need to scale the height, since the game screen was wider + // compared to the height than our output screen is. + rectWidth = screenWidth; + rectHeight = (int)(screenWidth / gameScreenRatio); + xOffset = 0; + yOffset = (screenHeight - rectHeight) / 2; + } + + [_keyboardView hideKeyboard]; + + //printf("Rect: %i, %i, %i, %i\n", xOffset, yOffset, rectWidth, rectHeight); + _gameScreenRect = CGRectMake(xOffset, yOffset, rectWidth, rectHeight); + overlayPortraitRatio = 1.0f; + } else { + GLfloat ratio = adjustedHeight / adjustedWidth; + int height = (int)(screenWidth * ratio); + //printf("Making rect (%u, %u)\n", screenWidth, height); + _gameScreenRect = CGRectMake(0, 0, screenWidth, height); + + CGRect keyFrame = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f); + if (_keyboardView == nil) { + _keyboardView = [[SoftKeyboard alloc] initWithFrame:keyFrame]; + [_keyboardView setInputDelegate:self]; + [self addSubview:[_keyboardView inputView]]; + [self addSubview: _keyboardView]; + } + + [_keyboardView showKeyboard]; + overlayPortraitRatio = (_videoContext.overlayHeight * ratio) / _videoContext.overlayWidth; + } + _overlayRect = CGRectMake(0, 0, screenWidth, screenHeight * overlayPortraitRatio); + + _gameScreenVertCoords[0] = _gameScreenVertCoords[4] = CGRectGetMinX(_gameScreenRect); + _gameScreenVertCoords[1] = _gameScreenVertCoords[3] = CGRectGetMinY(_gameScreenRect); + _gameScreenVertCoords[2] = _gameScreenVertCoords[6] = CGRectGetMaxX(_gameScreenRect); + _gameScreenVertCoords[5] = _gameScreenVertCoords[7] = CGRectGetMaxY(_gameScreenRect); + + _overlayVertCoords[2] = _overlayVertCoords[6] = CGRectGetMaxX(_overlayRect); + _overlayVertCoords[5] = _overlayVertCoords[7] = CGRectGetMaxY(_overlayRect); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrthof(0, screenWidth, screenHeight, 0, 0, 1); + + [self setViewTransformation]; + [self updateMouseCursorScaling]; +} + +- (void)setViewTransformation { + // Set the modelview matrix. This matrix will be used for the shake offset + // support. + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + // Scale the shake offset according to the overlay size. We need this to + // adjust the overlay mouse click coordinates when an offset is set. + _scaledShakeOffsetY = (int)(_videoContext.shakeOffsetY / (GLfloat)_videoContext.screenHeight * CGRectGetHeight(_overlayRect)); + + // Apply the shakeing to the output screen. + glTranslatef(0, -_scaledShakeOffsetY, 0); +} + +- (void)clearColorBuffer { + // The color buffer is triple-buffered, so we clear it multiple times right away to avid doing any glClears later. + int clearCount = 5; + while (clearCount-- > 0) { + glClear(GL_COLOR_BUFFER_BIT); printOpenGLError(); + [_context presentRenderbuffer:GL_RENDERBUFFER_OES]; + } +} + +- (void)addEvent:(InternalEvent)event { + [_eventLock lock]; + _events.push_back(event); + [_eventLock unlock]; +} + +- (bool)fetchEvent:(InternalEvent *)event { + [_eventLock lock]; + if (_events.empty()) { + [_eventLock unlock]; + return false; + } + + *event = *_events.begin(); + _events.pop_front(); + [_eventLock unlock]; + return true; +} + +- (bool)getMouseCoords:(CGPoint)point eventX:(int *)x eventY:(int *)y { + // We scale the input according to our scale factor to get actual screen + // cooridnates. + point.x *= _contentScaleFactor; + point.y *= _contentScaleFactor; + + CGRect *area; + int width, height, offsetY; + if (_videoContext.overlayVisible) { + area = &_overlayRect; + width = _videoContext.overlayWidth; + height = _videoContext.overlayHeight; + offsetY = _scaledShakeOffsetY; + } else { + area = &_gameScreenRect; + width = _videoContext.screenWidth; + height = _videoContext.screenHeight; + offsetY = _videoContext.shakeOffsetY; + } + + point.x = (point.x - CGRectGetMinX(*area)) / CGRectGetWidth(*area); + point.y = (point.y - CGRectGetMinY(*area)) / CGRectGetHeight(*area); + + *x = (int)(point.x * width); + // offsetY describes the translation of the screen in the upward direction, + // thus we need to add it here. + *y = (int)(point.y * height + offsetY); + + if (!iphone_touchpadModeEnabled()) { + // Clip coordinates + if (*x < 0 || *x > width || *y < 0 || *y > height) + return false; + } + + return true; +} + +- (void)deviceOrientationChanged:(UIDeviceOrientation)orientation { + [self addEvent:InternalEvent(kInputOrientationChanged, orientation, 0)]; +} + +- (UITouch *)secondTouchOtherTouchThan:(UITouch *)touch in:(NSSet *)set { + NSArray *all = [set allObjects]; + for (UITouch *t in all) { + if (t != touch) { + return t; + } + } + return nil; +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + int x, y; + + NSSet *allTouches = [event allTouches]; + if (allTouches.count == 1) { + _firstTouch = [allTouches anyObject]; + CGPoint point = [_firstTouch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent:InternalEvent(kInputMouseDown, x, y)]; + } + else if (allTouches.count == 2) { + _secondTouch = [self secondTouchOtherTouchThan:_firstTouch in:allTouches]; + if (_secondTouch) { + CGPoint point = [_secondTouch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent:InternalEvent(kInputMouseSecondDown, x, y)]; + } + } +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + int x, y; + + NSSet *allTouches = [event allTouches]; + for (UITouch *touch in allTouches) { + if (touch == _firstTouch) { + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent:InternalEvent(kInputMouseDragged, x, y)]; + } else if (touch == _secondTouch) { + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent:InternalEvent(kInputMouseSecondDragged, x, y)]; + } + } +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + int x, y; + + NSSet *allTouches = [event allTouches]; + if (allTouches.count == 1) { + UITouch *touch = [allTouches anyObject]; + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) { + return; + } + + [self addEvent:InternalEvent(kInputMouseUp, x, y)]; + } + else if (allTouches.count == 2) { + UITouch *touch = [[allTouches allObjects] objectAtIndex:1]; + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent:InternalEvent(kInputMouseSecondUp, x, y)]; + } + _firstTouch = nil; + _secondTouch = nil; +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + _firstTouch = nil; + _secondTouch = nil; +} + +- (void)twoFingersSwipeRight:(UISwipeGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeRight, 2)]; +} + +- (void)twoFingersSwipeLeft:(UISwipeGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeLeft, 2)]; +} + +- (void)twoFingersSwipeUp:(UISwipeGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeUp, 2)]; +} + +- (void)twoFingersSwipeDown:(UISwipeGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeDown, 2)]; +} + +- (void)twoFingersDoubleTap:(UITapGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputTap, kUIViewTapDouble, 2)]; +} + +- (void)handleKeyPress:(unichar)c { + [self addEvent:InternalEvent(kInputKeyPressed, c, 0)]; +} + +- (void)applicationSuspend { + [self addEvent:InternalEvent(kInputApplicationSuspended, 0, 0)]; +} + +- (void)applicationResume { + [self addEvent:InternalEvent(kInputApplicationResumed, 0, 0)]; +} + +@end diff --git a/backends/platform/ios7/module.mk b/backends/platform/ios7/module.mk new file mode 100644 index 0000000000..87721cc9e5 --- /dev/null +++ b/backends/platform/ios7/module.mk @@ -0,0 +1,15 @@ +MODULE := backends/platform/ios7 + +MODULE_OBJS := \ + osys_main.o \ + osys_events.o \ + osys_sound.o \ + osys_video.o \ + iphone_main.o \ + iphone_video.o \ + iphone_keyboard.o + +# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS. +MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) +OBJS := $(MODULE_OBJS) $(OBJS) +MODULE_DIRS += $(sort $(dir $(MODULE_OBJS))) diff --git a/backends/platform/ios7/osys_events.cpp b/backends/platform/ios7/osys_events.cpp new file mode 100644 index 0000000000..19da580c80 --- /dev/null +++ b/backends/platform/ios7/osys_events.cpp @@ -0,0 +1,562 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "gui/message.h" +#include "common/translation.h" + +#include "osys_main.h" + +static const int kQueuedInputEventDelay = 50; + +bool OSystem_IPHONE::pollEvent(Common::Event &event) { + //printf("pollEvent()\n"); + + long curTime = getMillis(); + + if (_timerCallback && (curTime >= _timerCallbackNext)) { + _timerCallback(_timerCallbackTimer); + _timerCallbackNext = curTime + _timerCallbackTimer; + } + + if (_queuedInputEvent.type != Common::EVENT_INVALID && curTime >= _queuedEventTime) { + event = _queuedInputEvent; + _queuedInputEvent.type = Common::EVENT_INVALID; + return true; + } + + InternalEvent internalEvent; + + if (iPhone_fetchEvent(&internalEvent)) { + switch (internalEvent.type) { + case kInputMouseDown: + if (!handleEvent_mouseDown(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + + case kInputMouseUp: + if (!handleEvent_mouseUp(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + + case kInputMouseDragged: + if (!handleEvent_mouseDragged(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + + case kInputOrientationChanged: + handleEvent_orientationChanged(internalEvent.value1); + return false; + break; + + case kInputApplicationSuspended: + suspendLoop(); + return false; + break; + + case kInputMouseSecondDragged: + if (!handleEvent_mouseSecondDragged(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + case kInputMouseSecondDown: + _secondaryTapped = true; + if (!handleEvent_secondMouseDown(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + case kInputMouseSecondUp: + _secondaryTapped = false; + if (!handleEvent_secondMouseUp(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + + case kInputKeyPressed: + handleEvent_keyPressed(event, internalEvent.value1); + break; + + case kInputSwipe: + if (!handleEvent_swipe(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + + case kInputTap: + if (!handleEvent_tap(event, (UIViewTapDescription) internalEvent.value1, internalEvent.value2)) + return false; + break; + + default: + break; + } + + return true; + } + return false; +} + +bool OSystem_IPHONE::handleEvent_mouseDown(Common::Event &event, int x, int y) { + //printf("Mouse down at (%u, %u)\n", x, y); + + // Workaround: kInputMouseSecondToggled isn't always sent when the + // secondary finger is lifted. Need to make sure we get out of that mode. + _secondaryTapped = false; + + if (_touchpadModeEnabled) { + _lastPadX = x; + _lastPadY = y; + } else + warpMouse(x, y); + + if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_LBUTTONDOWN; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + return true; + } else { + _lastMouseDown = getMillis(); + } + return false; +} + +bool OSystem_IPHONE::handleEvent_mouseUp(Common::Event &event, int x, int y) { + //printf("Mouse up at (%u, %u)\n", x, y); + + if (_secondaryTapped) { + _secondaryTapped = false; + if (!handleEvent_secondMouseUp(event, x, y)) + return false; + } else if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_LBUTTONUP; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + } else { + if (getMillis() - _lastMouseDown < 250) { + event.type = Common::EVENT_LBUTTONDOWN; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + + _queuedInputEvent.type = Common::EVENT_LBUTTONUP; + _queuedInputEvent.mouse.x = _videoContext->mouseX; + _queuedInputEvent.mouse.y = _videoContext->mouseY; + _lastMouseTap = getMillis(); + _queuedEventTime = _lastMouseTap + kQueuedInputEventDelay; + } else + return false; + } + + return true; +} + +bool OSystem_IPHONE::handleEvent_secondMouseDown(Common::Event &event, int x, int y) { + _lastSecondaryDown = getMillis(); + _gestureStartX = x; + _gestureStartY = y; + + if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_LBUTTONUP; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + + _queuedInputEvent.type = Common::EVENT_RBUTTONDOWN; + _queuedInputEvent.mouse.x = _videoContext->mouseX; + _queuedInputEvent.mouse.y = _videoContext->mouseY; + } else + return false; + + return true; +} + +bool OSystem_IPHONE::handleEvent_secondMouseUp(Common::Event &event, int x, int y) { + int curTime = getMillis(); + + if (curTime - _lastSecondaryDown < 400) { + //printf("Right tap!\n"); + if (curTime - _lastSecondaryTap < 400 && !_videoContext->overlayVisible) { + //printf("Right escape!\n"); + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE; + _queuedEventTime = curTime + kQueuedInputEventDelay; + _lastSecondaryTap = 0; + } else if (!_mouseClickAndDragEnabled) { + //printf("Rightclick!\n"); + event.type = Common::EVENT_RBUTTONDOWN; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + _queuedInputEvent.type = Common::EVENT_RBUTTONUP; + _queuedInputEvent.mouse.x = _videoContext->mouseX; + _queuedInputEvent.mouse.y = _videoContext->mouseY; + _lastSecondaryTap = curTime; + _queuedEventTime = curTime + kQueuedInputEventDelay; + } else { + //printf("Right nothing!\n"); + return false; + } + } + if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_RBUTTONUP; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + } + + return true; +} + +bool OSystem_IPHONE::handleEvent_mouseDragged(Common::Event &event, int x, int y) { + if (_lastDragPosX == x && _lastDragPosY == y) + return false; + + _lastDragPosX = x; + _lastDragPosY = y; + + //printf("Mouse dragged at (%u, %u)\n", x, y); + int mouseNewPosX; + int mouseNewPosY; + if (_touchpadModeEnabled) { + int deltaX = _lastPadX - x; + int deltaY = _lastPadY - y; + _lastPadX = x; + _lastPadY = y; + + mouseNewPosX = (int)(_videoContext->mouseX - deltaX / 0.5f); + mouseNewPosY = (int)(_videoContext->mouseY - deltaY / 0.5f); + + int widthCap = _videoContext->overlayVisible ? _videoContext->overlayWidth : _videoContext->screenWidth; + int heightCap = _videoContext->overlayVisible ? _videoContext->overlayHeight : _videoContext->screenHeight; + + if (mouseNewPosX < 0) + mouseNewPosX = 0; + else if (mouseNewPosX > widthCap) + mouseNewPosX = widthCap; + + if (mouseNewPosY < 0) + mouseNewPosY = 0; + else if (mouseNewPosY > heightCap) + mouseNewPosY = heightCap; + + } else { + mouseNewPosX = x; + mouseNewPosY = y; + } + + event.type = Common::EVENT_MOUSEMOVE; + event.mouse.x = mouseNewPosX; + event.mouse.y = mouseNewPosY; + warpMouse(mouseNewPosX, mouseNewPosY); + + return true; +} + +bool OSystem_IPHONE::handleEvent_mouseSecondDragged(Common::Event &event, int x, int y) { + if (_gestureStartX == -1 || _gestureStartY == -1) { + return false; + } + + static const int kNeededLength = 100; + static const int kMaxDeviation = 20; + + int vecX = (x - _gestureStartX); + int vecY = (y - _gestureStartY); + + int absX = abs(vecX); + int absY = abs(vecY); + + //printf("(%d, %d)\n", vecX, vecY); + + if (absX >= kNeededLength || absY >= kNeededLength) { // Long enough gesture to react upon. + _gestureStartX = -1; + _gestureStartY = -1; + + if (absX < kMaxDeviation && vecY >= kNeededLength) { + // Swipe down + event.type = Common::EVENT_MAINMENU; + _queuedInputEvent.type = Common::EVENT_INVALID; + + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + return true; + } + + if (absX < kMaxDeviation && -vecY >= kNeededLength) { + // Swipe up + _mouseClickAndDragEnabled = !_mouseClickAndDragEnabled; + const char *dialogMsg; + if (_mouseClickAndDragEnabled) { + _touchpadModeEnabled = false; + dialogMsg = _("Mouse-click-and-drag mode enabled."); + } else + dialogMsg = _("Mouse-click-and-drag mode disabled."); + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return false; + } + + if (absY < kMaxDeviation && vecX >= kNeededLength) { + // Swipe right + _touchpadModeEnabled = !_touchpadModeEnabled; + const char *dialogMsg; + if (_touchpadModeEnabled) + dialogMsg = _("Touchpad mode enabled."); + else + dialogMsg = _("Touchpad mode disabled."); + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return false; + + } + + if (absY < kMaxDeviation && -vecX >= kNeededLength) { + // Swipe left + return false; + } + } + + return false; +} + +void OSystem_IPHONE::handleEvent_orientationChanged(int orientation) { + //printf("Orientation: %i\n", orientation); + + ScreenOrientation newOrientation; + switch (orientation) { + case 1: + newOrientation = kScreenOrientationPortrait; + break; + case 3: + newOrientation = kScreenOrientationLandscape; + break; + case 4: + newOrientation = kScreenOrientationFlippedLandscape; + break; + default: + return; + } + + + if (_screenOrientation != newOrientation) { + _screenOrientation = newOrientation; + updateOutputSurface(); + + dirtyFullScreen(); + if (_videoContext->overlayVisible) + dirtyFullOverlayScreen(); + updateScreen(); + } +} + +void OSystem_IPHONE::handleEvent_keyPressed(Common::Event &event, int keyPressed) { + int ascii = keyPressed; + //printf("key: %i\n", keyPressed); + + // We remap some of the iPhone keyboard keys. + // The first ten here are the row of symbols below the numeric keys. + switch (keyPressed) { + case 45: + keyPressed = Common::KEYCODE_F1; + ascii = Common::ASCII_F1; + break; + case 47: + keyPressed = Common::KEYCODE_F2; + ascii = Common::ASCII_F2; + break; + case 58: + keyPressed = Common::KEYCODE_F3; + ascii = Common::ASCII_F3; + break; + case 59: + keyPressed = Common::KEYCODE_F4; + ascii = Common::ASCII_F4; + break; + case 40: + keyPressed = Common::KEYCODE_F5; + ascii = Common::ASCII_F5; + break; + case 41: + keyPressed = Common::KEYCODE_F6; + ascii = Common::ASCII_F6; + break; + case 36: + keyPressed = Common::KEYCODE_F7; + ascii = Common::ASCII_F7; + break; + case 38: + keyPressed = Common::KEYCODE_F8; + ascii = Common::ASCII_F8; + break; + case 64: + keyPressed = Common::KEYCODE_F9; + ascii = Common::ASCII_F9; + break; + case 34: + keyPressed = Common::KEYCODE_F10; + ascii = Common::ASCII_F10; + break; + case 10: + keyPressed = Common::KEYCODE_RETURN; + ascii = Common::ASCII_RETURN; + break; + } + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + event.kbd.keycode = _queuedInputEvent.kbd.keycode = (Common::KeyCode)keyPressed; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = ascii; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; +} + +bool OSystem_IPHONE::handleEvent_swipe(Common::Event &event, int direction, int touches) { + if (touches == 1) { + Common::KeyCode keycode = Common::KEYCODE_INVALID; + switch (_screenOrientation) { + case kScreenOrientationPortrait: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_UP; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_DOWN; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_RIGHT; + break; + default: + return false; + } + break; + case kScreenOrientationLandscape: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_RIGHT; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_DOWN; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_UP; + break; + default: + return false; + } + break; + case kScreenOrientationFlippedLandscape: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_RIGHT; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_UP; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_DOWN; + break; + default: + return false; + } + break; + } + + event.kbd.keycode = _queuedInputEvent.kbd.keycode = keycode; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = 0; + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + + return true; + } + else if (touches == 2) { + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: { + _mouseClickAndDragEnabled = !_mouseClickAndDragEnabled; + const char *dialogMsg; + if (_mouseClickAndDragEnabled) { + _touchpadModeEnabled = false; + dialogMsg = _("Mouse-click-and-drag mode enabled."); + } else + dialogMsg = _("Mouse-click-and-drag mode disabled."); + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return false; + } + + case kUIViewSwipeDown: { + // Swipe down + event.type = Common::EVENT_MAINMENU; + _queuedInputEvent.type = Common::EVENT_INVALID; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + return true; + } + + case kUIViewSwipeRight: { + // Swipe right + _touchpadModeEnabled = !_touchpadModeEnabled; + const char *dialogMsg; + if (_touchpadModeEnabled) + dialogMsg = _("Touchpad mode enabled."); + else + dialogMsg = _("Touchpad mode disabled."); + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return false; + } + + default: + break; + } + } + return false; +} + +bool OSystem_IPHONE::handleEvent_tap(Common::Event &event, UIViewTapDescription type, int touches) { + if (touches == 1) { + if (type == kUIViewTapDouble) { + event.type = Common::EVENT_RBUTTONDOWN; + _queuedInputEvent.type = Common::EVENT_RBUTTONUP; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + return true; + } + } + else if (touches == 2) { + if (type == kUIViewTapDouble) { + event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE; + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + return true; + } + } + return false; +} diff --git a/backends/platform/ios7/osys_main.cpp b/backends/platform/ios7/osys_main.cpp new file mode 100644 index 0000000000..ef3499d597 --- /dev/null +++ b/backends/platform/ios7/osys_main.cpp @@ -0,0 +1,344 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include +#include + +#include + +#include "common/scummsys.h" +#include "common/util.h" +#include "common/rect.h" +#include "common/file.h" +#include "common/fs.h" + +#include "base/main.h" + +#include "backends/saves/default/default-saves.h" +#include "backends/timer/default/default-timer.h" +#include "backends/fs/chroot/chroot-fs-factory.h" +#include "backends/fs/posix/posix-fs.h" +#include "audio/mixer.h" +#include "audio/mixer_intern.h" + +#include "osys_main.h" + + +const OSystem::GraphicsMode OSystem_IPHONE::s_supportedGraphicsModes[] = { + { "linear", "Linear filtering", kGraphicsModeLinear }, + { "none", "No filtering", kGraphicsModeNone }, + { 0, 0, 0 } +}; + +AQCallbackStruct OSystem_IPHONE::s_AudioQueue; +SoundProc OSystem_IPHONE::s_soundCallback = NULL; +void *OSystem_IPHONE::s_soundParam = NULL; + +OSystem_IPHONE::OSystem_IPHONE() : + _mixer(NULL), _lastMouseTap(0), _queuedEventTime(0), + _mouseNeedTextureUpdate(false), _secondaryTapped(false), _lastSecondaryTap(0), + _screenOrientation(kScreenOrientationFlippedLandscape), _mouseClickAndDragEnabled(false), + _gestureStartX(-1), _gestureStartY(-1), _fullScreenIsDirty(false), _fullScreenOverlayIsDirty(false), + _mouseDirty(false), _timeSuspended(0), _lastDragPosX(-1), _lastDragPosY(-1), _screenChangeCount(0), + _mouseCursorPaletteEnabled(false), _gfxTransactionError(kTransactionSuccess) { + _queuedInputEvent.type = Common::EVENT_INVALID; + _touchpadModeEnabled = !iPhone_isHighResDevice(); +#ifdef IPHONE_OFFICIAL + _fsFactory = new ChRootFilesystemFactory(iPhone_getDocumentsDir()); +#else + _fsFactory = new POSIXFilesystemFactory(); +#endif + initVideoContext(); + + memset(_gamePalette, 0, sizeof(_gamePalette)); + memset(_gamePaletteRGBA5551, 0, sizeof(_gamePaletteRGBA5551)); + memset(_mouseCursorPalette, 0, sizeof(_mouseCursorPalette)); +} + +OSystem_IPHONE::~OSystem_IPHONE() { + AudioQueueDispose(s_AudioQueue.queue, true); + + delete _mixer; + // Prevent accidental freeing of the screen texture here. This needs to be + // checked since we might use the screen texture as framebuffer in the case + // of hi-color games for example. Otherwise this can lead to a double free. + if (_framebuffer.getPixels() != _videoContext->screenTexture.getPixels()) + _framebuffer.free(); + _mouseBuffer.free(); +} + +bool OSystem_IPHONE::touchpadModeEnabled() const { + return _touchpadModeEnabled; +} + +int OSystem_IPHONE::timerHandler(int t) { + DefaultTimerManager *tm = (DefaultTimerManager *)g_system->getTimerManager(); + tm->handler(); + return t; +} + +void OSystem_IPHONE::initBackend() { +#ifdef IPHONE_OFFICIAL + _savefileManager = new DefaultSaveFileManager("/Savegames"); +#else + _savefileManager = new DefaultSaveFileManager(SCUMMVM_SAVE_PATH); +#endif + + _timerManager = new DefaultTimerManager(); + + gettimeofday(&_startTime, NULL); + + setupMixer(); + + setTimerCallback(&OSystem_IPHONE::timerHandler, 10); + + EventsBaseBackend::initBackend(); +} + +bool OSystem_IPHONE::hasFeature(Feature f) { + switch (f) { + case kFeatureCursorPalette: + return true; + + default: + return false; + } +} + +void OSystem_IPHONE::setFeatureState(Feature f, bool enable) { + switch (f) { + case kFeatureCursorPalette: + if (_mouseCursorPaletteEnabled != enable) { + _mouseNeedTextureUpdate = true; + _mouseDirty = true; + _mouseCursorPaletteEnabled = enable; + } + break; + case kFeatureAspectRatioCorrection: + _videoContext->asprectRatioCorrection = enable; + break; + + default: + break; + } +} + +bool OSystem_IPHONE::getFeatureState(Feature f) { + switch (f) { + case kFeatureCursorPalette: + return _mouseCursorPaletteEnabled; + case kFeatureAspectRatioCorrection: + return _videoContext->asprectRatioCorrection; + + default: + return false; + } +} + +void OSystem_IPHONE::suspendLoop() { + bool done = false; + uint32 startTime = getMillis(); + + stopSoundsystem(); + + InternalEvent event; + while (!done) { + if (iPhone_fetchEvent(&event)) + if (event.type == kInputApplicationResumed) + done = true; + usleep(100000); + } + + startSoundsystem(); + + _timeSuspended += getMillis() - startTime; +} + +uint32 OSystem_IPHONE::getMillis(bool skipRecord) { + //printf("getMillis()\n"); + + struct timeval currentTime; + gettimeofday(¤tTime, NULL); + return (uint32)(((currentTime.tv_sec - _startTime.tv_sec) * 1000) + + ((currentTime.tv_usec - _startTime.tv_usec) / 1000)) - _timeSuspended; +} + +void OSystem_IPHONE::delayMillis(uint msecs) { + //printf("delayMillis(%d)\n", msecs); + usleep(msecs * 1000); +} + +OSystem::MutexRef OSystem_IPHONE::createMutex(void) { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + + pthread_mutex_t *mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t)); + if (pthread_mutex_init(mutex, &attr) != 0) { + printf("pthread_mutex_init() failed!\n"); + free(mutex); + return NULL; + } + + return (MutexRef)mutex; +} + +void OSystem_IPHONE::lockMutex(MutexRef mutex) { + if (pthread_mutex_lock((pthread_mutex_t *) mutex) != 0) { + printf("pthread_mutex_lock() failed!\n"); + } +} + +void OSystem_IPHONE::unlockMutex(MutexRef mutex) { + if (pthread_mutex_unlock((pthread_mutex_t *) mutex) != 0) { + printf("pthread_mutex_unlock() failed!\n"); + } +} + +void OSystem_IPHONE::deleteMutex(MutexRef mutex) { + if (pthread_mutex_destroy((pthread_mutex_t *) mutex) != 0) { + printf("pthread_mutex_destroy() failed!\n"); + } else { + free(mutex); + } +} + + +void OSystem_IPHONE::setTimerCallback(TimerProc callback, int interval) { + //printf("setTimerCallback()\n"); + + if (callback != NULL) { + _timerCallbackTimer = interval; + _timerCallbackNext = getMillis() + interval; + _timerCallback = callback; + } else + _timerCallback = NULL; +} + +void OSystem_IPHONE::quit() { +} + +void OSystem_IPHONE::getTimeAndDate(TimeDate &td) const { + time_t curTime = time(0); + struct tm t = *localtime(&curTime); + td.tm_sec = t.tm_sec; + td.tm_min = t.tm_min; + td.tm_hour = t.tm_hour; + td.tm_mday = t.tm_mday; + td.tm_mon = t.tm_mon; + td.tm_year = t.tm_year; + td.tm_wday = t.tm_wday; +} + +Audio::Mixer *OSystem_IPHONE::getMixer() { + assert(_mixer); + return _mixer; +} + +OSystem *OSystem_IPHONE_create() { + return new OSystem_IPHONE(); +} + +Common::String OSystem_IPHONE::getDefaultConfigFileName() { +#ifdef IPHONE_OFFICIAL + Common::String path = "/Preferences"; + return path; +#else + return SCUMMVM_PREFS_PATH; +#endif +} + +void OSystem_IPHONE::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { + // Get URL of the Resource directory of the .app bundle + CFURLRef fileUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); + if (fileUrl) { + // Try to convert the URL to an absolute path + UInt8 buf[MAXPATHLEN]; + if (CFURLGetFileSystemRepresentation(fileUrl, true, buf, sizeof(buf))) { + // Success: Add it to the search path + Common::String bundlePath((const char *)buf); +#ifdef IPHONE_OFFICIAL + POSIXFilesystemNode *posixNode = new POSIXFilesystemNode(bundlePath); + Common::FSNode *node = new Common::FSNode(posixNode); + s.add("__OSX_BUNDLE__", new Common::FSDirectory(*node), priority); +#else + // OS X + s.add("__OSX_BUNDLE__", new Common::FSDirectory(bundlePath), priority); +#endif + } + CFRelease(fileUrl); + } +} + +void OSystem_IPHONE::logMessage(LogMessageType::Type type, const char *message) { + FILE *output = 0; + + if (type == LogMessageType::kInfo || type == LogMessageType::kDebug) + output = stdout; + else + output = stderr; + + fputs(message, output); + fflush(output); +} + +bool iphone_touchpadModeEnabled() { + OSystem_IPHONE *sys = (OSystem_IPHONE *) g_system; + return sys && sys->touchpadModeEnabled(); +} + +void iphone_main(int argc, char *argv[]) { + + //OSystem_IPHONE::migrateApp(); + + FILE *newfp = fopen("/var/mobile/.scummvm.log", "a"); + if (newfp != NULL) { + fclose(stdout); + fclose(stderr); + *stdout = *newfp; + *stderr = *newfp; + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + //extern int gDebugLevel; + //gDebugLevel = 10; + } + +#ifdef IPHONE_OFFICIAL + chdir(iPhone_getDocumentsDir()); +#else + system("mkdir " SCUMMVM_ROOT_PATH); + system("mkdir " SCUMMVM_SAVE_PATH); + + chdir("/var/mobile/"); +#endif + + g_system = OSystem_IPHONE_create(); + assert(g_system); + + // Invoke the actual ScummVM main entry point: + scummvm_main(argc, argv); + g_system->quit(); // TODO: Consider removing / replacing this! +} diff --git a/backends/platform/ios7/osys_main.h b/backends/platform/ios7/osys_main.h new file mode 100644 index 0000000000..04a531613f --- /dev/null +++ b/backends/platform/ios7/osys_main.h @@ -0,0 +1,224 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#ifndef BACKENDS_PLATFORM_IPHONE_OSYS_MAIN_H +#define BACKENDS_PLATFORM_IPHONE_OSYS_MAIN_H + +#include "graphics/surface.h" +#include "iphone_common.h" +#include "backends/base-backend.h" +#include "common/events.h" +#include "audio/mixer_intern.h" +#include "backends/fs/posix/posix-fs-factory.h" +#include "graphics/colormasks.h" +#include "graphics/palette.h" + +#include + +#define AUDIO_BUFFERS 3 +#define WAVE_BUFFER_SIZE 2048 +#define AUDIO_SAMPLE_RATE 44100 + +#define SCUMMVM_ROOT_PATH "/var/mobile/Library/ScummVM" +#define SCUMMVM_SAVE_PATH SCUMMVM_ROOT_PATH "/Savegames" +#define SCUMMVM_PREFS_PATH SCUMMVM_ROOT_PATH "/Preferences" + +typedef void (*SoundProc)(void *param, byte *buf, int len); +typedef int (*TimerProc)(int interval); + +struct AQCallbackStruct { + AudioQueueRef queue; + uint32 frameCount; + AudioQueueBufferRef buffers[AUDIO_BUFFERS]; + AudioStreamBasicDescription dataFormat; +}; + +class OSystem_IPHONE : public EventsBaseBackend, public PaletteManager { +protected: + static const OSystem::GraphicsMode s_supportedGraphicsModes[]; + static AQCallbackStruct s_AudioQueue; + static SoundProc s_soundCallback; + static void *s_soundParam; + + Audio::MixerImpl *_mixer; + + VideoContext *_videoContext; + + Graphics::Surface _framebuffer; + + // For signaling that screen format set up might have failed. + TransactionError _gfxTransactionError; + + // For use with the game texture + uint16 _gamePalette[256]; + // For use with the mouse texture + uint16 _gamePaletteRGBA5551[256]; + + struct timeval _startTime; + uint32 _timeSuspended; + + bool _mouseCursorPaletteEnabled; + uint16 _mouseCursorPalette[256]; + Graphics::Surface _mouseBuffer; + uint16 _mouseKeyColor; + bool _mouseDirty; + bool _mouseNeedTextureUpdate; + + long _lastMouseDown; + long _lastMouseTap; + long _queuedEventTime; + Common::Event _queuedInputEvent; + bool _secondaryTapped; + long _lastSecondaryDown; + long _lastSecondaryTap; + int _gestureStartX, _gestureStartY; + bool _mouseClickAndDragEnabled; + bool _touchpadModeEnabled; + int _lastPadX; + int _lastPadY; + int _lastDragPosX; + int _lastDragPosY; + + int _timerCallbackNext; + int _timerCallbackTimer; + TimerProc _timerCallback; + + Common::Array _dirtyRects; + Common::Array _dirtyOverlayRects; + ScreenOrientation _screenOrientation; + bool _fullScreenIsDirty; + bool _fullScreenOverlayIsDirty; + int _screenChangeCount; + +public: + + OSystem_IPHONE(); + virtual ~OSystem_IPHONE(); + + virtual void initBackend(); + + virtual bool hasFeature(Feature f); + virtual void setFeatureState(Feature f, bool enable); + virtual bool getFeatureState(Feature f); + virtual const GraphicsMode *getSupportedGraphicsModes() const; + virtual int getDefaultGraphicsMode() const; + virtual bool setGraphicsMode(int mode); + virtual int getGraphicsMode() const; + virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format); + + virtual void beginGFXTransaction(); + virtual TransactionError endGFXTransaction(); + + virtual int16 getHeight(); + virtual int16 getWidth(); + + bool touchpadModeEnabled() const; + +#ifdef USE_RGB_COLOR + virtual Graphics::PixelFormat getScreenFormat() const { return _framebuffer.format; } + virtual Common::List getSupportedFormats() const; +#endif + + virtual PaletteManager *getPaletteManager() { return this; } +protected: + // PaletteManager API + virtual void setPalette(const byte *colors, uint start, uint num); + virtual void grabPalette(byte *colors, uint start, uint num); + +public: + virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h); + virtual void updateScreen(); + virtual Graphics::Surface *lockScreen(); + virtual void unlockScreen(); + virtual void setShakePos(int shakeOffset); + + virtual void showOverlay(); + virtual void hideOverlay(); + virtual void clearOverlay(); + virtual void grabOverlay(void *buf, int pitch); + virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h); + virtual int16 getOverlayHeight(); + virtual int16 getOverlayWidth(); + virtual Graphics::PixelFormat getOverlayFormat() const { return Graphics::createPixelFormat<5551>(); } + + virtual bool showMouse(bool visible); + + virtual void warpMouse(int x, int y); + virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 255, bool dontScale = false, const Graphics::PixelFormat *format = NULL); + virtual void setCursorPalette(const byte *colors, uint start, uint num); + + virtual bool pollEvent(Common::Event &event); + virtual uint32 getMillis(bool skipRecord = false); + virtual void delayMillis(uint msecs); + + virtual MutexRef createMutex(void); + virtual void lockMutex(MutexRef mutex); + virtual void unlockMutex(MutexRef mutex); + virtual void deleteMutex(MutexRef mutex); + + static void mixCallback(void *sys, byte *samples, int len); + virtual void setupMixer(void); + virtual void setTimerCallback(TimerProc callback, int interval); + virtual int getScreenChangeID() const { return _screenChangeCount; } + virtual void quit(); + + virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); + virtual void getTimeAndDate(TimeDate &t) const; + + virtual Audio::Mixer *getMixer(); + + void startSoundsystem(); + void stopSoundsystem(); + + virtual Common::String getDefaultConfigFileName(); + + virtual void logMessage(LogMessageType::Type type, const char *message); + +protected: + void initVideoContext(); + void updateOutputSurface(); + + void internUpdateScreen(); + void dirtyFullScreen(); + void dirtyFullOverlayScreen(); + void suspendLoop(); + void drawDirtyRect(const Common::Rect &dirtyRect); + void updateMouseTexture(); + static void AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB); + static int timerHandler(int t); + + bool handleEvent_swipe(Common::Event &event, int direction, int touches); + bool handleEvent_tap(Common::Event &event, UIViewTapDescription type, int touches); + void handleEvent_keyPressed(Common::Event &event, int keyPressed); + void handleEvent_orientationChanged(int orientation); + + bool handleEvent_mouseDown(Common::Event &event, int x, int y); + bool handleEvent_mouseUp(Common::Event &event, int x, int y); + + bool handleEvent_secondMouseDown(Common::Event &event, int x, int y); + bool handleEvent_secondMouseUp(Common::Event &event, int x, int y); + + bool handleEvent_mouseDragged(Common::Event &event, int x, int y); + bool handleEvent_mouseSecondDragged(Common::Event &event, int x, int y); +}; + +#endif diff --git a/backends/platform/ios7/osys_sound.cpp b/backends/platform/ios7/osys_sound.cpp new file mode 100644 index 0000000000..bfee06c6f2 --- /dev/null +++ b/backends/platform/ios7/osys_sound.cpp @@ -0,0 +1,105 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "osys_main.h" + +void OSystem_IPHONE::AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB) { + //printf("AQBufferCallback()\n"); + if (s_AudioQueue.frameCount > 0 && s_soundCallback != NULL) { + outQB->mAudioDataByteSize = 4 * s_AudioQueue.frameCount; + s_soundCallback(s_soundParam, (byte *)outQB->mAudioData, outQB->mAudioDataByteSize); + AudioQueueEnqueueBuffer(inQ, outQB, 0, NULL); + } else { + AudioQueueStop(s_AudioQueue.queue, false); + } +} + +void OSystem_IPHONE::mixCallback(void *sys, byte *samples, int len) { + OSystem_IPHONE *this_ = (OSystem_IPHONE *)sys; + assert(this_); + + if (this_->_mixer) { + this_->_mixer->mixCallback(samples, len); + } +} + +void OSystem_IPHONE::setupMixer() { + _mixer = new Audio::MixerImpl(this, AUDIO_SAMPLE_RATE); + + s_soundCallback = mixCallback; + s_soundParam = this; + + startSoundsystem(); +} + +void OSystem_IPHONE::startSoundsystem() { + s_AudioQueue.dataFormat.mSampleRate = AUDIO_SAMPLE_RATE; + s_AudioQueue.dataFormat.mFormatID = kAudioFormatLinearPCM; + s_AudioQueue.dataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; + s_AudioQueue.dataFormat.mBytesPerPacket = 4; + s_AudioQueue.dataFormat.mFramesPerPacket = 1; + s_AudioQueue.dataFormat.mBytesPerFrame = 4; + s_AudioQueue.dataFormat.mChannelsPerFrame = 2; + s_AudioQueue.dataFormat.mBitsPerChannel = 16; + s_AudioQueue.frameCount = WAVE_BUFFER_SIZE; + + if (AudioQueueNewOutput(&s_AudioQueue.dataFormat, AQBufferCallback, &s_AudioQueue, 0, kCFRunLoopCommonModes, 0, &s_AudioQueue.queue)) { + printf("Couldn't set the AudioQueue callback!\n"); + _mixer->setReady(false); + return; + } + + uint32 bufferBytes = s_AudioQueue.frameCount * s_AudioQueue.dataFormat.mBytesPerFrame; + + for (int i = 0; i < AUDIO_BUFFERS; i++) { + if (AudioQueueAllocateBuffer(s_AudioQueue.queue, bufferBytes, &s_AudioQueue.buffers[i])) { + printf("Error allocating AudioQueue buffer!\n"); + _mixer->setReady(false); + return; + } + + AQBufferCallback(&s_AudioQueue, s_AudioQueue.queue, s_AudioQueue.buffers[i]); + } + + AudioQueueSetParameter(s_AudioQueue.queue, kAudioQueueParam_Volume, 1.0); + if (AudioQueueStart(s_AudioQueue.queue, NULL)) { + printf("Error starting the AudioQueue!\n"); + _mixer->setReady(false); + return; + } + + _mixer->setReady(true); +} + +void OSystem_IPHONE::stopSoundsystem() { + AudioQueueStop(s_AudioQueue.queue, true); + + for (int i = 0; i < AUDIO_BUFFERS; i++) { + AudioQueueFreeBuffer(s_AudioQueue.queue, s_AudioQueue.buffers[i]); + } + + AudioQueueDispose(s_AudioQueue.queue, true); + _mixer->setReady(false); +} diff --git a/backends/platform/ios7/osys_video.mm b/backends/platform/ios7/osys_video.mm new file mode 100644 index 0000000000..c76f432dda --- /dev/null +++ b/backends/platform/ios7/osys_video.mm @@ -0,0 +1,503 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "osys_main.h" +#include "iphone_video.h" + +#include "graphics/conversion.h" + +void OSystem_IPHONE::initVideoContext() { + _videoContext = [g_iPhoneViewInstance getVideoContext]; +} + +const OSystem::GraphicsMode *OSystem_IPHONE::getSupportedGraphicsModes() const { + return s_supportedGraphicsModes; +} + +int OSystem_IPHONE::getDefaultGraphicsMode() const { + return kGraphicsModeLinear; +} + +bool OSystem_IPHONE::setGraphicsMode(int mode) { + switch (mode) { + case kGraphicsModeNone: + case kGraphicsModeLinear: + _videoContext->graphicsMode = (GraphicsModes)mode; + return true; + + default: + return false; + } +} + +int OSystem_IPHONE::getGraphicsMode() const { + return _videoContext->graphicsMode; +} + +#ifdef USE_RGB_COLOR +Common::List OSystem_IPHONE::getSupportedFormats() const { + Common::List list; + // RGB565 + list.push_back(Graphics::createPixelFormat<565>()); + // CLUT8 + list.push_back(Graphics::PixelFormat::createFormatCLUT8()); + return list; +} +#endif + +void OSystem_IPHONE::initSize(uint width, uint height, const Graphics::PixelFormat *format) { + //printf("initSize(%u, %u, %p)\n", width, height, (const void *)format); + + _videoContext->screenWidth = width; + _videoContext->screenHeight = height; + _videoContext->shakeOffsetY = 0; + + // In case we use the screen texture as frame buffer we reset the pixels + // pointer here to avoid freeing the screen texture. + if (_framebuffer.getPixels() == _videoContext->screenTexture.getPixels()) + _framebuffer.setPixels(0); + + // Create the screen texture right here. We need to do this here, since + // when a game requests hi-color mode, we actually set the framebuffer + // to the texture buffer to avoid an additional copy step. + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(createScreenTexture) withObject:nil waitUntilDone: YES]; + + // In case the client code tries to set up a non supported mode, we will + // fall back to CLUT8 and set the transaction error accordingly. + if (format && format->bytesPerPixel != 1 && *format != _videoContext->screenTexture.format) { + format = 0; + _gfxTransactionError = kTransactionFormatNotSupported; + } + + if (!format || format->bytesPerPixel == 1) { + _framebuffer.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + } else { +#if 0 + printf("bytesPerPixel: %u RGBAlosses: %u,%u,%u,%u RGBAshifts: %u,%u,%u,%u\n", format->bytesPerPixel, + format->rLoss, format->gLoss, format->bLoss, format->aLoss, + format->rShift, format->gShift, format->bShift, format->aShift); +#endif + // We directly draw on the screen texture in hi-color mode. Thus + // we copy over its settings here and just replace the width and + // height to avoid any problems. + _framebuffer = _videoContext->screenTexture; + _framebuffer.w = width; + _framebuffer.h = height; + } + + _fullScreenIsDirty = false; + dirtyFullScreen(); + _mouseCursorPaletteEnabled = false; +} + +void OSystem_IPHONE::beginGFXTransaction() { + _gfxTransactionError = kTransactionSuccess; +} + +OSystem::TransactionError OSystem_IPHONE::endGFXTransaction() { + _screenChangeCount++; + updateOutputSurface(); + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(setGraphicsMode) withObject:nil waitUntilDone: YES]; + + return _gfxTransactionError; +} + +void OSystem_IPHONE::updateOutputSurface() { + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(initSurface) withObject:nil waitUntilDone: YES]; +} + +int16 OSystem_IPHONE::getHeight() { + return _videoContext->screenHeight; +} + +int16 OSystem_IPHONE::getWidth() { + return _videoContext->screenWidth; +} + +void OSystem_IPHONE::setPalette(const byte *colors, uint start, uint num) { + //printf("setPalette(%p, %u, %u)\n", colors, start, num); + assert(start + num <= 256); + const byte *b = colors; + + for (uint i = start; i < start + num; ++i) { + _gamePalette[i] = Graphics::RGBToColor >(b[0], b[1], b[2]); + _gamePaletteRGBA5551[i] = Graphics::RGBToColor >(b[0], b[1], b[2]); + b += 3; + } + + dirtyFullScreen(); + + // Automatically update the mouse texture when the palette changes while the + // cursor palette is disabled. + if (!_mouseCursorPaletteEnabled && _mouseBuffer.format.bytesPerPixel == 1) + _mouseDirty = _mouseNeedTextureUpdate = true; +} + +void OSystem_IPHONE::grabPalette(byte *colors, uint start, uint num) { + //printf("grabPalette(%p, %u, %u)\n", colors, start, num); + assert(start + num <= 256); + byte *b = colors; + + for (uint i = start; i < start + num; ++i) { + Graphics::colorToRGB >(_gamePalette[i], b[0], b[1], b[2]); + b += 3; + } +} + +void OSystem_IPHONE::copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) { + //printf("copyRectToScreen(%p, %d, %i, %i, %i, %i)\n", buf, pitch, x, y, w, h); + //Clip the coordinates + const byte *src = (const byte *)buf; + if (x < 0) { + w += x; + src -= x; + x = 0; + } + + if (y < 0) { + h += y; + src -= y * pitch; + y = 0; + } + + if (w > (int)_framebuffer.w - x) { + w = _framebuffer.w - x; + } + + if (h > (int)_framebuffer.h - y) { + h = _framebuffer.h - y; + } + + if (w <= 0 || h <= 0) + return; + + if (!_fullScreenIsDirty) { + _dirtyRects.push_back(Common::Rect(x, y, x + w, y + h)); + } + + byte *dst = (byte *)_framebuffer.getBasePtr(x, y); + if (_framebuffer.pitch == pitch && _framebuffer.w == w) { + memcpy(dst, src, h * pitch); + } else { + do { + memcpy(dst, src, w * _framebuffer.format.bytesPerPixel); + src += pitch; + dst += _framebuffer.pitch; + } while (--h); + } +} + +void OSystem_IPHONE::updateScreen() { + if (_dirtyRects.size() == 0 && _dirtyOverlayRects.size() == 0 && !_mouseDirty) + return; + + //printf("updateScreen(): %i dirty rects.\n", _dirtyRects.size()); + + internUpdateScreen(); + _mouseDirty = false; + _fullScreenIsDirty = false; + _fullScreenOverlayIsDirty = false; + + iPhone_updateScreen(); +} + +void OSystem_IPHONE::internUpdateScreen() { + if (_mouseNeedTextureUpdate) { + updateMouseTexture(); + _mouseNeedTextureUpdate = false; + } + + while (_dirtyRects.size()) { + Common::Rect dirtyRect = _dirtyRects.remove_at(_dirtyRects.size() - 1); + + //printf("Drawing: (%i, %i) -> (%i, %i)\n", dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); + drawDirtyRect(dirtyRect); + // TODO: Implement dirty rect code + //updateHardwareSurfaceForRect(dirtyRect); + } + + if (_videoContext->overlayVisible) { + // TODO: Implement dirty rect code + _dirtyOverlayRects.clear(); + /*while (_dirtyOverlayRects.size()) { + Common::Rect dirtyRect = _dirtyOverlayRects.remove_at(_dirtyOverlayRects.size() - 1); + + //printf("Drawing: (%i, %i) -> (%i, %i)\n", dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); + drawDirtyOverlayRect(dirtyRect); + }*/ + } +} + +void OSystem_IPHONE::drawDirtyRect(const Common::Rect &dirtyRect) { + // We only need to do a color look up for CLUT8 + if (_framebuffer.format.bytesPerPixel != 1) + return; + + int h = dirtyRect.bottom - dirtyRect.top; + int w = dirtyRect.right - dirtyRect.left; + + const byte *src = (const byte *)_framebuffer.getBasePtr(dirtyRect.left, dirtyRect.top); + byte *dstRaw = (byte *)_videoContext->screenTexture.getBasePtr(dirtyRect.left, dirtyRect.top); + + // When we use CLUT8 do a color look up + for (int y = h; y > 0; y--) { + uint16 *dst = (uint16 *)dstRaw; + for (int x = w; x > 0; x--) + *dst++ = _gamePalette[*src++]; + + dstRaw += _videoContext->screenTexture.pitch; + src += _framebuffer.pitch - w; + } +} + +Graphics::Surface *OSystem_IPHONE::lockScreen() { + //printf("lockScreen()\n"); + return &_framebuffer; +} + +void OSystem_IPHONE::unlockScreen() { + //printf("unlockScreen()\n"); + dirtyFullScreen(); +} + +void OSystem_IPHONE::setShakePos(int shakeOffset) { + //printf("setShakePos(%i)\n", shakeOffset); + _videoContext->shakeOffsetY = shakeOffset; + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(setViewTransformation) withObject:nil waitUntilDone: YES]; + // HACK: We use this to force a redraw. + _mouseDirty = true; +} + +void OSystem_IPHONE::showOverlay() { + //printf("showOverlay()\n"); + _videoContext->overlayVisible = true; + dirtyFullOverlayScreen(); + updateScreen(); + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateMouseCursorScaling) withObject:nil waitUntilDone: YES]; + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES]; +} + +void OSystem_IPHONE::hideOverlay() { + //printf("hideOverlay()\n"); + _videoContext->overlayVisible = false; + _dirtyOverlayRects.clear(); + dirtyFullScreen(); + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateMouseCursorScaling) withObject:nil waitUntilDone: YES]; + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES]; +} + +void OSystem_IPHONE::clearOverlay() { + //printf("clearOverlay()\n"); + bzero(_videoContext->overlayTexture.getPixels(), _videoContext->overlayTexture.h * _videoContext->overlayTexture.pitch); + dirtyFullOverlayScreen(); +} + +void OSystem_IPHONE::grabOverlay(void *buf, int pitch) { + //printf("grabOverlay()\n"); + int h = _videoContext->overlayHeight; + + byte *dst = (byte *)buf; + const byte *src = (const byte *)_videoContext->overlayTexture.getPixels(); + do { + memcpy(dst, src, _videoContext->overlayWidth * sizeof(uint16)); + src += _videoContext->overlayTexture.pitch; + dst += pitch; + } while (--h); +} + +void OSystem_IPHONE::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) { + //printf("copyRectToOverlay(%p, pitch=%i, x=%i, y=%i, w=%i, h=%i)\n", (const void *)buf, pitch, x, y, w, h); + const byte *src = (const byte *)buf; + + //Clip the coordinates + if (x < 0) { + w += x; + src -= x * sizeof(uint16); + x = 0; + } + + if (y < 0) { + h += y; + src -= y * pitch; + y = 0; + } + + if (w > (int)_videoContext->overlayWidth - x) + w = _videoContext->overlayWidth - x; + + if (h > (int)_videoContext->overlayHeight - y) + h = _videoContext->overlayHeight - y; + + if (w <= 0 || h <= 0) + return; + + if (!_fullScreenOverlayIsDirty) { + _dirtyOverlayRects.push_back(Common::Rect(x, y, x + w, y + h)); + } + + byte *dst = (byte *)_videoContext->overlayTexture.getBasePtr(x, y); + do { + memcpy(dst, src, w * sizeof(uint16)); + src += pitch; + dst += _videoContext->overlayTexture.pitch; + } while (--h); +} + +int16 OSystem_IPHONE::getOverlayHeight() { + return _videoContext->overlayHeight; +} + +int16 OSystem_IPHONE::getOverlayWidth() { + return _videoContext->overlayWidth; +} + +bool OSystem_IPHONE::showMouse(bool visible) { + //printf("showMouse(%d)\n", visible); + bool last = _videoContext->mouseIsVisible; + _videoContext->mouseIsVisible = visible; + _mouseDirty = true; + + return last; +} + +void OSystem_IPHONE::warpMouse(int x, int y) { + //printf("warpMouse(%d, %d)\n", x, y); + _videoContext->mouseX = x; + _videoContext->mouseY = y; + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(notifyMouseMove) withObject:nil waitUntilDone: YES]; + _mouseDirty = true; +} + +void OSystem_IPHONE::dirtyFullScreen() { + if (!_fullScreenIsDirty) { + _dirtyRects.clear(); + _dirtyRects.push_back(Common::Rect(0, 0, _videoContext->screenWidth, _videoContext->screenHeight)); + _fullScreenIsDirty = true; + } +} + +void OSystem_IPHONE::dirtyFullOverlayScreen() { + if (!_fullScreenOverlayIsDirty) { + _dirtyOverlayRects.clear(); + _dirtyOverlayRects.push_back(Common::Rect(0, 0, _videoContext->overlayWidth, _videoContext->overlayHeight)); + _fullScreenOverlayIsDirty = true; + } +} + +void OSystem_IPHONE::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { + //printf("setMouseCursor(%p, %u, %u, %i, %i, %u, %d, %p)\n", (const void *)buf, w, h, hotspotX, hotspotY, keycolor, dontScale, (const void *)format); + + const Graphics::PixelFormat pixelFormat = format ? *format : Graphics::PixelFormat::createFormatCLUT8(); +#if 0 + printf("bytesPerPixel: %u RGBAlosses: %u,%u,%u,%u RGBAshifts: %u,%u,%u,%u\n", pixelFormat.bytesPerPixel, + pixelFormat.rLoss, pixelFormat.gLoss, pixelFormat.bLoss, pixelFormat.aLoss, + pixelFormat.rShift, pixelFormat.gShift, pixelFormat.bShift, pixelFormat.aShift); +#endif + assert(pixelFormat.bytesPerPixel == 1 || pixelFormat.bytesPerPixel == 2); + + if (_mouseBuffer.w != w || _mouseBuffer.h != h || _mouseBuffer.format != pixelFormat || !_mouseBuffer.getPixels()) + _mouseBuffer.create(w, h, pixelFormat); + + _videoContext->mouseWidth = w; + _videoContext->mouseHeight = h; + + _videoContext->mouseHotspotX = hotspotX; + _videoContext->mouseHotspotY = hotspotY; + + _mouseKeyColor = keycolor; + + memcpy(_mouseBuffer.getPixels(), buf, h * _mouseBuffer.pitch); + + _mouseDirty = true; + _mouseNeedTextureUpdate = true; +} + +void OSystem_IPHONE::setCursorPalette(const byte *colors, uint start, uint num) { + //printf("setCursorPalette(%p, %u, %u)\n", (const void *)colors, start, num); + assert(start + num <= 256); + + for (uint i = start; i < start + num; ++i, colors += 3) + _mouseCursorPalette[i] = Graphics::RGBToColor >(colors[0], colors[1], colors[2]); + + // FIXME: This is just stupid, our client code seems to assume that this + // automatically enables the cursor palette. + _mouseCursorPaletteEnabled = true; + + if (_mouseCursorPaletteEnabled) + _mouseDirty = _mouseNeedTextureUpdate = true; +} + +void OSystem_IPHONE::updateMouseTexture() { + uint texWidth = getSizeNextPOT(_videoContext->mouseWidth); + uint texHeight = getSizeNextPOT(_videoContext->mouseHeight); + + Graphics::Surface &mouseTexture = _videoContext->mouseTexture; + if (mouseTexture.w != texWidth || mouseTexture.h != texHeight) + mouseTexture.create(texWidth, texHeight, Graphics::createPixelFormat<5551>()); + + if (_mouseBuffer.format.bytesPerPixel == 1) { + const uint16 *palette; + if (_mouseCursorPaletteEnabled) + palette = _mouseCursorPalette; + else + palette = _gamePaletteRGBA5551; + + uint16 *mouseBuf = (uint16 *)mouseTexture.getPixels(); + for (uint x = 0; x < _videoContext->mouseWidth; ++x) { + for (uint y = 0; y < _videoContext->mouseHeight; ++y) { + const byte color = *(const byte *)_mouseBuffer.getBasePtr(x, y); + if (color != _mouseKeyColor) + mouseBuf[y * texWidth + x] = palette[color] | 0x1; + else + mouseBuf[y * texWidth + x] = 0x0; + } + } + } else { + if (crossBlit((byte *)mouseTexture.getPixels(), (const byte *)_mouseBuffer.getPixels(), mouseTexture.pitch, + _mouseBuffer.pitch, _mouseBuffer.w, _mouseBuffer.h, mouseTexture.format, _mouseBuffer.format)) { + if (!_mouseBuffer.format.aBits()) { + // Apply color keying since the original cursor had no alpha channel. + const uint16 *src = (const uint16 *)_mouseBuffer.getPixels(); + uint8 *dstRaw = (uint8 *)mouseTexture.getPixels(); + + for (uint y = 0; y < _mouseBuffer.h; ++y, dstRaw += mouseTexture.pitch) { + uint16 *dst = (uint16 *)dstRaw; + for (uint x = 0; x < _mouseBuffer.w; ++x, ++dst) { + if (*src++ == _mouseKeyColor) + *dst &= ~1; + else + *dst |= 1; + } + } + } + } else { + // TODO: Log this! + // Make the cursor all transparent... we really need a better fallback ;-). + memset(mouseTexture.getPixels(), 0, mouseTexture.h * mouseTexture.pitch); + } + } + + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateMouseCursor) withObject:nil waitUntilDone: YES]; +} -- cgit v1.2.3 From 67ffd4b2bd3498476a309ce7133d5c1fef616fa3 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Fri, 4 Dec 2015 18:24:30 +0100 Subject: IOS: Updates compilation instructions --- backends/platform/ios7/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/README.md b/backends/platform/ios7/README.md index 0e22e6d2bd..a58905d3bc 100644 --- a/backends/platform/ios7/README.md +++ b/backends/platform/ios7/README.md @@ -42,9 +42,8 @@ For jailbroken devices, it is also possible to compile the project from command Open a terminal, and execute the following commands: ``` $ cd path_to_the_scummvm_sources -$ SDKROOT=$(xcrun --sdk iphoneos --show-sdk-path) CC=clang CXX=clang++ ./configure --host=iphone --disable-scalers --disable-mt32emu --enable-release -$ make iphone -$ make iphonebundle +$ SDKROOT=$(xcrun --sdk iphoneos --show-sdk-path) CC=clang CXX=clang++ ./configure --host=ios7 --disable-scalers --disable-mt32emu --enable-release +$ make ios7bundle ``` At the end of the compilation, you'll find a **ScummVM.app** application: copy it over SSH, and reboot your device. -- cgit v1.2.3 From 873e38372b6a8ec76f19e45e8680a064e39b53d2 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Sun, 6 Dec 2015 12:28:55 +0100 Subject: IOS: Removes new generic syntax to be able to compile with older clang toolchain --- backends/platform/ios7/iphone_video.mm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/iphone_video.mm b/backends/platform/ios7/iphone_video.mm index efd8ea3acf..8470651794 100644 --- a/backends/platform/ios7/iphone_video.mm +++ b/backends/platform/ios7/iphone_video.mm @@ -714,7 +714,7 @@ const char *iPhone_getDocumentsDir() { - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { int x, y; - NSSet *allTouches = [event allTouches]; + NSSet *allTouches = [event allTouches]; if (allTouches.count == 1) { _firstTouch = [allTouches anyObject]; CGPoint point = [_firstTouch locationInView:self]; @@ -738,7 +738,7 @@ const char *iPhone_getDocumentsDir() { - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { int x, y; - NSSet *allTouches = [event allTouches]; + NSSet *allTouches = [event allTouches]; for (UITouch *touch in allTouches) { if (touch == _firstTouch) { CGPoint point = [touch locationInView:self]; @@ -759,7 +759,7 @@ const char *iPhone_getDocumentsDir() { - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { int x, y; - NSSet *allTouches = [event allTouches]; + NSSet *allTouches = [event allTouches]; if (allTouches.count == 1) { UITouch *touch = [allTouches anyObject]; CGPoint point = [touch locationInView:self]; -- cgit v1.2.3 From 699c3504814300415ca983fbef2ed172fa9020de Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Mon, 7 Dec 2015 11:34:11 +0100 Subject: IOS: Renames iOS7 classes to avoid confusion --- backends/platform/ios7/iOS7MainApplication.h | 39 + backends/platform/ios7/iOS7MainApplication.mm | 121 +++ backends/platform/ios7/iOS7ScummVMViewController.h | 28 + .../platform/ios7/iOS7ScummVMViewController.mm | 32 + backends/platform/ios7/ios7_common.h | 117 +++ backends/platform/ios7/ios7_keyboard.h | 44 ++ backends/platform/ios7/ios7_keyboard.mm | 98 +++ backends/platform/ios7/ios7_main.mm | 47 ++ backends/platform/ios7/ios7_osys_events.cpp | 562 ++++++++++++++ backends/platform/ios7/ios7_osys_main.cpp | 344 +++++++++ backends/platform/ios7/ios7_osys_main.h | 224 ++++++ backends/platform/ios7/ios7_osys_sound.cpp | 105 +++ backends/platform/ios7/ios7_osys_video.mm | 503 +++++++++++++ backends/platform/ios7/ios7_video.h | 109 +++ backends/platform/ios7/ios7_video.mm | 815 ++++++++++++++++++++ backends/platform/ios7/iphone_common.h | 111 --- backends/platform/ios7/iphone_keyboard.h | 44 -- backends/platform/ios7/iphone_keyboard.mm | 98 --- backends/platform/ios7/iphone_main.mm | 154 ---- backends/platform/ios7/iphone_video.h | 109 --- backends/platform/ios7/iphone_video.mm | 821 --------------------- backends/platform/ios7/module.mk | 16 +- backends/platform/ios7/osys_events.cpp | 562 -------------- backends/platform/ios7/osys_main.cpp | 344 --------- backends/platform/ios7/osys_main.h | 224 ------ backends/platform/ios7/osys_sound.cpp | 105 --- backends/platform/ios7/osys_video.mm | 503 ------------- 27 files changed, 3197 insertions(+), 3082 deletions(-) create mode 100644 backends/platform/ios7/iOS7MainApplication.h create mode 100644 backends/platform/ios7/iOS7MainApplication.mm create mode 100644 backends/platform/ios7/iOS7ScummVMViewController.h create mode 100644 backends/platform/ios7/iOS7ScummVMViewController.mm create mode 100644 backends/platform/ios7/ios7_common.h create mode 100644 backends/platform/ios7/ios7_keyboard.h create mode 100644 backends/platform/ios7/ios7_keyboard.mm create mode 100644 backends/platform/ios7/ios7_main.mm create mode 100644 backends/platform/ios7/ios7_osys_events.cpp create mode 100644 backends/platform/ios7/ios7_osys_main.cpp create mode 100644 backends/platform/ios7/ios7_osys_main.h create mode 100644 backends/platform/ios7/ios7_osys_sound.cpp create mode 100644 backends/platform/ios7/ios7_osys_video.mm create mode 100644 backends/platform/ios7/ios7_video.h create mode 100644 backends/platform/ios7/ios7_video.mm delete mode 100644 backends/platform/ios7/iphone_common.h delete mode 100644 backends/platform/ios7/iphone_keyboard.h delete mode 100644 backends/platform/ios7/iphone_keyboard.mm delete mode 100644 backends/platform/ios7/iphone_main.mm delete mode 100644 backends/platform/ios7/iphone_video.h delete mode 100644 backends/platform/ios7/iphone_video.mm delete mode 100644 backends/platform/ios7/osys_events.cpp delete mode 100644 backends/platform/ios7/osys_main.cpp delete mode 100644 backends/platform/ios7/osys_main.h delete mode 100644 backends/platform/ios7/osys_sound.cpp delete mode 100644 backends/platform/ios7/osys_video.mm (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/iOS7MainApplication.h b/backends/platform/ios7/iOS7MainApplication.h new file mode 100644 index 0000000000..a47f5da9ce --- /dev/null +++ b/backends/platform/ios7/iOS7MainApplication.h @@ -0,0 +1,39 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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 + +@class iOS7ScummVMViewController; +@class iPhoneView; + +@interface iOS7MainApplication : UIApplication { + UIWindow *_window; + iOS7ScummVMViewController *_controller; + iPhoneView *_view; +} + +- (void)mainLoop:(id)param; +- (iPhoneView *)getView; +- (UIWindow *)getWindow; +- (void)didRotate:(NSNotification *)notification; +@end diff --git a/backends/platform/ios7/iOS7MainApplication.mm b/backends/platform/ios7/iOS7MainApplication.mm new file mode 100644 index 0000000000..c21c017174 --- /dev/null +++ b/backends/platform/ios7/iOS7MainApplication.mm @@ -0,0 +1,121 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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 "iOS7MainApplication.h" +#import "iOS7ScummVMViewController.h" + +#define FORBIDDEN_SYMBOL_ALLOW_ALL +#import "ios7_common.h" +#import "ios7_video.h" + + +@implementation iOS7MainApplication + +-(id)init { + [super init]; + _window = nil; + _view = nil; + return self; +} + +- (void)mainLoop:(id)param { + @autoreleasepool { + iOS7_main(iOS7_argc, iOS7_argv); + } + + exit(0); +} + +- (iPhoneView *)getView { + return _view; +} + +- (void)applicationDidFinishLaunching:(UIApplication *)application { + CGRect rect = [[UIScreen mainScreen] bounds]; + + // Create the directory for savegames +#ifdef IPHONE_OFFICIAL + NSFileManager *fm = [NSFileManager defaultManager]; + NSString *documentPath = [NSString stringWithUTF8String:iOS7_getDocumentsDir()]; + NSString *savePath = [documentPath stringByAppendingPathComponent:@"Savegames"]; + if (![fm fileExistsAtPath:savePath]) { + [fm createDirectoryAtPath:savePath withIntermediateDirectories:YES attributes:nil error:nil]; + } +#endif + + _window = [[UIWindow alloc] initWithFrame:rect]; + [_window retain]; + + _controller = [[iOS7ScummVMViewController alloc] init]; + + _view = [[iPhoneView alloc] initWithFrame:rect]; + _view.multipleTouchEnabled = YES; + _controller.view = _view; + + [_window setRootViewController:_controller]; + [_window makeKeyAndVisible]; + + [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didRotate:) + name:@"UIDeviceOrientationDidChangeNotification" + object:nil]; + + [NSThread detachNewThreadSelector:@selector(mainLoop:) toTarget:self withObject:nil]; +} + +- (void)applicationDidResume { +} + +- (void)applicationWillSuspend { +} + +- (void)applicationWillTerminate { +} + +- (void)applicationSuspend:(struct __GSEvent *)event { + //[self setApplicationBadge:NSLocalizedString(@"ON", nil)]; + [_view applicationSuspend]; +} + +- (void)applicationResume:(struct __GSEvent *)event { + [_view applicationResume]; +} + +- (void)didRotate:(NSNotification *)notification { + UIDeviceOrientation screenOrientation = [[UIDevice currentDevice] orientation]; + [_view deviceOrientationChanged:screenOrientation]; +} + +- (UIWindow*) getWindow { + return _window; +} + +@end + + +const char *iOS7_getDocumentsDir() { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + return [documentsDirectory UTF8String]; +} diff --git a/backends/platform/ios7/iOS7ScummVMViewController.h b/backends/platform/ios7/iOS7ScummVMViewController.h new file mode 100644 index 0000000000..0322bc6f7f --- /dev/null +++ b/backends/platform/ios7/iOS7ScummVMViewController.h @@ -0,0 +1,28 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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 + + +@interface iOS7ScummVMViewController : UIViewController + +@end diff --git a/backends/platform/ios7/iOS7ScummVMViewController.mm b/backends/platform/ios7/iOS7ScummVMViewController.mm new file mode 100644 index 0000000000..f92fd0115c --- /dev/null +++ b/backends/platform/ios7/iOS7ScummVMViewController.mm @@ -0,0 +1,32 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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 "iOS7ScummVMViewController.h" + + +@implementation iOS7ScummVMViewController + +- (BOOL)prefersStatusBarHidden { + return YES; +} + +@end diff --git a/backends/platform/ios7/ios7_common.h b/backends/platform/ios7/ios7_common.h new file mode 100644 index 0000000000..abc1180143 --- /dev/null +++ b/backends/platform/ios7/ios7_common.h @@ -0,0 +1,117 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#ifndef BACKENDS_PLATFORM_IPHONE_IPHONE_COMMON_H +#define BACKENDS_PLATFORM_IPHONE_IPHONE_COMMON_H + +#include "graphics/surface.h" + +enum InputEvent { + kInputMouseDown, + kInputMouseUp, + kInputMouseDragged, + kInputMouseSecondDragged, + kInputMouseSecondDown, + kInputMouseSecondUp, + kInputOrientationChanged, + kInputKeyPressed, + kInputApplicationSuspended, + kInputApplicationResumed, + kInputSwipe, + kInputTap +}; + +enum ScreenOrientation { + kScreenOrientationPortrait, + kScreenOrientationLandscape, + kScreenOrientationFlippedLandscape +}; + +enum UIViewSwipeDirection { + kUIViewSwipeUp = 1, + kUIViewSwipeDown = 2, + kUIViewSwipeLeft = 4, + kUIViewSwipeRight = 8 +}; + +enum UIViewTapDescription { + kUIViewTapSingle = 1, + kUIViewTapDouble = 2 +}; + +enum GraphicsModes { + kGraphicsModeLinear = 0, + kGraphicsModeNone = 1 +}; + +struct VideoContext { + VideoContext() : asprectRatioCorrection(), screenWidth(), screenHeight(), overlayVisible(false), + overlayWidth(), overlayHeight(), mouseX(), mouseY(), + mouseHotspotX(), mouseHotspotY(), mouseWidth(), mouseHeight(), + mouseIsVisible(), graphicsMode(kGraphicsModeLinear), shakeOffsetY() { + } + + // Game screen state + bool asprectRatioCorrection; + uint screenWidth, screenHeight; + Graphics::Surface screenTexture; + + // Overlay state + bool overlayVisible; + uint overlayWidth, overlayHeight; + Graphics::Surface overlayTexture; + + // Mouse cursor state + uint mouseX, mouseY; + int mouseHotspotX, mouseHotspotY; + uint mouseWidth, mouseHeight; + bool mouseIsVisible; + Graphics::Surface mouseTexture; + + // Misc state + GraphicsModes graphicsMode; + int shakeOffsetY; +}; + +struct InternalEvent { + InternalEvent() : type(), value1(), value2() {} + InternalEvent(InputEvent t, int v1, int v2) : type(t), value1(v1), value2(v2) {} + + InputEvent type; + int value1, value2; +}; + +// On the ObjC side + +extern int iOS7_argc; +extern char **iOS7_argv; + +void iOS7_updateScreen(); +bool iOS7_fetchEvent(InternalEvent *event); +bool iOS7_isHighResDevice(); + +void iOS7_main(int argc, char **argv); +const char *iOS7_getDocumentsDir(); + +uint getSizeNextPOT(uint size); + +#endif diff --git a/backends/platform/ios7/ios7_keyboard.h b/backends/platform/ios7/ios7_keyboard.h new file mode 100644 index 0000000000..ddd8f436e5 --- /dev/null +++ b/backends/platform/ios7/ios7_keyboard.h @@ -0,0 +1,44 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#ifndef BACKENDS_PLATFORM_IPHONE_IPHONE_KEYBOARD_H +#define BACKENDS_PLATFORM_IPHONE_IPHONE_KEYBOARD_H + +#include +#include + +@interface SoftKeyboard : UIView { + id inputDelegate; + UITextView *inputView; +} + +- (id)initWithFrame:(CGRect)frame; +- (UITextView *)inputView; +- (void)setInputDelegate:(id)delegate; +- (void)handleKeyPress:(unichar)c; + +- (void)showKeyboard; +- (void)hideKeyboard; + +@end + +#endif diff --git a/backends/platform/ios7/ios7_keyboard.mm b/backends/platform/ios7/ios7_keyboard.mm new file mode 100644 index 0000000000..7923a1cda9 --- /dev/null +++ b/backends/platform/ios7/ios7_keyboard.mm @@ -0,0 +1,98 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#include "ios7_keyboard.h" + +@interface UITextInputTraits +- (void)setAutocorrectionType:(int)type; +- (void)setAutocapitalizationType:(int)type; +- (void)setEnablesReturnKeyAutomatically:(BOOL)val; +@end + +@interface TextInputHandler : UITextView { + SoftKeyboard *softKeyboard; +} + +- (id)initWithKeyboard:(SoftKeyboard *)keyboard; + +@end + + +@implementation TextInputHandler + +- (id)initWithKeyboard:(SoftKeyboard *)keyboard { + self = [super initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.0f)]; + softKeyboard = keyboard; + + [self setAutocorrectionType:UITextAutocorrectionTypeNo]; + [self setAutocapitalizationType:UITextAutocapitalizationTypeNone]; + [self setEnablesReturnKeyAutomatically:NO]; + + return self; +} + +@end + + +@implementation SoftKeyboard + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + inputDelegate = nil; + inputView = [[TextInputHandler alloc] initWithKeyboard:self]; + inputView.delegate = self; + return self; +} + +- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { + unichar c; + if (text.length) { + c = [text characterAtIndex:0]; + } + else { + c = '\b'; + } + [inputDelegate handleKeyPress:c]; + return YES; +} + +- (UITextView *)inputView { + return inputView; +} + +- (void)setInputDelegate:(id)delegate { + inputDelegate = delegate; +} + +- (void)handleKeyPress:(unichar)c { + [inputDelegate handleKeyPress:c]; +} + +- (void)showKeyboard { + [inputView becomeFirstResponder]; +} + +- (void)hideKeyboard { + [inputView endEditing:YES]; +} + +@end diff --git a/backends/platform/ios7/ios7_main.mm b/backends/platform/ios7/ios7_main.mm new file mode 100644 index 0000000000..c6ca14d490 --- /dev/null +++ b/backends/platform/ios7/ios7_main.mm @@ -0,0 +1,47 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include +#include + +#include "ios7_video.h" + + +int iOS7_argc; +char **iOS7_argv; + +int main(int argc, char **argv) { + int returnCode; + + @autoreleasepool { + iOS7_argc = argc; + iOS7_argv = argv; + + returnCode = UIApplicationMain(argc, argv, @"iOS7MainApplication", @"iOS7MainApplication"); + } + + return returnCode; +} + diff --git a/backends/platform/ios7/ios7_osys_events.cpp b/backends/platform/ios7/ios7_osys_events.cpp new file mode 100644 index 0000000000..da44983b03 --- /dev/null +++ b/backends/platform/ios7/ios7_osys_events.cpp @@ -0,0 +1,562 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "gui/message.h" +#include "common/translation.h" + +#include "ios7_osys_main.h" + +static const int kQueuedInputEventDelay = 50; + +bool OSystem_iOS7::pollEvent(Common::Event &event) { + //printf("pollEvent()\n"); + + long curTime = getMillis(); + + if (_timerCallback && (curTime >= _timerCallbackNext)) { + _timerCallback(_timerCallbackTimer); + _timerCallbackNext = curTime + _timerCallbackTimer; + } + + if (_queuedInputEvent.type != Common::EVENT_INVALID && curTime >= _queuedEventTime) { + event = _queuedInputEvent; + _queuedInputEvent.type = Common::EVENT_INVALID; + return true; + } + + InternalEvent internalEvent; + + if (iOS7_fetchEvent(&internalEvent)) { + switch (internalEvent.type) { + case kInputMouseDown: + if (!handleEvent_mouseDown(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + + case kInputMouseUp: + if (!handleEvent_mouseUp(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + + case kInputMouseDragged: + if (!handleEvent_mouseDragged(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + + case kInputOrientationChanged: + handleEvent_orientationChanged(internalEvent.value1); + return false; + break; + + case kInputApplicationSuspended: + suspendLoop(); + return false; + break; + + case kInputMouseSecondDragged: + if (!handleEvent_mouseSecondDragged(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + case kInputMouseSecondDown: + _secondaryTapped = true; + if (!handleEvent_secondMouseDown(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + case kInputMouseSecondUp: + _secondaryTapped = false; + if (!handleEvent_secondMouseUp(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + + case kInputKeyPressed: + handleEvent_keyPressed(event, internalEvent.value1); + break; + + case kInputSwipe: + if (!handleEvent_swipe(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + + case kInputTap: + if (!handleEvent_tap(event, (UIViewTapDescription) internalEvent.value1, internalEvent.value2)) + return false; + break; + + default: + break; + } + + return true; + } + return false; +} + +bool OSystem_iOS7::handleEvent_mouseDown(Common::Event &event, int x, int y) { + //printf("Mouse down at (%u, %u)\n", x, y); + + // Workaround: kInputMouseSecondToggled isn't always sent when the + // secondary finger is lifted. Need to make sure we get out of that mode. + _secondaryTapped = false; + + if (_touchpadModeEnabled) { + _lastPadX = x; + _lastPadY = y; + } else + warpMouse(x, y); + + if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_LBUTTONDOWN; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + return true; + } else { + _lastMouseDown = getMillis(); + } + return false; +} + +bool OSystem_iOS7::handleEvent_mouseUp(Common::Event &event, int x, int y) { + //printf("Mouse up at (%u, %u)\n", x, y); + + if (_secondaryTapped) { + _secondaryTapped = false; + if (!handleEvent_secondMouseUp(event, x, y)) + return false; + } else if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_LBUTTONUP; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + } else { + if (getMillis() - _lastMouseDown < 250) { + event.type = Common::EVENT_LBUTTONDOWN; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + + _queuedInputEvent.type = Common::EVENT_LBUTTONUP; + _queuedInputEvent.mouse.x = _videoContext->mouseX; + _queuedInputEvent.mouse.y = _videoContext->mouseY; + _lastMouseTap = getMillis(); + _queuedEventTime = _lastMouseTap + kQueuedInputEventDelay; + } else + return false; + } + + return true; +} + +bool OSystem_iOS7::handleEvent_secondMouseDown(Common::Event &event, int x, int y) { + _lastSecondaryDown = getMillis(); + _gestureStartX = x; + _gestureStartY = y; + + if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_LBUTTONUP; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + + _queuedInputEvent.type = Common::EVENT_RBUTTONDOWN; + _queuedInputEvent.mouse.x = _videoContext->mouseX; + _queuedInputEvent.mouse.y = _videoContext->mouseY; + } else + return false; + + return true; +} + +bool OSystem_iOS7::handleEvent_secondMouseUp(Common::Event &event, int x, int y) { + int curTime = getMillis(); + + if (curTime - _lastSecondaryDown < 400) { + //printf("Right tap!\n"); + if (curTime - _lastSecondaryTap < 400 && !_videoContext->overlayVisible) { + //printf("Right escape!\n"); + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE; + _queuedEventTime = curTime + kQueuedInputEventDelay; + _lastSecondaryTap = 0; + } else if (!_mouseClickAndDragEnabled) { + //printf("Rightclick!\n"); + event.type = Common::EVENT_RBUTTONDOWN; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + _queuedInputEvent.type = Common::EVENT_RBUTTONUP; + _queuedInputEvent.mouse.x = _videoContext->mouseX; + _queuedInputEvent.mouse.y = _videoContext->mouseY; + _lastSecondaryTap = curTime; + _queuedEventTime = curTime + kQueuedInputEventDelay; + } else { + //printf("Right nothing!\n"); + return false; + } + } + if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_RBUTTONUP; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + } + + return true; +} + +bool OSystem_iOS7::handleEvent_mouseDragged(Common::Event &event, int x, int y) { + if (_lastDragPosX == x && _lastDragPosY == y) + return false; + + _lastDragPosX = x; + _lastDragPosY = y; + + //printf("Mouse dragged at (%u, %u)\n", x, y); + int mouseNewPosX; + int mouseNewPosY; + if (_touchpadModeEnabled) { + int deltaX = _lastPadX - x; + int deltaY = _lastPadY - y; + _lastPadX = x; + _lastPadY = y; + + mouseNewPosX = (int)(_videoContext->mouseX - deltaX / 0.5f); + mouseNewPosY = (int)(_videoContext->mouseY - deltaY / 0.5f); + + int widthCap = _videoContext->overlayVisible ? _videoContext->overlayWidth : _videoContext->screenWidth; + int heightCap = _videoContext->overlayVisible ? _videoContext->overlayHeight : _videoContext->screenHeight; + + if (mouseNewPosX < 0) + mouseNewPosX = 0; + else if (mouseNewPosX > widthCap) + mouseNewPosX = widthCap; + + if (mouseNewPosY < 0) + mouseNewPosY = 0; + else if (mouseNewPosY > heightCap) + mouseNewPosY = heightCap; + + } else { + mouseNewPosX = x; + mouseNewPosY = y; + } + + event.type = Common::EVENT_MOUSEMOVE; + event.mouse.x = mouseNewPosX; + event.mouse.y = mouseNewPosY; + warpMouse(mouseNewPosX, mouseNewPosY); + + return true; +} + +bool OSystem_iOS7::handleEvent_mouseSecondDragged(Common::Event &event, int x, int y) { + if (_gestureStartX == -1 || _gestureStartY == -1) { + return false; + } + + static const int kNeededLength = 100; + static const int kMaxDeviation = 20; + + int vecX = (x - _gestureStartX); + int vecY = (y - _gestureStartY); + + int absX = abs(vecX); + int absY = abs(vecY); + + //printf("(%d, %d)\n", vecX, vecY); + + if (absX >= kNeededLength || absY >= kNeededLength) { // Long enough gesture to react upon. + _gestureStartX = -1; + _gestureStartY = -1; + + if (absX < kMaxDeviation && vecY >= kNeededLength) { + // Swipe down + event.type = Common::EVENT_MAINMENU; + _queuedInputEvent.type = Common::EVENT_INVALID; + + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + return true; + } + + if (absX < kMaxDeviation && -vecY >= kNeededLength) { + // Swipe up + _mouseClickAndDragEnabled = !_mouseClickAndDragEnabled; + const char *dialogMsg; + if (_mouseClickAndDragEnabled) { + _touchpadModeEnabled = false; + dialogMsg = _("Mouse-click-and-drag mode enabled."); + } else + dialogMsg = _("Mouse-click-and-drag mode disabled."); + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return false; + } + + if (absY < kMaxDeviation && vecX >= kNeededLength) { + // Swipe right + _touchpadModeEnabled = !_touchpadModeEnabled; + const char *dialogMsg; + if (_touchpadModeEnabled) + dialogMsg = _("Touchpad mode enabled."); + else + dialogMsg = _("Touchpad mode disabled."); + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return false; + + } + + if (absY < kMaxDeviation && -vecX >= kNeededLength) { + // Swipe left + return false; + } + } + + return false; +} + +void OSystem_iOS7::handleEvent_orientationChanged(int orientation) { + //printf("Orientation: %i\n", orientation); + + ScreenOrientation newOrientation; + switch (orientation) { + case 1: + newOrientation = kScreenOrientationPortrait; + break; + case 3: + newOrientation = kScreenOrientationLandscape; + break; + case 4: + newOrientation = kScreenOrientationFlippedLandscape; + break; + default: + return; + } + + + if (_screenOrientation != newOrientation) { + _screenOrientation = newOrientation; + updateOutputSurface(); + + dirtyFullScreen(); + if (_videoContext->overlayVisible) + dirtyFullOverlayScreen(); + updateScreen(); + } +} + +void OSystem_iOS7::handleEvent_keyPressed(Common::Event &event, int keyPressed) { + int ascii = keyPressed; + //printf("key: %i\n", keyPressed); + + // We remap some of the iPhone keyboard keys. + // The first ten here are the row of symbols below the numeric keys. + switch (keyPressed) { + case 45: + keyPressed = Common::KEYCODE_F1; + ascii = Common::ASCII_F1; + break; + case 47: + keyPressed = Common::KEYCODE_F2; + ascii = Common::ASCII_F2; + break; + case 58: + keyPressed = Common::KEYCODE_F3; + ascii = Common::ASCII_F3; + break; + case 59: + keyPressed = Common::KEYCODE_F4; + ascii = Common::ASCII_F4; + break; + case 40: + keyPressed = Common::KEYCODE_F5; + ascii = Common::ASCII_F5; + break; + case 41: + keyPressed = Common::KEYCODE_F6; + ascii = Common::ASCII_F6; + break; + case 36: + keyPressed = Common::KEYCODE_F7; + ascii = Common::ASCII_F7; + break; + case 38: + keyPressed = Common::KEYCODE_F8; + ascii = Common::ASCII_F8; + break; + case 64: + keyPressed = Common::KEYCODE_F9; + ascii = Common::ASCII_F9; + break; + case 34: + keyPressed = Common::KEYCODE_F10; + ascii = Common::ASCII_F10; + break; + case 10: + keyPressed = Common::KEYCODE_RETURN; + ascii = Common::ASCII_RETURN; + break; + } + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + event.kbd.keycode = _queuedInputEvent.kbd.keycode = (Common::KeyCode)keyPressed; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = ascii; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; +} + +bool OSystem_iOS7::handleEvent_swipe(Common::Event &event, int direction, int touches) { + if (touches == 1) { + Common::KeyCode keycode = Common::KEYCODE_INVALID; + switch (_screenOrientation) { + case kScreenOrientationPortrait: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_UP; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_DOWN; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_RIGHT; + break; + default: + return false; + } + break; + case kScreenOrientationLandscape: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_RIGHT; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_DOWN; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_UP; + break; + default: + return false; + } + break; + case kScreenOrientationFlippedLandscape: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_RIGHT; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_UP; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_DOWN; + break; + default: + return false; + } + break; + } + + event.kbd.keycode = _queuedInputEvent.kbd.keycode = keycode; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = 0; + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + + return true; + } + else if (touches == 2) { + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: { + _mouseClickAndDragEnabled = !_mouseClickAndDragEnabled; + const char *dialogMsg; + if (_mouseClickAndDragEnabled) { + _touchpadModeEnabled = false; + dialogMsg = _("Mouse-click-and-drag mode enabled."); + } else + dialogMsg = _("Mouse-click-and-drag mode disabled."); + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return false; + } + + case kUIViewSwipeDown: { + // Swipe down + event.type = Common::EVENT_MAINMENU; + _queuedInputEvent.type = Common::EVENT_INVALID; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + return true; + } + + case kUIViewSwipeRight: { + // Swipe right + _touchpadModeEnabled = !_touchpadModeEnabled; + const char *dialogMsg; + if (_touchpadModeEnabled) + dialogMsg = _("Touchpad mode enabled."); + else + dialogMsg = _("Touchpad mode disabled."); + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return false; + } + + default: + break; + } + } + return false; +} + +bool OSystem_iOS7::handleEvent_tap(Common::Event &event, UIViewTapDescription type, int touches) { + if (touches == 1) { + if (type == kUIViewTapDouble) { + event.type = Common::EVENT_RBUTTONDOWN; + _queuedInputEvent.type = Common::EVENT_RBUTTONUP; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + return true; + } + } + else if (touches == 2) { + if (type == kUIViewTapDouble) { + event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE; + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + return true; + } + } + return false; +} diff --git a/backends/platform/ios7/ios7_osys_main.cpp b/backends/platform/ios7/ios7_osys_main.cpp new file mode 100644 index 0000000000..84ddff26df --- /dev/null +++ b/backends/platform/ios7/ios7_osys_main.cpp @@ -0,0 +1,344 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include +#include + +#include + +#include "common/scummsys.h" +#include "common/util.h" +#include "common/rect.h" +#include "common/file.h" +#include "common/fs.h" + +#include "base/main.h" + +#include "backends/saves/default/default-saves.h" +#include "backends/timer/default/default-timer.h" +#include "backends/fs/chroot/chroot-fs-factory.h" +#include "backends/fs/posix/posix-fs.h" +#include "audio/mixer.h" +#include "audio/mixer_intern.h" + +#include "ios7_osys_main.h" + + +const OSystem::GraphicsMode OSystem_iOS7::s_supportedGraphicsModes[] = { + { "linear", "Linear filtering", kGraphicsModeLinear }, + { "none", "No filtering", kGraphicsModeNone }, + { 0, 0, 0 } +}; + +AQCallbackStruct OSystem_iOS7::s_AudioQueue; +SoundProc OSystem_iOS7::s_soundCallback = NULL; +void *OSystem_iOS7::s_soundParam = NULL; + +OSystem_iOS7::OSystem_iOS7() : + _mixer(NULL), _lastMouseTap(0), _queuedEventTime(0), + _mouseNeedTextureUpdate(false), _secondaryTapped(false), _lastSecondaryTap(0), + _screenOrientation(kScreenOrientationFlippedLandscape), _mouseClickAndDragEnabled(false), + _gestureStartX(-1), _gestureStartY(-1), _fullScreenIsDirty(false), _fullScreenOverlayIsDirty(false), + _mouseDirty(false), _timeSuspended(0), _lastDragPosX(-1), _lastDragPosY(-1), _screenChangeCount(0), + _mouseCursorPaletteEnabled(false), _gfxTransactionError(kTransactionSuccess) { + _queuedInputEvent.type = Common::EVENT_INVALID; + _touchpadModeEnabled = !iOS7_isHighResDevice(); +#ifdef IPHONE_OFFICIAL + _fsFactory = new ChRootFilesystemFactory(iOS7_getDocumentsDir()); +#else + _fsFactory = new POSIXFilesystemFactory(); +#endif + initVideoContext(); + + memset(_gamePalette, 0, sizeof(_gamePalette)); + memset(_gamePaletteRGBA5551, 0, sizeof(_gamePaletteRGBA5551)); + memset(_mouseCursorPalette, 0, sizeof(_mouseCursorPalette)); +} + +OSystem_iOS7::~OSystem_iOS7() { + AudioQueueDispose(s_AudioQueue.queue, true); + + delete _mixer; + // Prevent accidental freeing of the screen texture here. This needs to be + // checked since we might use the screen texture as framebuffer in the case + // of hi-color games for example. Otherwise this can lead to a double free. + if (_framebuffer.getPixels() != _videoContext->screenTexture.getPixels()) + _framebuffer.free(); + _mouseBuffer.free(); +} + +bool OSystem_iOS7::touchpadModeEnabled() const { + return _touchpadModeEnabled; +} + +int OSystem_iOS7::timerHandler(int t) { + DefaultTimerManager *tm = (DefaultTimerManager *)g_system->getTimerManager(); + tm->handler(); + return t; +} + +void OSystem_iOS7::initBackend() { +#ifdef IPHONE_OFFICIAL + _savefileManager = new DefaultSaveFileManager("/Savegames"); +#else + _savefileManager = new DefaultSaveFileManager(SCUMMVM_SAVE_PATH); +#endif + + _timerManager = new DefaultTimerManager(); + + gettimeofday(&_startTime, NULL); + + setupMixer(); + + setTimerCallback(&OSystem_iOS7::timerHandler, 10); + + EventsBaseBackend::initBackend(); +} + +bool OSystem_iOS7::hasFeature(Feature f) { + switch (f) { + case kFeatureCursorPalette: + return true; + + default: + return false; + } +} + +void OSystem_iOS7::setFeatureState(Feature f, bool enable) { + switch (f) { + case kFeatureCursorPalette: + if (_mouseCursorPaletteEnabled != enable) { + _mouseNeedTextureUpdate = true; + _mouseDirty = true; + _mouseCursorPaletteEnabled = enable; + } + break; + case kFeatureAspectRatioCorrection: + _videoContext->asprectRatioCorrection = enable; + break; + + default: + break; + } +} + +bool OSystem_iOS7::getFeatureState(Feature f) { + switch (f) { + case kFeatureCursorPalette: + return _mouseCursorPaletteEnabled; + case kFeatureAspectRatioCorrection: + return _videoContext->asprectRatioCorrection; + + default: + return false; + } +} + +void OSystem_iOS7::suspendLoop() { + bool done = false; + uint32 startTime = getMillis(); + + stopSoundsystem(); + + InternalEvent event; + while (!done) { + if (iOS7_fetchEvent(&event)) + if (event.type == kInputApplicationResumed) + done = true; + usleep(100000); + } + + startSoundsystem(); + + _timeSuspended += getMillis() - startTime; +} + +uint32 OSystem_iOS7::getMillis(bool skipRecord) { + //printf("getMillis()\n"); + + struct timeval currentTime; + gettimeofday(¤tTime, NULL); + return (uint32)(((currentTime.tv_sec - _startTime.tv_sec) * 1000) + + ((currentTime.tv_usec - _startTime.tv_usec) / 1000)) - _timeSuspended; +} + +void OSystem_iOS7::delayMillis(uint msecs) { + //printf("delayMillis(%d)\n", msecs); + usleep(msecs * 1000); +} + +OSystem::MutexRef OSystem_iOS7::createMutex(void) { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + + pthread_mutex_t *mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t)); + if (pthread_mutex_init(mutex, &attr) != 0) { + printf("pthread_mutex_init() failed!\n"); + free(mutex); + return NULL; + } + + return (MutexRef)mutex; +} + +void OSystem_iOS7::lockMutex(MutexRef mutex) { + if (pthread_mutex_lock((pthread_mutex_t *) mutex) != 0) { + printf("pthread_mutex_lock() failed!\n"); + } +} + +void OSystem_iOS7::unlockMutex(MutexRef mutex) { + if (pthread_mutex_unlock((pthread_mutex_t *) mutex) != 0) { + printf("pthread_mutex_unlock() failed!\n"); + } +} + +void OSystem_iOS7::deleteMutex(MutexRef mutex) { + if (pthread_mutex_destroy((pthread_mutex_t *) mutex) != 0) { + printf("pthread_mutex_destroy() failed!\n"); + } else { + free(mutex); + } +} + + +void OSystem_iOS7::setTimerCallback(TimerProc callback, int interval) { + //printf("setTimerCallback()\n"); + + if (callback != NULL) { + _timerCallbackTimer = interval; + _timerCallbackNext = getMillis() + interval; + _timerCallback = callback; + } else + _timerCallback = NULL; +} + +void OSystem_iOS7::quit() { +} + +void OSystem_iOS7::getTimeAndDate(TimeDate &td) const { + time_t curTime = time(0); + struct tm t = *localtime(&curTime); + td.tm_sec = t.tm_sec; + td.tm_min = t.tm_min; + td.tm_hour = t.tm_hour; + td.tm_mday = t.tm_mday; + td.tm_mon = t.tm_mon; + td.tm_year = t.tm_year; + td.tm_wday = t.tm_wday; +} + +Audio::Mixer *OSystem_iOS7::getMixer() { + assert(_mixer); + return _mixer; +} + +OSystem *OSystem_iOS7_create() { + return new OSystem_iOS7(); +} + +Common::String OSystem_iOS7::getDefaultConfigFileName() { +#ifdef IPHONE_OFFICIAL + Common::String path = "/Preferences"; + return path; +#else + return SCUMMVM_PREFS_PATH; +#endif +} + +void OSystem_iOS7::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { + // Get URL of the Resource directory of the .app bundle + CFURLRef fileUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); + if (fileUrl) { + // Try to convert the URL to an absolute path + UInt8 buf[MAXPATHLEN]; + if (CFURLGetFileSystemRepresentation(fileUrl, true, buf, sizeof(buf))) { + // Success: Add it to the search path + Common::String bundlePath((const char *)buf); +#ifdef IPHONE_OFFICIAL + POSIXFilesystemNode *posixNode = new POSIXFilesystemNode(bundlePath); + Common::FSNode *node = new Common::FSNode(posixNode); + s.add("__OSX_BUNDLE__", new Common::FSDirectory(*node), priority); +#else + // OS X + s.add("__OSX_BUNDLE__", new Common::FSDirectory(bundlePath), priority); +#endif + } + CFRelease(fileUrl); + } +} + +void OSystem_iOS7::logMessage(LogMessageType::Type type, const char *message) { + FILE *output = 0; + + if (type == LogMessageType::kInfo || type == LogMessageType::kDebug) + output = stdout; + else + output = stderr; + + fputs(message, output); + fflush(output); +} + +bool iOS7_touchpadModeEnabled() { + OSystem_iOS7 *sys = (OSystem_iOS7 *) g_system; + return sys && sys->touchpadModeEnabled(); +} + +void iOS7_main(int argc, char **argv) { + + //OSystem_iOS7::migrateApp(); + + FILE *newfp = fopen("/var/mobile/.scummvm.log", "a"); + if (newfp != NULL) { + fclose(stdout); + fclose(stderr); + *stdout = *newfp; + *stderr = *newfp; + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + //extern int gDebugLevel; + //gDebugLevel = 10; + } + +#ifdef IPHONE_OFFICIAL + chdir(iOS7_getDocumentsDir()); +#else + system("mkdir " SCUMMVM_ROOT_PATH); + system("mkdir " SCUMMVM_SAVE_PATH); + + chdir("/var/mobile/"); +#endif + + g_system = OSystem_iOS7_create(); + assert(g_system); + + // Invoke the actual ScummVM main entry point: + scummvm_main(argc, argv); + g_system->quit(); // TODO: Consider removing / replacing this! +} diff --git a/backends/platform/ios7/ios7_osys_main.h b/backends/platform/ios7/ios7_osys_main.h new file mode 100644 index 0000000000..50114a9112 --- /dev/null +++ b/backends/platform/ios7/ios7_osys_main.h @@ -0,0 +1,224 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#ifndef BACKENDS_PLATFORM_IPHONE_OSYS_MAIN_H +#define BACKENDS_PLATFORM_IPHONE_OSYS_MAIN_H + +#include "graphics/surface.h" +#include "ios7_common.h" +#include "backends/base-backend.h" +#include "common/events.h" +#include "audio/mixer_intern.h" +#include "backends/fs/posix/posix-fs-factory.h" +#include "graphics/colormasks.h" +#include "graphics/palette.h" + +#include + +#define AUDIO_BUFFERS 3 +#define WAVE_BUFFER_SIZE 2048 +#define AUDIO_SAMPLE_RATE 44100 + +#define SCUMMVM_ROOT_PATH "/var/mobile/Library/ScummVM" +#define SCUMMVM_SAVE_PATH SCUMMVM_ROOT_PATH "/Savegames" +#define SCUMMVM_PREFS_PATH SCUMMVM_ROOT_PATH "/Preferences" + +typedef void (*SoundProc)(void *param, byte *buf, int len); +typedef int (*TimerProc)(int interval); + +struct AQCallbackStruct { + AudioQueueRef queue; + uint32 frameCount; + AudioQueueBufferRef buffers[AUDIO_BUFFERS]; + AudioStreamBasicDescription dataFormat; +}; + +class OSystem_iOS7 : public EventsBaseBackend, public PaletteManager { +protected: + static const OSystem::GraphicsMode s_supportedGraphicsModes[]; + static AQCallbackStruct s_AudioQueue; + static SoundProc s_soundCallback; + static void *s_soundParam; + + Audio::MixerImpl *_mixer; + + VideoContext *_videoContext; + + Graphics::Surface _framebuffer; + + // For signaling that screen format set up might have failed. + TransactionError _gfxTransactionError; + + // For use with the game texture + uint16 _gamePalette[256]; + // For use with the mouse texture + uint16 _gamePaletteRGBA5551[256]; + + struct timeval _startTime; + uint32 _timeSuspended; + + bool _mouseCursorPaletteEnabled; + uint16 _mouseCursorPalette[256]; + Graphics::Surface _mouseBuffer; + uint16 _mouseKeyColor; + bool _mouseDirty; + bool _mouseNeedTextureUpdate; + + long _lastMouseDown; + long _lastMouseTap; + long _queuedEventTime; + Common::Event _queuedInputEvent; + bool _secondaryTapped; + long _lastSecondaryDown; + long _lastSecondaryTap; + int _gestureStartX, _gestureStartY; + bool _mouseClickAndDragEnabled; + bool _touchpadModeEnabled; + int _lastPadX; + int _lastPadY; + int _lastDragPosX; + int _lastDragPosY; + + int _timerCallbackNext; + int _timerCallbackTimer; + TimerProc _timerCallback; + + Common::Array _dirtyRects; + Common::Array _dirtyOverlayRects; + ScreenOrientation _screenOrientation; + bool _fullScreenIsDirty; + bool _fullScreenOverlayIsDirty; + int _screenChangeCount; + +public: + + OSystem_iOS7(); + virtual ~OSystem_iOS7(); + + virtual void initBackend(); + + virtual bool hasFeature(Feature f); + virtual void setFeatureState(Feature f, bool enable); + virtual bool getFeatureState(Feature f); + virtual const GraphicsMode *getSupportedGraphicsModes() const; + virtual int getDefaultGraphicsMode() const; + virtual bool setGraphicsMode(int mode); + virtual int getGraphicsMode() const; + virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format); + + virtual void beginGFXTransaction(); + virtual TransactionError endGFXTransaction(); + + virtual int16 getHeight(); + virtual int16 getWidth(); + + bool touchpadModeEnabled() const; + +#ifdef USE_RGB_COLOR + virtual Graphics::PixelFormat getScreenFormat() const { return _framebuffer.format; } + virtual Common::List getSupportedFormats() const; +#endif + + virtual PaletteManager *getPaletteManager() { return this; } +protected: + // PaletteManager API + virtual void setPalette(const byte *colors, uint start, uint num); + virtual void grabPalette(byte *colors, uint start, uint num); + +public: + virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h); + virtual void updateScreen(); + virtual Graphics::Surface *lockScreen(); + virtual void unlockScreen(); + virtual void setShakePos(int shakeOffset); + + virtual void showOverlay(); + virtual void hideOverlay(); + virtual void clearOverlay(); + virtual void grabOverlay(void *buf, int pitch); + virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h); + virtual int16 getOverlayHeight(); + virtual int16 getOverlayWidth(); + virtual Graphics::PixelFormat getOverlayFormat() const { return Graphics::createPixelFormat<5551>(); } + + virtual bool showMouse(bool visible); + + virtual void warpMouse(int x, int y); + virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 255, bool dontScale = false, const Graphics::PixelFormat *format = NULL); + virtual void setCursorPalette(const byte *colors, uint start, uint num); + + virtual bool pollEvent(Common::Event &event); + virtual uint32 getMillis(bool skipRecord = false); + virtual void delayMillis(uint msecs); + + virtual MutexRef createMutex(void); + virtual void lockMutex(MutexRef mutex); + virtual void unlockMutex(MutexRef mutex); + virtual void deleteMutex(MutexRef mutex); + + static void mixCallback(void *sys, byte *samples, int len); + virtual void setupMixer(void); + virtual void setTimerCallback(TimerProc callback, int interval); + virtual int getScreenChangeID() const { return _screenChangeCount; } + virtual void quit(); + + virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); + virtual void getTimeAndDate(TimeDate &t) const; + + virtual Audio::Mixer *getMixer(); + + void startSoundsystem(); + void stopSoundsystem(); + + virtual Common::String getDefaultConfigFileName(); + + virtual void logMessage(LogMessageType::Type type, const char *message); + +protected: + void initVideoContext(); + void updateOutputSurface(); + + void internUpdateScreen(); + void dirtyFullScreen(); + void dirtyFullOverlayScreen(); + void suspendLoop(); + void drawDirtyRect(const Common::Rect &dirtyRect); + void updateMouseTexture(); + static void AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB); + static int timerHandler(int t); + + bool handleEvent_swipe(Common::Event &event, int direction, int touches); + bool handleEvent_tap(Common::Event &event, UIViewTapDescription type, int touches); + void handleEvent_keyPressed(Common::Event &event, int keyPressed); + void handleEvent_orientationChanged(int orientation); + + bool handleEvent_mouseDown(Common::Event &event, int x, int y); + bool handleEvent_mouseUp(Common::Event &event, int x, int y); + + bool handleEvent_secondMouseDown(Common::Event &event, int x, int y); + bool handleEvent_secondMouseUp(Common::Event &event, int x, int y); + + bool handleEvent_mouseDragged(Common::Event &event, int x, int y); + bool handleEvent_mouseSecondDragged(Common::Event &event, int x, int y); +}; + +#endif diff --git a/backends/platform/ios7/ios7_osys_sound.cpp b/backends/platform/ios7/ios7_osys_sound.cpp new file mode 100644 index 0000000000..0dc81a9385 --- /dev/null +++ b/backends/platform/ios7/ios7_osys_sound.cpp @@ -0,0 +1,105 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "ios7_osys_main.h" + +void OSystem_iOS7::AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB) { + //printf("AQBufferCallback()\n"); + if (s_AudioQueue.frameCount > 0 && s_soundCallback != NULL) { + outQB->mAudioDataByteSize = 4 * s_AudioQueue.frameCount; + s_soundCallback(s_soundParam, (byte *)outQB->mAudioData, outQB->mAudioDataByteSize); + AudioQueueEnqueueBuffer(inQ, outQB, 0, NULL); + } else { + AudioQueueStop(s_AudioQueue.queue, false); + } +} + +void OSystem_iOS7::mixCallback(void *sys, byte *samples, int len) { + OSystem_iOS7 *this_ = (OSystem_iOS7 *)sys; + assert(this_); + + if (this_->_mixer) { + this_->_mixer->mixCallback(samples, len); + } +} + +void OSystem_iOS7::setupMixer() { + _mixer = new Audio::MixerImpl(this, AUDIO_SAMPLE_RATE); + + s_soundCallback = mixCallback; + s_soundParam = this; + + startSoundsystem(); +} + +void OSystem_iOS7::startSoundsystem() { + s_AudioQueue.dataFormat.mSampleRate = AUDIO_SAMPLE_RATE; + s_AudioQueue.dataFormat.mFormatID = kAudioFormatLinearPCM; + s_AudioQueue.dataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; + s_AudioQueue.dataFormat.mBytesPerPacket = 4; + s_AudioQueue.dataFormat.mFramesPerPacket = 1; + s_AudioQueue.dataFormat.mBytesPerFrame = 4; + s_AudioQueue.dataFormat.mChannelsPerFrame = 2; + s_AudioQueue.dataFormat.mBitsPerChannel = 16; + s_AudioQueue.frameCount = WAVE_BUFFER_SIZE; + + if (AudioQueueNewOutput(&s_AudioQueue.dataFormat, AQBufferCallback, &s_AudioQueue, 0, kCFRunLoopCommonModes, 0, &s_AudioQueue.queue)) { + printf("Couldn't set the AudioQueue callback!\n"); + _mixer->setReady(false); + return; + } + + uint32 bufferBytes = s_AudioQueue.frameCount * s_AudioQueue.dataFormat.mBytesPerFrame; + + for (int i = 0; i < AUDIO_BUFFERS; i++) { + if (AudioQueueAllocateBuffer(s_AudioQueue.queue, bufferBytes, &s_AudioQueue.buffers[i])) { + printf("Error allocating AudioQueue buffer!\n"); + _mixer->setReady(false); + return; + } + + AQBufferCallback(&s_AudioQueue, s_AudioQueue.queue, s_AudioQueue.buffers[i]); + } + + AudioQueueSetParameter(s_AudioQueue.queue, kAudioQueueParam_Volume, 1.0); + if (AudioQueueStart(s_AudioQueue.queue, NULL)) { + printf("Error starting the AudioQueue!\n"); + _mixer->setReady(false); + return; + } + + _mixer->setReady(true); +} + +void OSystem_iOS7::stopSoundsystem() { + AudioQueueStop(s_AudioQueue.queue, true); + + for (int i = 0; i < AUDIO_BUFFERS; i++) { + AudioQueueFreeBuffer(s_AudioQueue.queue, s_AudioQueue.buffers[i]); + } + + AudioQueueDispose(s_AudioQueue.queue, true); + _mixer->setReady(false); +} diff --git a/backends/platform/ios7/ios7_osys_video.mm b/backends/platform/ios7/ios7_osys_video.mm new file mode 100644 index 0000000000..4835ef5638 --- /dev/null +++ b/backends/platform/ios7/ios7_osys_video.mm @@ -0,0 +1,503 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "ios7_osys_main.h" +#include "ios7_video.h" + +#include "graphics/conversion.h" + +void OSystem_iOS7::initVideoContext() { + _videoContext = [g_iPhoneViewInstance getVideoContext]; +} + +const OSystem::GraphicsMode *OSystem_iOS7::getSupportedGraphicsModes() const { + return s_supportedGraphicsModes; +} + +int OSystem_iOS7::getDefaultGraphicsMode() const { + return kGraphicsModeLinear; +} + +bool OSystem_iOS7::setGraphicsMode(int mode) { + switch (mode) { + case kGraphicsModeNone: + case kGraphicsModeLinear: + _videoContext->graphicsMode = (GraphicsModes)mode; + return true; + + default: + return false; + } +} + +int OSystem_iOS7::getGraphicsMode() const { + return _videoContext->graphicsMode; +} + +#ifdef USE_RGB_COLOR +Common::List OSystem_iOS7::getSupportedFormats() const { + Common::List list; + // RGB565 + list.push_back(Graphics::createPixelFormat<565>()); + // CLUT8 + list.push_back(Graphics::PixelFormat::createFormatCLUT8()); + return list; +} +#endif + +void OSystem_iOS7::initSize(uint width, uint height, const Graphics::PixelFormat *format) { + //printf("initSize(%u, %u, %p)\n", width, height, (const void *)format); + + _videoContext->screenWidth = width; + _videoContext->screenHeight = height; + _videoContext->shakeOffsetY = 0; + + // In case we use the screen texture as frame buffer we reset the pixels + // pointer here to avoid freeing the screen texture. + if (_framebuffer.getPixels() == _videoContext->screenTexture.getPixels()) + _framebuffer.setPixels(0); + + // Create the screen texture right here. We need to do this here, since + // when a game requests hi-color mode, we actually set the framebuffer + // to the texture buffer to avoid an additional copy step. + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(createScreenTexture) withObject:nil waitUntilDone: YES]; + + // In case the client code tries to set up a non supported mode, we will + // fall back to CLUT8 and set the transaction error accordingly. + if (format && format->bytesPerPixel != 1 && *format != _videoContext->screenTexture.format) { + format = 0; + _gfxTransactionError = kTransactionFormatNotSupported; + } + + if (!format || format->bytesPerPixel == 1) { + _framebuffer.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + } else { +#if 0 + printf("bytesPerPixel: %u RGBAlosses: %u,%u,%u,%u RGBAshifts: %u,%u,%u,%u\n", format->bytesPerPixel, + format->rLoss, format->gLoss, format->bLoss, format->aLoss, + format->rShift, format->gShift, format->bShift, format->aShift); +#endif + // We directly draw on the screen texture in hi-color mode. Thus + // we copy over its settings here and just replace the width and + // height to avoid any problems. + _framebuffer = _videoContext->screenTexture; + _framebuffer.w = width; + _framebuffer.h = height; + } + + _fullScreenIsDirty = false; + dirtyFullScreen(); + _mouseCursorPaletteEnabled = false; +} + +void OSystem_iOS7::beginGFXTransaction() { + _gfxTransactionError = kTransactionSuccess; +} + +OSystem::TransactionError OSystem_iOS7::endGFXTransaction() { + _screenChangeCount++; + updateOutputSurface(); + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(setGraphicsMode) withObject:nil waitUntilDone: YES]; + + return _gfxTransactionError; +} + +void OSystem_iOS7::updateOutputSurface() { + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(initSurface) withObject:nil waitUntilDone: YES]; +} + +int16 OSystem_iOS7::getHeight() { + return _videoContext->screenHeight; +} + +int16 OSystem_iOS7::getWidth() { + return _videoContext->screenWidth; +} + +void OSystem_iOS7::setPalette(const byte *colors, uint start, uint num) { + //printf("setPalette(%p, %u, %u)\n", colors, start, num); + assert(start + num <= 256); + const byte *b = colors; + + for (uint i = start; i < start + num; ++i) { + _gamePalette[i] = Graphics::RGBToColor >(b[0], b[1], b[2]); + _gamePaletteRGBA5551[i] = Graphics::RGBToColor >(b[0], b[1], b[2]); + b += 3; + } + + dirtyFullScreen(); + + // Automatically update the mouse texture when the palette changes while the + // cursor palette is disabled. + if (!_mouseCursorPaletteEnabled && _mouseBuffer.format.bytesPerPixel == 1) + _mouseDirty = _mouseNeedTextureUpdate = true; +} + +void OSystem_iOS7::grabPalette(byte *colors, uint start, uint num) { + //printf("grabPalette(%p, %u, %u)\n", colors, start, num); + assert(start + num <= 256); + byte *b = colors; + + for (uint i = start; i < start + num; ++i) { + Graphics::colorToRGB >(_gamePalette[i], b[0], b[1], b[2]); + b += 3; + } +} + +void OSystem_iOS7::copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) { + //printf("copyRectToScreen(%p, %d, %i, %i, %i, %i)\n", buf, pitch, x, y, w, h); + //Clip the coordinates + const byte *src = (const byte *)buf; + if (x < 0) { + w += x; + src -= x; + x = 0; + } + + if (y < 0) { + h += y; + src -= y * pitch; + y = 0; + } + + if (w > (int)_framebuffer.w - x) { + w = _framebuffer.w - x; + } + + if (h > (int)_framebuffer.h - y) { + h = _framebuffer.h - y; + } + + if (w <= 0 || h <= 0) + return; + + if (!_fullScreenIsDirty) { + _dirtyRects.push_back(Common::Rect(x, y, x + w, y + h)); + } + + byte *dst = (byte *)_framebuffer.getBasePtr(x, y); + if (_framebuffer.pitch == pitch && _framebuffer.w == w) { + memcpy(dst, src, h * pitch); + } else { + do { + memcpy(dst, src, w * _framebuffer.format.bytesPerPixel); + src += pitch; + dst += _framebuffer.pitch; + } while (--h); + } +} + +void OSystem_iOS7::updateScreen() { + if (_dirtyRects.size() == 0 && _dirtyOverlayRects.size() == 0 && !_mouseDirty) + return; + + //printf("updateScreen(): %i dirty rects.\n", _dirtyRects.size()); + + internUpdateScreen(); + _mouseDirty = false; + _fullScreenIsDirty = false; + _fullScreenOverlayIsDirty = false; + + iOS7_updateScreen(); +} + +void OSystem_iOS7::internUpdateScreen() { + if (_mouseNeedTextureUpdate) { + updateMouseTexture(); + _mouseNeedTextureUpdate = false; + } + + while (_dirtyRects.size()) { + Common::Rect dirtyRect = _dirtyRects.remove_at(_dirtyRects.size() - 1); + + //printf("Drawing: (%i, %i) -> (%i, %i)\n", dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); + drawDirtyRect(dirtyRect); + // TODO: Implement dirty rect code + //updateHardwareSurfaceForRect(dirtyRect); + } + + if (_videoContext->overlayVisible) { + // TODO: Implement dirty rect code + _dirtyOverlayRects.clear(); + /*while (_dirtyOverlayRects.size()) { + Common::Rect dirtyRect = _dirtyOverlayRects.remove_at(_dirtyOverlayRects.size() - 1); + + //printf("Drawing: (%i, %i) -> (%i, %i)\n", dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); + drawDirtyOverlayRect(dirtyRect); + }*/ + } +} + +void OSystem_iOS7::drawDirtyRect(const Common::Rect &dirtyRect) { + // We only need to do a color look up for CLUT8 + if (_framebuffer.format.bytesPerPixel != 1) + return; + + int h = dirtyRect.bottom - dirtyRect.top; + int w = dirtyRect.right - dirtyRect.left; + + const byte *src = (const byte *)_framebuffer.getBasePtr(dirtyRect.left, dirtyRect.top); + byte *dstRaw = (byte *)_videoContext->screenTexture.getBasePtr(dirtyRect.left, dirtyRect.top); + + // When we use CLUT8 do a color look up + for (int y = h; y > 0; y--) { + uint16 *dst = (uint16 *)dstRaw; + for (int x = w; x > 0; x--) + *dst++ = _gamePalette[*src++]; + + dstRaw += _videoContext->screenTexture.pitch; + src += _framebuffer.pitch - w; + } +} + +Graphics::Surface *OSystem_iOS7::lockScreen() { + //printf("lockScreen()\n"); + return &_framebuffer; +} + +void OSystem_iOS7::unlockScreen() { + //printf("unlockScreen()\n"); + dirtyFullScreen(); +} + +void OSystem_iOS7::setShakePos(int shakeOffset) { + //printf("setShakePos(%i)\n", shakeOffset); + _videoContext->shakeOffsetY = shakeOffset; + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(setViewTransformation) withObject:nil waitUntilDone: YES]; + // HACK: We use this to force a redraw. + _mouseDirty = true; +} + +void OSystem_iOS7::showOverlay() { + //printf("showOverlay()\n"); + _videoContext->overlayVisible = true; + dirtyFullOverlayScreen(); + updateScreen(); + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateMouseCursorScaling) withObject:nil waitUntilDone: YES]; + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES]; +} + +void OSystem_iOS7::hideOverlay() { + //printf("hideOverlay()\n"); + _videoContext->overlayVisible = false; + _dirtyOverlayRects.clear(); + dirtyFullScreen(); + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateMouseCursorScaling) withObject:nil waitUntilDone: YES]; + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES]; +} + +void OSystem_iOS7::clearOverlay() { + //printf("clearOverlay()\n"); + bzero(_videoContext->overlayTexture.getPixels(), _videoContext->overlayTexture.h * _videoContext->overlayTexture.pitch); + dirtyFullOverlayScreen(); +} + +void OSystem_iOS7::grabOverlay(void *buf, int pitch) { + //printf("grabOverlay()\n"); + int h = _videoContext->overlayHeight; + + byte *dst = (byte *)buf; + const byte *src = (const byte *)_videoContext->overlayTexture.getPixels(); + do { + memcpy(dst, src, _videoContext->overlayWidth * sizeof(uint16)); + src += _videoContext->overlayTexture.pitch; + dst += pitch; + } while (--h); +} + +void OSystem_iOS7::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) { + //printf("copyRectToOverlay(%p, pitch=%i, x=%i, y=%i, w=%i, h=%i)\n", (const void *)buf, pitch, x, y, w, h); + const byte *src = (const byte *)buf; + + //Clip the coordinates + if (x < 0) { + w += x; + src -= x * sizeof(uint16); + x = 0; + } + + if (y < 0) { + h += y; + src -= y * pitch; + y = 0; + } + + if (w > (int)_videoContext->overlayWidth - x) + w = _videoContext->overlayWidth - x; + + if (h > (int)_videoContext->overlayHeight - y) + h = _videoContext->overlayHeight - y; + + if (w <= 0 || h <= 0) + return; + + if (!_fullScreenOverlayIsDirty) { + _dirtyOverlayRects.push_back(Common::Rect(x, y, x + w, y + h)); + } + + byte *dst = (byte *)_videoContext->overlayTexture.getBasePtr(x, y); + do { + memcpy(dst, src, w * sizeof(uint16)); + src += pitch; + dst += _videoContext->overlayTexture.pitch; + } while (--h); +} + +int16 OSystem_iOS7::getOverlayHeight() { + return _videoContext->overlayHeight; +} + +int16 OSystem_iOS7::getOverlayWidth() { + return _videoContext->overlayWidth; +} + +bool OSystem_iOS7::showMouse(bool visible) { + //printf("showMouse(%d)\n", visible); + bool last = _videoContext->mouseIsVisible; + _videoContext->mouseIsVisible = visible; + _mouseDirty = true; + + return last; +} + +void OSystem_iOS7::warpMouse(int x, int y) { + //printf("warpMouse(%d, %d)\n", x, y); + _videoContext->mouseX = x; + _videoContext->mouseY = y; + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(notifyMouseMove) withObject:nil waitUntilDone: YES]; + _mouseDirty = true; +} + +void OSystem_iOS7::dirtyFullScreen() { + if (!_fullScreenIsDirty) { + _dirtyRects.clear(); + _dirtyRects.push_back(Common::Rect(0, 0, _videoContext->screenWidth, _videoContext->screenHeight)); + _fullScreenIsDirty = true; + } +} + +void OSystem_iOS7::dirtyFullOverlayScreen() { + if (!_fullScreenOverlayIsDirty) { + _dirtyOverlayRects.clear(); + _dirtyOverlayRects.push_back(Common::Rect(0, 0, _videoContext->overlayWidth, _videoContext->overlayHeight)); + _fullScreenOverlayIsDirty = true; + } +} + +void OSystem_iOS7::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { + //printf("setMouseCursor(%p, %u, %u, %i, %i, %u, %d, %p)\n", (const void *)buf, w, h, hotspotX, hotspotY, keycolor, dontScale, (const void *)format); + + const Graphics::PixelFormat pixelFormat = format ? *format : Graphics::PixelFormat::createFormatCLUT8(); +#if 0 + printf("bytesPerPixel: %u RGBAlosses: %u,%u,%u,%u RGBAshifts: %u,%u,%u,%u\n", pixelFormat.bytesPerPixel, + pixelFormat.rLoss, pixelFormat.gLoss, pixelFormat.bLoss, pixelFormat.aLoss, + pixelFormat.rShift, pixelFormat.gShift, pixelFormat.bShift, pixelFormat.aShift); +#endif + assert(pixelFormat.bytesPerPixel == 1 || pixelFormat.bytesPerPixel == 2); + + if (_mouseBuffer.w != w || _mouseBuffer.h != h || _mouseBuffer.format != pixelFormat || !_mouseBuffer.getPixels()) + _mouseBuffer.create(w, h, pixelFormat); + + _videoContext->mouseWidth = w; + _videoContext->mouseHeight = h; + + _videoContext->mouseHotspotX = hotspotX; + _videoContext->mouseHotspotY = hotspotY; + + _mouseKeyColor = keycolor; + + memcpy(_mouseBuffer.getPixels(), buf, h * _mouseBuffer.pitch); + + _mouseDirty = true; + _mouseNeedTextureUpdate = true; +} + +void OSystem_iOS7::setCursorPalette(const byte *colors, uint start, uint num) { + //printf("setCursorPalette(%p, %u, %u)\n", (const void *)colors, start, num); + assert(start + num <= 256); + + for (uint i = start; i < start + num; ++i, colors += 3) + _mouseCursorPalette[i] = Graphics::RGBToColor >(colors[0], colors[1], colors[2]); + + // FIXME: This is just stupid, our client code seems to assume that this + // automatically enables the cursor palette. + _mouseCursorPaletteEnabled = true; + + if (_mouseCursorPaletteEnabled) + _mouseDirty = _mouseNeedTextureUpdate = true; +} + +void OSystem_iOS7::updateMouseTexture() { + uint texWidth = getSizeNextPOT(_videoContext->mouseWidth); + uint texHeight = getSizeNextPOT(_videoContext->mouseHeight); + + Graphics::Surface &mouseTexture = _videoContext->mouseTexture; + if (mouseTexture.w != texWidth || mouseTexture.h != texHeight) + mouseTexture.create(texWidth, texHeight, Graphics::createPixelFormat<5551>()); + + if (_mouseBuffer.format.bytesPerPixel == 1) { + const uint16 *palette; + if (_mouseCursorPaletteEnabled) + palette = _mouseCursorPalette; + else + palette = _gamePaletteRGBA5551; + + uint16 *mouseBuf = (uint16 *)mouseTexture.getPixels(); + for (uint x = 0; x < _videoContext->mouseWidth; ++x) { + for (uint y = 0; y < _videoContext->mouseHeight; ++y) { + const byte color = *(const byte *)_mouseBuffer.getBasePtr(x, y); + if (color != _mouseKeyColor) + mouseBuf[y * texWidth + x] = palette[color] | 0x1; + else + mouseBuf[y * texWidth + x] = 0x0; + } + } + } else { + if (crossBlit((byte *)mouseTexture.getPixels(), (const byte *)_mouseBuffer.getPixels(), mouseTexture.pitch, + _mouseBuffer.pitch, _mouseBuffer.w, _mouseBuffer.h, mouseTexture.format, _mouseBuffer.format)) { + if (!_mouseBuffer.format.aBits()) { + // Apply color keying since the original cursor had no alpha channel. + const uint16 *src = (const uint16 *)_mouseBuffer.getPixels(); + uint8 *dstRaw = (uint8 *)mouseTexture.getPixels(); + + for (uint y = 0; y < _mouseBuffer.h; ++y, dstRaw += mouseTexture.pitch) { + uint16 *dst = (uint16 *)dstRaw; + for (uint x = 0; x < _mouseBuffer.w; ++x, ++dst) { + if (*src++ == _mouseKeyColor) + *dst &= ~1; + else + *dst |= 1; + } + } + } + } else { + // TODO: Log this! + // Make the cursor all transparent... we really need a better fallback ;-). + memset(mouseTexture.getPixels(), 0, mouseTexture.h * mouseTexture.pitch); + } + } + + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateMouseCursor) withObject:nil waitUntilDone: YES]; +} diff --git a/backends/platform/ios7/ios7_video.h b/backends/platform/ios7/ios7_video.h new file mode 100644 index 0000000000..63a570d19d --- /dev/null +++ b/backends/platform/ios7/ios7_video.h @@ -0,0 +1,109 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#ifndef BACKENDS_PLATFORM_IPHONE_IPHONE_VIDEO_H +#define BACKENDS_PLATFORM_IPHONE_IPHONE_VIDEO_H + +#include +#include +#include + +#include +#include +#include + +#include "ios7_keyboard.h" +#include "ios7_common.h" + +#include "common/list.h" + +@interface iPhoneView : UIView { + VideoContext _videoContext; + + Common::List _events; + NSLock *_eventLock; + SoftKeyboard *_keyboardView; + + EAGLContext *_context; + GLuint _viewRenderbuffer; + GLuint _viewFramebuffer; + GLuint _screenTexture; + GLuint _overlayTexture; + GLuint _mouseCursorTexture; + + GLint _renderBufferWidth; + GLint _renderBufferHeight; + + GLfloat _gameScreenVertCoords[4 * 2]; + GLfloat _gameScreenTexCoords[4 * 2]; + CGRect _gameScreenRect; + + GLfloat _overlayVertCoords[4 * 2]; + GLfloat _overlayTexCoords[4 * 2]; + CGRect _overlayRect; + + GLfloat _mouseVertCoords[4 * 2]; + GLfloat _mouseTexCoords[4 * 2]; + GLint _mouseHotspotX, _mouseHotspotY; + GLint _mouseWidth, _mouseHeight; + GLfloat _mouseScaleX, _mouseScaleY; + + int _scaledShakeOffsetY; + CGFloat _contentScaleFactor; + + UITouch *_firstTouch; + UITouch *_secondTouch; +} + +- (id)initWithFrame:(struct CGRect)frame; + +- (VideoContext *)getVideoContext; + +- (void)createScreenTexture; +- (void)initSurface; +- (void)setViewTransformation; + +- (void)setGraphicsMode; + +- (void)updateSurface; +- (void)updateMainSurface; +- (void)updateOverlaySurface; +- (void)updateMouseSurface; +- (void)clearColorBuffer; + +- (void)notifyMouseMove; +- (void)updateMouseCursorScaling; +- (void)updateMouseCursor; + +- (void)deviceOrientationChanged:(UIDeviceOrientation)orientation; + +- (void)applicationSuspend; + +- (void)applicationResume; + +- (bool)fetchEvent:(InternalEvent *)event; + +@end + +extern iPhoneView *g_iPhoneViewInstance; + +#endif diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm new file mode 100644 index 0000000000..8cd4751c59 --- /dev/null +++ b/backends/platform/ios7/ios7_video.mm @@ -0,0 +1,815 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "ios7_video.h" + +#include "graphics/colormasks.h" +#include "common/system.h" + +iPhoneView *g_iPhoneViewInstance = nil; +static int g_fullWidth; +static int g_fullHeight; + +static int g_needsScreenUpdate = 0; + +#if 0 +static long g_lastTick = 0; +static int g_frames = 0; +#endif + +extern bool iOS7_touchpadModeEnabled(); + +#define printOpenGLError() printOglError(__FILE__, __LINE__) + +int printOglError(const char *file, int line) { + int retCode = 0; + + // returns 1 if an OpenGL error occurred, 0 otherwise. + GLenum glErr = glGetError(); + while (glErr != GL_NO_ERROR) { + fprintf(stderr, "glError: %u (%s: %d)\n", glErr, file, line); + retCode = 1; + glErr = glGetError(); + } + return retCode; +} + +bool iOS7_isHighResDevice() { + return g_fullHeight > 480; +} + +void iOS7_updateScreen() { + //printf("Mouse: (%i, %i)\n", mouseX, mouseY); + if (!g_needsScreenUpdate) { + g_needsScreenUpdate = 1; + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateSurface) withObject:nil waitUntilDone: NO]; + } +} + +bool iOS7_fetchEvent(InternalEvent *event) { + return [g_iPhoneViewInstance fetchEvent:event]; +} + +uint getSizeNextPOT(uint size) { + if ((size & (size - 1)) || !size) { + int log = 0; + + while (size >>= 1) + ++log; + + size = (2 << log); + } + + return size; +} + +@implementation iPhoneView + ++ (Class)layerClass { + return [CAEAGLLayer class]; +} + +- (VideoContext *)getVideoContext { + return &_videoContext; +} + +- (void)createContext { + CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; + + eaglLayer.opaque = YES; + eaglLayer.drawableProperties = @{ + kEAGLDrawablePropertyRetainedBacking: @NO, + kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGB565 + }; + + _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; + + // In case creating the OpenGL ES context failed, we will error out here. + if (_context == nil) { + fprintf(stderr, "Could not create OpenGL ES context\n"); + exit(-1); + } + + if ([EAGLContext setCurrentContext:_context]) { + glGenFramebuffersOES(1, &_viewFramebuffer); printOpenGLError(); + glGenRenderbuffersOES(1, &_viewRenderbuffer); printOpenGLError(); + + glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); printOpenGLError(); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); + [_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id)self.layer]; + + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); + + // Retrieve the render buffer size. This *should* match the frame size, + // i.e. g_fullWidth and g_fullHeight. + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &_renderBufferWidth); printOpenGLError(); + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &_renderBufferHeight); printOpenGLError(); + + if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { + NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); + return; + } + uint maxValue = MAX(_renderBufferWidth, _renderBufferHeight), maxValuePOT = getSizeNextPOT(maxValue); + uint minValue = MIN(_renderBufferWidth, _renderBufferHeight), minValuePOT = getSizeNextPOT(minValue); + + _videoContext.overlayWidth = maxValue; + _videoContext.overlayHeight = minValue; + + uint overlayTextureWidth = maxValuePOT; + uint overlayTextureHeight = minValuePOT; + + // Since the overlay size won't change the whole run, we can + // precalculate the texture coordinates for the overlay texture here + // and just use it later on. + _overlayTexCoords[2] = _overlayTexCoords[6] = _videoContext.overlayWidth / (GLfloat)overlayTextureWidth; + _overlayTexCoords[5] = _overlayTexCoords[7] = _videoContext.overlayHeight / (GLfloat)overlayTextureHeight; + + _videoContext.overlayTexture.create(overlayTextureWidth, overlayTextureHeight, Graphics::createPixelFormat<5551>()); + + glViewport(0, 0, _renderBufferWidth, _renderBufferHeight); printOpenGLError(); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); printOpenGLError(); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_TEXTURE_2D); printOpenGLError(); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); printOpenGLError(); + glEnableClientState(GL_VERTEX_ARRAY); printOpenGLError(); + } +} + +- (void)setupGestureRecognizers { + UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeRight:)]; + swipeRight.direction = UISwipeGestureRecognizerDirectionRight; + swipeRight.numberOfTouchesRequired = 2; + + UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeLeft:)]; + swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft; + swipeLeft.numberOfTouchesRequired = 2; + + UISwipeGestureRecognizer *swipeUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeUp:)]; + swipeUp.direction = UISwipeGestureRecognizerDirectionUp; + swipeUp.numberOfTouchesRequired = 2; + + UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeDown:)]; + swipeDown.direction = UISwipeGestureRecognizerDirectionDown; + swipeDown.numberOfTouchesRequired = 2; + + UITapGestureRecognizer *doubleTapTwoFingers = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersDoubleTap:)]; + doubleTapTwoFingers.numberOfTapsRequired = 2; + doubleTapTwoFingers.numberOfTouchesRequired = 2; + + [self addGestureRecognizer:swipeRight]; + [self addGestureRecognizer:swipeLeft]; + [self addGestureRecognizer:swipeUp]; + [self addGestureRecognizer:swipeDown]; + [self addGestureRecognizer:doubleTapTwoFingers]; +} + +- (CGFloat)optimalScale { + CGFloat screenScale = [[UIScreen mainScreen] scale]; + if (screenScale < 2) return screenScale; + + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + return 1; + } + + CGSize screenSize; + UIScreen *mainScreen = [UIScreen mainScreen]; + if ([mainScreen respondsToSelector:@selector(nativeBounds)]) { + screenSize = [mainScreen nativeBounds].size; + } + else { + screenSize = [mainScreen bounds].size; + screenSize.width *= screenScale; + screenSize.height *= screenScale; + } + CGFloat mxSize = MAX(screenSize.width, screenSize.height); + + if (mxSize <= 1136) { + // iPhone 4S / 5 / 5S / 5C + return 1; + } + else { + // iPhone 6 / 6S / 6+ / 6S+ + return 2; + } +} + +- (id)initWithFrame:(struct CGRect)frame { + self = [super initWithFrame: frame]; + + [self setupGestureRecognizers]; + + g_fullWidth = (int)MAX(frame.size.width, frame.size.height); + g_fullHeight = (int)MIN(frame.size.width, frame.size.height); + + _contentScaleFactor = [self optimalScale]; + [self setContentScaleFactor:_contentScaleFactor]; + + g_iPhoneViewInstance = self; + + _keyboardView = nil; + _screenTexture = 0; + _overlayTexture = 0; + _mouseCursorTexture = 0; + + _scaledShakeOffsetY = 0; + + _firstTouch = NULL; + _secondTouch = NULL; + + _eventLock = [[NSLock alloc] init]; + + _gameScreenVertCoords[0] = _gameScreenVertCoords[1] = + _gameScreenVertCoords[2] = _gameScreenVertCoords[3] = + _gameScreenVertCoords[4] = _gameScreenVertCoords[5] = + _gameScreenVertCoords[6] = _gameScreenVertCoords[7] = 0; + + _gameScreenTexCoords[0] = _gameScreenTexCoords[1] = + _gameScreenTexCoords[2] = _gameScreenTexCoords[3] = + _gameScreenTexCoords[4] = _gameScreenTexCoords[5] = + _gameScreenTexCoords[6] = _gameScreenTexCoords[7] = 0; + + _overlayVertCoords[0] = _overlayVertCoords[1] = + _overlayVertCoords[2] = _overlayVertCoords[3] = + _overlayVertCoords[4] = _overlayVertCoords[5] = + _overlayVertCoords[6] = _overlayVertCoords[7] = 0; + + _overlayTexCoords[0] = _overlayTexCoords[1] = + _overlayTexCoords[2] = _overlayTexCoords[3] = + _overlayTexCoords[4] = _overlayTexCoords[5] = + _overlayTexCoords[6] = _overlayTexCoords[7] = 0; + + _mouseVertCoords[0] = _mouseVertCoords[1] = + _mouseVertCoords[2] = _mouseVertCoords[3] = + _mouseVertCoords[4] = _mouseVertCoords[5] = + _mouseVertCoords[6] = _mouseVertCoords[7] = 0; + + _mouseTexCoords[0] = _mouseTexCoords[1] = + _mouseTexCoords[2] = _mouseTexCoords[3] = + _mouseTexCoords[4] = _mouseTexCoords[5] = + _mouseTexCoords[6] = _mouseTexCoords[7] = 0; + + // Initialize the OpenGL ES context + [self createContext]; + + return self; +} + +- (void)dealloc { + if (_keyboardView != nil) { + [_keyboardView dealloc]; + } + + _videoContext.screenTexture.free(); + _videoContext.overlayTexture.free(); + _videoContext.mouseTexture.free(); + + [_eventLock dealloc]; + [super dealloc]; +} + +#if 0 +- (void)drawRect:(CGRect)frame { + if (g_lastTick == 0) { + g_lastTick = time(0); + } + + g_frames++; + if (time(0) > g_lastTick) { + g_lastTick = time(0); + printf("FPS: %i\n", g_frames); + g_frames = 0; + } +} +#endif + +- (void)setFilterModeForTexture:(GLuint)tex { + if (!tex) + return; + + glBindTexture(GL_TEXTURE_2D, tex); printOpenGLError(); + + GLint filter = GL_LINEAR; + + switch (_videoContext.graphicsMode) { + case kGraphicsModeLinear: + filter = GL_LINEAR; + break; + + case kGraphicsModeNone: + filter = GL_NEAREST; + break; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); printOpenGLError(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); printOpenGLError(); + // We use GL_CLAMP_TO_EDGE here to avoid artifacts when linear filtering + // is used. If we would not use this for example the cursor in Loom would + // have a line/border artifact on the right side of the covered rect. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); printOpenGLError(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); printOpenGLError(); +} + +- (void)setGraphicsMode { + [self setFilterModeForTexture:_screenTexture]; + [self setFilterModeForTexture:_overlayTexture]; + [self setFilterModeForTexture:_mouseCursorTexture]; +} + +- (void)updateSurface { + if (!g_needsScreenUpdate) { + return; + } + g_needsScreenUpdate = 0; + + glClear(GL_COLOR_BUFFER_BIT); printOpenGLError(); + + [self updateMainSurface]; + + if (_videoContext.overlayVisible) + [self updateOverlaySurface]; + + if (_videoContext.mouseIsVisible) + [self updateMouseSurface]; + + glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); + [_context presentRenderbuffer:GL_RENDERBUFFER_OES]; + +} + +- (void)notifyMouseMove { + const GLint mouseX = (GLint)(_videoContext.mouseX * _mouseScaleX) - _mouseHotspotX; + const GLint mouseY = (GLint)(_videoContext.mouseY * _mouseScaleY) - _mouseHotspotY; + + _mouseVertCoords[0] = _mouseVertCoords[4] = mouseX; + _mouseVertCoords[1] = _mouseVertCoords[3] = mouseY; + _mouseVertCoords[2] = _mouseVertCoords[6] = mouseX + _mouseWidth; + _mouseVertCoords[5] = _mouseVertCoords[7] = mouseY + _mouseHeight; +} + +- (void)updateMouseCursorScaling { + CGRect *rect; + int maxWidth, maxHeight; + + if (!_videoContext.overlayVisible) { + rect = &_gameScreenRect; + maxWidth = _videoContext.screenWidth; + maxHeight = _videoContext.screenHeight; + } else { + rect = &_overlayRect; + maxWidth = _videoContext.overlayWidth; + maxHeight = _videoContext.overlayHeight; + } + + if (!maxWidth || !maxHeight) { + printf("WARNING: updateMouseCursorScaling called when screen was not ready (%d)!\n", _videoContext.overlayVisible); + return; + } + + _mouseScaleX = CGRectGetWidth(*rect) / (GLfloat)maxWidth; + _mouseScaleY = CGRectGetHeight(*rect) / (GLfloat)maxHeight; + + _mouseWidth = (GLint)(_videoContext.mouseWidth * _mouseScaleX); + _mouseHeight = (GLint)(_videoContext.mouseHeight * _mouseScaleY); + + _mouseHotspotX = (GLint)(_videoContext.mouseHotspotX * _mouseScaleX); + _mouseHotspotY = (GLint)(_videoContext.mouseHotspotY * _mouseScaleY); + + // We subtract the screen offset to the hotspot here to simplify the + // screen offset handling in the mouse code. Note the subtraction here + // makes sure that the offset actually gets added to the mouse position, + // since the hotspot offset is substracted from the position. + _mouseHotspotX -= (GLint)CGRectGetMinX(*rect); + _mouseHotspotY -= (GLint)CGRectGetMinY(*rect); + + // FIXME: For now we also adapt the mouse position here. In reality we + // would be better off to also adjust the event position when switching + // from overlay to game screen or vica versa. + [self notifyMouseMove]; +} + +- (void)updateMouseCursor { + if (_mouseCursorTexture == 0) { + glGenTextures(1, &_mouseCursorTexture); printOpenGLError(); + [self setFilterModeForTexture:_mouseCursorTexture]; + } + + [self updateMouseCursorScaling]; + + _mouseTexCoords[2] = _mouseTexCoords[6] = _videoContext.mouseWidth / (GLfloat)_videoContext.mouseTexture.w; + _mouseTexCoords[5] = _mouseTexCoords[7] = _videoContext.mouseHeight / (GLfloat)_videoContext.mouseTexture.h; + + glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.mouseTexture.w, _videoContext.mouseTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.mouseTexture.getPixels()); printOpenGLError(); +} + +- (void)updateMainSurface { + glVertexPointer(2, GL_FLOAT, 0, _gameScreenVertCoords); printOpenGLError(); + glTexCoordPointer(2, GL_FLOAT, 0, _gameScreenTexCoords); printOpenGLError(); + + glBindTexture(GL_TEXTURE_2D, _screenTexture); printOpenGLError(); + + // Unfortunately we have to update the whole texture every frame, since glTexSubImage2D is actually slower in all cases + // due to the iPhone internals having to convert the whole texture back from its internal format when used. + // In the future we could use several tiled textures instead. + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w, _videoContext.screenTexture.h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _videoContext.screenTexture.getPixels()); printOpenGLError(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); +} + +- (void)updateOverlaySurface { + glVertexPointer(2, GL_FLOAT, 0, _overlayVertCoords); printOpenGLError(); + glTexCoordPointer(2, GL_FLOAT, 0, _overlayTexCoords); printOpenGLError(); + + glBindTexture(GL_TEXTURE_2D, _overlayTexture); printOpenGLError(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.overlayTexture.w, _videoContext.overlayTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.overlayTexture.getPixels()); printOpenGLError(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); +} + +- (void)updateMouseSurface { + glVertexPointer(2, GL_FLOAT, 0, _mouseVertCoords); printOpenGLError(); + glTexCoordPointer(2, GL_FLOAT, 0, _mouseTexCoords); printOpenGLError(); + + glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); +} + +- (void)createScreenTexture { + const uint screenTexWidth = getSizeNextPOT(_videoContext.screenWidth); + const uint screenTexHeight = getSizeNextPOT(_videoContext.screenHeight); + + _gameScreenTexCoords[2] = _gameScreenTexCoords[6] = _videoContext.screenWidth / (GLfloat)screenTexWidth; + _gameScreenTexCoords[5] = _gameScreenTexCoords[7] = _videoContext.screenHeight / (GLfloat)screenTexHeight; + + _videoContext.screenTexture.create(screenTexWidth, screenTexHeight, Graphics::createPixelFormat<565>()); +} + +- (void)initSurface { + if (_context) { + glDeleteTextures(1, &_screenTexture); printOpenGLError(); + glDeleteTextures(1, &_overlayTexture); printOpenGLError(); + + glDeleteRenderbuffersOES(1, &_viewRenderbuffer); + glDeleteFramebuffersOES(1, &_viewFramebuffer); + + glGenFramebuffersOES(1, &_viewFramebuffer); printOpenGLError(); + glGenRenderbuffersOES(1, &_viewRenderbuffer); printOpenGLError(); + + glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); printOpenGLError(); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); + [_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id)self.layer]; + + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); + + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &_renderBufferWidth); printOpenGLError(); + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &_renderBufferHeight); printOpenGLError(); + + if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { + NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); + return; + } + + glViewport(0, 0, _renderBufferWidth, _renderBufferHeight); printOpenGLError(); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); printOpenGLError(); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_TEXTURE_2D); printOpenGLError(); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); printOpenGLError(); + glEnableClientState(GL_VERTEX_ARRAY); printOpenGLError(); + } + + BOOL isLandscape = (self.bounds.size.width > self.bounds.size.height); // UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]); + +// glMatrixMode(GL_PROJECTION); +// glLoadIdentity(); + + int screenWidth, screenHeight; + if (isLandscape) { + screenWidth = MAX(_renderBufferWidth, _renderBufferHeight); + screenHeight = MIN(_renderBufferWidth, _renderBufferHeight); +// glOrthof(0, screenWidth, screenHeight, 0, 0, 1); printOpenGLError(); + } + else { + screenWidth = MIN(_renderBufferWidth, _renderBufferHeight); + screenHeight = MAX(_renderBufferWidth, _renderBufferHeight); +// glOrthof(0, screenHeight, screenWidth, 0, 0, 1); printOpenGLError(); + } + + glGenTextures(1, &_screenTexture); printOpenGLError(); + [self setFilterModeForTexture:_screenTexture]; + + glGenTextures(1, &_overlayTexture); printOpenGLError(); + [self setFilterModeForTexture:_overlayTexture]; + + glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); + + [self clearColorBuffer]; + +// if (_keyboardView != nil) { +// [_keyboardView removeFromSuperview]; +// [[_keyboardView inputView] removeFromSuperview]; +// } + + GLfloat adjustedWidth = _videoContext.screenWidth; + GLfloat adjustedHeight = _videoContext.screenHeight; + if (_videoContext.asprectRatioCorrection) { + if (_videoContext.screenWidth == 320 && _videoContext.screenHeight == 200) + adjustedHeight = 240; + else if (_videoContext.screenWidth == 640 && _videoContext.screenHeight == 400) + adjustedHeight = 480; + } + + float overlayPortraitRatio; + + if (isLandscape) { + GLfloat gameScreenRatio = adjustedWidth / adjustedHeight; + GLfloat screenRatio = (GLfloat)screenWidth / (GLfloat)screenHeight; + + // These are the width/height according to the portrait layout! + int rectWidth, rectHeight; + int xOffset, yOffset; + + if (gameScreenRatio < screenRatio) { + // When the game screen ratio is less than the screen ratio + // we need to scale the width, since the game screen was higher + // compared to the width than our output screen is. + rectWidth = (int)(screenHeight * gameScreenRatio); + rectHeight = screenHeight; + xOffset = (screenWidth - rectWidth) / 2; + yOffset = 0; + } else { + // When the game screen ratio is bigger than the screen ratio + // we need to scale the height, since the game screen was wider + // compared to the height than our output screen is. + rectWidth = screenWidth; + rectHeight = (int)(screenWidth / gameScreenRatio); + xOffset = 0; + yOffset = (screenHeight - rectHeight) / 2; + } + + [_keyboardView hideKeyboard]; + + //printf("Rect: %i, %i, %i, %i\n", xOffset, yOffset, rectWidth, rectHeight); + _gameScreenRect = CGRectMake(xOffset, yOffset, rectWidth, rectHeight); + overlayPortraitRatio = 1.0f; + } else { + GLfloat ratio = adjustedHeight / adjustedWidth; + int height = (int)(screenWidth * ratio); + //printf("Making rect (%u, %u)\n", screenWidth, height); + _gameScreenRect = CGRectMake(0, 0, screenWidth, height); + + CGRect keyFrame = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f); + if (_keyboardView == nil) { + _keyboardView = [[SoftKeyboard alloc] initWithFrame:keyFrame]; + [_keyboardView setInputDelegate:self]; + [self addSubview:[_keyboardView inputView]]; + [self addSubview: _keyboardView]; + } + + [_keyboardView showKeyboard]; + overlayPortraitRatio = (_videoContext.overlayHeight * ratio) / _videoContext.overlayWidth; + } + _overlayRect = CGRectMake(0, 0, screenWidth, screenHeight * overlayPortraitRatio); + + _gameScreenVertCoords[0] = _gameScreenVertCoords[4] = CGRectGetMinX(_gameScreenRect); + _gameScreenVertCoords[1] = _gameScreenVertCoords[3] = CGRectGetMinY(_gameScreenRect); + _gameScreenVertCoords[2] = _gameScreenVertCoords[6] = CGRectGetMaxX(_gameScreenRect); + _gameScreenVertCoords[5] = _gameScreenVertCoords[7] = CGRectGetMaxY(_gameScreenRect); + + _overlayVertCoords[2] = _overlayVertCoords[6] = CGRectGetMaxX(_overlayRect); + _overlayVertCoords[5] = _overlayVertCoords[7] = CGRectGetMaxY(_overlayRect); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrthof(0, screenWidth, screenHeight, 0, 0, 1); + + [self setViewTransformation]; + [self updateMouseCursorScaling]; +} + +- (void)setViewTransformation { + // Set the modelview matrix. This matrix will be used for the shake offset + // support. + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + // Scale the shake offset according to the overlay size. We need this to + // adjust the overlay mouse click coordinates when an offset is set. + _scaledShakeOffsetY = (int)(_videoContext.shakeOffsetY / (GLfloat)_videoContext.screenHeight * CGRectGetHeight(_overlayRect)); + + // Apply the shakeing to the output screen. + glTranslatef(0, -_scaledShakeOffsetY, 0); +} + +- (void)clearColorBuffer { + // The color buffer is triple-buffered, so we clear it multiple times right away to avid doing any glClears later. + int clearCount = 5; + while (clearCount-- > 0) { + glClear(GL_COLOR_BUFFER_BIT); printOpenGLError(); + [_context presentRenderbuffer:GL_RENDERBUFFER_OES]; + } +} + +- (void)addEvent:(InternalEvent)event { + [_eventLock lock]; + _events.push_back(event); + [_eventLock unlock]; +} + +- (bool)fetchEvent:(InternalEvent *)event { + [_eventLock lock]; + if (_events.empty()) { + [_eventLock unlock]; + return false; + } + + *event = *_events.begin(); + _events.pop_front(); + [_eventLock unlock]; + return true; +} + +- (bool)getMouseCoords:(CGPoint)point eventX:(int *)x eventY:(int *)y { + // We scale the input according to our scale factor to get actual screen + // cooridnates. + point.x *= _contentScaleFactor; + point.y *= _contentScaleFactor; + + CGRect *area; + int width, height, offsetY; + if (_videoContext.overlayVisible) { + area = &_overlayRect; + width = _videoContext.overlayWidth; + height = _videoContext.overlayHeight; + offsetY = _scaledShakeOffsetY; + } else { + area = &_gameScreenRect; + width = _videoContext.screenWidth; + height = _videoContext.screenHeight; + offsetY = _videoContext.shakeOffsetY; + } + + point.x = (point.x - CGRectGetMinX(*area)) / CGRectGetWidth(*area); + point.y = (point.y - CGRectGetMinY(*area)) / CGRectGetHeight(*area); + + *x = (int)(point.x * width); + // offsetY describes the translation of the screen in the upward direction, + // thus we need to add it here. + *y = (int)(point.y * height + offsetY); + + if (!iOS7_touchpadModeEnabled()) { + // Clip coordinates + if (*x < 0 || *x > width || *y < 0 || *y > height) + return false; + } + + return true; +} + +- (void)deviceOrientationChanged:(UIDeviceOrientation)orientation { + [self addEvent:InternalEvent(kInputOrientationChanged, orientation, 0)]; +} + +- (UITouch *)secondTouchOtherTouchThan:(UITouch *)touch in:(NSSet *)set { + NSArray *all = [set allObjects]; + for (UITouch *t in all) { + if (t != touch) { + return t; + } + } + return nil; +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + int x, y; + + NSSet *allTouches = [event allTouches]; + if (allTouches.count == 1) { + _firstTouch = [allTouches anyObject]; + CGPoint point = [_firstTouch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent:InternalEvent(kInputMouseDown, x, y)]; + } + else if (allTouches.count == 2) { + _secondTouch = [self secondTouchOtherTouchThan:_firstTouch in:allTouches]; + if (_secondTouch) { + CGPoint point = [_secondTouch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent:InternalEvent(kInputMouseSecondDown, x, y)]; + } + } +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + int x, y; + + NSSet *allTouches = [event allTouches]; + for (UITouch *touch in allTouches) { + if (touch == _firstTouch) { + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent:InternalEvent(kInputMouseDragged, x, y)]; + } else if (touch == _secondTouch) { + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent:InternalEvent(kInputMouseSecondDragged, x, y)]; + } + } +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + int x, y; + + NSSet *allTouches = [event allTouches]; + if (allTouches.count == 1) { + UITouch *touch = [allTouches anyObject]; + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) { + return; + } + + [self addEvent:InternalEvent(kInputMouseUp, x, y)]; + } + else if (allTouches.count == 2) { + UITouch *touch = [[allTouches allObjects] objectAtIndex:1]; + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent:InternalEvent(kInputMouseSecondUp, x, y)]; + } + _firstTouch = nil; + _secondTouch = nil; +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + _firstTouch = nil; + _secondTouch = nil; +} + +- (void)twoFingersSwipeRight:(UISwipeGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeRight, 2)]; +} + +- (void)twoFingersSwipeLeft:(UISwipeGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeLeft, 2)]; +} + +- (void)twoFingersSwipeUp:(UISwipeGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeUp, 2)]; +} + +- (void)twoFingersSwipeDown:(UISwipeGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeDown, 2)]; +} + +- (void)twoFingersDoubleTap:(UITapGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputTap, kUIViewTapDouble, 2)]; +} + +- (void)handleKeyPress:(unichar)c { + [self addEvent:InternalEvent(kInputKeyPressed, c, 0)]; +} + +- (void)applicationSuspend { + [self addEvent:InternalEvent(kInputApplicationSuspended, 0, 0)]; +} + +- (void)applicationResume { + [self addEvent:InternalEvent(kInputApplicationResumed, 0, 0)]; +} + +@end diff --git a/backends/platform/ios7/iphone_common.h b/backends/platform/ios7/iphone_common.h deleted file mode 100644 index 94836dabcd..0000000000 --- a/backends/platform/ios7/iphone_common.h +++ /dev/null @@ -1,111 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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. - * - */ - -#ifndef BACKENDS_PLATFORM_IPHONE_IPHONE_COMMON_H -#define BACKENDS_PLATFORM_IPHONE_IPHONE_COMMON_H - -#include "graphics/surface.h" - -enum InputEvent { - kInputMouseDown, - kInputMouseUp, - kInputMouseDragged, - kInputMouseSecondDragged, - kInputMouseSecondDown, - kInputMouseSecondUp, - kInputOrientationChanged, - kInputKeyPressed, - kInputApplicationSuspended, - kInputApplicationResumed, - kInputSwipe, - kInputTap -}; - -enum ScreenOrientation { - kScreenOrientationPortrait, - kScreenOrientationLandscape, - kScreenOrientationFlippedLandscape -}; - -enum UIViewSwipeDirection { - kUIViewSwipeUp = 1, - kUIViewSwipeDown = 2, - kUIViewSwipeLeft = 4, - kUIViewSwipeRight = 8 -}; - -enum UIViewTapDescription { - kUIViewTapSingle = 1, - kUIViewTapDouble = 2 -}; - -enum GraphicsModes { - kGraphicsModeLinear = 0, - kGraphicsModeNone = 1 -}; - -struct VideoContext { - VideoContext() : asprectRatioCorrection(), screenWidth(), screenHeight(), overlayVisible(false), - overlayWidth(), overlayHeight(), mouseX(), mouseY(), - mouseHotspotX(), mouseHotspotY(), mouseWidth(), mouseHeight(), - mouseIsVisible(), graphicsMode(kGraphicsModeLinear), shakeOffsetY() { - } - - // Game screen state - bool asprectRatioCorrection; - uint screenWidth, screenHeight; - Graphics::Surface screenTexture; - - // Overlay state - bool overlayVisible; - uint overlayWidth, overlayHeight; - Graphics::Surface overlayTexture; - - // Mouse cursor state - uint mouseX, mouseY; - int mouseHotspotX, mouseHotspotY; - uint mouseWidth, mouseHeight; - bool mouseIsVisible; - Graphics::Surface mouseTexture; - - // Misc state - GraphicsModes graphicsMode; - int shakeOffsetY; -}; - -struct InternalEvent { - InternalEvent() : type(), value1(), value2() {} - InternalEvent(InputEvent t, int v1, int v2) : type(t), value1(v1), value2(v2) {} - - InputEvent type; - int value1, value2; -}; - -// On the ObjC side -void iPhone_updateScreen(); -bool iPhone_fetchEvent(InternalEvent *event); -const char *iPhone_getDocumentsDir(); -bool iPhone_isHighResDevice(); - -uint getSizeNextPOT(uint size); - -#endif diff --git a/backends/platform/ios7/iphone_keyboard.h b/backends/platform/ios7/iphone_keyboard.h deleted file mode 100644 index ddd8f436e5..0000000000 --- a/backends/platform/ios7/iphone_keyboard.h +++ /dev/null @@ -1,44 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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. - * - */ - -#ifndef BACKENDS_PLATFORM_IPHONE_IPHONE_KEYBOARD_H -#define BACKENDS_PLATFORM_IPHONE_IPHONE_KEYBOARD_H - -#include -#include - -@interface SoftKeyboard : UIView { - id inputDelegate; - UITextView *inputView; -} - -- (id)initWithFrame:(CGRect)frame; -- (UITextView *)inputView; -- (void)setInputDelegate:(id)delegate; -- (void)handleKeyPress:(unichar)c; - -- (void)showKeyboard; -- (void)hideKeyboard; - -@end - -#endif diff --git a/backends/platform/ios7/iphone_keyboard.mm b/backends/platform/ios7/iphone_keyboard.mm deleted file mode 100644 index 0588aac8ab..0000000000 --- a/backends/platform/ios7/iphone_keyboard.mm +++ /dev/null @@ -1,98 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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. - * - */ - -#include "iphone_keyboard.h" - -@interface UITextInputTraits -- (void)setAutocorrectionType:(int)type; -- (void)setAutocapitalizationType:(int)type; -- (void)setEnablesReturnKeyAutomatically:(BOOL)val; -@end - -@interface TextInputHandler : UITextView { - SoftKeyboard *softKeyboard; -} - -- (id)initWithKeyboard:(SoftKeyboard *)keyboard; - -@end - - -@implementation TextInputHandler - -- (id)initWithKeyboard:(SoftKeyboard *)keyboard { - self = [super initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.0f)]; - softKeyboard = keyboard; - - [self setAutocorrectionType:UITextAutocorrectionTypeNo]; - [self setAutocapitalizationType:UITextAutocapitalizationTypeNone]; - [self setEnablesReturnKeyAutomatically:NO]; - - return self; -} - -@end - - -@implementation SoftKeyboard - -- (id)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - inputDelegate = nil; - inputView = [[TextInputHandler alloc] initWithKeyboard:self]; - inputView.delegate = self; - return self; -} - -- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { - unichar c; - if (text.length) { - c = [text characterAtIndex:0]; - } - else { - c = '\b'; - } - [inputDelegate handleKeyPress:c]; - return YES; -} - -- (UITextView *)inputView { - return inputView; -} - -- (void)setInputDelegate:(id)delegate { - inputDelegate = delegate; -} - -- (void)handleKeyPress:(unichar)c { - [inputDelegate handleKeyPress:c]; -} - -- (void)showKeyboard { - [inputView becomeFirstResponder]; -} - -- (void)hideKeyboard { - [inputView endEditing:YES]; -} - -@end diff --git a/backends/platform/ios7/iphone_main.mm b/backends/platform/ios7/iphone_main.mm deleted file mode 100644 index 02d46c1995..0000000000 --- a/backends/platform/ios7/iphone_main.mm +++ /dev/null @@ -1,154 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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. - * - */ - -// Disable symbol overrides so that we can use system headers. -#define FORBIDDEN_SYMBOL_ALLOW_ALL - -#include -#include - -#include "iphone_video.h" - -void iphone_main(int argc, char *argv[]); - -@interface ScummVMViewController : UIViewController - -@end - -@implementation ScummVMViewController - -- (BOOL)prefersStatusBarHidden { - return YES; -} - -@end - -@interface iPhoneMain : UIApplication { - UIWindow *_window; - ScummVMViewController *_controller; - iPhoneView *_view; -} - -- (void)mainLoop:(id)param; -- (iPhoneView *)getView; -- (UIWindow *)getWindow; -- (void)didRotate:(NSNotification *)notification; -@end - -static int g_argc; -static char **g_argv; - -int main(int argc, char **argv) { - g_argc = argc; - g_argv = argv; - - NSAutoreleasePool *autoreleasePool = [ - [NSAutoreleasePool alloc] init - ]; - - int returnCode = UIApplicationMain(argc, argv, @"iPhoneMain", @"iPhoneMain"); - [autoreleasePool release]; - return returnCode; -} - -@implementation iPhoneMain - --(id) init { - [super init]; - _window = nil; - _view = nil; - return self; -} - -- (void)mainLoop:(id)param { - [[NSAutoreleasePool alloc] init]; - - iphone_main(g_argc, g_argv); - exit(0); -} - -- (iPhoneView *)getView { - return _view; -} - -- (void)applicationDidFinishLaunching:(UIApplication *)application { - CGRect rect = [[UIScreen mainScreen] bounds]; - - // Create the directory for savegames -#ifdef IPHONE_OFFICIAL - NSFileManager *fm = [NSFileManager defaultManager]; - NSString *documentPath = [NSString stringWithUTF8String:iPhone_getDocumentsDir()]; - NSString *savePath = [documentPath stringByAppendingPathComponent:@"Savegames"]; - if (![fm fileExistsAtPath:savePath]) { - [fm createDirectoryAtPath:savePath withIntermediateDirectories:YES attributes:nil error:nil]; - } -#endif - - _window = [[UIWindow alloc] initWithFrame:rect]; - [_window retain]; - - _controller = [[ScummVMViewController alloc] init]; - - _view = [[iPhoneView alloc] initWithFrame:rect]; - _view.multipleTouchEnabled = YES; - _controller.view = _view; - - [_window setRootViewController:_controller]; - [_window makeKeyAndVisible]; - - [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(didRotate:) - name:@"UIDeviceOrientationDidChangeNotification" - object:nil]; - - [NSThread detachNewThreadSelector:@selector(mainLoop:) toTarget:self withObject:nil]; -} - -- (void)applicationDidResume { -} - -- (void)applicationWillSuspend { -} - -- (void)applicationWillTerminate { -} - -- (void)applicationSuspend:(struct __GSEvent *)event { - //[self setApplicationBadge:NSLocalizedString(@"ON", nil)]; - [_view applicationSuspend]; -} - -- (void)applicationResume:(struct __GSEvent *)event { - [_view applicationResume]; -} - -- (void)didRotate:(NSNotification *)notification { - UIDeviceOrientation screenOrientation = [[UIDevice currentDevice] orientation]; - [_view deviceOrientationChanged:screenOrientation]; -} - -- (UIWindow*) getWindow { - return _window; -} - -@end diff --git a/backends/platform/ios7/iphone_video.h b/backends/platform/ios7/iphone_video.h deleted file mode 100644 index 5c9766a116..0000000000 --- a/backends/platform/ios7/iphone_video.h +++ /dev/null @@ -1,109 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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. - * - */ - -#ifndef BACKENDS_PLATFORM_IPHONE_IPHONE_VIDEO_H -#define BACKENDS_PLATFORM_IPHONE_IPHONE_VIDEO_H - -#include -#include -#include - -#include -#include -#include - -#include "iphone_keyboard.h" -#include "iphone_common.h" - -#include "common/list.h" - -@interface iPhoneView : UIView { - VideoContext _videoContext; - - Common::List _events; - NSLock *_eventLock; - SoftKeyboard *_keyboardView; - - EAGLContext *_context; - GLuint _viewRenderbuffer; - GLuint _viewFramebuffer; - GLuint _screenTexture; - GLuint _overlayTexture; - GLuint _mouseCursorTexture; - - GLint _renderBufferWidth; - GLint _renderBufferHeight; - - GLfloat _gameScreenVertCoords[4 * 2]; - GLfloat _gameScreenTexCoords[4 * 2]; - CGRect _gameScreenRect; - - GLfloat _overlayVertCoords[4 * 2]; - GLfloat _overlayTexCoords[4 * 2]; - CGRect _overlayRect; - - GLfloat _mouseVertCoords[4 * 2]; - GLfloat _mouseTexCoords[4 * 2]; - GLint _mouseHotspotX, _mouseHotspotY; - GLint _mouseWidth, _mouseHeight; - GLfloat _mouseScaleX, _mouseScaleY; - - int _scaledShakeOffsetY; - CGFloat _contentScaleFactor; - - UITouch *_firstTouch; - UITouch *_secondTouch; -} - -- (id)initWithFrame:(struct CGRect)frame; - -- (VideoContext *)getVideoContext; - -- (void)createScreenTexture; -- (void)initSurface; -- (void)setViewTransformation; - -- (void)setGraphicsMode; - -- (void)updateSurface; -- (void)updateMainSurface; -- (void)updateOverlaySurface; -- (void)updateMouseSurface; -- (void)clearColorBuffer; - -- (void)notifyMouseMove; -- (void)updateMouseCursorScaling; -- (void)updateMouseCursor; - -- (void)deviceOrientationChanged:(UIDeviceOrientation)orientation; - -- (void)applicationSuspend; - -- (void)applicationResume; - -- (bool)fetchEvent:(InternalEvent *)event; - -@end - -extern iPhoneView *g_iPhoneViewInstance; - -#endif diff --git a/backends/platform/ios7/iphone_video.mm b/backends/platform/ios7/iphone_video.mm deleted file mode 100644 index 8470651794..0000000000 --- a/backends/platform/ios7/iphone_video.mm +++ /dev/null @@ -1,821 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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. - * - */ - -// Disable symbol overrides so that we can use system headers. -#define FORBIDDEN_SYMBOL_ALLOW_ALL - -#include "iphone_video.h" - -#include "graphics/colormasks.h" -#include "common/system.h" - -iPhoneView *g_iPhoneViewInstance = nil; -static int g_fullWidth; -static int g_fullHeight; - -static int g_needsScreenUpdate = 0; - -#if 0 -static long g_lastTick = 0; -static int g_frames = 0; -#endif - -extern bool iphone_touchpadModeEnabled(); - -#define printOpenGLError() printOglError(__FILE__, __LINE__) - -int printOglError(const char *file, int line) { - int retCode = 0; - - // returns 1 if an OpenGL error occurred, 0 otherwise. - GLenum glErr = glGetError(); - while (glErr != GL_NO_ERROR) { - fprintf(stderr, "glError: %u (%s: %d)\n", glErr, file, line); - retCode = 1; - glErr = glGetError(); - } - return retCode; -} - -bool iPhone_isHighResDevice() { - return g_fullHeight > 480; -} - -void iPhone_updateScreen() { - //printf("Mouse: (%i, %i)\n", mouseX, mouseY); - if (!g_needsScreenUpdate) { - g_needsScreenUpdate = 1; - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateSurface) withObject:nil waitUntilDone: NO]; - } -} - -bool iPhone_fetchEvent(InternalEvent *event) { - return [g_iPhoneViewInstance fetchEvent:event]; -} - -uint getSizeNextPOT(uint size) { - if ((size & (size - 1)) || !size) { - int log = 0; - - while (size >>= 1) - ++log; - - size = (2 << log); - } - - return size; -} - -const char *iPhone_getDocumentsDir() { - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString *documentsDirectory = [paths objectAtIndex:0]; - return [documentsDirectory UTF8String]; -} - -@implementation iPhoneView - -+ (Class)layerClass { - return [CAEAGLLayer class]; -} - -- (VideoContext *)getVideoContext { - return &_videoContext; -} - -- (void)createContext { - CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; - - eaglLayer.opaque = YES; - eaglLayer.drawableProperties = @{ - kEAGLDrawablePropertyRetainedBacking: @NO, - kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGB565 - }; - - _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; - - // In case creating the OpenGL ES context failed, we will error out here. - if (_context == nil) { - fprintf(stderr, "Could not create OpenGL ES context\n"); - exit(-1); - } - - if ([EAGLContext setCurrentContext:_context]) { - glGenFramebuffersOES(1, &_viewFramebuffer); printOpenGLError(); - glGenRenderbuffersOES(1, &_viewRenderbuffer); printOpenGLError(); - - glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); printOpenGLError(); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); - [_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id)self.layer]; - - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); - - // Retrieve the render buffer size. This *should* match the frame size, - // i.e. g_fullWidth and g_fullHeight. - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &_renderBufferWidth); printOpenGLError(); - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &_renderBufferHeight); printOpenGLError(); - - if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { - NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); - return; - } - uint maxValue = MAX(_renderBufferWidth, _renderBufferHeight), maxValuePOT = getSizeNextPOT(maxValue); - uint minValue = MIN(_renderBufferWidth, _renderBufferHeight), minValuePOT = getSizeNextPOT(minValue); - - _videoContext.overlayWidth = maxValue; - _videoContext.overlayHeight = minValue; - - uint overlayTextureWidth = maxValuePOT; - uint overlayTextureHeight = minValuePOT; - - // Since the overlay size won't change the whole run, we can - // precalculate the texture coordinates for the overlay texture here - // and just use it later on. - _overlayTexCoords[2] = _overlayTexCoords[6] = _videoContext.overlayWidth / (GLfloat)overlayTextureWidth; - _overlayTexCoords[5] = _overlayTexCoords[7] = _videoContext.overlayHeight / (GLfloat)overlayTextureHeight; - - _videoContext.overlayTexture.create(overlayTextureWidth, overlayTextureHeight, Graphics::createPixelFormat<5551>()); - - glViewport(0, 0, _renderBufferWidth, _renderBufferHeight); printOpenGLError(); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); printOpenGLError(); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glEnable(GL_TEXTURE_2D); printOpenGLError(); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); printOpenGLError(); - glEnableClientState(GL_VERTEX_ARRAY); printOpenGLError(); - } -} - -- (void)setupGestureRecognizers { - UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeRight:)]; - swipeRight.direction = UISwipeGestureRecognizerDirectionRight; - swipeRight.numberOfTouchesRequired = 2; - - UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeLeft:)]; - swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft; - swipeLeft.numberOfTouchesRequired = 2; - - UISwipeGestureRecognizer *swipeUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeUp:)]; - swipeUp.direction = UISwipeGestureRecognizerDirectionUp; - swipeUp.numberOfTouchesRequired = 2; - - UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeDown:)]; - swipeDown.direction = UISwipeGestureRecognizerDirectionDown; - swipeDown.numberOfTouchesRequired = 2; - - UITapGestureRecognizer *doubleTapTwoFingers = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersDoubleTap:)]; - doubleTapTwoFingers.numberOfTapsRequired = 2; - doubleTapTwoFingers.numberOfTouchesRequired = 2; - - [self addGestureRecognizer:swipeRight]; - [self addGestureRecognizer:swipeLeft]; - [self addGestureRecognizer:swipeUp]; - [self addGestureRecognizer:swipeDown]; - [self addGestureRecognizer:doubleTapTwoFingers]; -} - -- (CGFloat)optimalScale { - CGFloat screenScale = [[UIScreen mainScreen] scale]; - if (screenScale < 2) return screenScale; - - if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { - return 1; - } - - CGSize screenSize; - UIScreen *mainScreen = [UIScreen mainScreen]; - if ([mainScreen respondsToSelector:@selector(nativeBounds)]) { - screenSize = [mainScreen nativeBounds].size; - } - else { - screenSize = [mainScreen bounds].size; - screenSize.width *= screenScale; - screenSize.height *= screenScale; - } - CGFloat mxSize = MAX(screenSize.width, screenSize.height); - - if (mxSize <= 1136) { - // iPhone 4S / 5 / 5S / 5C - return 1; - } - else { - // iPhone 6 / 6S / 6+ / 6S+ - return 2; - } -} - -- (id)initWithFrame:(struct CGRect)frame { - self = [super initWithFrame: frame]; - - [self setupGestureRecognizers]; - - g_fullWidth = (int)MAX(frame.size.width, frame.size.height); - g_fullHeight = (int)MIN(frame.size.width, frame.size.height); - - _contentScaleFactor = [self optimalScale]; - [self setContentScaleFactor:_contentScaleFactor]; - - g_iPhoneViewInstance = self; - - _keyboardView = nil; - _screenTexture = 0; - _overlayTexture = 0; - _mouseCursorTexture = 0; - - _scaledShakeOffsetY = 0; - - _firstTouch = NULL; - _secondTouch = NULL; - - _eventLock = [[NSLock alloc] init]; - - _gameScreenVertCoords[0] = _gameScreenVertCoords[1] = - _gameScreenVertCoords[2] = _gameScreenVertCoords[3] = - _gameScreenVertCoords[4] = _gameScreenVertCoords[5] = - _gameScreenVertCoords[6] = _gameScreenVertCoords[7] = 0; - - _gameScreenTexCoords[0] = _gameScreenTexCoords[1] = - _gameScreenTexCoords[2] = _gameScreenTexCoords[3] = - _gameScreenTexCoords[4] = _gameScreenTexCoords[5] = - _gameScreenTexCoords[6] = _gameScreenTexCoords[7] = 0; - - _overlayVertCoords[0] = _overlayVertCoords[1] = - _overlayVertCoords[2] = _overlayVertCoords[3] = - _overlayVertCoords[4] = _overlayVertCoords[5] = - _overlayVertCoords[6] = _overlayVertCoords[7] = 0; - - _overlayTexCoords[0] = _overlayTexCoords[1] = - _overlayTexCoords[2] = _overlayTexCoords[3] = - _overlayTexCoords[4] = _overlayTexCoords[5] = - _overlayTexCoords[6] = _overlayTexCoords[7] = 0; - - _mouseVertCoords[0] = _mouseVertCoords[1] = - _mouseVertCoords[2] = _mouseVertCoords[3] = - _mouseVertCoords[4] = _mouseVertCoords[5] = - _mouseVertCoords[6] = _mouseVertCoords[7] = 0; - - _mouseTexCoords[0] = _mouseTexCoords[1] = - _mouseTexCoords[2] = _mouseTexCoords[3] = - _mouseTexCoords[4] = _mouseTexCoords[5] = - _mouseTexCoords[6] = _mouseTexCoords[7] = 0; - - // Initialize the OpenGL ES context - [self createContext]; - - return self; -} - -- (void)dealloc { - if (_keyboardView != nil) { - [_keyboardView dealloc]; - } - - _videoContext.screenTexture.free(); - _videoContext.overlayTexture.free(); - _videoContext.mouseTexture.free(); - - [_eventLock dealloc]; - [super dealloc]; -} - -#if 0 -- (void)drawRect:(CGRect)frame { - if (g_lastTick == 0) { - g_lastTick = time(0); - } - - g_frames++; - if (time(0) > g_lastTick) { - g_lastTick = time(0); - printf("FPS: %i\n", g_frames); - g_frames = 0; - } -} -#endif - -- (void)setFilterModeForTexture:(GLuint)tex { - if (!tex) - return; - - glBindTexture(GL_TEXTURE_2D, tex); printOpenGLError(); - - GLint filter = GL_LINEAR; - - switch (_videoContext.graphicsMode) { - case kGraphicsModeLinear: - filter = GL_LINEAR; - break; - - case kGraphicsModeNone: - filter = GL_NEAREST; - break; - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); printOpenGLError(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); printOpenGLError(); - // We use GL_CLAMP_TO_EDGE here to avoid artifacts when linear filtering - // is used. If we would not use this for example the cursor in Loom would - // have a line/border artifact on the right side of the covered rect. - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); printOpenGLError(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); printOpenGLError(); -} - -- (void)setGraphicsMode { - [self setFilterModeForTexture:_screenTexture]; - [self setFilterModeForTexture:_overlayTexture]; - [self setFilterModeForTexture:_mouseCursorTexture]; -} - -- (void)updateSurface { - if (!g_needsScreenUpdate) { - return; - } - g_needsScreenUpdate = 0; - - glClear(GL_COLOR_BUFFER_BIT); printOpenGLError(); - - [self updateMainSurface]; - - if (_videoContext.overlayVisible) - [self updateOverlaySurface]; - - if (_videoContext.mouseIsVisible) - [self updateMouseSurface]; - - glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); - [_context presentRenderbuffer:GL_RENDERBUFFER_OES]; - -} - -- (void)notifyMouseMove { - const GLint mouseX = (GLint)(_videoContext.mouseX * _mouseScaleX) - _mouseHotspotX; - const GLint mouseY = (GLint)(_videoContext.mouseY * _mouseScaleY) - _mouseHotspotY; - - _mouseVertCoords[0] = _mouseVertCoords[4] = mouseX; - _mouseVertCoords[1] = _mouseVertCoords[3] = mouseY; - _mouseVertCoords[2] = _mouseVertCoords[6] = mouseX + _mouseWidth; - _mouseVertCoords[5] = _mouseVertCoords[7] = mouseY + _mouseHeight; -} - -- (void)updateMouseCursorScaling { - CGRect *rect; - int maxWidth, maxHeight; - - if (!_videoContext.overlayVisible) { - rect = &_gameScreenRect; - maxWidth = _videoContext.screenWidth; - maxHeight = _videoContext.screenHeight; - } else { - rect = &_overlayRect; - maxWidth = _videoContext.overlayWidth; - maxHeight = _videoContext.overlayHeight; - } - - if (!maxWidth || !maxHeight) { - printf("WARNING: updateMouseCursorScaling called when screen was not ready (%d)!\n", _videoContext.overlayVisible); - return; - } - - _mouseScaleX = CGRectGetWidth(*rect) / (GLfloat)maxWidth; - _mouseScaleY = CGRectGetHeight(*rect) / (GLfloat)maxHeight; - - _mouseWidth = (GLint)(_videoContext.mouseWidth * _mouseScaleX); - _mouseHeight = (GLint)(_videoContext.mouseHeight * _mouseScaleY); - - _mouseHotspotX = (GLint)(_videoContext.mouseHotspotX * _mouseScaleX); - _mouseHotspotY = (GLint)(_videoContext.mouseHotspotY * _mouseScaleY); - - // We subtract the screen offset to the hotspot here to simplify the - // screen offset handling in the mouse code. Note the subtraction here - // makes sure that the offset actually gets added to the mouse position, - // since the hotspot offset is substracted from the position. - _mouseHotspotX -= (GLint)CGRectGetMinX(*rect); - _mouseHotspotY -= (GLint)CGRectGetMinY(*rect); - - // FIXME: For now we also adapt the mouse position here. In reality we - // would be better off to also adjust the event position when switching - // from overlay to game screen or vica versa. - [self notifyMouseMove]; -} - -- (void)updateMouseCursor { - if (_mouseCursorTexture == 0) { - glGenTextures(1, &_mouseCursorTexture); printOpenGLError(); - [self setFilterModeForTexture:_mouseCursorTexture]; - } - - [self updateMouseCursorScaling]; - - _mouseTexCoords[2] = _mouseTexCoords[6] = _videoContext.mouseWidth / (GLfloat)_videoContext.mouseTexture.w; - _mouseTexCoords[5] = _mouseTexCoords[7] = _videoContext.mouseHeight / (GLfloat)_videoContext.mouseTexture.h; - - glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.mouseTexture.w, _videoContext.mouseTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.mouseTexture.getPixels()); printOpenGLError(); -} - -- (void)updateMainSurface { - glVertexPointer(2, GL_FLOAT, 0, _gameScreenVertCoords); printOpenGLError(); - glTexCoordPointer(2, GL_FLOAT, 0, _gameScreenTexCoords); printOpenGLError(); - - glBindTexture(GL_TEXTURE_2D, _screenTexture); printOpenGLError(); - - // Unfortunately we have to update the whole texture every frame, since glTexSubImage2D is actually slower in all cases - // due to the iPhone internals having to convert the whole texture back from its internal format when used. - // In the future we could use several tiled textures instead. - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w, _videoContext.screenTexture.h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _videoContext.screenTexture.getPixels()); printOpenGLError(); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); -} - -- (void)updateOverlaySurface { - glVertexPointer(2, GL_FLOAT, 0, _overlayVertCoords); printOpenGLError(); - glTexCoordPointer(2, GL_FLOAT, 0, _overlayTexCoords); printOpenGLError(); - - glBindTexture(GL_TEXTURE_2D, _overlayTexture); printOpenGLError(); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.overlayTexture.w, _videoContext.overlayTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.overlayTexture.getPixels()); printOpenGLError(); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); -} - -- (void)updateMouseSurface { - glVertexPointer(2, GL_FLOAT, 0, _mouseVertCoords); printOpenGLError(); - glTexCoordPointer(2, GL_FLOAT, 0, _mouseTexCoords); printOpenGLError(); - - glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); -} - -- (void)createScreenTexture { - const uint screenTexWidth = getSizeNextPOT(_videoContext.screenWidth); - const uint screenTexHeight = getSizeNextPOT(_videoContext.screenHeight); - - _gameScreenTexCoords[2] = _gameScreenTexCoords[6] = _videoContext.screenWidth / (GLfloat)screenTexWidth; - _gameScreenTexCoords[5] = _gameScreenTexCoords[7] = _videoContext.screenHeight / (GLfloat)screenTexHeight; - - _videoContext.screenTexture.create(screenTexWidth, screenTexHeight, Graphics::createPixelFormat<565>()); -} - -- (void)initSurface { - if (_context) { - glDeleteTextures(1, &_screenTexture); printOpenGLError(); - glDeleteTextures(1, &_overlayTexture); printOpenGLError(); - - glDeleteRenderbuffersOES(1, &_viewRenderbuffer); - glDeleteFramebuffersOES(1, &_viewFramebuffer); - - glGenFramebuffersOES(1, &_viewFramebuffer); printOpenGLError(); - glGenRenderbuffersOES(1, &_viewRenderbuffer); printOpenGLError(); - - glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); printOpenGLError(); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); - [_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id)self.layer]; - - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); - - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &_renderBufferWidth); printOpenGLError(); - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &_renderBufferHeight); printOpenGLError(); - - if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { - NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); - return; - } - - glViewport(0, 0, _renderBufferWidth, _renderBufferHeight); printOpenGLError(); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); printOpenGLError(); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glEnable(GL_TEXTURE_2D); printOpenGLError(); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); printOpenGLError(); - glEnableClientState(GL_VERTEX_ARRAY); printOpenGLError(); - } - - BOOL isLandscape = (self.bounds.size.width > self.bounds.size.height); // UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]); - -// glMatrixMode(GL_PROJECTION); -// glLoadIdentity(); - - int screenWidth, screenHeight; - if (isLandscape) { - screenWidth = MAX(_renderBufferWidth, _renderBufferHeight); - screenHeight = MIN(_renderBufferWidth, _renderBufferHeight); -// glOrthof(0, screenWidth, screenHeight, 0, 0, 1); printOpenGLError(); - } - else { - screenWidth = MIN(_renderBufferWidth, _renderBufferHeight); - screenHeight = MAX(_renderBufferWidth, _renderBufferHeight); -// glOrthof(0, screenHeight, screenWidth, 0, 0, 1); printOpenGLError(); - } - - glGenTextures(1, &_screenTexture); printOpenGLError(); - [self setFilterModeForTexture:_screenTexture]; - - glGenTextures(1, &_overlayTexture); printOpenGLError(); - [self setFilterModeForTexture:_overlayTexture]; - - glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); - - [self clearColorBuffer]; - -// if (_keyboardView != nil) { -// [_keyboardView removeFromSuperview]; -// [[_keyboardView inputView] removeFromSuperview]; -// } - - GLfloat adjustedWidth = _videoContext.screenWidth; - GLfloat adjustedHeight = _videoContext.screenHeight; - if (_videoContext.asprectRatioCorrection) { - if (_videoContext.screenWidth == 320 && _videoContext.screenHeight == 200) - adjustedHeight = 240; - else if (_videoContext.screenWidth == 640 && _videoContext.screenHeight == 400) - adjustedHeight = 480; - } - - float overlayPortraitRatio; - - if (isLandscape) { - GLfloat gameScreenRatio = adjustedWidth / adjustedHeight; - GLfloat screenRatio = (GLfloat)screenWidth / (GLfloat)screenHeight; - - // These are the width/height according to the portrait layout! - int rectWidth, rectHeight; - int xOffset, yOffset; - - if (gameScreenRatio < screenRatio) { - // When the game screen ratio is less than the screen ratio - // we need to scale the width, since the game screen was higher - // compared to the width than our output screen is. - rectWidth = (int)(screenHeight * gameScreenRatio); - rectHeight = screenHeight; - xOffset = (screenWidth - rectWidth) / 2; - yOffset = 0; - } else { - // When the game screen ratio is bigger than the screen ratio - // we need to scale the height, since the game screen was wider - // compared to the height than our output screen is. - rectWidth = screenWidth; - rectHeight = (int)(screenWidth / gameScreenRatio); - xOffset = 0; - yOffset = (screenHeight - rectHeight) / 2; - } - - [_keyboardView hideKeyboard]; - - //printf("Rect: %i, %i, %i, %i\n", xOffset, yOffset, rectWidth, rectHeight); - _gameScreenRect = CGRectMake(xOffset, yOffset, rectWidth, rectHeight); - overlayPortraitRatio = 1.0f; - } else { - GLfloat ratio = adjustedHeight / adjustedWidth; - int height = (int)(screenWidth * ratio); - //printf("Making rect (%u, %u)\n", screenWidth, height); - _gameScreenRect = CGRectMake(0, 0, screenWidth, height); - - CGRect keyFrame = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f); - if (_keyboardView == nil) { - _keyboardView = [[SoftKeyboard alloc] initWithFrame:keyFrame]; - [_keyboardView setInputDelegate:self]; - [self addSubview:[_keyboardView inputView]]; - [self addSubview: _keyboardView]; - } - - [_keyboardView showKeyboard]; - overlayPortraitRatio = (_videoContext.overlayHeight * ratio) / _videoContext.overlayWidth; - } - _overlayRect = CGRectMake(0, 0, screenWidth, screenHeight * overlayPortraitRatio); - - _gameScreenVertCoords[0] = _gameScreenVertCoords[4] = CGRectGetMinX(_gameScreenRect); - _gameScreenVertCoords[1] = _gameScreenVertCoords[3] = CGRectGetMinY(_gameScreenRect); - _gameScreenVertCoords[2] = _gameScreenVertCoords[6] = CGRectGetMaxX(_gameScreenRect); - _gameScreenVertCoords[5] = _gameScreenVertCoords[7] = CGRectGetMaxY(_gameScreenRect); - - _overlayVertCoords[2] = _overlayVertCoords[6] = CGRectGetMaxX(_overlayRect); - _overlayVertCoords[5] = _overlayVertCoords[7] = CGRectGetMaxY(_overlayRect); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrthof(0, screenWidth, screenHeight, 0, 0, 1); - - [self setViewTransformation]; - [self updateMouseCursorScaling]; -} - -- (void)setViewTransformation { - // Set the modelview matrix. This matrix will be used for the shake offset - // support. - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - // Scale the shake offset according to the overlay size. We need this to - // adjust the overlay mouse click coordinates when an offset is set. - _scaledShakeOffsetY = (int)(_videoContext.shakeOffsetY / (GLfloat)_videoContext.screenHeight * CGRectGetHeight(_overlayRect)); - - // Apply the shakeing to the output screen. - glTranslatef(0, -_scaledShakeOffsetY, 0); -} - -- (void)clearColorBuffer { - // The color buffer is triple-buffered, so we clear it multiple times right away to avid doing any glClears later. - int clearCount = 5; - while (clearCount-- > 0) { - glClear(GL_COLOR_BUFFER_BIT); printOpenGLError(); - [_context presentRenderbuffer:GL_RENDERBUFFER_OES]; - } -} - -- (void)addEvent:(InternalEvent)event { - [_eventLock lock]; - _events.push_back(event); - [_eventLock unlock]; -} - -- (bool)fetchEvent:(InternalEvent *)event { - [_eventLock lock]; - if (_events.empty()) { - [_eventLock unlock]; - return false; - } - - *event = *_events.begin(); - _events.pop_front(); - [_eventLock unlock]; - return true; -} - -- (bool)getMouseCoords:(CGPoint)point eventX:(int *)x eventY:(int *)y { - // We scale the input according to our scale factor to get actual screen - // cooridnates. - point.x *= _contentScaleFactor; - point.y *= _contentScaleFactor; - - CGRect *area; - int width, height, offsetY; - if (_videoContext.overlayVisible) { - area = &_overlayRect; - width = _videoContext.overlayWidth; - height = _videoContext.overlayHeight; - offsetY = _scaledShakeOffsetY; - } else { - area = &_gameScreenRect; - width = _videoContext.screenWidth; - height = _videoContext.screenHeight; - offsetY = _videoContext.shakeOffsetY; - } - - point.x = (point.x - CGRectGetMinX(*area)) / CGRectGetWidth(*area); - point.y = (point.y - CGRectGetMinY(*area)) / CGRectGetHeight(*area); - - *x = (int)(point.x * width); - // offsetY describes the translation of the screen in the upward direction, - // thus we need to add it here. - *y = (int)(point.y * height + offsetY); - - if (!iphone_touchpadModeEnabled()) { - // Clip coordinates - if (*x < 0 || *x > width || *y < 0 || *y > height) - return false; - } - - return true; -} - -- (void)deviceOrientationChanged:(UIDeviceOrientation)orientation { - [self addEvent:InternalEvent(kInputOrientationChanged, orientation, 0)]; -} - -- (UITouch *)secondTouchOtherTouchThan:(UITouch *)touch in:(NSSet *)set { - NSArray *all = [set allObjects]; - for (UITouch *t in all) { - if (t != touch) { - return t; - } - } - return nil; -} - -- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - int x, y; - - NSSet *allTouches = [event allTouches]; - if (allTouches.count == 1) { - _firstTouch = [allTouches anyObject]; - CGPoint point = [_firstTouch locationInView:self]; - if (![self getMouseCoords:point eventX:&x eventY:&y]) - return; - - [self addEvent:InternalEvent(kInputMouseDown, x, y)]; - } - else if (allTouches.count == 2) { - _secondTouch = [self secondTouchOtherTouchThan:_firstTouch in:allTouches]; - if (_secondTouch) { - CGPoint point = [_secondTouch locationInView:self]; - if (![self getMouseCoords:point eventX:&x eventY:&y]) - return; - - [self addEvent:InternalEvent(kInputMouseSecondDown, x, y)]; - } - } -} - -- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - int x, y; - - NSSet *allTouches = [event allTouches]; - for (UITouch *touch in allTouches) { - if (touch == _firstTouch) { - CGPoint point = [touch locationInView:self]; - if (![self getMouseCoords:point eventX:&x eventY:&y]) - return; - - [self addEvent:InternalEvent(kInputMouseDragged, x, y)]; - } else if (touch == _secondTouch) { - CGPoint point = [touch locationInView:self]; - if (![self getMouseCoords:point eventX:&x eventY:&y]) - return; - - [self addEvent:InternalEvent(kInputMouseSecondDragged, x, y)]; - } - } -} - -- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - int x, y; - - NSSet *allTouches = [event allTouches]; - if (allTouches.count == 1) { - UITouch *touch = [allTouches anyObject]; - CGPoint point = [touch locationInView:self]; - if (![self getMouseCoords:point eventX:&x eventY:&y]) { - return; - } - - [self addEvent:InternalEvent(kInputMouseUp, x, y)]; - } - else if (allTouches.count == 2) { - UITouch *touch = [[allTouches allObjects] objectAtIndex:1]; - CGPoint point = [touch locationInView:self]; - if (![self getMouseCoords:point eventX:&x eventY:&y]) - return; - - [self addEvent:InternalEvent(kInputMouseSecondUp, x, y)]; - } - _firstTouch = nil; - _secondTouch = nil; -} - -- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { - _firstTouch = nil; - _secondTouch = nil; -} - -- (void)twoFingersSwipeRight:(UISwipeGestureRecognizer *)recognizer { - [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeRight, 2)]; -} - -- (void)twoFingersSwipeLeft:(UISwipeGestureRecognizer *)recognizer { - [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeLeft, 2)]; -} - -- (void)twoFingersSwipeUp:(UISwipeGestureRecognizer *)recognizer { - [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeUp, 2)]; -} - -- (void)twoFingersSwipeDown:(UISwipeGestureRecognizer *)recognizer { - [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeDown, 2)]; -} - -- (void)twoFingersDoubleTap:(UITapGestureRecognizer *)recognizer { - [self addEvent:InternalEvent(kInputTap, kUIViewTapDouble, 2)]; -} - -- (void)handleKeyPress:(unichar)c { - [self addEvent:InternalEvent(kInputKeyPressed, c, 0)]; -} - -- (void)applicationSuspend { - [self addEvent:InternalEvent(kInputApplicationSuspended, 0, 0)]; -} - -- (void)applicationResume { - [self addEvent:InternalEvent(kInputApplicationResumed, 0, 0)]; -} - -@end diff --git a/backends/platform/ios7/module.mk b/backends/platform/ios7/module.mk index 87721cc9e5..fad69d715e 100644 --- a/backends/platform/ios7/module.mk +++ b/backends/platform/ios7/module.mk @@ -1,13 +1,15 @@ MODULE := backends/platform/ios7 MODULE_OBJS := \ - osys_main.o \ - osys_events.o \ - osys_sound.o \ - osys_video.o \ - iphone_main.o \ - iphone_video.o \ - iphone_keyboard.o + ios7_osys_main.o \ + ios7_osys_events.o \ + ios7_osys_sound.o \ + ios7_osys_video.o \ + ios7_main.o \ + ios7_video.o \ + ios7_keyboard.o \ + iOS7ScummVMViewController.o \ + iOS7MainApplication.o # We don't use rules.mk but rather manually update OBJS and MODULE_DIRS. MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) diff --git a/backends/platform/ios7/osys_events.cpp b/backends/platform/ios7/osys_events.cpp deleted file mode 100644 index 19da580c80..0000000000 --- a/backends/platform/ios7/osys_events.cpp +++ /dev/null @@ -1,562 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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. - * - */ - -// Disable symbol overrides so that we can use system headers. -#define FORBIDDEN_SYMBOL_ALLOW_ALL - -#include "gui/message.h" -#include "common/translation.h" - -#include "osys_main.h" - -static const int kQueuedInputEventDelay = 50; - -bool OSystem_IPHONE::pollEvent(Common::Event &event) { - //printf("pollEvent()\n"); - - long curTime = getMillis(); - - if (_timerCallback && (curTime >= _timerCallbackNext)) { - _timerCallback(_timerCallbackTimer); - _timerCallbackNext = curTime + _timerCallbackTimer; - } - - if (_queuedInputEvent.type != Common::EVENT_INVALID && curTime >= _queuedEventTime) { - event = _queuedInputEvent; - _queuedInputEvent.type = Common::EVENT_INVALID; - return true; - } - - InternalEvent internalEvent; - - if (iPhone_fetchEvent(&internalEvent)) { - switch (internalEvent.type) { - case kInputMouseDown: - if (!handleEvent_mouseDown(event, internalEvent.value1, internalEvent.value2)) - return false; - break; - - case kInputMouseUp: - if (!handleEvent_mouseUp(event, internalEvent.value1, internalEvent.value2)) - return false; - break; - - case kInputMouseDragged: - if (!handleEvent_mouseDragged(event, internalEvent.value1, internalEvent.value2)) - return false; - break; - - case kInputOrientationChanged: - handleEvent_orientationChanged(internalEvent.value1); - return false; - break; - - case kInputApplicationSuspended: - suspendLoop(); - return false; - break; - - case kInputMouseSecondDragged: - if (!handleEvent_mouseSecondDragged(event, internalEvent.value1, internalEvent.value2)) - return false; - break; - case kInputMouseSecondDown: - _secondaryTapped = true; - if (!handleEvent_secondMouseDown(event, internalEvent.value1, internalEvent.value2)) - return false; - break; - case kInputMouseSecondUp: - _secondaryTapped = false; - if (!handleEvent_secondMouseUp(event, internalEvent.value1, internalEvent.value2)) - return false; - break; - - case kInputKeyPressed: - handleEvent_keyPressed(event, internalEvent.value1); - break; - - case kInputSwipe: - if (!handleEvent_swipe(event, internalEvent.value1, internalEvent.value2)) - return false; - break; - - case kInputTap: - if (!handleEvent_tap(event, (UIViewTapDescription) internalEvent.value1, internalEvent.value2)) - return false; - break; - - default: - break; - } - - return true; - } - return false; -} - -bool OSystem_IPHONE::handleEvent_mouseDown(Common::Event &event, int x, int y) { - //printf("Mouse down at (%u, %u)\n", x, y); - - // Workaround: kInputMouseSecondToggled isn't always sent when the - // secondary finger is lifted. Need to make sure we get out of that mode. - _secondaryTapped = false; - - if (_touchpadModeEnabled) { - _lastPadX = x; - _lastPadY = y; - } else - warpMouse(x, y); - - if (_mouseClickAndDragEnabled) { - event.type = Common::EVENT_LBUTTONDOWN; - event.mouse.x = _videoContext->mouseX; - event.mouse.y = _videoContext->mouseY; - return true; - } else { - _lastMouseDown = getMillis(); - } - return false; -} - -bool OSystem_IPHONE::handleEvent_mouseUp(Common::Event &event, int x, int y) { - //printf("Mouse up at (%u, %u)\n", x, y); - - if (_secondaryTapped) { - _secondaryTapped = false; - if (!handleEvent_secondMouseUp(event, x, y)) - return false; - } else if (_mouseClickAndDragEnabled) { - event.type = Common::EVENT_LBUTTONUP; - event.mouse.x = _videoContext->mouseX; - event.mouse.y = _videoContext->mouseY; - } else { - if (getMillis() - _lastMouseDown < 250) { - event.type = Common::EVENT_LBUTTONDOWN; - event.mouse.x = _videoContext->mouseX; - event.mouse.y = _videoContext->mouseY; - - _queuedInputEvent.type = Common::EVENT_LBUTTONUP; - _queuedInputEvent.mouse.x = _videoContext->mouseX; - _queuedInputEvent.mouse.y = _videoContext->mouseY; - _lastMouseTap = getMillis(); - _queuedEventTime = _lastMouseTap + kQueuedInputEventDelay; - } else - return false; - } - - return true; -} - -bool OSystem_IPHONE::handleEvent_secondMouseDown(Common::Event &event, int x, int y) { - _lastSecondaryDown = getMillis(); - _gestureStartX = x; - _gestureStartY = y; - - if (_mouseClickAndDragEnabled) { - event.type = Common::EVENT_LBUTTONUP; - event.mouse.x = _videoContext->mouseX; - event.mouse.y = _videoContext->mouseY; - - _queuedInputEvent.type = Common::EVENT_RBUTTONDOWN; - _queuedInputEvent.mouse.x = _videoContext->mouseX; - _queuedInputEvent.mouse.y = _videoContext->mouseY; - } else - return false; - - return true; -} - -bool OSystem_IPHONE::handleEvent_secondMouseUp(Common::Event &event, int x, int y) { - int curTime = getMillis(); - - if (curTime - _lastSecondaryDown < 400) { - //printf("Right tap!\n"); - if (curTime - _lastSecondaryTap < 400 && !_videoContext->overlayVisible) { - //printf("Right escape!\n"); - event.type = Common::EVENT_KEYDOWN; - _queuedInputEvent.type = Common::EVENT_KEYUP; - - event.kbd.flags = _queuedInputEvent.kbd.flags = 0; - event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE; - event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE; - _queuedEventTime = curTime + kQueuedInputEventDelay; - _lastSecondaryTap = 0; - } else if (!_mouseClickAndDragEnabled) { - //printf("Rightclick!\n"); - event.type = Common::EVENT_RBUTTONDOWN; - event.mouse.x = _videoContext->mouseX; - event.mouse.y = _videoContext->mouseY; - _queuedInputEvent.type = Common::EVENT_RBUTTONUP; - _queuedInputEvent.mouse.x = _videoContext->mouseX; - _queuedInputEvent.mouse.y = _videoContext->mouseY; - _lastSecondaryTap = curTime; - _queuedEventTime = curTime + kQueuedInputEventDelay; - } else { - //printf("Right nothing!\n"); - return false; - } - } - if (_mouseClickAndDragEnabled) { - event.type = Common::EVENT_RBUTTONUP; - event.mouse.x = _videoContext->mouseX; - event.mouse.y = _videoContext->mouseY; - } - - return true; -} - -bool OSystem_IPHONE::handleEvent_mouseDragged(Common::Event &event, int x, int y) { - if (_lastDragPosX == x && _lastDragPosY == y) - return false; - - _lastDragPosX = x; - _lastDragPosY = y; - - //printf("Mouse dragged at (%u, %u)\n", x, y); - int mouseNewPosX; - int mouseNewPosY; - if (_touchpadModeEnabled) { - int deltaX = _lastPadX - x; - int deltaY = _lastPadY - y; - _lastPadX = x; - _lastPadY = y; - - mouseNewPosX = (int)(_videoContext->mouseX - deltaX / 0.5f); - mouseNewPosY = (int)(_videoContext->mouseY - deltaY / 0.5f); - - int widthCap = _videoContext->overlayVisible ? _videoContext->overlayWidth : _videoContext->screenWidth; - int heightCap = _videoContext->overlayVisible ? _videoContext->overlayHeight : _videoContext->screenHeight; - - if (mouseNewPosX < 0) - mouseNewPosX = 0; - else if (mouseNewPosX > widthCap) - mouseNewPosX = widthCap; - - if (mouseNewPosY < 0) - mouseNewPosY = 0; - else if (mouseNewPosY > heightCap) - mouseNewPosY = heightCap; - - } else { - mouseNewPosX = x; - mouseNewPosY = y; - } - - event.type = Common::EVENT_MOUSEMOVE; - event.mouse.x = mouseNewPosX; - event.mouse.y = mouseNewPosY; - warpMouse(mouseNewPosX, mouseNewPosY); - - return true; -} - -bool OSystem_IPHONE::handleEvent_mouseSecondDragged(Common::Event &event, int x, int y) { - if (_gestureStartX == -1 || _gestureStartY == -1) { - return false; - } - - static const int kNeededLength = 100; - static const int kMaxDeviation = 20; - - int vecX = (x - _gestureStartX); - int vecY = (y - _gestureStartY); - - int absX = abs(vecX); - int absY = abs(vecY); - - //printf("(%d, %d)\n", vecX, vecY); - - if (absX >= kNeededLength || absY >= kNeededLength) { // Long enough gesture to react upon. - _gestureStartX = -1; - _gestureStartY = -1; - - if (absX < kMaxDeviation && vecY >= kNeededLength) { - // Swipe down - event.type = Common::EVENT_MAINMENU; - _queuedInputEvent.type = Common::EVENT_INVALID; - - _queuedEventTime = getMillis() + kQueuedInputEventDelay; - return true; - } - - if (absX < kMaxDeviation && -vecY >= kNeededLength) { - // Swipe up - _mouseClickAndDragEnabled = !_mouseClickAndDragEnabled; - const char *dialogMsg; - if (_mouseClickAndDragEnabled) { - _touchpadModeEnabled = false; - dialogMsg = _("Mouse-click-and-drag mode enabled."); - } else - dialogMsg = _("Mouse-click-and-drag mode disabled."); - GUI::TimedMessageDialog dialog(dialogMsg, 1500); - dialog.runModal(); - return false; - } - - if (absY < kMaxDeviation && vecX >= kNeededLength) { - // Swipe right - _touchpadModeEnabled = !_touchpadModeEnabled; - const char *dialogMsg; - if (_touchpadModeEnabled) - dialogMsg = _("Touchpad mode enabled."); - else - dialogMsg = _("Touchpad mode disabled."); - GUI::TimedMessageDialog dialog(dialogMsg, 1500); - dialog.runModal(); - return false; - - } - - if (absY < kMaxDeviation && -vecX >= kNeededLength) { - // Swipe left - return false; - } - } - - return false; -} - -void OSystem_IPHONE::handleEvent_orientationChanged(int orientation) { - //printf("Orientation: %i\n", orientation); - - ScreenOrientation newOrientation; - switch (orientation) { - case 1: - newOrientation = kScreenOrientationPortrait; - break; - case 3: - newOrientation = kScreenOrientationLandscape; - break; - case 4: - newOrientation = kScreenOrientationFlippedLandscape; - break; - default: - return; - } - - - if (_screenOrientation != newOrientation) { - _screenOrientation = newOrientation; - updateOutputSurface(); - - dirtyFullScreen(); - if (_videoContext->overlayVisible) - dirtyFullOverlayScreen(); - updateScreen(); - } -} - -void OSystem_IPHONE::handleEvent_keyPressed(Common::Event &event, int keyPressed) { - int ascii = keyPressed; - //printf("key: %i\n", keyPressed); - - // We remap some of the iPhone keyboard keys. - // The first ten here are the row of symbols below the numeric keys. - switch (keyPressed) { - case 45: - keyPressed = Common::KEYCODE_F1; - ascii = Common::ASCII_F1; - break; - case 47: - keyPressed = Common::KEYCODE_F2; - ascii = Common::ASCII_F2; - break; - case 58: - keyPressed = Common::KEYCODE_F3; - ascii = Common::ASCII_F3; - break; - case 59: - keyPressed = Common::KEYCODE_F4; - ascii = Common::ASCII_F4; - break; - case 40: - keyPressed = Common::KEYCODE_F5; - ascii = Common::ASCII_F5; - break; - case 41: - keyPressed = Common::KEYCODE_F6; - ascii = Common::ASCII_F6; - break; - case 36: - keyPressed = Common::KEYCODE_F7; - ascii = Common::ASCII_F7; - break; - case 38: - keyPressed = Common::KEYCODE_F8; - ascii = Common::ASCII_F8; - break; - case 64: - keyPressed = Common::KEYCODE_F9; - ascii = Common::ASCII_F9; - break; - case 34: - keyPressed = Common::KEYCODE_F10; - ascii = Common::ASCII_F10; - break; - case 10: - keyPressed = Common::KEYCODE_RETURN; - ascii = Common::ASCII_RETURN; - break; - } - event.type = Common::EVENT_KEYDOWN; - _queuedInputEvent.type = Common::EVENT_KEYUP; - - event.kbd.flags = _queuedInputEvent.kbd.flags = 0; - event.kbd.keycode = _queuedInputEvent.kbd.keycode = (Common::KeyCode)keyPressed; - event.kbd.ascii = _queuedInputEvent.kbd.ascii = ascii; - _queuedEventTime = getMillis() + kQueuedInputEventDelay; -} - -bool OSystem_IPHONE::handleEvent_swipe(Common::Event &event, int direction, int touches) { - if (touches == 1) { - Common::KeyCode keycode = Common::KEYCODE_INVALID; - switch (_screenOrientation) { - case kScreenOrientationPortrait: - switch ((UIViewSwipeDirection)direction) { - case kUIViewSwipeUp: - keycode = Common::KEYCODE_UP; - break; - case kUIViewSwipeDown: - keycode = Common::KEYCODE_DOWN; - break; - case kUIViewSwipeLeft: - keycode = Common::KEYCODE_LEFT; - break; - case kUIViewSwipeRight: - keycode = Common::KEYCODE_RIGHT; - break; - default: - return false; - } - break; - case kScreenOrientationLandscape: - switch ((UIViewSwipeDirection)direction) { - case kUIViewSwipeUp: - keycode = Common::KEYCODE_LEFT; - break; - case kUIViewSwipeDown: - keycode = Common::KEYCODE_RIGHT; - break; - case kUIViewSwipeLeft: - keycode = Common::KEYCODE_DOWN; - break; - case kUIViewSwipeRight: - keycode = Common::KEYCODE_UP; - break; - default: - return false; - } - break; - case kScreenOrientationFlippedLandscape: - switch ((UIViewSwipeDirection)direction) { - case kUIViewSwipeUp: - keycode = Common::KEYCODE_RIGHT; - break; - case kUIViewSwipeDown: - keycode = Common::KEYCODE_LEFT; - break; - case kUIViewSwipeLeft: - keycode = Common::KEYCODE_UP; - break; - case kUIViewSwipeRight: - keycode = Common::KEYCODE_DOWN; - break; - default: - return false; - } - break; - } - - event.kbd.keycode = _queuedInputEvent.kbd.keycode = keycode; - event.kbd.ascii = _queuedInputEvent.kbd.ascii = 0; - event.type = Common::EVENT_KEYDOWN; - _queuedInputEvent.type = Common::EVENT_KEYUP; - event.kbd.flags = _queuedInputEvent.kbd.flags = 0; - _queuedEventTime = getMillis() + kQueuedInputEventDelay; - - return true; - } - else if (touches == 2) { - switch ((UIViewSwipeDirection)direction) { - case kUIViewSwipeUp: { - _mouseClickAndDragEnabled = !_mouseClickAndDragEnabled; - const char *dialogMsg; - if (_mouseClickAndDragEnabled) { - _touchpadModeEnabled = false; - dialogMsg = _("Mouse-click-and-drag mode enabled."); - } else - dialogMsg = _("Mouse-click-and-drag mode disabled."); - GUI::TimedMessageDialog dialog(dialogMsg, 1500); - dialog.runModal(); - return false; - } - - case kUIViewSwipeDown: { - // Swipe down - event.type = Common::EVENT_MAINMENU; - _queuedInputEvent.type = Common::EVENT_INVALID; - _queuedEventTime = getMillis() + kQueuedInputEventDelay; - return true; - } - - case kUIViewSwipeRight: { - // Swipe right - _touchpadModeEnabled = !_touchpadModeEnabled; - const char *dialogMsg; - if (_touchpadModeEnabled) - dialogMsg = _("Touchpad mode enabled."); - else - dialogMsg = _("Touchpad mode disabled."); - GUI::TimedMessageDialog dialog(dialogMsg, 1500); - dialog.runModal(); - return false; - } - - default: - break; - } - } - return false; -} - -bool OSystem_IPHONE::handleEvent_tap(Common::Event &event, UIViewTapDescription type, int touches) { - if (touches == 1) { - if (type == kUIViewTapDouble) { - event.type = Common::EVENT_RBUTTONDOWN; - _queuedInputEvent.type = Common::EVENT_RBUTTONUP; - _queuedEventTime = getMillis() + kQueuedInputEventDelay; - return true; - } - } - else if (touches == 2) { - if (type == kUIViewTapDouble) { - event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE; - event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE; - event.type = Common::EVENT_KEYDOWN; - _queuedInputEvent.type = Common::EVENT_KEYUP; - event.kbd.flags = _queuedInputEvent.kbd.flags = 0; - _queuedEventTime = getMillis() + kQueuedInputEventDelay; - return true; - } - } - return false; -} diff --git a/backends/platform/ios7/osys_main.cpp b/backends/platform/ios7/osys_main.cpp deleted file mode 100644 index ef3499d597..0000000000 --- a/backends/platform/ios7/osys_main.cpp +++ /dev/null @@ -1,344 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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. - * - */ - -// Disable symbol overrides so that we can use system headers. -#define FORBIDDEN_SYMBOL_ALLOW_ALL - -#include -#include - -#include - -#include "common/scummsys.h" -#include "common/util.h" -#include "common/rect.h" -#include "common/file.h" -#include "common/fs.h" - -#include "base/main.h" - -#include "backends/saves/default/default-saves.h" -#include "backends/timer/default/default-timer.h" -#include "backends/fs/chroot/chroot-fs-factory.h" -#include "backends/fs/posix/posix-fs.h" -#include "audio/mixer.h" -#include "audio/mixer_intern.h" - -#include "osys_main.h" - - -const OSystem::GraphicsMode OSystem_IPHONE::s_supportedGraphicsModes[] = { - { "linear", "Linear filtering", kGraphicsModeLinear }, - { "none", "No filtering", kGraphicsModeNone }, - { 0, 0, 0 } -}; - -AQCallbackStruct OSystem_IPHONE::s_AudioQueue; -SoundProc OSystem_IPHONE::s_soundCallback = NULL; -void *OSystem_IPHONE::s_soundParam = NULL; - -OSystem_IPHONE::OSystem_IPHONE() : - _mixer(NULL), _lastMouseTap(0), _queuedEventTime(0), - _mouseNeedTextureUpdate(false), _secondaryTapped(false), _lastSecondaryTap(0), - _screenOrientation(kScreenOrientationFlippedLandscape), _mouseClickAndDragEnabled(false), - _gestureStartX(-1), _gestureStartY(-1), _fullScreenIsDirty(false), _fullScreenOverlayIsDirty(false), - _mouseDirty(false), _timeSuspended(0), _lastDragPosX(-1), _lastDragPosY(-1), _screenChangeCount(0), - _mouseCursorPaletteEnabled(false), _gfxTransactionError(kTransactionSuccess) { - _queuedInputEvent.type = Common::EVENT_INVALID; - _touchpadModeEnabled = !iPhone_isHighResDevice(); -#ifdef IPHONE_OFFICIAL - _fsFactory = new ChRootFilesystemFactory(iPhone_getDocumentsDir()); -#else - _fsFactory = new POSIXFilesystemFactory(); -#endif - initVideoContext(); - - memset(_gamePalette, 0, sizeof(_gamePalette)); - memset(_gamePaletteRGBA5551, 0, sizeof(_gamePaletteRGBA5551)); - memset(_mouseCursorPalette, 0, sizeof(_mouseCursorPalette)); -} - -OSystem_IPHONE::~OSystem_IPHONE() { - AudioQueueDispose(s_AudioQueue.queue, true); - - delete _mixer; - // Prevent accidental freeing of the screen texture here. This needs to be - // checked since we might use the screen texture as framebuffer in the case - // of hi-color games for example. Otherwise this can lead to a double free. - if (_framebuffer.getPixels() != _videoContext->screenTexture.getPixels()) - _framebuffer.free(); - _mouseBuffer.free(); -} - -bool OSystem_IPHONE::touchpadModeEnabled() const { - return _touchpadModeEnabled; -} - -int OSystem_IPHONE::timerHandler(int t) { - DefaultTimerManager *tm = (DefaultTimerManager *)g_system->getTimerManager(); - tm->handler(); - return t; -} - -void OSystem_IPHONE::initBackend() { -#ifdef IPHONE_OFFICIAL - _savefileManager = new DefaultSaveFileManager("/Savegames"); -#else - _savefileManager = new DefaultSaveFileManager(SCUMMVM_SAVE_PATH); -#endif - - _timerManager = new DefaultTimerManager(); - - gettimeofday(&_startTime, NULL); - - setupMixer(); - - setTimerCallback(&OSystem_IPHONE::timerHandler, 10); - - EventsBaseBackend::initBackend(); -} - -bool OSystem_IPHONE::hasFeature(Feature f) { - switch (f) { - case kFeatureCursorPalette: - return true; - - default: - return false; - } -} - -void OSystem_IPHONE::setFeatureState(Feature f, bool enable) { - switch (f) { - case kFeatureCursorPalette: - if (_mouseCursorPaletteEnabled != enable) { - _mouseNeedTextureUpdate = true; - _mouseDirty = true; - _mouseCursorPaletteEnabled = enable; - } - break; - case kFeatureAspectRatioCorrection: - _videoContext->asprectRatioCorrection = enable; - break; - - default: - break; - } -} - -bool OSystem_IPHONE::getFeatureState(Feature f) { - switch (f) { - case kFeatureCursorPalette: - return _mouseCursorPaletteEnabled; - case kFeatureAspectRatioCorrection: - return _videoContext->asprectRatioCorrection; - - default: - return false; - } -} - -void OSystem_IPHONE::suspendLoop() { - bool done = false; - uint32 startTime = getMillis(); - - stopSoundsystem(); - - InternalEvent event; - while (!done) { - if (iPhone_fetchEvent(&event)) - if (event.type == kInputApplicationResumed) - done = true; - usleep(100000); - } - - startSoundsystem(); - - _timeSuspended += getMillis() - startTime; -} - -uint32 OSystem_IPHONE::getMillis(bool skipRecord) { - //printf("getMillis()\n"); - - struct timeval currentTime; - gettimeofday(¤tTime, NULL); - return (uint32)(((currentTime.tv_sec - _startTime.tv_sec) * 1000) + - ((currentTime.tv_usec - _startTime.tv_usec) / 1000)) - _timeSuspended; -} - -void OSystem_IPHONE::delayMillis(uint msecs) { - //printf("delayMillis(%d)\n", msecs); - usleep(msecs * 1000); -} - -OSystem::MutexRef OSystem_IPHONE::createMutex(void) { - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - - pthread_mutex_t *mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t)); - if (pthread_mutex_init(mutex, &attr) != 0) { - printf("pthread_mutex_init() failed!\n"); - free(mutex); - return NULL; - } - - return (MutexRef)mutex; -} - -void OSystem_IPHONE::lockMutex(MutexRef mutex) { - if (pthread_mutex_lock((pthread_mutex_t *) mutex) != 0) { - printf("pthread_mutex_lock() failed!\n"); - } -} - -void OSystem_IPHONE::unlockMutex(MutexRef mutex) { - if (pthread_mutex_unlock((pthread_mutex_t *) mutex) != 0) { - printf("pthread_mutex_unlock() failed!\n"); - } -} - -void OSystem_IPHONE::deleteMutex(MutexRef mutex) { - if (pthread_mutex_destroy((pthread_mutex_t *) mutex) != 0) { - printf("pthread_mutex_destroy() failed!\n"); - } else { - free(mutex); - } -} - - -void OSystem_IPHONE::setTimerCallback(TimerProc callback, int interval) { - //printf("setTimerCallback()\n"); - - if (callback != NULL) { - _timerCallbackTimer = interval; - _timerCallbackNext = getMillis() + interval; - _timerCallback = callback; - } else - _timerCallback = NULL; -} - -void OSystem_IPHONE::quit() { -} - -void OSystem_IPHONE::getTimeAndDate(TimeDate &td) const { - time_t curTime = time(0); - struct tm t = *localtime(&curTime); - td.tm_sec = t.tm_sec; - td.tm_min = t.tm_min; - td.tm_hour = t.tm_hour; - td.tm_mday = t.tm_mday; - td.tm_mon = t.tm_mon; - td.tm_year = t.tm_year; - td.tm_wday = t.tm_wday; -} - -Audio::Mixer *OSystem_IPHONE::getMixer() { - assert(_mixer); - return _mixer; -} - -OSystem *OSystem_IPHONE_create() { - return new OSystem_IPHONE(); -} - -Common::String OSystem_IPHONE::getDefaultConfigFileName() { -#ifdef IPHONE_OFFICIAL - Common::String path = "/Preferences"; - return path; -#else - return SCUMMVM_PREFS_PATH; -#endif -} - -void OSystem_IPHONE::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { - // Get URL of the Resource directory of the .app bundle - CFURLRef fileUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); - if (fileUrl) { - // Try to convert the URL to an absolute path - UInt8 buf[MAXPATHLEN]; - if (CFURLGetFileSystemRepresentation(fileUrl, true, buf, sizeof(buf))) { - // Success: Add it to the search path - Common::String bundlePath((const char *)buf); -#ifdef IPHONE_OFFICIAL - POSIXFilesystemNode *posixNode = new POSIXFilesystemNode(bundlePath); - Common::FSNode *node = new Common::FSNode(posixNode); - s.add("__OSX_BUNDLE__", new Common::FSDirectory(*node), priority); -#else - // OS X - s.add("__OSX_BUNDLE__", new Common::FSDirectory(bundlePath), priority); -#endif - } - CFRelease(fileUrl); - } -} - -void OSystem_IPHONE::logMessage(LogMessageType::Type type, const char *message) { - FILE *output = 0; - - if (type == LogMessageType::kInfo || type == LogMessageType::kDebug) - output = stdout; - else - output = stderr; - - fputs(message, output); - fflush(output); -} - -bool iphone_touchpadModeEnabled() { - OSystem_IPHONE *sys = (OSystem_IPHONE *) g_system; - return sys && sys->touchpadModeEnabled(); -} - -void iphone_main(int argc, char *argv[]) { - - //OSystem_IPHONE::migrateApp(); - - FILE *newfp = fopen("/var/mobile/.scummvm.log", "a"); - if (newfp != NULL) { - fclose(stdout); - fclose(stderr); - *stdout = *newfp; - *stderr = *newfp; - setbuf(stdout, NULL); - setbuf(stderr, NULL); - - //extern int gDebugLevel; - //gDebugLevel = 10; - } - -#ifdef IPHONE_OFFICIAL - chdir(iPhone_getDocumentsDir()); -#else - system("mkdir " SCUMMVM_ROOT_PATH); - system("mkdir " SCUMMVM_SAVE_PATH); - - chdir("/var/mobile/"); -#endif - - g_system = OSystem_IPHONE_create(); - assert(g_system); - - // Invoke the actual ScummVM main entry point: - scummvm_main(argc, argv); - g_system->quit(); // TODO: Consider removing / replacing this! -} diff --git a/backends/platform/ios7/osys_main.h b/backends/platform/ios7/osys_main.h deleted file mode 100644 index 04a531613f..0000000000 --- a/backends/platform/ios7/osys_main.h +++ /dev/null @@ -1,224 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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. - * - */ - -#ifndef BACKENDS_PLATFORM_IPHONE_OSYS_MAIN_H -#define BACKENDS_PLATFORM_IPHONE_OSYS_MAIN_H - -#include "graphics/surface.h" -#include "iphone_common.h" -#include "backends/base-backend.h" -#include "common/events.h" -#include "audio/mixer_intern.h" -#include "backends/fs/posix/posix-fs-factory.h" -#include "graphics/colormasks.h" -#include "graphics/palette.h" - -#include - -#define AUDIO_BUFFERS 3 -#define WAVE_BUFFER_SIZE 2048 -#define AUDIO_SAMPLE_RATE 44100 - -#define SCUMMVM_ROOT_PATH "/var/mobile/Library/ScummVM" -#define SCUMMVM_SAVE_PATH SCUMMVM_ROOT_PATH "/Savegames" -#define SCUMMVM_PREFS_PATH SCUMMVM_ROOT_PATH "/Preferences" - -typedef void (*SoundProc)(void *param, byte *buf, int len); -typedef int (*TimerProc)(int interval); - -struct AQCallbackStruct { - AudioQueueRef queue; - uint32 frameCount; - AudioQueueBufferRef buffers[AUDIO_BUFFERS]; - AudioStreamBasicDescription dataFormat; -}; - -class OSystem_IPHONE : public EventsBaseBackend, public PaletteManager { -protected: - static const OSystem::GraphicsMode s_supportedGraphicsModes[]; - static AQCallbackStruct s_AudioQueue; - static SoundProc s_soundCallback; - static void *s_soundParam; - - Audio::MixerImpl *_mixer; - - VideoContext *_videoContext; - - Graphics::Surface _framebuffer; - - // For signaling that screen format set up might have failed. - TransactionError _gfxTransactionError; - - // For use with the game texture - uint16 _gamePalette[256]; - // For use with the mouse texture - uint16 _gamePaletteRGBA5551[256]; - - struct timeval _startTime; - uint32 _timeSuspended; - - bool _mouseCursorPaletteEnabled; - uint16 _mouseCursorPalette[256]; - Graphics::Surface _mouseBuffer; - uint16 _mouseKeyColor; - bool _mouseDirty; - bool _mouseNeedTextureUpdate; - - long _lastMouseDown; - long _lastMouseTap; - long _queuedEventTime; - Common::Event _queuedInputEvent; - bool _secondaryTapped; - long _lastSecondaryDown; - long _lastSecondaryTap; - int _gestureStartX, _gestureStartY; - bool _mouseClickAndDragEnabled; - bool _touchpadModeEnabled; - int _lastPadX; - int _lastPadY; - int _lastDragPosX; - int _lastDragPosY; - - int _timerCallbackNext; - int _timerCallbackTimer; - TimerProc _timerCallback; - - Common::Array _dirtyRects; - Common::Array _dirtyOverlayRects; - ScreenOrientation _screenOrientation; - bool _fullScreenIsDirty; - bool _fullScreenOverlayIsDirty; - int _screenChangeCount; - -public: - - OSystem_IPHONE(); - virtual ~OSystem_IPHONE(); - - virtual void initBackend(); - - virtual bool hasFeature(Feature f); - virtual void setFeatureState(Feature f, bool enable); - virtual bool getFeatureState(Feature f); - virtual const GraphicsMode *getSupportedGraphicsModes() const; - virtual int getDefaultGraphicsMode() const; - virtual bool setGraphicsMode(int mode); - virtual int getGraphicsMode() const; - virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format); - - virtual void beginGFXTransaction(); - virtual TransactionError endGFXTransaction(); - - virtual int16 getHeight(); - virtual int16 getWidth(); - - bool touchpadModeEnabled() const; - -#ifdef USE_RGB_COLOR - virtual Graphics::PixelFormat getScreenFormat() const { return _framebuffer.format; } - virtual Common::List getSupportedFormats() const; -#endif - - virtual PaletteManager *getPaletteManager() { return this; } -protected: - // PaletteManager API - virtual void setPalette(const byte *colors, uint start, uint num); - virtual void grabPalette(byte *colors, uint start, uint num); - -public: - virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h); - virtual void updateScreen(); - virtual Graphics::Surface *lockScreen(); - virtual void unlockScreen(); - virtual void setShakePos(int shakeOffset); - - virtual void showOverlay(); - virtual void hideOverlay(); - virtual void clearOverlay(); - virtual void grabOverlay(void *buf, int pitch); - virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h); - virtual int16 getOverlayHeight(); - virtual int16 getOverlayWidth(); - virtual Graphics::PixelFormat getOverlayFormat() const { return Graphics::createPixelFormat<5551>(); } - - virtual bool showMouse(bool visible); - - virtual void warpMouse(int x, int y); - virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 255, bool dontScale = false, const Graphics::PixelFormat *format = NULL); - virtual void setCursorPalette(const byte *colors, uint start, uint num); - - virtual bool pollEvent(Common::Event &event); - virtual uint32 getMillis(bool skipRecord = false); - virtual void delayMillis(uint msecs); - - virtual MutexRef createMutex(void); - virtual void lockMutex(MutexRef mutex); - virtual void unlockMutex(MutexRef mutex); - virtual void deleteMutex(MutexRef mutex); - - static void mixCallback(void *sys, byte *samples, int len); - virtual void setupMixer(void); - virtual void setTimerCallback(TimerProc callback, int interval); - virtual int getScreenChangeID() const { return _screenChangeCount; } - virtual void quit(); - - virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); - virtual void getTimeAndDate(TimeDate &t) const; - - virtual Audio::Mixer *getMixer(); - - void startSoundsystem(); - void stopSoundsystem(); - - virtual Common::String getDefaultConfigFileName(); - - virtual void logMessage(LogMessageType::Type type, const char *message); - -protected: - void initVideoContext(); - void updateOutputSurface(); - - void internUpdateScreen(); - void dirtyFullScreen(); - void dirtyFullOverlayScreen(); - void suspendLoop(); - void drawDirtyRect(const Common::Rect &dirtyRect); - void updateMouseTexture(); - static void AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB); - static int timerHandler(int t); - - bool handleEvent_swipe(Common::Event &event, int direction, int touches); - bool handleEvent_tap(Common::Event &event, UIViewTapDescription type, int touches); - void handleEvent_keyPressed(Common::Event &event, int keyPressed); - void handleEvent_orientationChanged(int orientation); - - bool handleEvent_mouseDown(Common::Event &event, int x, int y); - bool handleEvent_mouseUp(Common::Event &event, int x, int y); - - bool handleEvent_secondMouseDown(Common::Event &event, int x, int y); - bool handleEvent_secondMouseUp(Common::Event &event, int x, int y); - - bool handleEvent_mouseDragged(Common::Event &event, int x, int y); - bool handleEvent_mouseSecondDragged(Common::Event &event, int x, int y); -}; - -#endif diff --git a/backends/platform/ios7/osys_sound.cpp b/backends/platform/ios7/osys_sound.cpp deleted file mode 100644 index bfee06c6f2..0000000000 --- a/backends/platform/ios7/osys_sound.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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. - * - */ - -// Disable symbol overrides so that we can use system headers. -#define FORBIDDEN_SYMBOL_ALLOW_ALL - -#include "osys_main.h" - -void OSystem_IPHONE::AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB) { - //printf("AQBufferCallback()\n"); - if (s_AudioQueue.frameCount > 0 && s_soundCallback != NULL) { - outQB->mAudioDataByteSize = 4 * s_AudioQueue.frameCount; - s_soundCallback(s_soundParam, (byte *)outQB->mAudioData, outQB->mAudioDataByteSize); - AudioQueueEnqueueBuffer(inQ, outQB, 0, NULL); - } else { - AudioQueueStop(s_AudioQueue.queue, false); - } -} - -void OSystem_IPHONE::mixCallback(void *sys, byte *samples, int len) { - OSystem_IPHONE *this_ = (OSystem_IPHONE *)sys; - assert(this_); - - if (this_->_mixer) { - this_->_mixer->mixCallback(samples, len); - } -} - -void OSystem_IPHONE::setupMixer() { - _mixer = new Audio::MixerImpl(this, AUDIO_SAMPLE_RATE); - - s_soundCallback = mixCallback; - s_soundParam = this; - - startSoundsystem(); -} - -void OSystem_IPHONE::startSoundsystem() { - s_AudioQueue.dataFormat.mSampleRate = AUDIO_SAMPLE_RATE; - s_AudioQueue.dataFormat.mFormatID = kAudioFormatLinearPCM; - s_AudioQueue.dataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; - s_AudioQueue.dataFormat.mBytesPerPacket = 4; - s_AudioQueue.dataFormat.mFramesPerPacket = 1; - s_AudioQueue.dataFormat.mBytesPerFrame = 4; - s_AudioQueue.dataFormat.mChannelsPerFrame = 2; - s_AudioQueue.dataFormat.mBitsPerChannel = 16; - s_AudioQueue.frameCount = WAVE_BUFFER_SIZE; - - if (AudioQueueNewOutput(&s_AudioQueue.dataFormat, AQBufferCallback, &s_AudioQueue, 0, kCFRunLoopCommonModes, 0, &s_AudioQueue.queue)) { - printf("Couldn't set the AudioQueue callback!\n"); - _mixer->setReady(false); - return; - } - - uint32 bufferBytes = s_AudioQueue.frameCount * s_AudioQueue.dataFormat.mBytesPerFrame; - - for (int i = 0; i < AUDIO_BUFFERS; i++) { - if (AudioQueueAllocateBuffer(s_AudioQueue.queue, bufferBytes, &s_AudioQueue.buffers[i])) { - printf("Error allocating AudioQueue buffer!\n"); - _mixer->setReady(false); - return; - } - - AQBufferCallback(&s_AudioQueue, s_AudioQueue.queue, s_AudioQueue.buffers[i]); - } - - AudioQueueSetParameter(s_AudioQueue.queue, kAudioQueueParam_Volume, 1.0); - if (AudioQueueStart(s_AudioQueue.queue, NULL)) { - printf("Error starting the AudioQueue!\n"); - _mixer->setReady(false); - return; - } - - _mixer->setReady(true); -} - -void OSystem_IPHONE::stopSoundsystem() { - AudioQueueStop(s_AudioQueue.queue, true); - - for (int i = 0; i < AUDIO_BUFFERS; i++) { - AudioQueueFreeBuffer(s_AudioQueue.queue, s_AudioQueue.buffers[i]); - } - - AudioQueueDispose(s_AudioQueue.queue, true); - _mixer->setReady(false); -} diff --git a/backends/platform/ios7/osys_video.mm b/backends/platform/ios7/osys_video.mm deleted file mode 100644 index c76f432dda..0000000000 --- a/backends/platform/ios7/osys_video.mm +++ /dev/null @@ -1,503 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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. - * - */ - -// Disable symbol overrides so that we can use system headers. -#define FORBIDDEN_SYMBOL_ALLOW_ALL - -#include "osys_main.h" -#include "iphone_video.h" - -#include "graphics/conversion.h" - -void OSystem_IPHONE::initVideoContext() { - _videoContext = [g_iPhoneViewInstance getVideoContext]; -} - -const OSystem::GraphicsMode *OSystem_IPHONE::getSupportedGraphicsModes() const { - return s_supportedGraphicsModes; -} - -int OSystem_IPHONE::getDefaultGraphicsMode() const { - return kGraphicsModeLinear; -} - -bool OSystem_IPHONE::setGraphicsMode(int mode) { - switch (mode) { - case kGraphicsModeNone: - case kGraphicsModeLinear: - _videoContext->graphicsMode = (GraphicsModes)mode; - return true; - - default: - return false; - } -} - -int OSystem_IPHONE::getGraphicsMode() const { - return _videoContext->graphicsMode; -} - -#ifdef USE_RGB_COLOR -Common::List OSystem_IPHONE::getSupportedFormats() const { - Common::List list; - // RGB565 - list.push_back(Graphics::createPixelFormat<565>()); - // CLUT8 - list.push_back(Graphics::PixelFormat::createFormatCLUT8()); - return list; -} -#endif - -void OSystem_IPHONE::initSize(uint width, uint height, const Graphics::PixelFormat *format) { - //printf("initSize(%u, %u, %p)\n", width, height, (const void *)format); - - _videoContext->screenWidth = width; - _videoContext->screenHeight = height; - _videoContext->shakeOffsetY = 0; - - // In case we use the screen texture as frame buffer we reset the pixels - // pointer here to avoid freeing the screen texture. - if (_framebuffer.getPixels() == _videoContext->screenTexture.getPixels()) - _framebuffer.setPixels(0); - - // Create the screen texture right here. We need to do this here, since - // when a game requests hi-color mode, we actually set the framebuffer - // to the texture buffer to avoid an additional copy step. - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(createScreenTexture) withObject:nil waitUntilDone: YES]; - - // In case the client code tries to set up a non supported mode, we will - // fall back to CLUT8 and set the transaction error accordingly. - if (format && format->bytesPerPixel != 1 && *format != _videoContext->screenTexture.format) { - format = 0; - _gfxTransactionError = kTransactionFormatNotSupported; - } - - if (!format || format->bytesPerPixel == 1) { - _framebuffer.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); - } else { -#if 0 - printf("bytesPerPixel: %u RGBAlosses: %u,%u,%u,%u RGBAshifts: %u,%u,%u,%u\n", format->bytesPerPixel, - format->rLoss, format->gLoss, format->bLoss, format->aLoss, - format->rShift, format->gShift, format->bShift, format->aShift); -#endif - // We directly draw on the screen texture in hi-color mode. Thus - // we copy over its settings here and just replace the width and - // height to avoid any problems. - _framebuffer = _videoContext->screenTexture; - _framebuffer.w = width; - _framebuffer.h = height; - } - - _fullScreenIsDirty = false; - dirtyFullScreen(); - _mouseCursorPaletteEnabled = false; -} - -void OSystem_IPHONE::beginGFXTransaction() { - _gfxTransactionError = kTransactionSuccess; -} - -OSystem::TransactionError OSystem_IPHONE::endGFXTransaction() { - _screenChangeCount++; - updateOutputSurface(); - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(setGraphicsMode) withObject:nil waitUntilDone: YES]; - - return _gfxTransactionError; -} - -void OSystem_IPHONE::updateOutputSurface() { - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(initSurface) withObject:nil waitUntilDone: YES]; -} - -int16 OSystem_IPHONE::getHeight() { - return _videoContext->screenHeight; -} - -int16 OSystem_IPHONE::getWidth() { - return _videoContext->screenWidth; -} - -void OSystem_IPHONE::setPalette(const byte *colors, uint start, uint num) { - //printf("setPalette(%p, %u, %u)\n", colors, start, num); - assert(start + num <= 256); - const byte *b = colors; - - for (uint i = start; i < start + num; ++i) { - _gamePalette[i] = Graphics::RGBToColor >(b[0], b[1], b[2]); - _gamePaletteRGBA5551[i] = Graphics::RGBToColor >(b[0], b[1], b[2]); - b += 3; - } - - dirtyFullScreen(); - - // Automatically update the mouse texture when the palette changes while the - // cursor palette is disabled. - if (!_mouseCursorPaletteEnabled && _mouseBuffer.format.bytesPerPixel == 1) - _mouseDirty = _mouseNeedTextureUpdate = true; -} - -void OSystem_IPHONE::grabPalette(byte *colors, uint start, uint num) { - //printf("grabPalette(%p, %u, %u)\n", colors, start, num); - assert(start + num <= 256); - byte *b = colors; - - for (uint i = start; i < start + num; ++i) { - Graphics::colorToRGB >(_gamePalette[i], b[0], b[1], b[2]); - b += 3; - } -} - -void OSystem_IPHONE::copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) { - //printf("copyRectToScreen(%p, %d, %i, %i, %i, %i)\n", buf, pitch, x, y, w, h); - //Clip the coordinates - const byte *src = (const byte *)buf; - if (x < 0) { - w += x; - src -= x; - x = 0; - } - - if (y < 0) { - h += y; - src -= y * pitch; - y = 0; - } - - if (w > (int)_framebuffer.w - x) { - w = _framebuffer.w - x; - } - - if (h > (int)_framebuffer.h - y) { - h = _framebuffer.h - y; - } - - if (w <= 0 || h <= 0) - return; - - if (!_fullScreenIsDirty) { - _dirtyRects.push_back(Common::Rect(x, y, x + w, y + h)); - } - - byte *dst = (byte *)_framebuffer.getBasePtr(x, y); - if (_framebuffer.pitch == pitch && _framebuffer.w == w) { - memcpy(dst, src, h * pitch); - } else { - do { - memcpy(dst, src, w * _framebuffer.format.bytesPerPixel); - src += pitch; - dst += _framebuffer.pitch; - } while (--h); - } -} - -void OSystem_IPHONE::updateScreen() { - if (_dirtyRects.size() == 0 && _dirtyOverlayRects.size() == 0 && !_mouseDirty) - return; - - //printf("updateScreen(): %i dirty rects.\n", _dirtyRects.size()); - - internUpdateScreen(); - _mouseDirty = false; - _fullScreenIsDirty = false; - _fullScreenOverlayIsDirty = false; - - iPhone_updateScreen(); -} - -void OSystem_IPHONE::internUpdateScreen() { - if (_mouseNeedTextureUpdate) { - updateMouseTexture(); - _mouseNeedTextureUpdate = false; - } - - while (_dirtyRects.size()) { - Common::Rect dirtyRect = _dirtyRects.remove_at(_dirtyRects.size() - 1); - - //printf("Drawing: (%i, %i) -> (%i, %i)\n", dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); - drawDirtyRect(dirtyRect); - // TODO: Implement dirty rect code - //updateHardwareSurfaceForRect(dirtyRect); - } - - if (_videoContext->overlayVisible) { - // TODO: Implement dirty rect code - _dirtyOverlayRects.clear(); - /*while (_dirtyOverlayRects.size()) { - Common::Rect dirtyRect = _dirtyOverlayRects.remove_at(_dirtyOverlayRects.size() - 1); - - //printf("Drawing: (%i, %i) -> (%i, %i)\n", dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); - drawDirtyOverlayRect(dirtyRect); - }*/ - } -} - -void OSystem_IPHONE::drawDirtyRect(const Common::Rect &dirtyRect) { - // We only need to do a color look up for CLUT8 - if (_framebuffer.format.bytesPerPixel != 1) - return; - - int h = dirtyRect.bottom - dirtyRect.top; - int w = dirtyRect.right - dirtyRect.left; - - const byte *src = (const byte *)_framebuffer.getBasePtr(dirtyRect.left, dirtyRect.top); - byte *dstRaw = (byte *)_videoContext->screenTexture.getBasePtr(dirtyRect.left, dirtyRect.top); - - // When we use CLUT8 do a color look up - for (int y = h; y > 0; y--) { - uint16 *dst = (uint16 *)dstRaw; - for (int x = w; x > 0; x--) - *dst++ = _gamePalette[*src++]; - - dstRaw += _videoContext->screenTexture.pitch; - src += _framebuffer.pitch - w; - } -} - -Graphics::Surface *OSystem_IPHONE::lockScreen() { - //printf("lockScreen()\n"); - return &_framebuffer; -} - -void OSystem_IPHONE::unlockScreen() { - //printf("unlockScreen()\n"); - dirtyFullScreen(); -} - -void OSystem_IPHONE::setShakePos(int shakeOffset) { - //printf("setShakePos(%i)\n", shakeOffset); - _videoContext->shakeOffsetY = shakeOffset; - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(setViewTransformation) withObject:nil waitUntilDone: YES]; - // HACK: We use this to force a redraw. - _mouseDirty = true; -} - -void OSystem_IPHONE::showOverlay() { - //printf("showOverlay()\n"); - _videoContext->overlayVisible = true; - dirtyFullOverlayScreen(); - updateScreen(); - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateMouseCursorScaling) withObject:nil waitUntilDone: YES]; - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES]; -} - -void OSystem_IPHONE::hideOverlay() { - //printf("hideOverlay()\n"); - _videoContext->overlayVisible = false; - _dirtyOverlayRects.clear(); - dirtyFullScreen(); - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateMouseCursorScaling) withObject:nil waitUntilDone: YES]; - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES]; -} - -void OSystem_IPHONE::clearOverlay() { - //printf("clearOverlay()\n"); - bzero(_videoContext->overlayTexture.getPixels(), _videoContext->overlayTexture.h * _videoContext->overlayTexture.pitch); - dirtyFullOverlayScreen(); -} - -void OSystem_IPHONE::grabOverlay(void *buf, int pitch) { - //printf("grabOverlay()\n"); - int h = _videoContext->overlayHeight; - - byte *dst = (byte *)buf; - const byte *src = (const byte *)_videoContext->overlayTexture.getPixels(); - do { - memcpy(dst, src, _videoContext->overlayWidth * sizeof(uint16)); - src += _videoContext->overlayTexture.pitch; - dst += pitch; - } while (--h); -} - -void OSystem_IPHONE::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) { - //printf("copyRectToOverlay(%p, pitch=%i, x=%i, y=%i, w=%i, h=%i)\n", (const void *)buf, pitch, x, y, w, h); - const byte *src = (const byte *)buf; - - //Clip the coordinates - if (x < 0) { - w += x; - src -= x * sizeof(uint16); - x = 0; - } - - if (y < 0) { - h += y; - src -= y * pitch; - y = 0; - } - - if (w > (int)_videoContext->overlayWidth - x) - w = _videoContext->overlayWidth - x; - - if (h > (int)_videoContext->overlayHeight - y) - h = _videoContext->overlayHeight - y; - - if (w <= 0 || h <= 0) - return; - - if (!_fullScreenOverlayIsDirty) { - _dirtyOverlayRects.push_back(Common::Rect(x, y, x + w, y + h)); - } - - byte *dst = (byte *)_videoContext->overlayTexture.getBasePtr(x, y); - do { - memcpy(dst, src, w * sizeof(uint16)); - src += pitch; - dst += _videoContext->overlayTexture.pitch; - } while (--h); -} - -int16 OSystem_IPHONE::getOverlayHeight() { - return _videoContext->overlayHeight; -} - -int16 OSystem_IPHONE::getOverlayWidth() { - return _videoContext->overlayWidth; -} - -bool OSystem_IPHONE::showMouse(bool visible) { - //printf("showMouse(%d)\n", visible); - bool last = _videoContext->mouseIsVisible; - _videoContext->mouseIsVisible = visible; - _mouseDirty = true; - - return last; -} - -void OSystem_IPHONE::warpMouse(int x, int y) { - //printf("warpMouse(%d, %d)\n", x, y); - _videoContext->mouseX = x; - _videoContext->mouseY = y; - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(notifyMouseMove) withObject:nil waitUntilDone: YES]; - _mouseDirty = true; -} - -void OSystem_IPHONE::dirtyFullScreen() { - if (!_fullScreenIsDirty) { - _dirtyRects.clear(); - _dirtyRects.push_back(Common::Rect(0, 0, _videoContext->screenWidth, _videoContext->screenHeight)); - _fullScreenIsDirty = true; - } -} - -void OSystem_IPHONE::dirtyFullOverlayScreen() { - if (!_fullScreenOverlayIsDirty) { - _dirtyOverlayRects.clear(); - _dirtyOverlayRects.push_back(Common::Rect(0, 0, _videoContext->overlayWidth, _videoContext->overlayHeight)); - _fullScreenOverlayIsDirty = true; - } -} - -void OSystem_IPHONE::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { - //printf("setMouseCursor(%p, %u, %u, %i, %i, %u, %d, %p)\n", (const void *)buf, w, h, hotspotX, hotspotY, keycolor, dontScale, (const void *)format); - - const Graphics::PixelFormat pixelFormat = format ? *format : Graphics::PixelFormat::createFormatCLUT8(); -#if 0 - printf("bytesPerPixel: %u RGBAlosses: %u,%u,%u,%u RGBAshifts: %u,%u,%u,%u\n", pixelFormat.bytesPerPixel, - pixelFormat.rLoss, pixelFormat.gLoss, pixelFormat.bLoss, pixelFormat.aLoss, - pixelFormat.rShift, pixelFormat.gShift, pixelFormat.bShift, pixelFormat.aShift); -#endif - assert(pixelFormat.bytesPerPixel == 1 || pixelFormat.bytesPerPixel == 2); - - if (_mouseBuffer.w != w || _mouseBuffer.h != h || _mouseBuffer.format != pixelFormat || !_mouseBuffer.getPixels()) - _mouseBuffer.create(w, h, pixelFormat); - - _videoContext->mouseWidth = w; - _videoContext->mouseHeight = h; - - _videoContext->mouseHotspotX = hotspotX; - _videoContext->mouseHotspotY = hotspotY; - - _mouseKeyColor = keycolor; - - memcpy(_mouseBuffer.getPixels(), buf, h * _mouseBuffer.pitch); - - _mouseDirty = true; - _mouseNeedTextureUpdate = true; -} - -void OSystem_IPHONE::setCursorPalette(const byte *colors, uint start, uint num) { - //printf("setCursorPalette(%p, %u, %u)\n", (const void *)colors, start, num); - assert(start + num <= 256); - - for (uint i = start; i < start + num; ++i, colors += 3) - _mouseCursorPalette[i] = Graphics::RGBToColor >(colors[0], colors[1], colors[2]); - - // FIXME: This is just stupid, our client code seems to assume that this - // automatically enables the cursor palette. - _mouseCursorPaletteEnabled = true; - - if (_mouseCursorPaletteEnabled) - _mouseDirty = _mouseNeedTextureUpdate = true; -} - -void OSystem_IPHONE::updateMouseTexture() { - uint texWidth = getSizeNextPOT(_videoContext->mouseWidth); - uint texHeight = getSizeNextPOT(_videoContext->mouseHeight); - - Graphics::Surface &mouseTexture = _videoContext->mouseTexture; - if (mouseTexture.w != texWidth || mouseTexture.h != texHeight) - mouseTexture.create(texWidth, texHeight, Graphics::createPixelFormat<5551>()); - - if (_mouseBuffer.format.bytesPerPixel == 1) { - const uint16 *palette; - if (_mouseCursorPaletteEnabled) - palette = _mouseCursorPalette; - else - palette = _gamePaletteRGBA5551; - - uint16 *mouseBuf = (uint16 *)mouseTexture.getPixels(); - for (uint x = 0; x < _videoContext->mouseWidth; ++x) { - for (uint y = 0; y < _videoContext->mouseHeight; ++y) { - const byte color = *(const byte *)_mouseBuffer.getBasePtr(x, y); - if (color != _mouseKeyColor) - mouseBuf[y * texWidth + x] = palette[color] | 0x1; - else - mouseBuf[y * texWidth + x] = 0x0; - } - } - } else { - if (crossBlit((byte *)mouseTexture.getPixels(), (const byte *)_mouseBuffer.getPixels(), mouseTexture.pitch, - _mouseBuffer.pitch, _mouseBuffer.w, _mouseBuffer.h, mouseTexture.format, _mouseBuffer.format)) { - if (!_mouseBuffer.format.aBits()) { - // Apply color keying since the original cursor had no alpha channel. - const uint16 *src = (const uint16 *)_mouseBuffer.getPixels(); - uint8 *dstRaw = (uint8 *)mouseTexture.getPixels(); - - for (uint y = 0; y < _mouseBuffer.h; ++y, dstRaw += mouseTexture.pitch) { - uint16 *dst = (uint16 *)dstRaw; - for (uint x = 0; x < _mouseBuffer.w; ++x, ++dst) { - if (*src++ == _mouseKeyColor) - *dst &= ~1; - else - *dst |= 1; - } - } - } - } else { - // TODO: Log this! - // Make the cursor all transparent... we really need a better fallback ;-). - memset(mouseTexture.getPixels(), 0, mouseTexture.h * mouseTexture.pitch); - } - } - - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateMouseCursor) withObject:nil waitUntilDone: YES]; -} -- cgit v1.2.3 From 5b15f06b9299a27be5df028855ee6b592361bdf3 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Mon, 7 Dec 2015 13:39:20 +0100 Subject: IOS: Wrong deallocator called --- backends/platform/ios7/ios7_video.mm | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm index 8cd4751c59..266386bdd4 100644 --- a/backends/platform/ios7/ios7_video.mm +++ b/backends/platform/ios7/ios7_video.mm @@ -280,15 +280,13 @@ uint getSizeNextPOT(uint size) { } - (void)dealloc { - if (_keyboardView != nil) { - [_keyboardView dealloc]; - } + [_keyboardView release]; _videoContext.screenTexture.free(); _videoContext.overlayTexture.free(); _videoContext.mouseTexture.free(); - [_eventLock dealloc]; + [_eventLock release]; [super dealloc]; } -- cgit v1.2.3 From e9378ccf3e07fc564daafd5099f95439d7b612a3 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Mon, 7 Dec 2015 14:12:16 +0100 Subject: IOS: Avoid subclassing UIApplication, and handle multitasking --- backends/platform/ios7/iOS7AppDelegate.h | 9 ++ backends/platform/ios7/iOS7AppDelegate.mm | 85 ++++++++++++++++++ backends/platform/ios7/iOS7MainApplication.h | 39 --------- backends/platform/ios7/iOS7MainApplication.mm | 121 -------------------------- backends/platform/ios7/ios7_main.mm | 2 +- backends/platform/ios7/ios7_osys_events.cpp | 32 +++++-- backends/platform/ios7/ios7_osys_main.cpp | 2 +- backends/platform/ios7/ios7_osys_main.h | 4 + backends/platform/ios7/module.mk | 2 +- 9 files changed, 124 insertions(+), 172 deletions(-) create mode 100644 backends/platform/ios7/iOS7AppDelegate.h create mode 100644 backends/platform/ios7/iOS7AppDelegate.mm delete mode 100644 backends/platform/ios7/iOS7MainApplication.h delete mode 100644 backends/platform/ios7/iOS7MainApplication.mm (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/iOS7AppDelegate.h b/backends/platform/ios7/iOS7AppDelegate.h new file mode 100644 index 0000000000..49411698c1 --- /dev/null +++ b/backends/platform/ios7/iOS7AppDelegate.h @@ -0,0 +1,9 @@ +// +// Created by Vincent Bénony on 07/12/2015. +// + +#import + + +@interface iOS7AppDelegate : NSObject +@end diff --git a/backends/platform/ios7/iOS7AppDelegate.mm b/backends/platform/ios7/iOS7AppDelegate.mm new file mode 100644 index 0000000000..784566228c --- /dev/null +++ b/backends/platform/ios7/iOS7AppDelegate.mm @@ -0,0 +1,85 @@ +// +// Created by Vincent Bénony on 07/12/2015. +// + +#define FORBIDDEN_SYMBOL_ALLOW_ALL +#import "iOS7AppDelegate.h" +#import "iOS7ScummVMViewController.h" +#import "ios7_video.h" + +@implementation iOS7AppDelegate { + UIWindow *_window; + iOS7ScummVMViewController *_controller; + iPhoneView *_view; +} + +- (id)init { + if (self = [super init]) { + _window = nil; + _view = nil; + } + return self; +} + +- (void)mainLoop:(id)param { + @autoreleasepool { + iOS7_main(iOS7_argc, iOS7_argv); + } + + exit(0); +} + +- (void)applicationDidFinishLaunching:(UIApplication *)application { + CGRect rect = [[UIScreen mainScreen] bounds]; + + // Create the directory for savegames +#ifdef IPHONE_OFFICIAL + NSFileManager *fm = [NSFileManager defaultManager]; + NSString *documentPath = [NSString stringWithUTF8String:iOS7_getDocumentsDir()]; + NSString *savePath = [documentPath stringByAppendingPathComponent:@"Savegames"]; + if (![fm fileExistsAtPath:savePath]) { + [fm createDirectoryAtPath:savePath withIntermediateDirectories:YES attributes:nil error:nil]; + } +#endif + + _window = [[UIWindow alloc] initWithFrame:rect]; + [_window retain]; + + _controller = [[iOS7ScummVMViewController alloc] init]; + + _view = [[iPhoneView alloc] initWithFrame:rect]; + _view.multipleTouchEnabled = YES; + _controller.view = _view; + + [_window setRootViewController:_controller]; + [_window makeKeyAndVisible]; + + [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didRotate:) + name:@"UIDeviceOrientationDidChangeNotification" + object:nil]; + + [NSThread detachNewThreadSelector:@selector(mainLoop:) toTarget:self withObject:nil]; +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + [_view applicationSuspend]; +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + [_view applicationResume]; +} + +- (void)didRotate:(NSNotification *)notification { + UIDeviceOrientation screenOrientation = [[UIDevice currentDevice] orientation]; + [_view deviceOrientationChanged:screenOrientation]; +} + +@end + +const char *iOS7_getDocumentsDir() { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + return [documentsDirectory UTF8String]; +} diff --git a/backends/platform/ios7/iOS7MainApplication.h b/backends/platform/ios7/iOS7MainApplication.h deleted file mode 100644 index a47f5da9ce..0000000000 --- a/backends/platform/ios7/iOS7MainApplication.h +++ /dev/null @@ -1,39 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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 - -@class iOS7ScummVMViewController; -@class iPhoneView; - -@interface iOS7MainApplication : UIApplication { - UIWindow *_window; - iOS7ScummVMViewController *_controller; - iPhoneView *_view; -} - -- (void)mainLoop:(id)param; -- (iPhoneView *)getView; -- (UIWindow *)getWindow; -- (void)didRotate:(NSNotification *)notification; -@end diff --git a/backends/platform/ios7/iOS7MainApplication.mm b/backends/platform/ios7/iOS7MainApplication.mm deleted file mode 100644 index c21c017174..0000000000 --- a/backends/platform/ios7/iOS7MainApplication.mm +++ /dev/null @@ -1,121 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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 "iOS7MainApplication.h" -#import "iOS7ScummVMViewController.h" - -#define FORBIDDEN_SYMBOL_ALLOW_ALL -#import "ios7_common.h" -#import "ios7_video.h" - - -@implementation iOS7MainApplication - --(id)init { - [super init]; - _window = nil; - _view = nil; - return self; -} - -- (void)mainLoop:(id)param { - @autoreleasepool { - iOS7_main(iOS7_argc, iOS7_argv); - } - - exit(0); -} - -- (iPhoneView *)getView { - return _view; -} - -- (void)applicationDidFinishLaunching:(UIApplication *)application { - CGRect rect = [[UIScreen mainScreen] bounds]; - - // Create the directory for savegames -#ifdef IPHONE_OFFICIAL - NSFileManager *fm = [NSFileManager defaultManager]; - NSString *documentPath = [NSString stringWithUTF8String:iOS7_getDocumentsDir()]; - NSString *savePath = [documentPath stringByAppendingPathComponent:@"Savegames"]; - if (![fm fileExistsAtPath:savePath]) { - [fm createDirectoryAtPath:savePath withIntermediateDirectories:YES attributes:nil error:nil]; - } -#endif - - _window = [[UIWindow alloc] initWithFrame:rect]; - [_window retain]; - - _controller = [[iOS7ScummVMViewController alloc] init]; - - _view = [[iPhoneView alloc] initWithFrame:rect]; - _view.multipleTouchEnabled = YES; - _controller.view = _view; - - [_window setRootViewController:_controller]; - [_window makeKeyAndVisible]; - - [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(didRotate:) - name:@"UIDeviceOrientationDidChangeNotification" - object:nil]; - - [NSThread detachNewThreadSelector:@selector(mainLoop:) toTarget:self withObject:nil]; -} - -- (void)applicationDidResume { -} - -- (void)applicationWillSuspend { -} - -- (void)applicationWillTerminate { -} - -- (void)applicationSuspend:(struct __GSEvent *)event { - //[self setApplicationBadge:NSLocalizedString(@"ON", nil)]; - [_view applicationSuspend]; -} - -- (void)applicationResume:(struct __GSEvent *)event { - [_view applicationResume]; -} - -- (void)didRotate:(NSNotification *)notification { - UIDeviceOrientation screenOrientation = [[UIDevice currentDevice] orientation]; - [_view deviceOrientationChanged:screenOrientation]; -} - -- (UIWindow*) getWindow { - return _window; -} - -@end - - -const char *iOS7_getDocumentsDir() { - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString *documentsDirectory = [paths objectAtIndex:0]; - return [documentsDirectory UTF8String]; -} diff --git a/backends/platform/ios7/ios7_main.mm b/backends/platform/ios7/ios7_main.mm index c6ca14d490..96f41f4c02 100644 --- a/backends/platform/ios7/ios7_main.mm +++ b/backends/platform/ios7/ios7_main.mm @@ -39,7 +39,7 @@ int main(int argc, char **argv) { iOS7_argc = argc; iOS7_argv = argv; - returnCode = UIApplicationMain(argc, argv, @"iOS7MainApplication", @"iOS7MainApplication"); + returnCode = UIApplicationMain(argc, argv, @"UIApplication", @"iOS7AppDelegate"); } return returnCode; diff --git a/backends/platform/ios7/ios7_osys_events.cpp b/backends/platform/ios7/ios7_osys_events.cpp index da44983b03..7e805f34b7 100644 --- a/backends/platform/ios7/ios7_osys_events.cpp +++ b/backends/platform/ios7/ios7_osys_events.cpp @@ -68,12 +68,14 @@ bool OSystem_iOS7::pollEvent(Common::Event &event) { case kInputOrientationChanged: handleEvent_orientationChanged(internalEvent.value1); return false; - break; case kInputApplicationSuspended: - suspendLoop(); + handleEvent_applicationSuspended(); + return false; + + case kInputApplicationResumed: + handleEvent_applicationResumed(); return false; - break; case kInputMouseSecondDragged: if (!handleEvent_mouseSecondDragged(event, internalEvent.value1, internalEvent.value2)) @@ -353,16 +355,28 @@ void OSystem_iOS7::handleEvent_orientationChanged(int orientation) { return; } - if (_screenOrientation != newOrientation) { _screenOrientation = newOrientation; - updateOutputSurface(); + rebuildSurface(); + } +} - dirtyFullScreen(); - if (_videoContext->overlayVisible) +void OSystem_iOS7::rebuildSurface() { + updateOutputSurface(); + + dirtyFullScreen(); + if (_videoContext->overlayVisible) { dirtyFullOverlayScreen(); - updateScreen(); - } + } + updateScreen(); +} + +void OSystem_iOS7::handleEvent_applicationSuspended() { + suspendLoop(); +} + +void OSystem_iOS7::handleEvent_applicationResumed() { + rebuildSurface(); } void OSystem_iOS7::handleEvent_keyPressed(Common::Event &event, int keyPressed) { diff --git a/backends/platform/ios7/ios7_osys_main.cpp b/backends/platform/ios7/ios7_osys_main.cpp index 84ddff26df..a58aa10340 100644 --- a/backends/platform/ios7/ios7_osys_main.cpp +++ b/backends/platform/ios7/ios7_osys_main.cpp @@ -339,6 +339,6 @@ void iOS7_main(int argc, char **argv) { assert(g_system); // Invoke the actual ScummVM main entry point: - scummvm_main(argc, argv); + scummvm_main(argc, (const char *const *) argv); g_system->quit(); // TODO: Consider removing / replacing this! } diff --git a/backends/platform/ios7/ios7_osys_main.h b/backends/platform/ios7/ios7_osys_main.h index 50114a9112..26b147e2a1 100644 --- a/backends/platform/ios7/ios7_osys_main.h +++ b/backends/platform/ios7/ios7_osys_main.h @@ -210,6 +210,8 @@ protected: bool handleEvent_tap(Common::Event &event, UIViewTapDescription type, int touches); void handleEvent_keyPressed(Common::Event &event, int keyPressed); void handleEvent_orientationChanged(int orientation); + void handleEvent_applicationSuspended(); + void handleEvent_applicationResumed(); bool handleEvent_mouseDown(Common::Event &event, int x, int y); bool handleEvent_mouseUp(Common::Event &event, int x, int y); @@ -219,6 +221,8 @@ protected: bool handleEvent_mouseDragged(Common::Event &event, int x, int y); bool handleEvent_mouseSecondDragged(Common::Event &event, int x, int y); + + void rebuildSurface(); }; #endif diff --git a/backends/platform/ios7/module.mk b/backends/platform/ios7/module.mk index fad69d715e..5ee4c7a601 100644 --- a/backends/platform/ios7/module.mk +++ b/backends/platform/ios7/module.mk @@ -9,7 +9,7 @@ MODULE_OBJS := \ ios7_video.o \ ios7_keyboard.o \ iOS7ScummVMViewController.o \ - iOS7MainApplication.o + iOS7AppDelegate.o # We don't use rules.mk but rather manually update OBJS and MODULE_DIRS. MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) -- cgit v1.2.3 From c813e5d87e7e2bb8a23e86ed04f689390dac1b60 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Tue, 8 Dec 2015 10:38:47 +0100 Subject: IOS: Move declarations in the common header file --- backends/platform/ios7/ios7_common.h | 1 + backends/platform/ios7/ios7_video.mm | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/ios7_common.h b/backends/platform/ios7/ios7_common.h index abc1180143..fe79e6d6cc 100644 --- a/backends/platform/ios7/ios7_common.h +++ b/backends/platform/ios7/ios7_common.h @@ -111,6 +111,7 @@ bool iOS7_isHighResDevice(); void iOS7_main(int argc, char **argv); const char *iOS7_getDocumentsDir(); +bool iOS7_touchpadModeEnabled(); uint getSizeNextPOT(uint size); diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm index 266386bdd4..49c4466a9c 100644 --- a/backends/platform/ios7/ios7_video.mm +++ b/backends/platform/ios7/ios7_video.mm @@ -39,8 +39,6 @@ static long g_lastTick = 0; static int g_frames = 0; #endif -extern bool iOS7_touchpadModeEnabled(); - #define printOpenGLError() printOglError(__FILE__, __LINE__) int printOglError(const char *file, int line) { -- cgit v1.2.3 From dad50ae0cc5c6daaa27d89cc85b07fffcaca7a77 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Tue, 8 Dec 2015 10:48:18 +0100 Subject: IOS: Fixes memory leak --- backends/platform/ios7/ios7_video.mm | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm index 49c4466a9c..dbb750362c 100644 --- a/backends/platform/ios7/ios7_video.mm +++ b/backends/platform/ios7/ios7_video.mm @@ -184,6 +184,12 @@ uint getSizeNextPOT(uint size) { [self addGestureRecognizer:swipeUp]; [self addGestureRecognizer:swipeDown]; [self addGestureRecognizer:doubleTapTwoFingers]; + + [swipeRight release]; + [swipeLeft release]; + [swipeUp release]; + [swipeDown release]; + [doubleTapTwoFingers release]; } - (CGFloat)optimalScale { -- cgit v1.2.3 From dd950fdb22dcc3d4be06ed416c09b6fb438144c4 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Tue, 8 Dec 2015 11:04:04 +0100 Subject: IOS: Removes a global variable --- backends/platform/ios7/iOS7AppDelegate.h | 6 ++++++ backends/platform/ios7/iOS7AppDelegate.mm | 10 ++++++++++ backends/platform/ios7/ios7_osys_video.mm | 23 ++++++++++++----------- backends/platform/ios7/ios7_video.h | 2 -- backends/platform/ios7/ios7_video.mm | 8 +++----- 5 files changed, 31 insertions(+), 18 deletions(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/iOS7AppDelegate.h b/backends/platform/ios7/iOS7AppDelegate.h index 49411698c1..7f903a692d 100644 --- a/backends/platform/ios7/iOS7AppDelegate.h +++ b/backends/platform/ios7/iOS7AppDelegate.h @@ -4,6 +4,12 @@ #import +@class iPhoneView; + @interface iOS7AppDelegate : NSObject + ++ (iOS7AppDelegate *)iOS7AppDelegate; ++ (iPhoneView *)iPhoneView; + @end diff --git a/backends/platform/ios7/iOS7AppDelegate.mm b/backends/platform/ios7/iOS7AppDelegate.mm index 784566228c..0f645e5055 100644 --- a/backends/platform/ios7/iOS7AppDelegate.mm +++ b/backends/platform/ios7/iOS7AppDelegate.mm @@ -76,6 +76,16 @@ [_view deviceOrientationChanged:screenOrientation]; } ++ (iOS7AppDelegate *)iOS7AppDelegate { + UIApplication *app = [UIApplication sharedApplication]; + return (iOS7AppDelegate *) app.delegate; +} + ++ (iPhoneView *)iPhoneView { + iOS7AppDelegate *appDelegate = [self iOS7AppDelegate]; + return appDelegate->_view; +} + @end const char *iOS7_getDocumentsDir() { diff --git a/backends/platform/ios7/ios7_osys_video.mm b/backends/platform/ios7/ios7_osys_video.mm index 4835ef5638..e2ac189baa 100644 --- a/backends/platform/ios7/ios7_osys_video.mm +++ b/backends/platform/ios7/ios7_osys_video.mm @@ -27,9 +27,10 @@ #include "ios7_video.h" #include "graphics/conversion.h" +#import "iOS7AppDelegate.h" void OSystem_iOS7::initVideoContext() { - _videoContext = [g_iPhoneViewInstance getVideoContext]; + _videoContext = [[iOS7AppDelegate iPhoneView] getVideoContext]; } const OSystem::GraphicsMode *OSystem_iOS7::getSupportedGraphicsModes() const { @@ -82,7 +83,7 @@ void OSystem_iOS7::initSize(uint width, uint height, const Graphics::PixelFormat // Create the screen texture right here. We need to do this here, since // when a game requests hi-color mode, we actually set the framebuffer // to the texture buffer to avoid an additional copy step. - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(createScreenTexture) withObject:nil waitUntilDone: YES]; + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(createScreenTexture) withObject:nil waitUntilDone: YES]; // In case the client code tries to set up a non supported mode, we will // fall back to CLUT8 and set the transaction error accordingly. @@ -119,13 +120,13 @@ void OSystem_iOS7::beginGFXTransaction() { OSystem::TransactionError OSystem_iOS7::endGFXTransaction() { _screenChangeCount++; updateOutputSurface(); - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(setGraphicsMode) withObject:nil waitUntilDone: YES]; + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(setGraphicsMode) withObject:nil waitUntilDone: YES]; return _gfxTransactionError; } void OSystem_iOS7::updateOutputSurface() { - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(initSurface) withObject:nil waitUntilDone: YES]; + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(initSurface) withObject:nil waitUntilDone: YES]; } int16 OSystem_iOS7::getHeight() { @@ -285,7 +286,7 @@ void OSystem_iOS7::unlockScreen() { void OSystem_iOS7::setShakePos(int shakeOffset) { //printf("setShakePos(%i)\n", shakeOffset); _videoContext->shakeOffsetY = shakeOffset; - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(setViewTransformation) withObject:nil waitUntilDone: YES]; + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(setViewTransformation) withObject:nil waitUntilDone: YES]; // HACK: We use this to force a redraw. _mouseDirty = true; } @@ -295,8 +296,8 @@ void OSystem_iOS7::showOverlay() { _videoContext->overlayVisible = true; dirtyFullOverlayScreen(); updateScreen(); - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateMouseCursorScaling) withObject:nil waitUntilDone: YES]; - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES]; + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(updateMouseCursorScaling) withObject:nil waitUntilDone: YES]; + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES]; } void OSystem_iOS7::hideOverlay() { @@ -304,8 +305,8 @@ void OSystem_iOS7::hideOverlay() { _videoContext->overlayVisible = false; _dirtyOverlayRects.clear(); dirtyFullScreen(); - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateMouseCursorScaling) withObject:nil waitUntilDone: YES]; - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES]; + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(updateMouseCursorScaling) withObject:nil waitUntilDone: YES]; + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES]; } void OSystem_iOS7::clearOverlay() { @@ -386,7 +387,7 @@ void OSystem_iOS7::warpMouse(int x, int y) { //printf("warpMouse(%d, %d)\n", x, y); _videoContext->mouseX = x; _videoContext->mouseY = y; - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(notifyMouseMove) withObject:nil waitUntilDone: YES]; + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(notifyMouseMove) withObject:nil waitUntilDone: YES]; _mouseDirty = true; } @@ -499,5 +500,5 @@ void OSystem_iOS7::updateMouseTexture() { } } - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateMouseCursor) withObject:nil waitUntilDone: YES]; + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(updateMouseCursor) withObject:nil waitUntilDone: YES]; } diff --git a/backends/platform/ios7/ios7_video.h b/backends/platform/ios7/ios7_video.h index 63a570d19d..09a84b5498 100644 --- a/backends/platform/ios7/ios7_video.h +++ b/backends/platform/ios7/ios7_video.h @@ -104,6 +104,4 @@ @end -extern iPhoneView *g_iPhoneViewInstance; - #endif diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm index dbb750362c..1a2ae5ee91 100644 --- a/backends/platform/ios7/ios7_video.mm +++ b/backends/platform/ios7/ios7_video.mm @@ -27,8 +27,8 @@ #include "graphics/colormasks.h" #include "common/system.h" +#import "iOS7AppDelegate.h" -iPhoneView *g_iPhoneViewInstance = nil; static int g_fullWidth; static int g_fullHeight; @@ -62,12 +62,12 @@ void iOS7_updateScreen() { //printf("Mouse: (%i, %i)\n", mouseX, mouseY); if (!g_needsScreenUpdate) { g_needsScreenUpdate = 1; - [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateSurface) withObject:nil waitUntilDone: NO]; + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(updateSurface) withObject:nil waitUntilDone: NO]; } } bool iOS7_fetchEvent(InternalEvent *event) { - return [g_iPhoneViewInstance fetchEvent:event]; + return [[iOS7AppDelegate iPhoneView] fetchEvent:event]; } uint getSizeNextPOT(uint size) { @@ -233,8 +233,6 @@ uint getSizeNextPOT(uint size) { _contentScaleFactor = [self optimalScale]; [self setContentScaleFactor:_contentScaleFactor]; - g_iPhoneViewInstance = self; - _keyboardView = nil; _screenTexture = 0; _overlayTexture = 0; -- cgit v1.2.3 From 14a0a3d032059ab489a9f5f535972449ba036010 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Tue, 8 Dec 2015 12:17:46 +0100 Subject: IOS: Better resolution handling --- backends/platform/ios7/ios7_common.h | 2 +- backends/platform/ios7/ios7_osys_main.cpp | 2 +- backends/platform/ios7/ios7_osys_video.mm | 2 +- backends/platform/ios7/ios7_video.mm | 62 ++++++++++--------------------- 4 files changed, 23 insertions(+), 45 deletions(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/ios7_common.h b/backends/platform/ios7/ios7_common.h index fe79e6d6cc..73db72a068 100644 --- a/backends/platform/ios7/ios7_common.h +++ b/backends/platform/ios7/ios7_common.h @@ -107,7 +107,7 @@ extern char **iOS7_argv; void iOS7_updateScreen(); bool iOS7_fetchEvent(InternalEvent *event); -bool iOS7_isHighResDevice(); +bool iOS7_isBigDevice(); void iOS7_main(int argc, char **argv); const char *iOS7_getDocumentsDir(); diff --git a/backends/platform/ios7/ios7_osys_main.cpp b/backends/platform/ios7/ios7_osys_main.cpp index a58aa10340..d8eb84e214 100644 --- a/backends/platform/ios7/ios7_osys_main.cpp +++ b/backends/platform/ios7/ios7_osys_main.cpp @@ -64,7 +64,7 @@ OSystem_iOS7::OSystem_iOS7() : _mouseDirty(false), _timeSuspended(0), _lastDragPosX(-1), _lastDragPosY(-1), _screenChangeCount(0), _mouseCursorPaletteEnabled(false), _gfxTransactionError(kTransactionSuccess) { _queuedInputEvent.type = Common::EVENT_INVALID; - _touchpadModeEnabled = !iOS7_isHighResDevice(); + _touchpadModeEnabled = !iOS7_isBigDevice(); #ifdef IPHONE_OFFICIAL _fsFactory = new ChRootFilesystemFactory(iOS7_getDocumentsDir()); #else diff --git a/backends/platform/ios7/ios7_osys_video.mm b/backends/platform/ios7/ios7_osys_video.mm index e2ac189baa..f2f00069f9 100644 --- a/backends/platform/ios7/ios7_osys_video.mm +++ b/backends/platform/ios7/ios7_osys_video.mm @@ -38,7 +38,7 @@ const OSystem::GraphicsMode *OSystem_iOS7::getSupportedGraphicsModes() const { } int OSystem_iOS7::getDefaultGraphicsMode() const { - return kGraphicsModeLinear; + return kGraphicsModeNone; } bool OSystem_iOS7::setGraphicsMode(int mode) { diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm index 1a2ae5ee91..191faa806b 100644 --- a/backends/platform/ios7/ios7_video.mm +++ b/backends/platform/ios7/ios7_video.mm @@ -54,8 +54,8 @@ int printOglError(const char *file, int line) { return retCode; } -bool iOS7_isHighResDevice() { - return g_fullHeight > 480; +bool iOS7_isBigDevice() { + return UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad; } void iOS7_updateScreen() { @@ -129,22 +129,30 @@ uint getSizeNextPOT(uint size) { NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); return; } - uint maxValue = MAX(_renderBufferWidth, _renderBufferHeight), maxValuePOT = getSizeNextPOT(maxValue); - uint minValue = MIN(_renderBufferWidth, _renderBufferHeight), minValuePOT = getSizeNextPOT(minValue); + uint overlayWidth = MAX(_renderBufferWidth, _renderBufferHeight); + uint overlayHeight = MIN(_renderBufferWidth, _renderBufferHeight); + + if (!iOS7_isBigDevice()) { + // On small devices, we force the user interface to use the small theme + while (overlayHeight > 480) { + overlayWidth /= 2; + overlayHeight /= 2; + } + } - _videoContext.overlayWidth = maxValue; - _videoContext.overlayHeight = minValue; + _videoContext.overlayWidth = overlayWidth; + _videoContext.overlayHeight = overlayHeight; - uint overlayTextureWidth = maxValuePOT; - uint overlayTextureHeight = minValuePOT; + uint overlayTextureWidthPOT = getSizeNextPOT(overlayWidth); + uint overlayTextureHeightPOT = getSizeNextPOT(overlayHeight); // Since the overlay size won't change the whole run, we can // precalculate the texture coordinates for the overlay texture here // and just use it later on. - _overlayTexCoords[2] = _overlayTexCoords[6] = _videoContext.overlayWidth / (GLfloat)overlayTextureWidth; - _overlayTexCoords[5] = _overlayTexCoords[7] = _videoContext.overlayHeight / (GLfloat)overlayTextureHeight; + _overlayTexCoords[2] = _overlayTexCoords[6] = _videoContext.overlayWidth / (GLfloat) overlayTextureWidthPOT; + _overlayTexCoords[5] = _overlayTexCoords[7] = _videoContext.overlayHeight / (GLfloat) overlayTextureHeightPOT; - _videoContext.overlayTexture.create(overlayTextureWidth, overlayTextureHeight, Graphics::createPixelFormat<5551>()); + _videoContext.overlayTexture.create(overlayTextureWidthPOT, overlayTextureHeightPOT, Graphics::createPixelFormat<5551>()); glViewport(0, 0, _renderBufferWidth, _renderBufferHeight); printOpenGLError(); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); printOpenGLError(); @@ -192,36 +200,6 @@ uint getSizeNextPOT(uint size) { [doubleTapTwoFingers release]; } -- (CGFloat)optimalScale { - CGFloat screenScale = [[UIScreen mainScreen] scale]; - if (screenScale < 2) return screenScale; - - if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { - return 1; - } - - CGSize screenSize; - UIScreen *mainScreen = [UIScreen mainScreen]; - if ([mainScreen respondsToSelector:@selector(nativeBounds)]) { - screenSize = [mainScreen nativeBounds].size; - } - else { - screenSize = [mainScreen bounds].size; - screenSize.width *= screenScale; - screenSize.height *= screenScale; - } - CGFloat mxSize = MAX(screenSize.width, screenSize.height); - - if (mxSize <= 1136) { - // iPhone 4S / 5 / 5S / 5C - return 1; - } - else { - // iPhone 6 / 6S / 6+ / 6S+ - return 2; - } -} - - (id)initWithFrame:(struct CGRect)frame { self = [super initWithFrame: frame]; @@ -230,7 +208,7 @@ uint getSizeNextPOT(uint size) { g_fullWidth = (int)MAX(frame.size.width, frame.size.height); g_fullHeight = (int)MIN(frame.size.width, frame.size.height); - _contentScaleFactor = [self optimalScale]; + _contentScaleFactor = [[UIScreen mainScreen] scale]; [self setContentScaleFactor:_contentScaleFactor]; _keyboardView = nil; -- cgit v1.2.3 From 56ca0b9dc257b7da1dd8c2fdd93a95fc5b802076 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Wed, 9 Dec 2015 17:48:46 +0100 Subject: IOS: Scales the GUI for the iPad Pro --- backends/platform/ios7/ios7_video.mm | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm index 191faa806b..235f8f28f1 100644 --- a/backends/platform/ios7/ios7_video.mm +++ b/backends/platform/ios7/ios7_video.mm @@ -132,7 +132,15 @@ uint getSizeNextPOT(uint size) { uint overlayWidth = MAX(_renderBufferWidth, _renderBufferHeight); uint overlayHeight = MIN(_renderBufferWidth, _renderBufferHeight); - if (!iOS7_isBigDevice()) { + if (iOS7_isBigDevice()) { + // On really big displays, like the iPad Pro, we scale the interface down + // so that the controls are not too small.. + while (overlayHeight > 1024) { + overlayWidth /= 2; + overlayHeight /= 2; + } + } + else { // On small devices, we force the user interface to use the small theme while (overlayHeight > 480) { overlayWidth /= 2; -- cgit v1.2.3 From 80afba232a30b7d80d9331f597aee208d80cd2e1 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Wed, 9 Dec 2015 17:49:54 +0100 Subject: IOS: Implements scalers --- backends/platform/ios7/ios7_common.h | 14 +++- backends/platform/ios7/ios7_osys_main.cpp | 20 +++++- backends/platform/ios7/ios7_osys_video.mm | 9 +++ backends/platform/ios7/ios7_video.h | 8 +++ backends/platform/ios7/ios7_video.mm | 108 +++++++++++++++++++++++++++++- 5 files changed, 155 insertions(+), 4 deletions(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/ios7_common.h b/backends/platform/ios7/ios7_common.h index 73db72a068..b7a47eda8a 100644 --- a/backends/platform/ios7/ios7_common.h +++ b/backends/platform/ios7/ios7_common.h @@ -60,14 +60,24 @@ enum UIViewTapDescription { enum GraphicsModes { kGraphicsModeLinear = 0, - kGraphicsModeNone = 1 + kGraphicsModeNone = 1, + + kGraphicsMode2xSaI, + kGraphicsModeSuper2xSaI, + kGraphicsModeSuperEagle, + kGraphicsModeAdvMame2x, + kGraphicsModeAdvMame3x, + kGraphicsModeHQ2x, + kGraphicsModeHQ3x, + kGraphicsModeTV2x, + kGraphicsModeDotMatrix }; struct VideoContext { VideoContext() : asprectRatioCorrection(), screenWidth(), screenHeight(), overlayVisible(false), overlayWidth(), overlayHeight(), mouseX(), mouseY(), mouseHotspotX(), mouseHotspotY(), mouseWidth(), mouseHeight(), - mouseIsVisible(), graphicsMode(kGraphicsModeLinear), shakeOffsetY() { + mouseIsVisible(), graphicsMode(kGraphicsModeNone), shakeOffsetY() { } // Game screen state diff --git a/backends/platform/ios7/ios7_osys_main.cpp b/backends/platform/ios7/ios7_osys_main.cpp index d8eb84e214..76739423c1 100644 --- a/backends/platform/ios7/ios7_osys_main.cpp +++ b/backends/platform/ios7/ios7_osys_main.cpp @@ -43,12 +43,30 @@ #include "audio/mixer.h" #include "audio/mixer_intern.h" +#include "graphics/scaler.h" +#include "graphics/scaler/aspect.h" + #include "ios7_osys_main.h" const OSystem::GraphicsMode OSystem_iOS7::s_supportedGraphicsModes[] = { - { "linear", "Linear filtering", kGraphicsModeLinear }, { "none", "No filtering", kGraphicsModeNone }, + { "linear", "Linear filtering", kGraphicsModeLinear }, +#ifdef USE_SCALERS +// {"2x", "2x", GFX_DOUBLESIZE}, +// {"3x", "3x", GFX_TRIPLESIZE}, + { "2xsai", "2xSAI", kGraphicsMode2xSaI}, + {"super2xsai", "Super2xSAI", kGraphicsModeSuper2xSaI}, + {"supereagle", "SuperEagle", kGraphicsModeSuperEagle}, + {"advmame2x", "AdvMAME2x", kGraphicsModeAdvMame2x}, + {"advmame3x", "AdvMAME3x", kGraphicsModeAdvMame3x}, +#ifdef USE_HQ_SCALERS + {"hq2x", "HQ2x", kGraphicsModeHQ2x}, + {"hq3x", "HQ3x", kGraphicsModeHQ3x}, +#endif + {"tv2x", "TV2x", kGraphicsModeTV2x}, + {"dotmatrix", "DotMatrix", kGraphicsModeDotMatrix}, +#endif { 0, 0, 0 } }; diff --git a/backends/platform/ios7/ios7_osys_video.mm b/backends/platform/ios7/ios7_osys_video.mm index f2f00069f9..7cce56c800 100644 --- a/backends/platform/ios7/ios7_osys_video.mm +++ b/backends/platform/ios7/ios7_osys_video.mm @@ -45,6 +45,15 @@ bool OSystem_iOS7::setGraphicsMode(int mode) { switch (mode) { case kGraphicsModeNone: case kGraphicsModeLinear: + case kGraphicsMode2xSaI: + case kGraphicsModeSuper2xSaI: + case kGraphicsModeSuperEagle: + case kGraphicsModeAdvMame2x: + case kGraphicsModeAdvMame3x: + case kGraphicsModeHQ2x: + case kGraphicsModeHQ3x: + case kGraphicsModeTV2x: + case kGraphicsModeDotMatrix: _videoContext->graphicsMode = (GraphicsModes)mode; return true; diff --git a/backends/platform/ios7/ios7_video.h b/backends/platform/ios7/ios7_video.h index 09a84b5498..96a0984882 100644 --- a/backends/platform/ios7/ios7_video.h +++ b/backends/platform/ios7/ios7_video.h @@ -35,6 +35,7 @@ #include "ios7_common.h" #include "common/list.h" +#import "graphics/scaler.h" @interface iPhoneView : UIView { VideoContext _videoContext; @@ -72,6 +73,13 @@ UITouch *_firstTouch; UITouch *_secondTouch; + + uint8_t *_scalerMemorySrc; + uint8_t *_scalerMemoryDst; + size_t _scalerMemorySrcSize; + size_t _scalerMemoryDstSize; + int _scalerScale; + ScalerProc *_scaler; } - (id)initWithFrame:(struct CGRect)frame; diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm index 235f8f28f1..1660dd4612 100644 --- a/backends/platform/ios7/ios7_video.mm +++ b/backends/platform/ios7/ios7_video.mm @@ -211,6 +211,10 @@ uint getSizeNextPOT(uint size) { - (id)initWithFrame:(struct CGRect)frame { self = [super initWithFrame: frame]; +#if defined(USE_SCALERS) || defined(USE_HQ_SCALERS) + InitScalers(565); +#endif + [self setupGestureRecognizers]; g_fullWidth = (int)MAX(frame.size.width, frame.size.height); @@ -219,6 +223,13 @@ uint getSizeNextPOT(uint size) { _contentScaleFactor = [[UIScreen mainScreen] scale]; [self setContentScaleFactor:_contentScaleFactor]; + _scalerMemorySrc = NULL; + _scalerMemoryDst = NULL; + _scalerMemorySrcSize = 0; + _scalerMemoryDstSize = 0; + _scaler = NULL; + _scalerScale = 1; + _keyboardView = nil; _screenTexture = 0; _overlayTexture = 0; @@ -274,6 +285,9 @@ uint getSizeNextPOT(uint size) { _videoContext.overlayTexture.free(); _videoContext.mouseTexture.free(); + free(_scalerMemorySrc); + free(_scalerMemoryDst); + [_eventLock release]; [super dealloc]; } @@ -300,6 +314,8 @@ uint getSizeNextPOT(uint size) { glBindTexture(GL_TEXTURE_2D, tex); printOpenGLError(); GLint filter = GL_LINEAR; + ScalerProc *scaler = NULL; + int scalerScale = 1; switch (_videoContext.graphicsMode) { case kGraphicsModeLinear: @@ -309,6 +325,64 @@ uint getSizeNextPOT(uint size) { case kGraphicsModeNone: filter = GL_NEAREST; break; +#ifdef USE_SCALERS + case kGraphicsMode2xSaI: + filter = GL_LINEAR; + scaler = _2xSaI; + scalerScale = 2; + break; + + case kGraphicsModeSuper2xSaI: + filter = GL_LINEAR; + scaler = Super2xSaI; + scalerScale = 2; + break; + + case kGraphicsModeSuperEagle: + filter = GL_LINEAR; + scaler = SuperEagle; + scalerScale = 2; + break; + + case kGraphicsModeAdvMame2x: + filter = GL_LINEAR; + scaler = AdvMame2x; + scalerScale = 2; + break; + + case kGraphicsModeAdvMame3x: + filter = GL_LINEAR; + scaler = AdvMame3x; + scalerScale = 3; + break; + +#ifdef USE_HQ_SCALERS + case kGraphicsModeHQ2x: + filter = GL_LINEAR; + scaler = HQ2x; + scalerScale = 2; + break; + + case kGraphicsModeHQ3x: + filter = GL_LINEAR; + scaler = HQ3x; + scalerScale = 3; + break; +#endif + + case kGraphicsModeTV2x: + filter = GL_LINEAR; + scaler = TV2x; + scalerScale = 2; + break; + + case kGraphicsModeDotMatrix: + filter = GL_LINEAR; + scaler = DotMatrix; + scalerScale = 2; + break; + +#endif } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); printOpenGLError(); @@ -318,6 +392,9 @@ uint getSizeNextPOT(uint size) { // have a line/border artifact on the right side of the covered rect. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); printOpenGLError(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); printOpenGLError(); + + _scaler = scaler; + _scalerScale = scalerScale; } - (void)setGraphicsMode { @@ -422,7 +499,36 @@ uint getSizeNextPOT(uint size) { // Unfortunately we have to update the whole texture every frame, since glTexSubImage2D is actually slower in all cases // due to the iPhone internals having to convert the whole texture back from its internal format when used. // In the future we could use several tiled textures instead. - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w, _videoContext.screenTexture.h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _videoContext.screenTexture.getPixels()); printOpenGLError(); + if (_scaler) { + size_t neededSrcMemorySize = (size_t) (_videoContext.screenTexture.pitch * (_videoContext.screenTexture.h + 4)); + size_t neededDstMemorySize = (size_t) (_videoContext.screenTexture.pitch * (_videoContext.screenTexture.h + 4) * _scalerScale * _scalerScale); + if (neededSrcMemorySize != _scalerMemorySrcSize) { + _scalerMemorySrc = (uint8_t *) realloc(_scalerMemorySrc, neededSrcMemorySize); + _scalerMemorySrcSize = neededSrcMemorySize; + } + if (neededDstMemorySize != _scalerMemoryDstSize) { + _scalerMemoryDst = (uint8_t *) realloc(_scalerMemoryDst, neededDstMemorySize); + _scalerMemoryDstSize = neededDstMemorySize; + } + + // Clear two lines before + memset(_scalerMemorySrc, 0, _videoContext.screenTexture.pitch * 2); + // Copy original buffer + memcpy(_scalerMemorySrc + _videoContext.screenTexture.pitch * 2, _videoContext.screenTexture.getPixels(), _videoContext.screenTexture.pitch * _videoContext.screenTexture.h); + // Clear two linex after + memset(_scalerMemorySrc + _videoContext.screenTexture.pitch * (2 + _videoContext.screenTexture.h), 0, _videoContext.screenTexture.pitch * 2); + // Apply scaler + _scaler(_scalerMemorySrc + _videoContext.screenTexture.pitch * 2, + _videoContext.screenTexture.pitch, + _scalerMemoryDst, + (uint32) (_videoContext.screenTexture.pitch * _scalerScale), + _videoContext.screenTexture.w, + _videoContext.screenTexture.h); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w * _scalerScale, _videoContext.screenTexture.h * _scalerScale, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _scalerMemoryDst); printOpenGLError(); + } + else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w, _videoContext.screenTexture.h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _videoContext.screenTexture.getPixels()); printOpenGLError(); + } glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); } -- cgit v1.2.3 From 9b51cafc0448adbef5523e89a4d1ab4a43b82da6 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Wed, 9 Dec 2015 17:51:58 +0100 Subject: IOS: Updates compilation instructions --- backends/platform/ios7/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/README.md b/backends/platform/ios7/README.md index a58905d3bc..88084b8d96 100644 --- a/backends/platform/ios7/README.md +++ b/backends/platform/ios7/README.md @@ -20,7 +20,7 @@ The next step is to compile the **create_project** tool. Open the Xcode project Execute the following commands in a terminal: ``` $ cd path_to_the_build_directory -$ create_project path_to_scummvm_repository --xcode --disable-mad --disable-jpeg --disable-bink --disable-scalers --disable-hqscalers --disable-16bit --disable-mt32emu --disable-nasm --disable-opengl --disable-theora --disable-taskbar +$ create_project path_to_scummvm_repository --xcode --disable-mad --disable-jpeg --disable-bink --disable-16bit --disable-mt32emu --disable-nasm --disable-opengl --disable-theora --disable-taskbar ``` This will create an Xcode project for ScummVM, for both the OS X, and the iOS target. -- cgit v1.2.3 From c4b8db5589ec69d4ed781fceb14c6add150ddbcf Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Thu, 10 Dec 2015 09:11:01 +0100 Subject: IOS: Typo --- backends/platform/ios7/ios7_video.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm index 1660dd4612..10900b4d55 100644 --- a/backends/platform/ios7/ios7_video.mm +++ b/backends/platform/ios7/ios7_video.mm @@ -515,7 +515,7 @@ uint getSizeNextPOT(uint size) { memset(_scalerMemorySrc, 0, _videoContext.screenTexture.pitch * 2); // Copy original buffer memcpy(_scalerMemorySrc + _videoContext.screenTexture.pitch * 2, _videoContext.screenTexture.getPixels(), _videoContext.screenTexture.pitch * _videoContext.screenTexture.h); - // Clear two linex after + // Clear two lines after memset(_scalerMemorySrc + _videoContext.screenTexture.pitch * (2 + _videoContext.screenTexture.h), 0, _videoContext.screenTexture.pitch * 2); // Apply scaler _scaler(_scalerMemorySrc + _videoContext.screenTexture.pitch * 2, -- cgit v1.2.3 From 7324f87b9af3a5f2da9d84dad5f2e6df26e1ddb2 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Thu, 10 Dec 2015 15:49:00 +0100 Subject: IOS: Switches to OpenGL ES 2.0 to ease debugging with Xcode --- backends/platform/ios7/ios7_video.h | 31 ++- backends/platform/ios7/ios7_video.mm | 500 ++++++++++++++++++++--------------- 2 files changed, 314 insertions(+), 217 deletions(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/ios7_video.h b/backends/platform/ios7/ios7_video.h index 96a0984882..bed552c7cf 100644 --- a/backends/platform/ios7/ios7_video.h +++ b/backends/platform/ios7/ios7_video.h @@ -28,8 +28,8 @@ #include #include -#include -#include +#include +#include #include "ios7_keyboard.h" #include "ios7_common.h" @@ -37,6 +37,11 @@ #include "common/list.h" #import "graphics/scaler.h" +typedef struct { + GLfloat x, y; + GLfloat u,v; +} GLVertex; + @interface iPhoneView : UIView { VideoContext _videoContext; @@ -51,19 +56,29 @@ GLuint _overlayTexture; GLuint _mouseCursorTexture; + GLuint _vertexShader; + GLuint _fragmentShader; + + GLuint _vertexBuffer; + + GLuint _screenSizeSlot; + GLuint _textureSlot; + GLuint _shakeSlot; + + GLuint _positionSlot; + GLuint _textureCoordSlot; + GLint _renderBufferWidth; GLint _renderBufferHeight; - GLfloat _gameScreenVertCoords[4 * 2]; - GLfloat _gameScreenTexCoords[4 * 2]; + GLVertex _gameScreenCoords[4]; CGRect _gameScreenRect; - GLfloat _overlayVertCoords[4 * 2]; - GLfloat _overlayTexCoords[4 * 2]; + GLVertex _overlayCoords[4]; CGRect _overlayRect; - GLfloat _mouseVertCoords[4 * 2]; - GLfloat _mouseTexCoords[4 * 2]; + GLVertex _mouseCoords[4]; + GLint _mouseHotspotX, _mouseHotspotY; GLint _mouseWidth, _mouseHeight; GLfloat _mouseScaleX, _mouseScaleY; diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm index 10900b4d55..fe2285253c 100644 --- a/backends/platform/ios7/ios7_video.mm +++ b/backends/platform/ios7/ios7_video.mm @@ -102,7 +102,7 @@ uint getSizeNextPOT(uint size) { kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGB565 }; - _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; + _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; // In case creating the OpenGL ES context failed, we will error out here. if (_context == nil) { @@ -111,66 +111,226 @@ uint getSizeNextPOT(uint size) { } if ([EAGLContext setCurrentContext:_context]) { - glGenFramebuffersOES(1, &_viewFramebuffer); printOpenGLError(); - glGenRenderbuffersOES(1, &_viewRenderbuffer); printOpenGLError(); + // glEnableClientState(GL_TEXTURE_COORD_ARRAY); printOpenGLError(); + // glEnableClientState(GL_VERTEX_ARRAY); printOpenGLError(); + [self setupOpenGL]; + } +} - glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); printOpenGLError(); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); - [_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id)self.layer]; +- (void)setupOpenGL { + [self setupFramebuffer]; + [self createOverlaySurface]; + [self compileShaders]; + [self setupVBOs]; + [self setupTextures]; - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); + [self finishGLSetup]; +} - // Retrieve the render buffer size. This *should* match the frame size, - // i.e. g_fullWidth and g_fullHeight. - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &_renderBufferWidth); printOpenGLError(); - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &_renderBufferHeight); printOpenGLError(); +- (void)finishGLSetup { + glViewport(0, 0, _renderBufferWidth, _renderBufferHeight); printOpenGLError(); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); printOpenGLError(); - if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { - NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); - return; - } - uint overlayWidth = MAX(_renderBufferWidth, _renderBufferHeight); - uint overlayHeight = MIN(_renderBufferWidth, _renderBufferHeight); - - if (iOS7_isBigDevice()) { - // On really big displays, like the iPad Pro, we scale the interface down - // so that the controls are not too small.. - while (overlayHeight > 1024) { - overlayWidth /= 2; - overlayHeight /= 2; - } + glUniform2f(_screenSizeSlot, _renderBufferWidth, _renderBufferHeight); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +} + +- (void)freeOpenGL { + [self deleteTextures]; + [self deleteVBOs]; + [self deleteShaders]; + [self deleteFramebuffer]; +} + +- (void)rebuildFrameBuffer { + [self deleteFramebuffer]; + [self setupFramebuffer]; + [self finishGLSetup]; +} + +- (void)setupFramebuffer { + glGenRenderbuffers(1, &_viewRenderbuffer); + printOpenGLError(); + glBindRenderbuffer(GL_RENDERBUFFER, _viewRenderbuffer); + printOpenGLError(); + [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(id ) self.layer]; + + glGenFramebuffers(1, &_viewFramebuffer); + printOpenGLError(); + glBindFramebuffer(GL_FRAMEBUFFER, _viewFramebuffer); + printOpenGLError(); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _viewRenderbuffer); + printOpenGLError(); + + // Retrieve the render buffer size. This *should* match the frame size, + // i.e. g_fullWidth and g_fullHeight. + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_renderBufferWidth); + printOpenGLError(); + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_renderBufferHeight); + printOpenGLError(); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatus(GL_FRAMEBUFFER)); + return; + } +} + +- (void)createOverlaySurface { + uint overlayWidth = (uint) MAX(_renderBufferWidth, _renderBufferHeight); + uint overlayHeight = (uint) MIN(_renderBufferWidth, _renderBufferHeight); + + if (iOS7_isBigDevice()) { + // On really big displays, like the iPad Pro, we scale the interface down + // so that the controls are not too small.. + while (overlayHeight > 1024) { + overlayWidth /= 2; + overlayHeight /= 2; } - else { - // On small devices, we force the user interface to use the small theme - while (overlayHeight > 480) { - overlayWidth /= 2; - overlayHeight /= 2; - } + } + else { + // On small devices, we force the user interface to use the small theme + while (overlayHeight > 480) { + overlayWidth /= 2; + overlayHeight /= 2; } + } + + _videoContext.overlayWidth = overlayWidth; + _videoContext.overlayHeight = overlayHeight; + + uint overlayTextureWidthPOT = getSizeNextPOT(overlayWidth); + uint overlayTextureHeightPOT = getSizeNextPOT(overlayHeight); + + // Since the overlay size won't change the whole run, we can + // precalculate the texture coordinates for the overlay texture here + // and just use it later on. + GLfloat u = _videoContext.overlayWidth / (GLfloat) overlayTextureWidthPOT; + GLfloat v = _videoContext.overlayHeight / (GLfloat) overlayTextureHeightPOT; + _overlayCoords[0].x = 0; _overlayCoords[0].y = 0; _overlayCoords[0].u = 0; _overlayCoords[0].v = 0; + _overlayCoords[1].x = 0; _overlayCoords[1].y = 0; _overlayCoords[1].u = u; _overlayCoords[1].v = 0; + _overlayCoords[2].x = 0; _overlayCoords[2].y = 0; _overlayCoords[2].u = 0; _overlayCoords[2].v = v; + _overlayCoords[3].x = 0; _overlayCoords[3].y = 0; _overlayCoords[3].u = u; _overlayCoords[3].v = v; + + _videoContext.overlayTexture.create((uint16) overlayTextureWidthPOT, (uint16) overlayTextureHeightPOT, Graphics::createPixelFormat<5551>()); +} + +- (void)deleteFramebuffer { + glDeleteRenderbuffers(1, &_viewRenderbuffer); + glDeleteFramebuffers(1, &_viewFramebuffer); +} + +- (void)setupVBOs { + glGenBuffers(1, &_vertexBuffer); + glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); +} + +- (void)deleteVBOs { + glDeleteBuffers(1, &_vertexBuffer); +} + +- (GLuint)compileShader:(const char*)shaderPrg withType:(GLenum)shaderType { + GLuint shaderHandle = glCreateShader(shaderType); + + int shaderPrgLength = strlen(shaderPrg); + glShaderSource(shaderHandle, 1, &shaderPrg, &shaderPrgLength); + + glCompileShader(shaderHandle); - _videoContext.overlayWidth = overlayWidth; - _videoContext.overlayHeight = overlayHeight; + GLint compileSuccess; + glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess); + if (compileSuccess == GL_FALSE) { + GLchar messages[256]; + glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]); + NSString *messageString = [NSString stringWithUTF8String:messages]; + NSLog(@"%@", messageString); + exit(1); + } + + return shaderHandle; +} + +- (void)compileShaders { + const char *vertexPrg = + "uniform vec2 ScreenSize;" + "uniform float Shake;" + "" + "attribute vec2 Position;" + "attribute vec2 TexCoord;" + "" + "varying vec4 DestColor;" + "varying vec2 o_TexCoord;" + "" + "void main(void) {" + " DestColor = vec4(Position.x, Position.y, 0, 1);" + " o_TexCoord = TexCoord;" + " gl_Position = vec4((Position.x / ScreenSize.x) * 2.0 - 1.0, (1.0 - (Position.y + Shake) / ScreenSize.y) * 2.0 - 1.0, 0, 1);" + "}"; + + const char *fragmentPrg = + "uniform sampler2D Texture;" + "" + "varying lowp vec4 DestColor;" + "varying lowp vec2 o_TexCoord;" + "" + "void main(void) {" + " gl_FragColor = texture2D(Texture, o_TexCoord);" + "}"; + + _vertexShader = [self compileShader:vertexPrg withType:GL_VERTEX_SHADER]; + _fragmentShader = [self compileShader:fragmentPrg withType:GL_FRAGMENT_SHADER]; + + GLuint programHandle = glCreateProgram(); + glAttachShader(programHandle, _vertexShader); + glAttachShader(programHandle, _fragmentShader); + glLinkProgram(programHandle); + + GLint linkSuccess; + glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess); + if (linkSuccess == GL_FALSE) { + printOpenGLError(); + exit(1); + } + + glUseProgram(programHandle); + + _screenSizeSlot = (GLuint) glGetUniformLocation(programHandle, "ScreenSize"); + _textureSlot = (GLuint) glGetUniformLocation(programHandle, "Texture"); + _shakeSlot = (GLuint) glGetUniformLocation(programHandle, "Shake"); - uint overlayTextureWidthPOT = getSizeNextPOT(overlayWidth); - uint overlayTextureHeightPOT = getSizeNextPOT(overlayHeight); + _positionSlot = (GLuint) glGetAttribLocation(programHandle, "Position"); + _textureCoordSlot = (GLuint) glGetAttribLocation(programHandle, "TexCoord"); - // Since the overlay size won't change the whole run, we can - // precalculate the texture coordinates for the overlay texture here - // and just use it later on. - _overlayTexCoords[2] = _overlayTexCoords[6] = _videoContext.overlayWidth / (GLfloat) overlayTextureWidthPOT; - _overlayTexCoords[5] = _overlayTexCoords[7] = _videoContext.overlayHeight / (GLfloat) overlayTextureHeightPOT; + glEnableVertexAttribArray(_positionSlot); + glEnableVertexAttribArray(_textureCoordSlot); +} - _videoContext.overlayTexture.create(overlayTextureWidthPOT, overlayTextureHeightPOT, Graphics::createPixelFormat<5551>()); +- (void)deleteShaders { + glDeleteShader(_vertexShader); + glDeleteShader(_fragmentShader); +} - glViewport(0, 0, _renderBufferWidth, _renderBufferHeight); printOpenGLError(); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); printOpenGLError(); +- (void)setupTextures { + glGenTextures(1, &_screenTexture); printOpenGLError(); + glGenTextures(1, &_overlayTexture); printOpenGLError(); + glGenTextures(1, &_mouseCursorTexture); printOpenGLError(); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + [self setGraphicsMode]; +} - glEnable(GL_TEXTURE_2D); printOpenGLError(); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); printOpenGLError(); - glEnableClientState(GL_VERTEX_ARRAY); printOpenGLError(); +- (void)deleteTextures { + if (_screenTexture) { + glDeleteTextures(1, &_screenTexture); printOpenGLError(); + _screenTexture = 0; + } + if (_overlayTexture) { + glDeleteTextures(1, &_overlayTexture); printOpenGLError(); + _overlayTexture = 0; + } + if (_mouseCursorTexture) { + glDeleteTextures(1, &_mouseCursorTexture); printOpenGLError(); + _mouseCursorTexture = 0; } } @@ -242,35 +402,9 @@ uint getSizeNextPOT(uint size) { _eventLock = [[NSLock alloc] init]; - _gameScreenVertCoords[0] = _gameScreenVertCoords[1] = - _gameScreenVertCoords[2] = _gameScreenVertCoords[3] = - _gameScreenVertCoords[4] = _gameScreenVertCoords[5] = - _gameScreenVertCoords[6] = _gameScreenVertCoords[7] = 0; - - _gameScreenTexCoords[0] = _gameScreenTexCoords[1] = - _gameScreenTexCoords[2] = _gameScreenTexCoords[3] = - _gameScreenTexCoords[4] = _gameScreenTexCoords[5] = - _gameScreenTexCoords[6] = _gameScreenTexCoords[7] = 0; - - _overlayVertCoords[0] = _overlayVertCoords[1] = - _overlayVertCoords[2] = _overlayVertCoords[3] = - _overlayVertCoords[4] = _overlayVertCoords[5] = - _overlayVertCoords[6] = _overlayVertCoords[7] = 0; - - _overlayTexCoords[0] = _overlayTexCoords[1] = - _overlayTexCoords[2] = _overlayTexCoords[3] = - _overlayTexCoords[4] = _overlayTexCoords[5] = - _overlayTexCoords[6] = _overlayTexCoords[7] = 0; - - _mouseVertCoords[0] = _mouseVertCoords[1] = - _mouseVertCoords[2] = _mouseVertCoords[3] = - _mouseVertCoords[4] = _mouseVertCoords[5] = - _mouseVertCoords[6] = _mouseVertCoords[7] = 0; - - _mouseTexCoords[0] = _mouseTexCoords[1] = - _mouseTexCoords[2] = _mouseTexCoords[3] = - _mouseTexCoords[4] = _mouseTexCoords[5] = - _mouseTexCoords[6] = _mouseTexCoords[7] = 0; + memset(_gameScreenCoords, 0, sizeof(GLVertex) * 4); + memset(_overlayCoords, 0, sizeof(GLVertex) * 4); + memset(_mouseCoords, 0, sizeof(GLVertex) * 4); // Initialize the OpenGL ES context [self createContext]; @@ -292,106 +426,105 @@ uint getSizeNextPOT(uint size) { [super dealloc]; } -#if 0 -- (void)drawRect:(CGRect)frame { - if (g_lastTick == 0) { - g_lastTick = time(0); - } - - g_frames++; - if (time(0) > g_lastTick) { - g_lastTick = time(0); - printf("FPS: %i\n", g_frames); - g_frames = 0; - } -} -#endif - - (void)setFilterModeForTexture:(GLuint)tex { if (!tex) return; + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); printOpenGLError(); GLint filter = GL_LINEAR; + + switch (_videoContext.graphicsMode) { + case kGraphicsModeNone: + filter = GL_NEAREST; + break; + + case kGraphicsModeLinear: + case kGraphicsMode2xSaI: + case kGraphicsModeSuper2xSaI: + case kGraphicsModeSuperEagle: + case kGraphicsModeAdvMame2x: + case kGraphicsModeAdvMame3x: + case kGraphicsModeHQ2x: + case kGraphicsModeHQ3x: + case kGraphicsModeTV2x: + case kGraphicsModeDotMatrix: + filter = GL_LINEAR; + break; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); printOpenGLError(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); printOpenGLError(); + // We use GL_CLAMP_TO_EDGE here to avoid artifacts when linear filtering + // is used. If we would not use this for example the cursor in Loom would + // have a line/border artifact on the right side of the covered rect. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); printOpenGLError(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); printOpenGLError(); +} + +- (void)setScaler { ScalerProc *scaler = NULL; int scalerScale = 1; switch (_videoContext.graphicsMode) { case kGraphicsModeLinear: - filter = GL_LINEAR; break; case kGraphicsModeNone: - filter = GL_NEAREST; break; #ifdef USE_SCALERS case kGraphicsMode2xSaI: - filter = GL_LINEAR; scaler = _2xSaI; scalerScale = 2; break; case kGraphicsModeSuper2xSaI: - filter = GL_LINEAR; scaler = Super2xSaI; scalerScale = 2; break; case kGraphicsModeSuperEagle: - filter = GL_LINEAR; scaler = SuperEagle; scalerScale = 2; break; case kGraphicsModeAdvMame2x: - filter = GL_LINEAR; scaler = AdvMame2x; scalerScale = 2; break; case kGraphicsModeAdvMame3x: - filter = GL_LINEAR; scaler = AdvMame3x; scalerScale = 3; break; #ifdef USE_HQ_SCALERS case kGraphicsModeHQ2x: - filter = GL_LINEAR; scaler = HQ2x; scalerScale = 2; break; case kGraphicsModeHQ3x: - filter = GL_LINEAR; scaler = HQ3x; scalerScale = 3; break; #endif case kGraphicsModeTV2x: - filter = GL_LINEAR; scaler = TV2x; scalerScale = 2; break; case kGraphicsModeDotMatrix: - filter = GL_LINEAR; scaler = DotMatrix; scalerScale = 2; break; - #endif - } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); printOpenGLError(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); printOpenGLError(); - // We use GL_CLAMP_TO_EDGE here to avoid artifacts when linear filtering - // is used. If we would not use this for example the cursor in Loom would - // have a line/border artifact on the right side of the covered rect. - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); printOpenGLError(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); printOpenGLError(); + default: + break; + } _scaler = scaler; _scalerScale = scalerScale; @@ -401,6 +534,7 @@ uint getSizeNextPOT(uint size) { [self setFilterModeForTexture:_screenTexture]; [self setFilterModeForTexture:_overlayTexture]; [self setFilterModeForTexture:_mouseCursorTexture]; + [self setScaler]; } - (void)updateSurface { @@ -419,19 +553,18 @@ uint getSizeNextPOT(uint size) { if (_videoContext.mouseIsVisible) [self updateMouseSurface]; - glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); - [_context presentRenderbuffer:GL_RENDERBUFFER_OES]; - + [_context presentRenderbuffer:GL_RENDERBUFFER]; + glFinish(); } - (void)notifyMouseMove { const GLint mouseX = (GLint)(_videoContext.mouseX * _mouseScaleX) - _mouseHotspotX; const GLint mouseY = (GLint)(_videoContext.mouseY * _mouseScaleY) - _mouseHotspotY; - _mouseVertCoords[0] = _mouseVertCoords[4] = mouseX; - _mouseVertCoords[1] = _mouseVertCoords[3] = mouseY; - _mouseVertCoords[2] = _mouseVertCoords[6] = mouseX + _mouseWidth; - _mouseVertCoords[5] = _mouseVertCoords[7] = mouseY + _mouseHeight; + _mouseCoords[0].x = _mouseCoords[2].x = mouseX; + _mouseCoords[0].y = _mouseCoords[1].y = mouseY; + _mouseCoords[1].x = _mouseCoords[3].x = mouseX + _mouseWidth; + _mouseCoords[2].y = _mouseCoords[3].y = mouseY + _mouseHeight; } - (void)updateMouseCursorScaling { @@ -476,25 +609,23 @@ uint getSizeNextPOT(uint size) { } - (void)updateMouseCursor { - if (_mouseCursorTexture == 0) { - glGenTextures(1, &_mouseCursorTexture); printOpenGLError(); - [self setFilterModeForTexture:_mouseCursorTexture]; - } - [self updateMouseCursorScaling]; - _mouseTexCoords[2] = _mouseTexCoords[6] = _videoContext.mouseWidth / (GLfloat)_videoContext.mouseTexture.w; - _mouseTexCoords[5] = _mouseTexCoords[7] = _videoContext.mouseHeight / (GLfloat)_videoContext.mouseTexture.h; + _mouseCoords[1].u = _mouseCoords[3].u = _videoContext.mouseWidth / (GLfloat)_videoContext.mouseTexture.w; + _mouseCoords[2].v = _mouseCoords[3].v = _videoContext.mouseHeight / (GLfloat)_videoContext.mouseTexture.h; - glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); + [self setFilterModeForTexture:_mouseCursorTexture]; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.mouseTexture.w, _videoContext.mouseTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.mouseTexture.getPixels()); printOpenGLError(); + glUniform1i(_textureSlot, 0); printOpenGLError(); } - (void)updateMainSurface { - glVertexPointer(2, GL_FLOAT, 0, _gameScreenVertCoords); printOpenGLError(); - glTexCoordPointer(2, GL_FLOAT, 0, _gameScreenTexCoords); printOpenGLError(); + glBufferData(GL_ARRAY_BUFFER, sizeof(GLVertex) * 4, _gameScreenCoords, GL_STATIC_DRAW); + glVertexAttribPointer(_positionSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), 0); + glVertexAttribPointer(_textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), (GLvoid *) (sizeof(GLfloat) * 2)); - glBindTexture(GL_TEXTURE_2D, _screenTexture); printOpenGLError(); + [self setFilterModeForTexture:_screenTexture]; + glUniform1i(_textureSlot, 0); printOpenGLError(); // Unfortunately we have to update the whole texture every frame, since glTexSubImage2D is actually slower in all cases // due to the iPhone internals having to convert the whole texture back from its internal format when used. @@ -512,16 +643,16 @@ uint getSizeNextPOT(uint size) { } // Clear two lines before - memset(_scalerMemorySrc, 0, _videoContext.screenTexture.pitch * 2); + memset(_scalerMemorySrc, 0, (size_t) (_videoContext.screenTexture.pitch * 2)); // Copy original buffer memcpy(_scalerMemorySrc + _videoContext.screenTexture.pitch * 2, _videoContext.screenTexture.getPixels(), _videoContext.screenTexture.pitch * _videoContext.screenTexture.h); // Clear two lines after - memset(_scalerMemorySrc + _videoContext.screenTexture.pitch * (2 + _videoContext.screenTexture.h), 0, _videoContext.screenTexture.pitch * 2); + memset(_scalerMemorySrc + _videoContext.screenTexture.pitch * (2 + _videoContext.screenTexture.h), 0, (size_t) (_videoContext.screenTexture.pitch * 2)); // Apply scaler _scaler(_scalerMemorySrc + _videoContext.screenTexture.pitch * 2, _videoContext.screenTexture.pitch, _scalerMemoryDst, - (uint32) (_videoContext.screenTexture.pitch * _scalerScale), + (uint32) (_videoContext.screenTexture.pitch * _scalerScale), _videoContext.screenTexture.w, _videoContext.screenTexture.h); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w * _scalerScale, _videoContext.screenTexture.h * _scalerScale, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _scalerMemoryDst); printOpenGLError(); @@ -529,23 +660,30 @@ uint getSizeNextPOT(uint size) { else { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w, _videoContext.screenTexture.h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _videoContext.screenTexture.getPixels()); printOpenGLError(); } + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); } - (void)updateOverlaySurface { - glVertexPointer(2, GL_FLOAT, 0, _overlayVertCoords); printOpenGLError(); - glTexCoordPointer(2, GL_FLOAT, 0, _overlayTexCoords); printOpenGLError(); + glBufferData(GL_ARRAY_BUFFER, sizeof(GLVertex) * 4, _overlayCoords, GL_STATIC_DRAW); + glVertexAttribPointer(_positionSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), 0); + glVertexAttribPointer(_textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), (GLvoid *) (sizeof(GLfloat) * 2)); + + [self setFilterModeForTexture:_overlayTexture]; + glUniform1i(_textureSlot, 0); printOpenGLError(); - glBindTexture(GL_TEXTURE_2D, _overlayTexture); printOpenGLError(); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.overlayTexture.w, _videoContext.overlayTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.overlayTexture.getPixels()); printOpenGLError(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); } - (void)updateMouseSurface { - glVertexPointer(2, GL_FLOAT, 0, _mouseVertCoords); printOpenGLError(); - glTexCoordPointer(2, GL_FLOAT, 0, _mouseTexCoords); printOpenGLError(); + glBufferData(GL_ARRAY_BUFFER, sizeof(GLVertex) * 4, _mouseCoords, GL_STATIC_DRAW); + glVertexAttribPointer(_positionSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), 0); + glVertexAttribPointer(_textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), (GLvoid *) (sizeof(GLfloat) * 2)); glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); + glUniform1i(_textureSlot, 0); printOpenGLError(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); } @@ -553,80 +691,33 @@ uint getSizeNextPOT(uint size) { const uint screenTexWidth = getSizeNextPOT(_videoContext.screenWidth); const uint screenTexHeight = getSizeNextPOT(_videoContext.screenHeight); - _gameScreenTexCoords[2] = _gameScreenTexCoords[6] = _videoContext.screenWidth / (GLfloat)screenTexWidth; - _gameScreenTexCoords[5] = _gameScreenTexCoords[7] = _videoContext.screenHeight / (GLfloat)screenTexHeight; + _gameScreenCoords[1].u = _gameScreenCoords[3].u = _videoContext.screenWidth / (GLfloat)screenTexWidth; + _gameScreenCoords[2].v = _gameScreenCoords[3].v = _videoContext.screenHeight / (GLfloat)screenTexHeight; - _videoContext.screenTexture.create(screenTexWidth, screenTexHeight, Graphics::createPixelFormat<565>()); + _videoContext.screenTexture.create((uint16) screenTexWidth, (uint16) screenTexHeight, Graphics::createPixelFormat<565>()); } - (void)initSurface { if (_context) { - glDeleteTextures(1, &_screenTexture); printOpenGLError(); - glDeleteTextures(1, &_overlayTexture); printOpenGLError(); - - glDeleteRenderbuffersOES(1, &_viewRenderbuffer); - glDeleteFramebuffersOES(1, &_viewFramebuffer); - - glGenFramebuffersOES(1, &_viewFramebuffer); printOpenGLError(); - glGenRenderbuffersOES(1, &_viewRenderbuffer); printOpenGLError(); - - glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); printOpenGLError(); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); - [_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id)self.layer]; - - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); - - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &_renderBufferWidth); printOpenGLError(); - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &_renderBufferHeight); printOpenGLError(); - - if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { - NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); - return; - } - - glViewport(0, 0, _renderBufferWidth, _renderBufferHeight); printOpenGLError(); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); printOpenGLError(); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glEnable(GL_TEXTURE_2D); printOpenGLError(); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); printOpenGLError(); - glEnableClientState(GL_VERTEX_ARRAY); printOpenGLError(); + [self rebuildFrameBuffer]; } BOOL isLandscape = (self.bounds.size.width > self.bounds.size.height); // UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]); -// glMatrixMode(GL_PROJECTION); -// glLoadIdentity(); - int screenWidth, screenHeight; if (isLandscape) { screenWidth = MAX(_renderBufferWidth, _renderBufferHeight); screenHeight = MIN(_renderBufferWidth, _renderBufferHeight); -// glOrthof(0, screenWidth, screenHeight, 0, 0, 1); printOpenGLError(); } else { screenWidth = MIN(_renderBufferWidth, _renderBufferHeight); screenHeight = MAX(_renderBufferWidth, _renderBufferHeight); -// glOrthof(0, screenHeight, screenWidth, 0, 0, 1); printOpenGLError(); } - glGenTextures(1, &_screenTexture); printOpenGLError(); - [self setFilterModeForTexture:_screenTexture]; - - glGenTextures(1, &_overlayTexture); printOpenGLError(); - [self setFilterModeForTexture:_overlayTexture]; - - glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); + glBindRenderbuffer(GL_RENDERBUFFER, _viewRenderbuffer); printOpenGLError(); [self clearColorBuffer]; -// if (_keyboardView != nil) { -// [_keyboardView removeFromSuperview]; -// [[_keyboardView inputView] removeFromSuperview]; -// } - GLfloat adjustedWidth = _videoContext.screenWidth; GLfloat adjustedHeight = _videoContext.screenHeight; if (_videoContext.asprectRatioCorrection) { @@ -688,34 +779,24 @@ uint getSizeNextPOT(uint size) { } _overlayRect = CGRectMake(0, 0, screenWidth, screenHeight * overlayPortraitRatio); - _gameScreenVertCoords[0] = _gameScreenVertCoords[4] = CGRectGetMinX(_gameScreenRect); - _gameScreenVertCoords[1] = _gameScreenVertCoords[3] = CGRectGetMinY(_gameScreenRect); - _gameScreenVertCoords[2] = _gameScreenVertCoords[6] = CGRectGetMaxX(_gameScreenRect); - _gameScreenVertCoords[5] = _gameScreenVertCoords[7] = CGRectGetMaxY(_gameScreenRect); + _gameScreenCoords[0].x = _gameScreenCoords[2].x = CGRectGetMinX(_gameScreenRect); + _gameScreenCoords[0].y = _gameScreenCoords[1].y = CGRectGetMinY(_gameScreenRect); + _gameScreenCoords[1].x = _gameScreenCoords[3].x = CGRectGetMaxX(_gameScreenRect); + _gameScreenCoords[2].y = _gameScreenCoords[3].y = CGRectGetMaxY(_gameScreenRect); - _overlayVertCoords[2] = _overlayVertCoords[6] = CGRectGetMaxX(_overlayRect); - _overlayVertCoords[5] = _overlayVertCoords[7] = CGRectGetMaxY(_overlayRect); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrthof(0, screenWidth, screenHeight, 0, 0, 1); + _overlayCoords[1].x = _overlayCoords[3].x = CGRectGetMaxX(_overlayRect); + _overlayCoords[2].y = _overlayCoords[3].y = CGRectGetMaxY(_overlayRect); [self setViewTransformation]; [self updateMouseCursorScaling]; } - (void)setViewTransformation { - // Set the modelview matrix. This matrix will be used for the shake offset - // support. - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - // Scale the shake offset according to the overlay size. We need this to // adjust the overlay mouse click coordinates when an offset is set. _scaledShakeOffsetY = (int)(_videoContext.shakeOffsetY / (GLfloat)_videoContext.screenHeight * CGRectGetHeight(_overlayRect)); - // Apply the shakeing to the output screen. - glTranslatef(0, -_scaledShakeOffsetY, 0); + glUniform1f(_shakeSlot, _scaledShakeOffsetY); } - (void)clearColorBuffer { @@ -723,7 +804,8 @@ uint getSizeNextPOT(uint size) { int clearCount = 5; while (clearCount-- > 0) { glClear(GL_COLOR_BUFFER_BIT); printOpenGLError(); - [_context presentRenderbuffer:GL_RENDERBUFFER_OES]; + [_context presentRenderbuffer:GL_RENDERBUFFER]; + glFinish(); } } @@ -748,7 +830,7 @@ uint getSizeNextPOT(uint size) { - (bool)getMouseCoords:(CGPoint)point eventX:(int *)x eventY:(int *)y { // We scale the input according to our scale factor to get actual screen - // cooridnates. + // coordinates. point.x *= _contentScaleFactor; point.y *= _contentScaleFactor; -- cgit v1.2.3 From cfcd3842ed0b46c1eeb7d1e490a882e5d3f26441 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Thu, 10 Dec 2015 18:44:31 +0100 Subject: IOS: Adds iPhone 6/6+ launch screens --- backends/platform/ios7/iOS7AppDelegate.mm | 6 +++--- backends/platform/ios7/ios7_video.h | 1 - backends/platform/ios7/ios7_video.mm | 7 +++---- 3 files changed, 6 insertions(+), 8 deletions(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/iOS7AppDelegate.mm b/backends/platform/ios7/iOS7AppDelegate.mm index 0f645e5055..d664f91ccc 100644 --- a/backends/platform/ios7/iOS7AppDelegate.mm +++ b/backends/platform/ios7/iOS7AppDelegate.mm @@ -30,7 +30,7 @@ } - (void)applicationDidFinishLaunching:(UIApplication *)application { - CGRect rect = [[UIScreen mainScreen] bounds]; + CGRect rect = [[UIScreen mainScreen] bounds]; // Create the directory for savegames #ifdef IPHONE_OFFICIAL @@ -63,11 +63,11 @@ [NSThread detachNewThreadSelector:@selector(mainLoop:) toTarget:self withObject:nil]; } -- (void)applicationDidEnterBackground:(UIApplication *)application { +- (void)applicationWillResignActive:(UIApplication *)application { [_view applicationSuspend]; } -- (void)applicationWillEnterForeground:(UIApplication *)application { +- (void)applicationDidBecomeActive:(UIApplication *)application { [_view applicationResume]; } diff --git a/backends/platform/ios7/ios7_video.h b/backends/platform/ios7/ios7_video.h index bed552c7cf..799cd21a94 100644 --- a/backends/platform/ios7/ios7_video.h +++ b/backends/platform/ios7/ios7_video.h @@ -84,7 +84,6 @@ typedef struct { GLfloat _mouseScaleX, _mouseScaleY; int _scaledShakeOffsetY; - CGFloat _contentScaleFactor; UITouch *_firstTouch; UITouch *_secondTouch; diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm index fe2285253c..300ab044a7 100644 --- a/backends/platform/ios7/ios7_video.mm +++ b/backends/platform/ios7/ios7_video.mm @@ -380,8 +380,7 @@ uint getSizeNextPOT(uint size) { g_fullWidth = (int)MAX(frame.size.width, frame.size.height); g_fullHeight = (int)MIN(frame.size.width, frame.size.height); - _contentScaleFactor = [[UIScreen mainScreen] scale]; - [self setContentScaleFactor:_contentScaleFactor]; + [self setContentScaleFactor:[[UIScreen mainScreen] scale]]; _scalerMemorySrc = NULL; _scalerMemoryDst = NULL; @@ -831,8 +830,8 @@ uint getSizeNextPOT(uint size) { - (bool)getMouseCoords:(CGPoint)point eventX:(int *)x eventY:(int *)y { // We scale the input according to our scale factor to get actual screen // coordinates. - point.x *= _contentScaleFactor; - point.y *= _contentScaleFactor; + point.x *= self.contentScaleFactor; + point.y *= self.contentScaleFactor; CGRect *area; int width, height, offsetY; -- cgit v1.2.3 From dcfe197317ccd026e5ae25f048826800aa3288b4 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Thu, 10 Dec 2015 18:54:49 +0100 Subject: IOS: Info on Linux toolchain, and compilation instructions --- backends/platform/ios7/README.md | 93 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 4 deletions(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/README.md b/backends/platform/ios7/README.md index 88084b8d96..8061c84502 100644 --- a/backends/platform/ios7/README.md +++ b/backends/platform/ios7/README.md @@ -37,12 +37,97 @@ You are ready to compile ScummVM: open the **scummvm.xcodeproj** project, and bu ### Compilation from command line ### -For jailbroken devices, it is also possible to compile the project from command line. You'll need some tools, like **ldid**, to fake the code signature. +For jailbroken devices, it is also possible to compile the project from command line. You'll need a working toolchain, and some tools, like **ldid**, to fake the code signature. -Open a terminal, and execute the following commands: +Here is a script to download, and compile all the required tools. This script has been wrote for Debian 8.2, and should be run as root. + +``` +#!/bin/bash + +if [ $UID -ne 0 ]; then + echo "This script should be run by the root user" + exit 1 +fi + +# Install the Clang compiler +apt-get install -y clang-3.4 libclang-3.4-dev llvm-3.4 libtool bison flex automake subversion git pkg-config wget libssl-dev uuid-dev libxml2-dev || exit 1 + +# Add LLVM to the linker library path +echo /usr/lib/llvm-3.4/lib > /etc/ld.so.conf.d/libllvm-3.4.conf +ldconfig + +# Add symlinks for the LLVM headers +ln -s /usr/lib/llvm-3.4/bin/llvm-config /usr/bin/llvm-config || exit 1 +ln -s /usr/include/llvm-3.4/llvm /usr/include/llvm || exit 1 +ln -s /usr/include/llvm-c-3.4/llvm-c /usr/include/llvm-c || exit 1 +ln -s /usr/bin/clang-3.4 /usr/bin/clang || exit 1 +ln -s /usr/bin/clang++-3.4 /usr/bin/clang++ || exit 1 + +# Build the linker +svn checkout http://ios-toolchain-based-on-clang-for-linux.googlecode.com/svn/trunk/cctools-porting || exit 1 +cd cctools-porting +sed -i'' 's/proz -k=20 --no-curses/wget/g' cctools-ld64.sh +./cctools-ld64.sh || exit 1 + +cd cctools-855-ld64-236.3 +./autogen.sh || exit 1 +./configure --prefix=/usr/local --target=arm-apple-darwin11 || exit 1 +make || exit 1 +make install || exit 1 +cd ../.. + +# Install ios-tools +wget https://ios-toolchain-based-on-clang-for-linux.googlecode.com/files/iphonesdk-utils-2.0.tar.gz || exit 1 +tar xzf iphonesdk-utils-2.0.tar.gz +cd iphonesdk-utils-2.0 +patch -p0 <<_EOF +*** genLocalization2/getLocalizedStringFromFile.cpp 2015-04-02 04:45:39.309837816 +0530 +--- genLocalization2/getLocalizedStringFromFile.cpp 2015-04-02 04:45:11.525700021 +0530 +*************** +*** 113,115 **** + clang::HeaderSearch headerSearch(headerSearchOptions, +- fileManager, + *pDiagnosticsEngine, +--- 113,115 ---- + clang::HeaderSearch headerSearch(headerSearchOptions, ++ sourceManager, + *pDiagnosticsEngine, +*************** +*** 129,134 **** + false); +- clang::HeaderSearch headerSearch(fileManager, + *pDiagnosticsEngine, + languageOptions, +- pTargetInfo); + ApplyHeaderSearchOptions(headerSearch, headerSearchOptions, languageOptions, pTargetInfo->getTriple()); +--- 129,134 ---- + false); ++ clang::HeaderSearch headerSearch(fileManager);/*, + *pDiagnosticsEngine, + languageOptions, ++ pTargetInfo);*/ + ApplyHeaderSearchOptions(headerSearch, headerSearchOptions, languageOptio +_EOF + +./autogen.sh || exit 1 +CC=clang CXX=clang++ ./configure --prefix=/usr/local || exit 1 +make || exit 1 +make install || exit 1 + +# Install the iOS SDK 8.1 +mkdir -p /usr/share/ios-sdk +cd /usr/share/ios-sdk +wget http://iphone.howett.net/sdks/dl/iPhoneOS8.1.sdk.tbz2 || exit 1 +tar xjf iPhoneOS8.1.sdk.tbz2 +rm iPhoneOS8.1.sdk.tbz2 +``` + +Now, in order to compile ScummVM, execute the following commands: ``` -$ cd path_to_the_scummvm_sources -$ SDKROOT=$(xcrun --sdk iphoneos --show-sdk-path) CC=clang CXX=clang++ ./configure --host=ios7 --disable-scalers --disable-mt32emu --enable-release +$ export SDKROOT=/usr/share/ios-sdk/iPhoneOS8.1.sdk +$ export CC=ios-clang +$ export CXX=ios-clang++ +$ ./configure --host=ios7 --disable-mt32emu --enable-release $ make ios7bundle ``` -- cgit v1.2.3 From 8d9b13059b82ea4b8a38203c34c4939abc0feb25 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Fri, 11 Dec 2015 10:39:39 +0100 Subject: IOS: Updates compilation instructions --- backends/platform/ios7/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/README.md b/backends/platform/ios7/README.md index 8061c84502..b93ba20133 100644 --- a/backends/platform/ios7/README.md +++ b/backends/platform/ios7/README.md @@ -20,7 +20,7 @@ The next step is to compile the **create_project** tool. Open the Xcode project Execute the following commands in a terminal: ``` $ cd path_to_the_build_directory -$ create_project path_to_scummvm_repository --xcode --disable-mad --disable-jpeg --disable-bink --disable-16bit --disable-mt32emu --disable-nasm --disable-opengl --disable-theora --disable-taskbar +$ create_project path_to_scummvm_repository --xcode --disable-jpeg --disable-bink --disable-16bit --disable-mt32emu --disable-nasm --disable-opengl --disable-theora --disable-taskbar ``` This will create an Xcode project for ScummVM, for both the OS X, and the iOS target. -- cgit v1.2.3 From c99456ecff9ae645385ea5a8aa423d0115dce08e Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Fri, 11 Dec 2015 14:24:29 +0100 Subject: IOS: Brings support for FluidSynth --- backends/platform/ios7/ios7_osys_main.cpp | 15 +++++++++++---- backends/platform/ios7/ios7_osys_main.h | 5 +++++ backends/platform/ios7/ios7_osys_video.mm | 32 +++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/ios7_osys_main.cpp b/backends/platform/ios7/ios7_osys_main.cpp index 76739423c1..cb712b9c38 100644 --- a/backends/platform/ios7/ios7_osys_main.cpp +++ b/backends/platform/ios7/ios7_osys_main.cpp @@ -25,6 +25,7 @@ #include #include +#include #include @@ -80,7 +81,7 @@ OSystem_iOS7::OSystem_iOS7() : _screenOrientation(kScreenOrientationFlippedLandscape), _mouseClickAndDragEnabled(false), _gestureStartX(-1), _gestureStartY(-1), _fullScreenIsDirty(false), _fullScreenOverlayIsDirty(false), _mouseDirty(false), _timeSuspended(0), _lastDragPosX(-1), _lastDragPosY(-1), _screenChangeCount(0), - _mouseCursorPaletteEnabled(false), _gfxTransactionError(kTransactionSuccess) { + _lastErrorMessage(NULL), _mouseCursorPaletteEnabled(false), _gfxTransactionError(kTransactionSuccess) { _queuedInputEvent.type = Common::EVENT_INVALID; _touchpadModeEnabled = !iOS7_isBigDevice(); #ifdef IPHONE_OFFICIAL @@ -275,8 +276,9 @@ Audio::Mixer *OSystem_iOS7::getMixer() { return _mixer; } -OSystem *OSystem_iOS7_create() { - return new OSystem_iOS7(); +OSystem_iOS7 *OSystem_iOS7::sharedInstance() { + static OSystem_iOS7 *instance = new OSystem_iOS7(); + return instance; } Common::String OSystem_iOS7::getDefaultConfigFileName() { @@ -318,6 +320,11 @@ void OSystem_iOS7::logMessage(LogMessageType::Type type, const char *message) { else output = stderr; + if (type == LogMessageType::kError) { + free(_lastErrorMessage); + _lastErrorMessage = strdup(message); + } + fputs(message, output); fflush(output); } @@ -353,7 +360,7 @@ void iOS7_main(int argc, char **argv) { chdir("/var/mobile/"); #endif - g_system = OSystem_iOS7_create(); + g_system = OSystem_iOS7::sharedInstance(); assert(g_system); // Invoke the actual ScummVM main entry point: diff --git a/backends/platform/ios7/ios7_osys_main.h b/backends/platform/ios7/ios7_osys_main.h index 26b147e2a1..eadb49e5ac 100644 --- a/backends/platform/ios7/ios7_osys_main.h +++ b/backends/platform/ios7/ios7_osys_main.h @@ -109,11 +109,15 @@ protected: bool _fullScreenOverlayIsDirty; int _screenChangeCount; + char *_lastErrorMessage; + public: OSystem_iOS7(); virtual ~OSystem_iOS7(); + static OSystem_iOS7 *sharedInstance(); + virtual void initBackend(); virtual bool hasFeature(Feature f); @@ -192,6 +196,7 @@ public: virtual Common::String getDefaultConfigFileName(); virtual void logMessage(LogMessageType::Type type, const char *message); + virtual void fatalError() override; protected: void initVideoContext(); diff --git a/backends/platform/ios7/ios7_osys_video.mm b/backends/platform/ios7/ios7_osys_video.mm index 7cce56c800..0d183ce834 100644 --- a/backends/platform/ios7/ios7_osys_video.mm +++ b/backends/platform/ios7/ios7_osys_video.mm @@ -29,6 +29,38 @@ #include "graphics/conversion.h" #import "iOS7AppDelegate.h" +@interface iOS7AlertHandler : NSObject +@end + +@implementation iOS7AlertHandler + +- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex { + OSystem_iOS7::sharedInstance()->quit(); + exit(1); +} + +@end + +static void displayAlert(void *ctx) { + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Fatal Error" + message:[NSString stringWithCString:(const char *)ctx encoding:NSUTF8StringEncoding] + delegate:[[iOS7AlertHandler alloc] init] + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; + [alert show]; + [alert autorelease]; +} + +void OSystem_iOS7::fatalError() { + if (_lastErrorMessage) { + dispatch_async_f(dispatch_get_main_queue(), _lastErrorMessage, displayAlert); + for(;;); + } + else { + OSystem::fatalError(); + } +} + void OSystem_iOS7::initVideoContext() { _videoContext = [[iOS7AppDelegate iPhoneView] getVideoContext]; } -- cgit v1.2.3 From 71b2fa9b49f2f492448c2b2f351fceaa8ff4d34f Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Fri, 11 Dec 2015 14:41:30 +0100 Subject: IOS: Fixes an issue with the mouse pointer when returning from Sam&Max --- backends/platform/ios7/ios7_video.mm | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm index 300ab044a7..3a3feafcf8 100644 --- a/backends/platform/ios7/ios7_video.mm +++ b/backends/platform/ios7/ios7_video.mm @@ -304,6 +304,8 @@ uint getSizeNextPOT(uint size) { glEnableVertexAttribArray(_positionSlot); glEnableVertexAttribArray(_textureCoordSlot); + + glUniform1i(_textureSlot, 0); printOpenGLError(); } - (void)deleteShaders { @@ -610,12 +612,11 @@ uint getSizeNextPOT(uint size) { - (void)updateMouseCursor { [self updateMouseCursorScaling]; - _mouseCoords[1].u = _mouseCoords[3].u = _videoContext.mouseWidth / (GLfloat)_videoContext.mouseTexture.w; - _mouseCoords[2].v = _mouseCoords[3].v = _videoContext.mouseHeight / (GLfloat)_videoContext.mouseTexture.h; + _mouseCoords[1].u = _mouseCoords[3].u = (_videoContext.mouseWidth - 1) / (GLfloat)_videoContext.mouseTexture.w; + _mouseCoords[2].v = _mouseCoords[3].v = (_videoContext.mouseHeight - 1) / (GLfloat)_videoContext.mouseTexture.h; [self setFilterModeForTexture:_mouseCursorTexture]; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.mouseTexture.w, _videoContext.mouseTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.mouseTexture.getPixels()); printOpenGLError(); - glUniform1i(_textureSlot, 0); printOpenGLError(); } - (void)updateMainSurface { @@ -624,7 +625,6 @@ uint getSizeNextPOT(uint size) { glVertexAttribPointer(_textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), (GLvoid *) (sizeof(GLfloat) * 2)); [self setFilterModeForTexture:_screenTexture]; - glUniform1i(_textureSlot, 0); printOpenGLError(); // Unfortunately we have to update the whole texture every frame, since glTexSubImage2D is actually slower in all cases // due to the iPhone internals having to convert the whole texture back from its internal format when used. @@ -669,7 +669,6 @@ uint getSizeNextPOT(uint size) { glVertexAttribPointer(_textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), (GLvoid *) (sizeof(GLfloat) * 2)); [self setFilterModeForTexture:_overlayTexture]; - glUniform1i(_textureSlot, 0); printOpenGLError(); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.overlayTexture.w, _videoContext.overlayTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.overlayTexture.getPixels()); printOpenGLError(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); @@ -681,7 +680,6 @@ uint getSizeNextPOT(uint size) { glVertexAttribPointer(_textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), (GLvoid *) (sizeof(GLfloat) * 2)); glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); - glUniform1i(_textureSlot, 0); printOpenGLError(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); } -- cgit v1.2.3 From 1657b9d4326d7749d4e5b6928364416c3936a726 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Fri, 11 Dec 2015 14:43:59 +0100 Subject: IOS: Update compilation instructions for FluidSynth --- backends/platform/ios7/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/README.md b/backends/platform/ios7/README.md index b93ba20133..1f34c15cc6 100644 --- a/backends/platform/ios7/README.md +++ b/backends/platform/ios7/README.md @@ -20,7 +20,7 @@ The next step is to compile the **create_project** tool. Open the Xcode project Execute the following commands in a terminal: ``` $ cd path_to_the_build_directory -$ create_project path_to_scummvm_repository --xcode --disable-jpeg --disable-bink --disable-16bit --disable-mt32emu --disable-nasm --disable-opengl --disable-theora --disable-taskbar +$ create_project path_to_scummvm_repository --xcode --enable-fluidsynth --disable-jpeg --disable-bink --disable-16bit --disable-mt32emu --disable-nasm --disable-opengl --disable-theora --disable-taskbar ``` This will create an Xcode project for ScummVM, for both the OS X, and the iOS target. -- cgit v1.2.3 From fae79955e5ce6e215dcf457059c5744a85c76a80 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Fri, 11 Dec 2015 15:25:48 +0100 Subject: IOS: Better emulation of the right mouse button --- backends/platform/ios7/ios7_osys_main.cpp | 9 +++------ backends/platform/ios7/ios7_video.mm | 10 ++++++++++ 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/ios7_osys_main.cpp b/backends/platform/ios7/ios7_osys_main.cpp index cb712b9c38..cd62148ca9 100644 --- a/backends/platform/ios7/ios7_osys_main.cpp +++ b/backends/platform/ios7/ios7_osys_main.cpp @@ -28,6 +28,7 @@ #include #include +#include #include "common/scummsys.h" #include "common/util.h" @@ -196,12 +197,8 @@ void OSystem_iOS7::suspendLoop() { } uint32 OSystem_iOS7::getMillis(bool skipRecord) { - //printf("getMillis()\n"); - - struct timeval currentTime; - gettimeofday(¤tTime, NULL); - return (uint32)(((currentTime.tv_sec - _startTime.tv_sec) * 1000) + - ((currentTime.tv_usec - _startTime.tv_usec) / 1000)) - _timeSuspended; + CFTimeInterval timeInSeconds = CACurrentMediaTime(); + return (uint32) (timeInSeconds * 1000.0); } void OSystem_iOS7::delayMillis(uint msecs) { diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm index 3a3feafcf8..e3c3edf06b 100644 --- a/backends/platform/ios7/ios7_video.mm +++ b/backends/platform/ios7/ios7_video.mm @@ -340,22 +340,32 @@ uint getSizeNextPOT(uint size) { UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeRight:)]; swipeRight.direction = UISwipeGestureRecognizerDirectionRight; swipeRight.numberOfTouchesRequired = 2; + swipeRight.delaysTouchesBegan = NO; + swipeRight.delaysTouchesEnded = NO; UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeLeft:)]; swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft; swipeLeft.numberOfTouchesRequired = 2; + swipeLeft.delaysTouchesBegan = NO; + swipeLeft.delaysTouchesEnded = NO; UISwipeGestureRecognizer *swipeUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeUp:)]; swipeUp.direction = UISwipeGestureRecognizerDirectionUp; swipeUp.numberOfTouchesRequired = 2; + swipeUp.delaysTouchesBegan = NO; + swipeUp.delaysTouchesEnded = NO; UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeDown:)]; swipeDown.direction = UISwipeGestureRecognizerDirectionDown; swipeDown.numberOfTouchesRequired = 2; + swipeDown.delaysTouchesBegan = NO; + swipeDown.delaysTouchesEnded = NO; UITapGestureRecognizer *doubleTapTwoFingers = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersDoubleTap:)]; doubleTapTwoFingers.numberOfTapsRequired = 2; doubleTapTwoFingers.numberOfTouchesRequired = 2; + doubleTapTwoFingers.delaysTouchesBegan = NO; + doubleTapTwoFingers.delaysTouchesEnded = NO; [self addGestureRecognizer:swipeRight]; [self addGestureRecognizer:swipeLeft]; -- cgit v1.2.3 From a522c82f853a50163bd36fc64234f9a6c6c0b395 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Wed, 6 Jan 2016 08:33:56 +0100 Subject: IOS: Removes a useless variable --- backends/platform/ios7/ios7_video.mm | 6 ------ 1 file changed, 6 deletions(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm index e3c3edf06b..78e7dc254c 100644 --- a/backends/platform/ios7/ios7_video.mm +++ b/backends/platform/ios7/ios7_video.mm @@ -29,9 +29,6 @@ #include "common/system.h" #import "iOS7AppDelegate.h" -static int g_fullWidth; -static int g_fullHeight; - static int g_needsScreenUpdate = 0; #if 0 @@ -389,9 +386,6 @@ uint getSizeNextPOT(uint size) { [self setupGestureRecognizers]; - g_fullWidth = (int)MAX(frame.size.width, frame.size.height); - g_fullHeight = (int)MIN(frame.size.width, frame.size.height); - [self setContentScaleFactor:[[UIScreen mainScreen] scale]]; _scalerMemorySrc = NULL; -- cgit v1.2.3 From aa77c0c92ddf76fb2284d3df5a75a36bacf0a976 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Wed, 6 Jan 2016 08:41:45 +0100 Subject: IOS: Disable scalers --- backends/platform/ios7/ios7_common.h | 3 +++ backends/platform/ios7/ios7_osys_main.cpp | 3 +++ backends/platform/ios7/ios7_video.h | 2 ++ backends/platform/ios7/ios7_video.mm | 12 ++++++++++++ 4 files changed, 20 insertions(+) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/ios7_common.h b/backends/platform/ios7/ios7_common.h index b7a47eda8a..a32a59a541 100644 --- a/backends/platform/ios7/ios7_common.h +++ b/backends/platform/ios7/ios7_common.h @@ -25,6 +25,9 @@ #include "graphics/surface.h" +// #define ENABLE_IOS7_SCALERS + + enum InputEvent { kInputMouseDown, kInputMouseUp, diff --git a/backends/platform/ios7/ios7_osys_main.cpp b/backends/platform/ios7/ios7_osys_main.cpp index cd62148ca9..d6b9ce3741 100644 --- a/backends/platform/ios7/ios7_osys_main.cpp +++ b/backends/platform/ios7/ios7_osys_main.cpp @@ -54,6 +54,8 @@ const OSystem::GraphicsMode OSystem_iOS7::s_supportedGraphicsModes[] = { { "none", "No filtering", kGraphicsModeNone }, { "linear", "Linear filtering", kGraphicsModeLinear }, + +#ifdef ENABLE_IOS7_SCALERS #ifdef USE_SCALERS // {"2x", "2x", GFX_DOUBLESIZE}, // {"3x", "3x", GFX_TRIPLESIZE}, @@ -68,6 +70,7 @@ const OSystem::GraphicsMode OSystem_iOS7::s_supportedGraphicsModes[] = { #endif {"tv2x", "TV2x", kGraphicsModeTV2x}, {"dotmatrix", "DotMatrix", kGraphicsModeDotMatrix}, +#endif #endif { 0, 0, 0 } }; diff --git a/backends/platform/ios7/ios7_video.h b/backends/platform/ios7/ios7_video.h index 799cd21a94..ab261a977b 100644 --- a/backends/platform/ios7/ios7_video.h +++ b/backends/platform/ios7/ios7_video.h @@ -88,12 +88,14 @@ typedef struct { UITouch *_firstTouch; UITouch *_secondTouch; +#ifdef ENABLE_IOS7_SCALERS uint8_t *_scalerMemorySrc; uint8_t *_scalerMemoryDst; size_t _scalerMemorySrcSize; size_t _scalerMemoryDstSize; int _scalerScale; ScalerProc *_scaler; +#endif } - (id)initWithFrame:(struct CGRect)frame; diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm index 78e7dc254c..2cfc3e05f7 100644 --- a/backends/platform/ios7/ios7_video.mm +++ b/backends/platform/ios7/ios7_video.mm @@ -388,12 +388,14 @@ uint getSizeNextPOT(uint size) { [self setContentScaleFactor:[[UIScreen mainScreen] scale]]; +#ifdef ENABLE_IOS7_SCALERS _scalerMemorySrc = NULL; _scalerMemoryDst = NULL; _scalerMemorySrcSize = 0; _scalerMemoryDstSize = 0; _scaler = NULL; _scalerScale = 1; +#endif _keyboardView = nil; _screenTexture = 0; @@ -424,8 +426,10 @@ uint getSizeNextPOT(uint size) { _videoContext.overlayTexture.free(); _videoContext.mouseTexture.free(); +#ifdef ENABLE_IOS7_SCALERS free(_scalerMemorySrc); free(_scalerMemoryDst); +#endif [_eventLock release]; [super dealloc]; @@ -468,6 +472,7 @@ uint getSizeNextPOT(uint size) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); printOpenGLError(); } +#ifdef ENABLE_IOS7_SCALERS - (void)setScaler { ScalerProc *scaler = NULL; int scalerScale = 1; @@ -534,12 +539,15 @@ uint getSizeNextPOT(uint size) { _scaler = scaler; _scalerScale = scalerScale; } +#endif - (void)setGraphicsMode { [self setFilterModeForTexture:_screenTexture]; [self setFilterModeForTexture:_overlayTexture]; [self setFilterModeForTexture:_mouseCursorTexture]; +#ifdef ENABLE_IOS7_SCALERS [self setScaler]; +#endif } - (void)updateSurface { @@ -633,6 +641,7 @@ uint getSizeNextPOT(uint size) { // Unfortunately we have to update the whole texture every frame, since glTexSubImage2D is actually slower in all cases // due to the iPhone internals having to convert the whole texture back from its internal format when used. // In the future we could use several tiled textures instead. +#ifdef ENABLE_IOS7_SCALERS if (_scaler) { size_t neededSrcMemorySize = (size_t) (_videoContext.screenTexture.pitch * (_videoContext.screenTexture.h + 4)); size_t neededDstMemorySize = (size_t) (_videoContext.screenTexture.pitch * (_videoContext.screenTexture.h + 4) * _scalerScale * _scalerScale); @@ -661,8 +670,11 @@ uint getSizeNextPOT(uint size) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w * _scalerScale, _videoContext.screenTexture.h * _scalerScale, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _scalerMemoryDst); printOpenGLError(); } else { +#endif glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w, _videoContext.screenTexture.h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _videoContext.screenTexture.getPixels()); printOpenGLError(); +#ifdef ENABLE_IOS7_SCALERS } +#endif glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); } -- cgit v1.2.3 From b5ef98637c54a453a6f0ac0ca8c501ceb59924d5 Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Thu, 7 Jan 2016 09:51:13 +0100 Subject: IOS: Renames a macro --- backends/platform/ios7/iOS7AppDelegate.mm | 2 +- backends/platform/ios7/ios7_osys_main.cpp | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'backends/platform/ios7') diff --git a/backends/platform/ios7/iOS7AppDelegate.mm b/backends/platform/ios7/iOS7AppDelegate.mm index d664f91ccc..e9908ec146 100644 --- a/backends/platform/ios7/iOS7AppDelegate.mm +++ b/backends/platform/ios7/iOS7AppDelegate.mm @@ -32,8 +32,8 @@ - (void)applicationDidFinishLaunching:(UIApplication *)application { CGRect rect = [[UIScreen mainScreen] bounds]; +#ifdef IPHONE_SANDBOXED // Create the directory for savegames -#ifdef IPHONE_OFFICIAL NSFileManager *fm = [NSFileManager defaultManager]; NSString *documentPath = [NSString stringWithUTF8String:iOS7_getDocumentsDir()]; NSString *savePath = [documentPath stringByAppendingPathComponent:@"Savegames"]; diff --git a/backends/platform/ios7/ios7_osys_main.cpp b/backends/platform/ios7/ios7_osys_main.cpp index d6b9ce3741..37fa34ce33 100644 --- a/backends/platform/ios7/ios7_osys_main.cpp +++ b/backends/platform/ios7/ios7_osys_main.cpp @@ -88,7 +88,7 @@ OSystem_iOS7::OSystem_iOS7() : _lastErrorMessage(NULL), _mouseCursorPaletteEnabled(false), _gfxTransactionError(kTransactionSuccess) { _queuedInputEvent.type = Common::EVENT_INVALID; _touchpadModeEnabled = !iOS7_isBigDevice(); -#ifdef IPHONE_OFFICIAL +#ifdef IPHONE_SANDBOXED _fsFactory = new ChRootFilesystemFactory(iOS7_getDocumentsDir()); #else _fsFactory = new POSIXFilesystemFactory(); @@ -123,7 +123,7 @@ int OSystem_iOS7::timerHandler(int t) { } void OSystem_iOS7::initBackend() { -#ifdef IPHONE_OFFICIAL +#ifdef IPHONE_SANDBOXED _savefileManager = new DefaultSaveFileManager("/Savegames"); #else _savefileManager = new DefaultSaveFileManager(SCUMMVM_SAVE_PATH); @@ -282,7 +282,7 @@ OSystem_iOS7 *OSystem_iOS7::sharedInstance() { } Common::String OSystem_iOS7::getDefaultConfigFileName() { -#ifdef IPHONE_OFFICIAL +#ifdef IPHONE_SANDBOXED Common::String path = "/Preferences"; return path; #else @@ -299,13 +299,12 @@ void OSystem_iOS7::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) if (CFURLGetFileSystemRepresentation(fileUrl, true, buf, sizeof(buf))) { // Success: Add it to the search path Common::String bundlePath((const char *)buf); -#ifdef IPHONE_OFFICIAL +#ifdef IPHONE_SANDBOXED POSIXFilesystemNode *posixNode = new POSIXFilesystemNode(bundlePath); Common::FSNode *node = new Common::FSNode(posixNode); - s.add("__OSX_BUNDLE__", new Common::FSDirectory(*node), priority); + s.add("__IOS_BUNDLE__", new Common::FSDirectory(*node), priority); #else - // OS X - s.add("__OSX_BUNDLE__", new Common::FSDirectory(bundlePath), priority); + s.add("__IOS_BUNDLE__", new Common::FSDirectory(bundlePath), priority); #endif } CFRelease(fileUrl); @@ -351,7 +350,7 @@ void iOS7_main(int argc, char **argv) { //gDebugLevel = 10; } -#ifdef IPHONE_OFFICIAL +#ifdef IPHONE_SANDBOXED chdir(iOS7_getDocumentsDir()); #else system("mkdir " SCUMMVM_ROOT_PATH); -- cgit v1.2.3