diff options
Diffstat (limited to 'backends/platform/iphone')
-rw-r--r-- | backends/platform/iphone/blit.cpp | 48 | ||||
-rw-r--r-- | backends/platform/iphone/blit_arm.h | 35 | ||||
-rw-r--r-- | backends/platform/iphone/blit_arm.s | 137 | ||||
-rw-r--r-- | backends/platform/iphone/iphone_common.h | 66 | ||||
-rw-r--r-- | backends/platform/iphone/iphone_keyboard.h | 13 | ||||
-rw-r--r-- | backends/platform/iphone/iphone_keyboard.mm (renamed from backends/platform/iphone/iphone_keyboard.m) | 10 | ||||
-rw-r--r-- | backends/platform/iphone/iphone_main.mm (renamed from backends/platform/iphone/iphone_main.m) | 77 | ||||
-rw-r--r-- | backends/platform/iphone/iphone_video.h | 79 | ||||
-rw-r--r-- | backends/platform/iphone/iphone_video.m | 756 | ||||
-rw-r--r-- | backends/platform/iphone/iphone_video.mm | 851 | ||||
-rw-r--r-- | backends/platform/iphone/module.mk | 3 | ||||
-rw-r--r-- | backends/platform/iphone/osys_events.cpp | 401 | ||||
-rw-r--r-- | backends/platform/iphone/osys_main.cpp | 66 | ||||
-rw-r--r-- | backends/platform/iphone/osys_main.h | 71 | ||||
-rw-r--r-- | backends/platform/iphone/osys_video.cpp | 503 | ||||
-rw-r--r-- | backends/platform/iphone/osys_video.mm | 491 |
16 files changed, 1758 insertions, 1849 deletions
diff --git a/backends/platform/iphone/blit.cpp b/backends/platform/iphone/blit.cpp deleted file mode 100644 index 58de22bf75..0000000000 --- a/backends/platform/iphone/blit.cpp +++ /dev/null @@ -1,48 +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 "common/scummsys.h" -#include "blit_arm.h" - -void blitLandscapeScreenRect16bpp(uint16 *dst, uint16 *src, int width, int height, int screenWidth, int screenHeight) -{ - for (int x = width; x > 0; x--) { - for (int y = height; y > 0; y--) { - *(dst++) = *src; - src += screenWidth; - } - dst -= screenHeight + height; - src += 1 - height * screenWidth; - } -} - -void blitLandscapeScreenRect8bpp(uint16 *dst, byte *src, int width, int height, uint16 *palette, int screenWidth, int screenHeight) -{ - for (int x = width; x > 0; x--) { - for (int y = height; y > 0; y--) { - *(dst++) = palette[*src]; - src += screenWidth; - } - dst -= screenHeight + height; - src += 1 - height * screenWidth; - } -} diff --git a/backends/platform/iphone/blit_arm.h b/backends/platform/iphone/blit_arm.h deleted file mode 100644 index 77bb3578ab..0000000000 --- a/backends/platform/iphone/blit_arm.h +++ /dev/null @@ -1,35 +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. - * - */ - -extern "C" void blitLandscapeScreenRect16bpp(uint16 *dst, uint16 *src, - int width, - int height, - int screenWidth, - int screenHeight); - -extern "C" void blitLandscapeScreenRect8bpp(uint16 *dst, - byte *src, - int width, - int height, - uint16 *palette, - int screenWidth, - int screenHeight); diff --git a/backends/platform/iphone/blit_arm.s b/backends/platform/iphone/blit_arm.s deleted file mode 100644 index 04f9a87614..0000000000 --- a/backends/platform/iphone/blit_arm.s +++ /dev/null @@ -1,137 +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. -@ -@ @author Robin Watts (robin@wss.co.uk) - - .text - - .global _blitLandscapeScreenRect16bpp - .global _blitLandscapeScreenRect8bpp - - -_blitLandscapeScreenRect16bpp: - @ r0 = dst - @ r1 = src - @ r2 = w - @ r3 = h - @ <> = _screenWidth - @ <> = _screenHeight - mov r12,r13 - stmfd r13!,{r4-r11,r14} - ldmfd r12,{r12,r14} @ r12 = _screenWidth - @ r14 = _screenHeight - add r14,r14,r3 @ r14 = _screenHeight + h - mvn r11,#0 - mla r11,r3,r12,r11 @ r11= _screenWidth*h-1 - add r12,r12,r12 -xloop: - subs r4,r3,#5 @ r4 = y = h - ble thin -yloop: - ldrh r5, [r1],r12 @ r5 = *src src += _screenWidth - ldrh r6, [r1],r12 @ r6 = *src src += _screenWidth - ldrh r7, [r1],r12 @ r7 = *src src += _screenWidth - ldrh r8, [r1],r12 @ r8 = *src src += _screenWidth - ldrh r9, [r1],r12 @ r9 = *src src += _screenWidth - ldrh r10,[r1],r12 @ r10= *src src += _screenWidth - subs r4,r4,#6 - strh r5, [r0],#2 @ *dst++ = r5 - strh r6, [r0],#2 @ *dst++ = r6 - strh r7, [r0],#2 @ *dst++ = r7 - strh r8, [r0],#2 @ *dst++ = r8 - strh r9, [r0],#2 @ *dst++ = r9 - strh r10,[r0],#2 @ *dst++ = r10 - bgt yloop -thin: - adds r4,r4,#5 - beq lineend -thin_loop: - ldrh r5,[r1],r12 @ r5 = *src src += _screenWidth - subs r4,r4,#1 - strh r5,[r0],#2 @ *dst++ = r5 - bgt thin_loop -lineend: - sub r0,r0,r14,LSL #1 @ dst -= _screenHeight + h - sub r1,r1,r11,LSL #1 @ src += 1-_screenWidth*h - subs r2,r2,#1 - bgt xloop - - ldmfd r13!,{r4-r11,PC} - -_blitLandscapeScreenRect8bpp: - @ r0 = dst - @ r1 = src - @ r2 = w - @ r3 = h - @ <> = _palette - @ <> = _screenWidth - @ <> = _screenHeight - mov r12,r13 - stmfd r13!,{r4-r11,r14} - ldmfd r12,{r11,r12,r14} @ r11 = _palette - @ r12 = _screenWidth - @ r14 = _screenHeight - add r14,r14,r3 @ r14 = _screenHeight + h - mvn r6,#0 - mla r6,r3,r12,r6 @ r6 = _screenWidth*h-1 -xloop8: - mov r4,r3 @ r4 = y = h - subs r4,r3,#4 @ r4 = y = h - ble thin8 -yloop8: - ldrb r5, [r1],r12 @ r5 = *src src += _screenWidth - ldrb r7, [r1],r12 @ r7 = *src src += _screenWidth - ldrb r8, [r1],r12 @ r8 = *src src += _screenWidth - ldrb r9, [r1],r12 @ r9 = *src src += _screenWidth - ldrb r10,[r1],r12 @ r10= *src src += _screenWidth - add r5, r5, r5 - add r7, r7, r7 - add r8, r8, r8 - add r9, r9, r9 - add r10,r10,r10 - ldrh r5, [r11,r5] - ldrh r7, [r11,r7] - ldrh r8, [r11,r8] - ldrh r9, [r11,r9] - ldrh r10,[r11,r10] - subs r4,r4,#5 - strh r5, [r0],#2 @ *dst++ = r5 - strh r7, [r0],#2 @ *dst++ = r7 - strh r8, [r0],#2 @ *dst++ = r8 - strh r9, [r0],#2 @ *dst++ = r9 - strh r10,[r0],#2 @ *dst++ = r10 - bgt yloop8 -thin8: - adds r4,r4,#4 - beq lineend8 -thin_loop8: - ldrb r5,[r1],r12 @ r5 = *src src += _screenWidth - add r5,r5,r5 - ldrh r5,[r11,r5] - subs r4,r4,#1 - strh r5,[r0],#2 @ *dst++ = r5 - bgt thin_loop8 -lineend8: - sub r0,r0,r14,LSL #1 @ dst -= _screenHeight + h - sub r1,r1,r6 @ src += 1-_screenWidth*h - subs r2,r2,#1 - bgt xloop8 - - ldmfd r13!,{r4-r11,PC} diff --git a/backends/platform/iphone/iphone_common.h b/backends/platform/iphone/iphone_common.h index 0cbcb77bcb..19e4f2ce9b 100644 --- a/backends/platform/iphone/iphone_common.h +++ b/backends/platform/iphone/iphone_common.h @@ -20,6 +20,10 @@ * */ +#ifndef BACKENDS_PLATFORM_IPHONE_IPHONE_COMMON_H +#define BACKENDS_PLATFORM_IPHONE_IPHONE_COMMON_H + +#include "graphics/surface.h" enum InputEvent { kInputMouseDown, @@ -41,43 +45,53 @@ enum ScreenOrientation { kScreenOrientationFlippedLandscape }; -typedef enum -{ +enum UIViewSwipeDirection { kUIViewSwipeUp = 1, kUIViewSwipeDown = 2, kUIViewSwipeLeft = 4, kUIViewSwipeRight = 8 -} UIViewSwipeDirection; +}; -#ifdef IPHONE_OFFICIAL -void iphone_main(int argc, char **argv); -#endif +enum GraphicsModes { + kGraphicsModeLinear = 0, + kGraphicsModeNone = 1 +}; -// We need this to be able to call functions from/in Objective-C. -#ifdef __cplusplus -extern "C" { -#endif +struct VideoContext { + VideoContext() : asprectRatioCorrection(), screenWidth(), screenHeight(), overlayVisible(false), + overlayWidth(), overlayHeight(), mouseX(), mouseY(), + mouseHotspotX(), mouseHotspotY(), mouseWidth(), mouseHeight(), + mouseIsVisible(), graphicsMode(kGraphicsModeLinear), shakeOffsetY() { + } -// On the C++ side -#ifndef IPHONE_OFFICIAL -void iphone_main(int argc, char *argv[]); -#endif + // 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; +}; // On the ObjC side -void iPhone_updateScreen(int mouseX, int mouseY); -void iPhone_updateScreenRect(unsigned short* screen, int x1, int y1, int x2, int y2); -void iPhone_updateOverlayRect(unsigned short* screen, int x1, int y1, int x2, int y2); -void iPhone_initSurface(int width, int height); -bool iPhone_fetchEvent(int *outEvent, float *outX, float *outY); -const char* iPhone_getDocumentsDir(); +void iPhone_updateScreen(); +bool iPhone_fetchEvent(int *outEvent, int *outX, int *outY); +const char *iPhone_getDocumentsDir(); bool iPhone_isHighResDevice(); -int iPhone_getScreenHeight(); -int iPhone_getScreenWidth(); -void iPhone_enableOverlay(int state); -void iPhone_setMouseCursor(short* buffer, int width, int height); uint getSizeNextPOT(uint size); -#ifdef __cplusplus -} #endif diff --git a/backends/platform/iphone/iphone_keyboard.h b/backends/platform/iphone/iphone_keyboard.h index eecad09398..2d1238c92f 100644 --- a/backends/platform/iphone/iphone_keyboard.h +++ b/backends/platform/iphone/iphone_keyboard.h @@ -20,17 +20,22 @@ * */ -#import <UIKit/UIKit.h> -#import <UIKit/UITextView.h> +#ifndef BACKENDS_PLATFORM_IPHONE_IPHONE_KEYBOARD_H +#define BACKENDS_PLATFORM_IPHONE_IPHONE_KEYBOARD_H + +#include <UIKit/UIKit.h> +#include <UIKit/UITextView.h> @interface SoftKeyboard : UIView { id inputDelegate; - UITextView* inputView; + UITextView *inputView; } - (id)initWithFrame:(CGRect)frame; -- (UITextView*)inputView; +- (UITextView *)inputView; - (void)setInputDelegate:(id)delegate; - (void)handleKeyPress:(unichar)c; @end + +#endif diff --git a/backends/platform/iphone/iphone_keyboard.m b/backends/platform/iphone/iphone_keyboard.mm index 1624d02977..b00930ab31 100644 --- a/backends/platform/iphone/iphone_keyboard.m +++ b/backends/platform/iphone/iphone_keyboard.mm @@ -20,7 +20,7 @@ * */ -#import "iphone_keyboard.h" +#include "iphone_keyboard.h" @interface UITextInputTraits - (void)setAutocorrectionType:(int)type; @@ -29,17 +29,17 @@ @end @interface TextInputHandler : UITextView { - SoftKeyboard* softKeyboard; + SoftKeyboard *softKeyboard; } -- (id)initWithKeyboard:(SoftKeyboard*)keyboard; +- (id)initWithKeyboard:(SoftKeyboard *)keyboard; @end @implementation TextInputHandler -- (id)initWithKeyboard:(SoftKeyboard*)keyboard; { +- (id)initWithKeyboard:(SoftKeyboard *)keyboard; { self = [super initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.0f)]; softKeyboard = keyboard; @@ -80,7 +80,7 @@ return self; } -- (UITextView*)inputView { +- (UITextView *)inputView { return inputView; } diff --git a/backends/platform/iphone/iphone_main.m b/backends/platform/iphone/iphone_main.mm index c2ec328bf5..e76ffe866e 100644 --- a/backends/platform/iphone/iphone_main.m +++ b/backends/platform/iphone/iphone_main.mm @@ -20,38 +20,41 @@ * */ -#import <UIKit/UIKit.h> -#import <Foundation/NSThread.h> +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include <UIKit/UIKit.h> +#include <Foundation/NSThread.h> #include "iphone_video.h" void iphone_main(int argc, char *argv[]); @interface iPhoneMain : UIApplication { - UIWindow* _window; - iPhoneView* _view; + UIWindow *_window; + iPhoneView *_view; } -- (void) mainLoop: (id)param; -- (iPhoneView*) getView; -- (UIWindow*) getWindow; +- (void)mainLoop:(id)param; +- (iPhoneView *)getView; +- (UIWindow *)getWindow; - (void)didRotate:(NSNotification *)notification; @end -static int gArgc; -static char** gArgv; +static int g_argc; +static char **g_argv; -int main(int argc, char** argv) { - gArgc = argc; - gArgv = argv; +int main(int argc, char **argv) { + g_argc = argc; + g_argv = argv; - NSAutoreleasePool *autoreleasePool = [ - [ NSAutoreleasePool alloc ] init - ]; + NSAutoreleasePool *autoreleasePool = [ + [NSAutoreleasePool alloc] init + ]; - int returnCode = UIApplicationMain(argc, argv, @"iPhoneMain", @"iPhoneMain"); - [ autoreleasePool release ]; - return returnCode; + int returnCode = UIApplicationMain(argc, argv, @"iPhoneMain", @"iPhoneMain"); + [autoreleasePool release]; + return returnCode; } @implementation iPhoneMain @@ -63,14 +66,14 @@ int main(int argc, char** argv) { return self; } -- (void) mainLoop: (id)param { +- (void)mainLoop:(id)param { [[NSAutoreleasePool alloc] init]; - iphone_main(gArgc, gArgv); + iphone_main(g_argc, g_argv); exit(0); } -- (iPhoneView*) getView { +- (iPhoneView *)getView { return _view; } @@ -78,38 +81,36 @@ int main(int argc, char** argv) { CGRect rect = [[UIScreen mainScreen] bounds]; // hide the status bar - [application setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:NO]; - [application setStatusBarHidden:YES animated:YES]; + [application setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:NO]; + [application setStatusBarHidden:YES animated:YES]; _window = [[UIWindow alloc] initWithFrame:rect]; [_window retain]; - _view = [[iPhoneView alloc] initWithFrame: rect]; + _view = [[iPhoneView alloc] initWithFrame:rect]; _view.multipleTouchEnabled = YES; - [_window setContentView: _view]; + [_window setContentView:_view]; [_window addSubview:_view]; [_window makeKeyAndVisible]; [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(didRotate:) - name:@"UIDeviceOrientationDidChangeNotification" object:nil]; + selector:@selector(didRotate:) + name:@"UIDeviceOrientationDidChangeNotification" + object:nil]; [NSThread detachNewThreadSelector:@selector(mainLoop:) toTarget:self withObject:nil]; } -- (void)applicationDidResume -{ +- (void)applicationDidResume { } -- (void)applicationWillSuspend -{ +- (void)applicationWillSuspend { } -- (void)applicationWillTerminate -{ +- (void)applicationWillTerminate { } - (void)applicationSuspend:(struct __GSEvent *)event { @@ -122,14 +123,14 @@ int main(int argc, char** argv) { // Workaround, need to "hide" and unhide the statusbar to properly remove it, // since the Springboard has put it back without apparently flagging our application. - [self setStatusBarHidden:YES animated:YES]; - [self setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:NO]; - [self setStatusBarHidden:YES animated:YES]; + [self setStatusBarHidden:YES animated:YES]; + [self setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:NO]; + [self setStatusBarHidden:YES animated:YES]; } - (void)didRotate:(NSNotification *)notification { - int screenOrientation = [[UIDevice currentDevice] orientation]; - [_view deviceOrientationChanged: screenOrientation]; + UIDeviceOrientation screenOrientation = [[UIDevice currentDevice] orientation]; + [_view deviceOrientationChanged:screenOrientation]; } - (UIWindow*) getWindow { diff --git a/backends/platform/iphone/iphone_video.h b/backends/platform/iphone/iphone_video.h index 223f025978..1405fe35f1 100644 --- a/backends/platform/iphone/iphone_video.h +++ b/backends/platform/iphone/iphone_video.h @@ -20,48 +20,69 @@ * */ -#ifndef _IPHONE_VIDEO__H -#define _IPHONE_VIDEO__H +#ifndef BACKENDS_PLATFORM_IPHONE_IPHONE_VIDEO_H +#define BACKENDS_PLATFORM_IPHONE_IPHONE_VIDEO_H -#import <UIKit/UIKit.h> -#import <Foundation/Foundation.h> -#import <QuartzCore/QuartzCore.h> +#include <UIKit/UIKit.h> +#include <Foundation/Foundation.h> +#include <QuartzCore/QuartzCore.h> -#import <OpenGLES/EAGL.h> -#import <OpenGLES/ES1/gl.h> -#import <OpenGLES/ES1/glext.h> +#include <OpenGLES/EAGL.h> +#include <OpenGLES/ES1/gl.h> +#include <OpenGLES/ES1/glext.h> -#import "iphone_keyboard.h" +#include "iphone_keyboard.h" +#include "iphone_common.h" -@interface iPhoneView : UIView -{ - void* _screenSurface; - NSMutableArray* _events; - SoftKeyboard* _keyboardView; - CALayer* _screenLayer; +@interface iPhoneView : UIView { + VideoContext _videoContext; - int _widthOffset; - int _heightOffset; + NSMutableArray *_events; + SoftKeyboard *_keyboardView; - EAGLContext* _context; + EAGLContext *_context; GLuint _viewRenderbuffer; GLuint _viewFramebuffer; - GLint _backingWidth; - GLint _backingHeight; - GLint _visibleWidth; - GLint _visibleHeight; GLuint _screenTexture; GLuint _overlayTexture; GLuint _mouseCursorTexture; + + UIDeviceOrientation _orientation; + + 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; + + UITouch *_firstTouch; + UITouch *_secondTouch; } - (id)initWithFrame:(struct CGRect)frame; -- (void)drawRect:(CGRect)frame; +- (VideoContext *)getVideoContext; -- (void *)getSurface; +- (void)drawRect:(CGRect)frame; +- (void)createScreenTexture; - (void)initSurface; +- (void)setViewTransformation; + +- (void)setGraphicsMode; - (void)updateSurface; - (void)updateMainSurface; @@ -69,11 +90,13 @@ - (void)updateMouseSurface; - (void)clearColorBuffer; --(void)updateMouseCursor; +- (void)notifyMouseMove; +- (void)updateMouseCursorScaling; +- (void)updateMouseCursor; - (id)getEvent; -- (void)deviceOrientationChanged:(int)orientation; +- (void)deviceOrientationChanged:(UIDeviceOrientation)orientation; - (void)applicationSuspend; @@ -81,6 +104,6 @@ @end +extern iPhoneView *g_iPhoneViewInstance; - -#endif /* _IPHONE_VIDEO__H */ +#endif diff --git a/backends/platform/iphone/iphone_video.m b/backends/platform/iphone/iphone_video.m deleted file mode 100644 index eb16676428..0000000000 --- a/backends/platform/iphone/iphone_video.m +++ /dev/null @@ -1,756 +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_video.h" -#include "iphone_common.h" - -static iPhoneView *sharedInstance = nil; -static int _width = 0; -static int _height = 0; -static int _fullWidth; -static int _fullHeight; -static CGRect _screenRect; - -static char* _textureBuffer = 0; -static int _textureWidth = 0; -static int _textureHeight = 0; - -static char* _overlayTexBuffer = 0; -static int _overlayTexWidth = 0; -static int _overlayTexHeight = 0; -static int _overlayWidth = 0; -static int _overlayHeight = 0; -static float _overlayPortraitRatio = 1.0f; - -NSLock* _lock = nil; -static int _needsScreenUpdate = 0; -static int _overlayIsEnabled = 0; - -static UITouch* _firstTouch = NULL; -static UITouch* _secondTouch = NULL; - -static short* _mouseCursor = NULL; -static int _mouseCursorHeight = 0; -static int _mouseCursorWidth = 0; -static int _mouseX = 0; -static int _mouseY = 0; - -// static long lastTick = 0; -// static int frames = 0; - -#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; -} - -void iPhone_setMouseCursor(short* buffer, int width, int height) { - _mouseCursor = buffer; - - _mouseCursorWidth = width; - _mouseCursorHeight = height; - - [sharedInstance performSelectorOnMainThread:@selector(updateMouseCursor) withObject:nil waitUntilDone: YES]; -} - -void iPhone_enableOverlay(int state) { - _overlayIsEnabled = state; - - [sharedInstance performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES]; -} - -int iPhone_getScreenHeight() { - return _overlayHeight; -} - -int iPhone_getScreenWidth() { - return _overlayWidth; -} - -bool iPhone_isHighResDevice() { - return _fullHeight > 480; -} - -void iPhone_updateScreen(int mouseX, int mouseY) { - //printf("Mouse: (%i, %i)\n", mouseX, mouseY); - - //_mouseX = _overlayHeight - (float)mouseX / _width * _overlayHeight; - //_mouseY = (float)mouseY / _height * _overlayWidth; - - //_mouseX = _overlayHeight - mouseX; - //_mouseY = mouseY; - - _mouseX = (_overlayWidth - mouseX) / (float)_overlayWidth * _overlayHeight; - _mouseY = mouseY / (float)_overlayHeight * _overlayWidth; - - if (!_needsScreenUpdate) { - _needsScreenUpdate = 1; - [sharedInstance performSelectorOnMainThread:@selector(updateSurface) withObject:nil waitUntilDone: NO]; - } -} - -void iPhone_updateScreenRect(unsigned short* screen, int x1, int y1, int x2, int y2) { - int y; - for (y = y1; y < y2; ++y) - memcpy(&_textureBuffer[(y * _textureWidth + x1 )* 2], &screen[y * _width + x1], (x2 - x1) * 2); -} - -void iPhone_updateOverlayRect(unsigned short* screen, int x1, int y1, int x2, int y2) { - int y; - //printf("Overlaywidth: %u, fullwidth %u\n", _overlayWidth, _fullWidth); - for (y = y1; y < y2; ++y) - memcpy(&_overlayTexBuffer[(y * _overlayTexWidth + x1 )* 2], &screen[y * _overlayWidth + x1], (x2 - x1) * 2); -} - -void iPhone_initSurface(int width, int height) { - _width = width; - _height = height; - [sharedInstance performSelectorOnMainThread:@selector(initSurface) withObject:nil waitUntilDone: YES]; -} - -bool iPhone_fetchEvent(int *outEvent, float *outX, float *outY) { - id event = [sharedInstance getEvent]; - if (event == nil) { - return false; - } - - id type = [event objectForKey:@"type"]; - - if (type == nil) { - printf("fetchEvent says: No type!\n"); - return false; - } - - *outEvent = [type intValue]; - *outX = [[event objectForKey:@"x"] floatValue]; - *outY = [[event objectForKey:@"y"] floatValue]; - return true; -} - -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]; -} - -bool getLocalMouseCoords(CGPoint *point) { - if (_overlayIsEnabled) { - point->x = point->x / _overlayHeight; - point->y = point->y / _overlayWidth; - } else { - if (point->x < _screenRect.origin.x || point->x >= _screenRect.origin.x + _screenRect.size.width || - point->y < _screenRect.origin.y || point->y >= _screenRect.origin.y + _screenRect.size.height) { - return false; - } - - point->x = (point->x - _screenRect.origin.x) / _screenRect.size.width; - point->y = (point->y - _screenRect.origin.y) / _screenRect.size.height; - } - - return true; -} - - -@implementation iPhoneView - -+ (Class) layerClass -{ - return [CAEAGLLayer class]; -} - -- (id)initWithFrame:(struct CGRect)frame { - self = [super initWithFrame: frame]; - - if([[UIScreen mainScreen] respondsToSelector: NSSelectorFromString(@"scale")]) - { - if([self respondsToSelector: NSSelectorFromString(@"contentScaleFactor")]) - { - //self.contentScaleFactor = [[UIScreen mainScreen] scale]; - } - } - - _fullWidth = frame.size.width; - _fullHeight = frame.size.height; - _screenLayer = nil; - - sharedInstance = self; - - _lock = [NSLock new]; - _keyboardView = nil; - _context = nil; - _screenTexture = 0; - _overlayTexture = 0; - _mouseCursorTexture = 0; - - return self; -} - --(void) dealloc { - [super dealloc]; - - if (_keyboardView != nil) { - [_keyboardView dealloc]; - } - - if (_screenTexture) - free(_textureBuffer); - - free(_overlayTexBuffer); -} - -- (void *)getSurface { - return _screenSurface; -} - -- (void)drawRect:(CGRect)frame { - // if (lastTick == 0) { - // lastTick = time(0); - // } - // - // frames++; - // if (time(0) > lastTick) { - // lastTick = time(0); - // printf("FPS: %i\n", frames); - // frames = 0; - // } -} - -- (void)updateSurface { - if (!_needsScreenUpdate) { - return; - } - _needsScreenUpdate = 0; - - if (_overlayIsEnabled) { - glClear(GL_COLOR_BUFFER_BIT); printOpenGLError(); - } - - [self updateMainSurface]; - - if (_overlayIsEnabled) { - [self updateOverlaySurface]; - [self updateMouseSurface]; - } - - glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); - [_context presentRenderbuffer:GL_RENDERBUFFER_OES]; - -} - --(void)updateMouseCursor { - if (_mouseCursorTexture == 0) { - glGenTextures(1, &_mouseCursorTexture); printOpenGLError(); - glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); printOpenGLError(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); printOpenGLError(); - } - - glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getSizeNextPOT(_mouseCursorWidth), getSizeNextPOT(_mouseCursorHeight), 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _mouseCursor); printOpenGLError(); - - free(_mouseCursor); - _mouseCursor = NULL; -} - -- (void)updateMainSurface { - GLfloat vertices[] = { - 0.0f + _heightOffset, 0.0f + _widthOffset, - _visibleWidth - _heightOffset, 0.0f + _widthOffset, - 0.0f + _heightOffset, _visibleHeight - _widthOffset, - _visibleWidth - _heightOffset, _visibleHeight - _widthOffset - }; - - float texWidth = _width / (float)_textureWidth; - float texHeight = _height / (float)_textureHeight; - - const GLfloat texCoords[] = { - texWidth, 0.0f, - 0.0f, 0.0f, - texWidth, texHeight, - 0.0f, texHeight - }; - - glVertexPointer(2, GL_FLOAT, 0, vertices); printOpenGLError(); - glTexCoordPointer(2, GL_FLOAT, 0, texCoords); 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, _textureWidth, _textureHeight, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _textureBuffer); printOpenGLError(); - glDisable(GL_BLEND); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); -} - -- (void)updateOverlaySurface { - GLfloat vertices[] = { - 0.0f, 0.0f, - _overlayHeight, 0.0f, - 0.0f, _overlayWidth * _overlayPortraitRatio, - _overlayHeight, _overlayWidth * _overlayPortraitRatio - }; - - float texWidth = _overlayWidth / (float)_overlayTexWidth; - float texHeight = _overlayHeight / (float)_overlayTexHeight; - - const GLfloat texCoords[] = { - texWidth, 0.0f, - 0.0f, 0.0f, - texWidth, texHeight, - 0.0f, texHeight - }; - - glVertexPointer(2, GL_FLOAT, 0, vertices); printOpenGLError(); - glTexCoordPointer(2, GL_FLOAT, 0, texCoords); printOpenGLError(); - - glBindTexture(GL_TEXTURE_2D, _overlayTexture); printOpenGLError(); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _overlayTexWidth, _overlayTexHeight, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _overlayTexBuffer); printOpenGLError(); - glEnable(GL_BLEND); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); -} - -- (void)updateMouseSurface { - - int width = _mouseCursorWidth / (float)_backingWidth * _backingHeight; - int height = _mouseCursorHeight / (float)_backingHeight * _backingWidth; - - GLfloat vertices[] = { - _mouseX, _mouseY, - _mouseX + height, _mouseY, - _mouseX, _mouseY + width, - _mouseX + height, _mouseY + width - }; - - //printf("Cursor: width %u height %u\n", _mouseCursorWidth, _mouseCursorHeight); - - float texWidth = _mouseCursorWidth / (float)getSizeNextPOT(_mouseCursorWidth); - float texHeight = _mouseCursorHeight / (float)getSizeNextPOT(_mouseCursorHeight); - - const GLfloat texCoords[] = { - texWidth, 0.0f, - 0.0f, 0.0f, - texWidth, texHeight, - 0.0f, texHeight - }; - - glVertexPointer(2, GL_FLOAT, 0, vertices); printOpenGLError(); - glTexCoordPointer(2, GL_FLOAT, 0, texCoords); printOpenGLError(); - - glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); - glEnable(GL_BLEND); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); -} - -- (void)initSurface { - _textureWidth = getSizeNextPOT(_width); - _textureHeight = getSizeNextPOT(_height); - - UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; - - //printf("Window: (%d, %d), Surface: (%d, %d), Texture(%d, %d)\n", _fullWidth, _fullHeight, _width, _height, _textureWidth, _textureHeight); - - if (_context == nil) { - orientation = UIDeviceOrientationLandscapeRight; - CAEAGLLayer *eaglLayer = (CAEAGLLayer*) self.layer; - - eaglLayer.opaque = YES; - eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGB565, kEAGLDrawablePropertyColorFormat, nil]; - - _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; - if (!_context || [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<EAGLDrawable>)self.layer]; - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); - - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &_backingWidth); printOpenGLError(); - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &_backingHeight); printOpenGLError(); - - if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { - NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); - return; - } - - _overlayHeight = _backingWidth; - _overlayWidth = _backingHeight; - _overlayTexWidth = getSizeNextPOT(_overlayHeight); - _overlayTexHeight = getSizeNextPOT(_overlayWidth); - - int textureSize = _overlayTexWidth * _overlayTexHeight * 2; - _overlayTexBuffer = (char *)malloc(textureSize); - memset(_overlayTexBuffer, 0, textureSize); - - glViewport(0, 0, _backingWidth, _backingHeight); printOpenGLError(); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); printOpenGLError(); - - 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(); - } - } - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - if (orientation == UIDeviceOrientationLandscapeRight) { - glRotatef(-90, 0, 0, 1); printOpenGLError(); - } else if (orientation == UIDeviceOrientationLandscapeLeft) { - glRotatef(90, 0, 0, 1); printOpenGLError(); - } else { - glRotatef(180, 0, 0, 1); printOpenGLError(); - } - - glOrthof(0, _backingWidth, 0, _backingHeight, 0, 1); printOpenGLError(); - - if (_screenTexture > 0) { - glDeleteTextures(1, &_screenTexture); printOpenGLError(); - } - - glGenTextures(1, &_screenTexture); printOpenGLError(); - glBindTexture(GL_TEXTURE_2D, _screenTexture); printOpenGLError(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); printOpenGLError(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); printOpenGLError(); - - if (_overlayTexture > 0) { - glDeleteTextures(1, &_overlayTexture); printOpenGLError(); - } - - glGenTextures(1, &_overlayTexture); printOpenGLError(); - glBindTexture(GL_TEXTURE_2D, _overlayTexture); printOpenGLError(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); printOpenGLError(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); printOpenGLError(); - - if (_textureBuffer) { - free(_textureBuffer); - } - - int textureSize = _textureWidth * _textureHeight * 2; - _textureBuffer = (char*)malloc(textureSize); - memset(_textureBuffer, 0, textureSize); - - glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); - - [self clearColorBuffer]; - - if (_keyboardView != nil) { - [_keyboardView removeFromSuperview]; - [[_keyboardView inputView] removeFromSuperview]; - } - - if (orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight) { - _visibleHeight = _backingHeight; - _visibleWidth = _backingWidth; - - float ratioDifference = ((float)_height / (float)_width) / ((float)_fullWidth / (float)_fullHeight); - int rectWidth, rectHeight; - if (ratioDifference < 1.0f) { - rectWidth = _fullWidth * ratioDifference; - rectHeight = _fullHeight; - _widthOffset = (_fullWidth - rectWidth) / 2; - _heightOffset = 0; - } else { - rectWidth = _fullWidth; - rectHeight = _fullHeight / ratioDifference; - _heightOffset = (_fullHeight - rectHeight) / 2; - _widthOffset = 0; - } - - //printf("Rect: %i, %i, %i, %i\n", _widthOffset, _heightOffset, rectWidth, rectHeight); - _screenRect = CGRectMake(_widthOffset, _heightOffset, rectWidth, rectHeight); - _overlayPortraitRatio = 1.0f; - } else { - float ratio = (float)_height / (float)_width; - int height = _fullWidth * ratio; - //printf("Making rect (%u, %u)\n", _fullWidth, height); - _screenRect = CGRectMake(0, 0, _fullWidth - 1, height - 1); - - _visibleHeight = height; - _visibleWidth = _backingWidth; - _heightOffset = 0.0f; - _widthOffset = 0.0f; - - 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 inputView] becomeFirstResponder]; - _overlayPortraitRatio = (_overlayHeight * ratio) / _overlayWidth; - } -} - -- (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]; - } -} - -- (id)getEvent { - if (_events == nil || [_events count] == 0) { - return nil; - } - - - id event = [_events objectAtIndex: 0]; - - [_events removeObjectAtIndex: 0]; - - return event; -} - -- (void)addEvent:(NSDictionary*)event { - - if (_events == nil) - _events = [[NSMutableArray alloc] init]; - - [_events addObject: event]; -} - -- (void)deviceOrientationChanged:(int)orientation { - [self addEvent: - [[NSDictionary alloc] initWithObjectsAndKeys: - [NSNumber numberWithInt:kInputOrientationChanged], @"type", - [NSNumber numberWithFloat:(float)orientation], @"x", - [NSNumber numberWithFloat:0], @"y", - nil - ] - ]; -} - -- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event -{ - NSSet *allTouches = [event allTouches]; - - switch ([allTouches count]) { - case 1: - { - UITouch *touch = [touches anyObject]; - CGPoint point = [touch locationInView:self]; - if (!getLocalMouseCoords(&point)) - return; - - _firstTouch = touch; - [self addEvent: - [[NSDictionary alloc] initWithObjectsAndKeys: - [NSNumber numberWithInt:kInputMouseDown], @"type", - [NSNumber numberWithFloat:point.x], @"x", - [NSNumber numberWithFloat:point.y], @"y", - nil - ] - ]; - break; - } - case 2: - { - UITouch *touch = [touches anyObject]; - CGPoint point = [touch locationInView:self]; - if (!getLocalMouseCoords(&point)) - return; - - _secondTouch = touch; - [self addEvent: - [[NSDictionary alloc] initWithObjectsAndKeys: - [NSNumber numberWithInt:kInputMouseSecondDown], @"type", - [NSNumber numberWithFloat:point.x], @"x", - [NSNumber numberWithFloat:point.y], @"y", - nil - ] - ]; - break; - } - } -} - -- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event -{ - //NSSet *allTouches = [event allTouches]; - - for (UITouch* touch in touches) { - if (touch == _firstTouch) { - - CGPoint point = [touch locationInView:self]; - if (!getLocalMouseCoords(&point)) - return; - - [self addEvent: - [[NSDictionary alloc] initWithObjectsAndKeys: - [NSNumber numberWithInt:kInputMouseDragged], @"type", - [NSNumber numberWithFloat:point.x], @"x", - [NSNumber numberWithFloat:point.y], @"y", - nil - ] - ]; - - } else if (touch == _secondTouch) { - - CGPoint point = [touch locationInView:self]; - if (!getLocalMouseCoords(&point)) - return; - - [self addEvent: - [[NSDictionary alloc] initWithObjectsAndKeys: - [NSNumber numberWithInt:kInputMouseSecondDragged], @"type", - [NSNumber numberWithFloat:point.x], @"x", - [NSNumber numberWithFloat:point.y], @"y", - nil - ] - ]; - - } - } -} - -- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event -{ - NSSet *allTouches = [event allTouches]; - - switch ([allTouches count]) { - case 1: - { - UITouch *touch = [[allTouches allObjects] objectAtIndex:0]; - CGPoint point = [touch locationInView:self]; - if (!getLocalMouseCoords(&point)) - return; - - [self addEvent: - [[NSDictionary alloc] initWithObjectsAndKeys: - [NSNumber numberWithInt:kInputMouseUp], @"type", - [NSNumber numberWithFloat:point.x], @"x", - [NSNumber numberWithFloat:point.y], @"y", - nil - ] - ]; - break; - } - case 2: - { - UITouch *touch = [[allTouches allObjects] objectAtIndex:1]; - CGPoint point = [touch locationInView:self]; - if (!getLocalMouseCoords(&point)) - return; - - [self addEvent: - [[NSDictionary alloc] initWithObjectsAndKeys: - [NSNumber numberWithInt:kInputMouseSecondUp], @"type", - [NSNumber numberWithFloat:point.x], @"x", - [NSNumber numberWithFloat:point.y], @"y", - nil - ] - ]; - break; - } - } -} - -- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event -{ - -} - -- (void)handleKeyPress:(unichar)c { - [self addEvent: - [[NSDictionary alloc] initWithObjectsAndKeys: - [NSNumber numberWithInt:kInputKeyPressed], @"type", - [NSNumber numberWithFloat:(float)c], @"x", - [NSNumber numberWithFloat:0], @"y", - nil - ] - ]; -} - -- (BOOL)canHandleSwipes { - return TRUE; -} - -- (int)swipe:(int)num withEvent:(struct __GSEvent *)event { - //printf("swipe: %i\n", num); - - [self addEvent: - [[NSDictionary alloc] initWithObjectsAndKeys: - [NSNumber numberWithInt:kInputSwipe], @"type", - [NSNumber numberWithFloat:(float)num], @"x", - [NSNumber numberWithFloat:0], @"y", - nil - ] - ]; -} - -- (void)applicationSuspend { - [self addEvent: - [[NSDictionary alloc] initWithObjectsAndKeys: - [NSNumber numberWithInt:kInputApplicationSuspended], @"type", - [NSNumber numberWithFloat:0], @"x", - [NSNumber numberWithFloat:0], @"y", - nil - ] - ]; -} - -- (void)applicationResume { - [self addEvent: - [[NSDictionary alloc] initWithObjectsAndKeys: - [NSNumber numberWithInt:kInputApplicationResumed], @"type", - [NSNumber numberWithFloat:0], @"x", - [NSNumber numberWithFloat:0], @"y", - nil - ] - ]; -} - -@end diff --git a/backends/platform/iphone/iphone_video.mm b/backends/platform/iphone/iphone_video.mm new file mode 100644 index 0000000000..5b78237ff7 --- /dev/null +++ b/backends/platform/iphone/iphone_video.mm @@ -0,0 +1,851 @@ +/* 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" + +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 + +#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(int *outEvent, int *outX, int *outY) { + id event = [g_iPhoneViewInstance getEvent]; + if (event == nil) { + return false; + } + + id type = [event objectForKey:@"type"]; + + if (type == nil) { + printf("fetchEvent says: No type!\n"); + return false; + } + + *outEvent = [type intValue]; + *outX = [[event objectForKey:@"x"] intValue]; + *outY = [[event objectForKey:@"y"] intValue]; + return true; +} + +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 = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGB565, kEAGLDrawablePropertyColorFormat, nil]; + + _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<EAGLDrawable>)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; + } + + _videoContext.overlayHeight = _renderBufferWidth; + _videoContext.overlayWidth = _renderBufferHeight; + uint overlayTextureWidth = getSizeNextPOT(_videoContext.overlayHeight); + uint overlayTextureHeight = getSizeNextPOT(_videoContext.overlayWidth); + + // 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(); + } +} + +- (id)initWithFrame:(struct CGRect)frame { + self = [super initWithFrame: frame]; + + if ([[UIScreen mainScreen] respondsToSelector: NSSelectorFromString(@"scale")]) { + if ([self respondsToSelector: NSSelectorFromString(@"contentScaleFactor")]) { + //self.contentScaleFactor = [[UIScreen mainScreen] scale]; + } + } + + g_fullWidth = (int)frame.size.width; + g_fullHeight = (int)frame.size.height; + + g_iPhoneViewInstance = self; + + _keyboardView = nil; + _screenTexture = 0; + _overlayTexture = 0; + _mouseCursorTexture = 0; + + _scaledShakeOffsetY = 0; + + _firstTouch = NULL; + _secondTouch = NULL; + + _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(); + + [super dealloc]; +} + +- (void)drawRect:(CGRect)frame { +#if 0 + 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(); +} + +- (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.pixels); 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.pixels); 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.pixels); 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)setUpOrientation:(UIDeviceOrientation)orientation width:(int *)width height:(int *)height { + _orientation = orientation; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + // We always force the origin (0,0) to be in the upper left corner. + switch (_orientation) { + case UIDeviceOrientationLandscapeRight: + glRotatef( 90, 0, 0, 1); printOpenGLError(); + glOrthof(0, _renderBufferHeight, _renderBufferWidth, 0, 0, 1); printOpenGLError(); + + *width = _renderBufferHeight; + *height = _renderBufferWidth; + break; + + case UIDeviceOrientationLandscapeLeft: + glRotatef(-90, 0, 0, 1); printOpenGLError(); + glOrthof(0, _renderBufferHeight, _renderBufferWidth, 0, 0, 1); printOpenGLError(); + + *width = _renderBufferHeight; + *height = _renderBufferWidth; + break; + + case UIDeviceOrientationPortrait: + default: + // We must force the portrait orientation here, since we might not know + // the real orientation. + _orientation = UIDeviceOrientationPortrait; + + glOrthof(0, _renderBufferWidth, _renderBufferHeight, 0, 0, 1); printOpenGLError(); + + *width = _renderBufferWidth; + *height = _renderBufferHeight; + break; + } +} + +- (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 { + int screenWidth, screenHeight; + [self setUpOrientation:[[UIDevice currentDevice] orientation] width:&screenWidth height:&screenHeight]; + + if (_screenTexture > 0) { + glDeleteTextures(1, &_screenTexture); printOpenGLError(); + } + + glGenTextures(1, &_screenTexture); printOpenGLError(); + [self setFilterModeForTexture:_screenTexture]; + + if (_overlayTexture > 0) { + glDeleteTextures(1, &_overlayTexture); printOpenGLError(); + } + + 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 (_orientation == UIDeviceOrientationLandscapeLeft || _orientation == UIDeviceOrientationLandscapeRight) { + 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; + } + + //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 inputView] becomeFirstResponder]; + 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); + + [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]; + } +} + +- (id)getEvent { + if (_events == nil || [_events count] == 0) { + return nil; + } + + id event = [_events objectAtIndex: 0]; + + [_events removeObjectAtIndex: 0]; + + return event; +} + +- (void)addEvent:(NSDictionary *)event { + if (_events == nil) + _events = [[NSMutableArray alloc] init]; + + [_events addObject: event]; +} + +/** + * Converts portrait mode coordinates into rotated mode coordinates. + */ +- (bool)convertToRotatedCoords:(CGPoint)point result:(CGPoint *)result { + switch (_orientation) { + case UIDeviceOrientationLandscapeLeft: + result->x = point.y; + result->y = _renderBufferWidth - point.x; + return true; + + case UIDeviceOrientationLandscapeRight: + result->x = _renderBufferHeight - point.y; + result->y = point.x; + return true; + + case UIDeviceOrientationPortrait: + result->x = point.x; + result->y = point.y; + return true; + + default: + return false; + } +} + +- (bool)getMouseCoords:(CGPoint)point eventX:(int *)x eventY:(int *)y { + if (![self convertToRotatedCoords:point result:&point]) + return false; + + 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); + + // Clip coordinates + if (*x < 0 || *x > width || *y < 0 || *y > height) + return false; + + return true; +} + +- (void)deviceOrientationChanged:(UIDeviceOrientation)orientation { + switch (orientation) { + case UIDeviceOrientationLandscapeLeft: + case UIDeviceOrientationLandscapeRight: + case UIDeviceOrientationPortrait: + _orientation = orientation; + break; + + default: + return; + } + + [self addEvent: + [[NSDictionary alloc] initWithObjectsAndKeys: + [NSNumber numberWithInt:kInputOrientationChanged], @"type", + [NSNumber numberWithInt:orientation], @"x", + [NSNumber numberWithInt:0], @"y", + nil + ] + ]; +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + NSSet *allTouches = [event allTouches]; + int x, y; + + switch ([allTouches count]) { + case 1: { + UITouch *touch = [touches anyObject]; + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + _firstTouch = touch; + [self addEvent: + [[NSDictionary alloc] initWithObjectsAndKeys: + [NSNumber numberWithInt:kInputMouseDown], @"type", + [NSNumber numberWithInt:x], @"x", + [NSNumber numberWithInt:y], @"y", + nil + ] + ]; + break; + } + + case 2: { + UITouch *touch = [touches anyObject]; + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + _secondTouch = touch; + [self addEvent: + [[NSDictionary alloc] initWithObjectsAndKeys: + [NSNumber numberWithInt:kInputMouseSecondDown], @"type", + [NSNumber numberWithInt:x], @"x", + [NSNumber numberWithInt:y], @"y", + nil + ] + ]; + break; + } + } +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + //NSSet *allTouches = [event allTouches]; + int x, y; + + for (UITouch *touch in touches) { + if (touch == _firstTouch) { + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent: + [[NSDictionary alloc] initWithObjectsAndKeys: + [NSNumber numberWithInt:kInputMouseDragged], @"type", + [NSNumber numberWithInt:x], @"x", + [NSNumber numberWithInt:y], @"y", + nil + ] + ]; + } else if (touch == _secondTouch) { + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent: + [[NSDictionary alloc] initWithObjectsAndKeys: + [NSNumber numberWithInt:kInputMouseSecondDragged], @"type", + [NSNumber numberWithInt:x], @"x", + [NSNumber numberWithInt:y], @"y", + nil + ] + ]; + } + } +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + NSSet *allTouches = [event allTouches]; + int x, y; + + switch ([allTouches count]) { + case 1: { + UITouch *touch = [[allTouches allObjects] objectAtIndex:0]; + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent: + [[NSDictionary alloc] initWithObjectsAndKeys: + [NSNumber numberWithInt:kInputMouseUp], @"type", + [NSNumber numberWithInt:x], @"x", + [NSNumber numberWithInt:y], @"y", + nil + ] + ]; + break; + } + + case 2: { + UITouch *touch = [[allTouches allObjects] objectAtIndex:1]; + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent: + [[NSDictionary alloc] initWithObjectsAndKeys: + [NSNumber numberWithInt:kInputMouseSecondUp], @"type", + [NSNumber numberWithInt:x], @"x", + [NSNumber numberWithInt:y], @"y", + nil + ] + ]; + break; + } + } +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { +} + +- (void)handleKeyPress:(unichar)c { + [self addEvent: + [[NSDictionary alloc] initWithObjectsAndKeys: + [NSNumber numberWithInt:kInputKeyPressed], @"type", + [NSNumber numberWithInt:c], @"x", + [NSNumber numberWithInt:0], @"y", + nil + ] + ]; +} + +- (BOOL)canHandleSwipes { + return TRUE; +} + +- (int)swipe:(int)num withEvent:(struct __GSEvent *)event { + //printf("swipe: %i\n", num); + + [self addEvent: + [[NSDictionary alloc] initWithObjectsAndKeys: + [NSNumber numberWithInt:kInputSwipe], @"type", + [NSNumber numberWithInt:num], @"x", + [NSNumber numberWithInt:0], @"y", + nil + ] + ]; + + return 0; +} + +- (void)applicationSuspend { + [self addEvent: + [[NSDictionary alloc] initWithObjectsAndKeys: + [NSNumber numberWithInt:kInputApplicationSuspended], @"type", + [NSNumber numberWithInt:0], @"x", + [NSNumber numberWithInt:0], @"y", + nil + ] + ]; +} + +- (void)applicationResume { + [self addEvent: + [[NSDictionary alloc] initWithObjectsAndKeys: + [NSNumber numberWithInt:kInputApplicationResumed], @"type", + [NSNumber numberWithInt:0], @"x", + [NSNumber numberWithInt:0], @"y", + nil + ] + ]; +} + +@end diff --git a/backends/platform/iphone/module.mk b/backends/platform/iphone/module.mk index 9768e6ded4..ea5115782f 100644 --- a/backends/platform/iphone/module.mk +++ b/backends/platform/iphone/module.mk @@ -7,8 +7,7 @@ MODULE_OBJS := \ osys_video.o \ iphone_main.o \ iphone_video.o \ - iphone_keyboard.o \ - blit_arm.o + iphone_keyboard.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/iphone/osys_events.cpp b/backends/platform/iphone/osys_events.cpp index 1ab1db0f27..85efbda208 100644 --- a/backends/platform/iphone/osys_events.cpp +++ b/backends/platform/iphone/osys_events.cpp @@ -40,98 +40,66 @@ bool OSystem_IPHONE::pollEvent(Common::Event &event) { _timerCallbackNext = curTime + _timerCallbackTimer; } - if (_queuedInputEvent.type != (Common::EventType)0 && curTime >= _queuedEventTime) { + if (_queuedInputEvent.type != Common::EVENT_INVALID && curTime >= _queuedEventTime) { event = _queuedInputEvent; - _queuedInputEvent.type = (Common::EventType)0; + _queuedInputEvent.type = Common::EVENT_INVALID; return true; } int eventType; - float xUnit, yUnit; - - if (iPhone_fetchEvent(&eventType, &xUnit, &yUnit)) { - int x = 0; - int y = 0; - switch (_screenOrientation) { - case kScreenOrientationPortrait: - if (_overlayVisible) { - x = (int)(xUnit * _overlayWidth); - y = (int)(yUnit * _overlayHeight); - } else { - x = (int)(xUnit * _screenWidth); - y = (int)(yUnit * _screenHeight); - } - break; - case kScreenOrientationLandscape: - if (_overlayVisible) { - x = (int)(yUnit * _overlayWidth); - y = (int)((1.0 - xUnit) * _overlayHeight); - } else { - x = (int)(yUnit * _screenWidth); - y = (int)((1.0 - xUnit) * _screenHeight); - } - break; - case kScreenOrientationFlippedLandscape: - if (_overlayVisible) { - x = (int)((1.0 - yUnit) * _overlayWidth); - y = (int)(xUnit * _overlayHeight); - } else { - x = (int)((1.0 - yUnit) * _screenWidth); - y = (int)(xUnit * _screenHeight); - } - break; - } + int x, y; + if (iPhone_fetchEvent(&eventType, &x, &y)) { switch ((InputEvent)eventType) { - case kInputMouseDown: - if (!handleEvent_mouseDown(event, x, y)) - return false; - break; + case kInputMouseDown: + if (!handleEvent_mouseDown(event, x, y)) + return false; + break; - case kInputMouseUp: + case kInputMouseUp: if (!handleEvent_mouseUp(event, x, y)) return false; - break; - - case kInputMouseDragged: - if (!handleEvent_mouseDragged(event, x, y)) - return false; - break; - case kInputMouseSecondDragged: - if (!handleEvent_mouseSecondDragged(event, x, y)) - return false; - break; - case kInputMouseSecondDown: - _secondaryTapped = true; - if (!handleEvent_secondMouseDown(event, x, y)) - return false; - break; - case kInputMouseSecondUp: - _secondaryTapped = false; - if (!handleEvent_secondMouseUp(event, x, y)) - return false; - break; - case kInputOrientationChanged: - handleEvent_orientationChanged((int)xUnit); - return false; - break; + break; - case kInputApplicationSuspended: - suspendLoop(); + case kInputMouseDragged: + if (!handleEvent_mouseDragged(event, x, y)) + return false; + break; + case kInputMouseSecondDragged: + if (!handleEvent_mouseSecondDragged(event, x, y)) + return false; + break; + case kInputMouseSecondDown: + _secondaryTapped = true; + if (!handleEvent_secondMouseDown(event, x, y)) + return false; + break; + case kInputMouseSecondUp: + _secondaryTapped = false; + if (!handleEvent_secondMouseUp(event, x, y)) return false; - break; + break; + case kInputOrientationChanged: + handleEvent_orientationChanged(x); + return false; + break; - case kInputKeyPressed: - handleEvent_keyPressed(event, (int)xUnit); - break; + case kInputApplicationSuspended: + suspendLoop(); + return false; + break; - case kInputSwipe: - if (!handleEvent_swipe(event, (int)xUnit)) - return false; - break; + case kInputKeyPressed: + handleEvent_keyPressed(event, x); + break; + + case kInputSwipe: + if (!handleEvent_swipe(event, x)) + return false; + break; - default: - break; + default: + break; } return true; @@ -154,8 +122,8 @@ bool OSystem_IPHONE::handleEvent_mouseDown(Common::Event &event, int x, int y) { if (_mouseClickAndDragEnabled) { event.type = Common::EVENT_LBUTTONDOWN; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; return true; } else { _lastMouseDown = getMillis(); @@ -170,20 +138,19 @@ bool OSystem_IPHONE::handleEvent_mouseUp(Common::Event &event, int x, int y) { _secondaryTapped = false; if (!handleEvent_secondMouseUp(event, x, y)) return false; - } - else if (_mouseClickAndDragEnabled) { + } else if (_mouseClickAndDragEnabled) { event.type = Common::EVENT_LBUTTONUP; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; } else { if (getMillis() - _lastMouseDown < 250) { event.type = Common::EVENT_LBUTTONDOWN; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; _queuedInputEvent.type = Common::EVENT_LBUTTONUP; - _queuedInputEvent.mouse.x = _mouseX; - _queuedInputEvent.mouse.y = _mouseY; + _queuedInputEvent.mouse.x = _videoContext->mouseX; + _queuedInputEvent.mouse.y = _videoContext->mouseY; _lastMouseTap = getMillis(); _queuedEventTime = _lastMouseTap + kQueuedInputEventDelay; } else @@ -200,14 +167,13 @@ bool OSystem_IPHONE::handleEvent_secondMouseDown(Common::Event &event, int x, in if (_mouseClickAndDragEnabled) { event.type = Common::EVENT_LBUTTONUP; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; _queuedInputEvent.type = Common::EVENT_RBUTTONDOWN; - _queuedInputEvent.mouse.x = _mouseX; - _queuedInputEvent.mouse.y = _mouseY; - } - else + _queuedInputEvent.mouse.x = _videoContext->mouseX; + _queuedInputEvent.mouse.y = _videoContext->mouseY; + } else return false; return true; @@ -216,9 +182,9 @@ bool OSystem_IPHONE::handleEvent_secondMouseDown(Common::Event &event, int x, in bool OSystem_IPHONE::handleEvent_secondMouseUp(Common::Event &event, int x, int y) { int curTime = getMillis(); - if (curTime - _lastSecondaryDown < 400 ) { + if (curTime - _lastSecondaryDown < 400) { //printf("Right tap!\n"); - if (curTime - _lastSecondaryTap < 400 && !_overlayVisible) { + if (curTime - _lastSecondaryTap < 400 && !_videoContext->overlayVisible) { //printf("Right escape!\n"); event.type = Common::EVENT_KEYDOWN; _queuedInputEvent.type = Common::EVENT_KEYUP; @@ -231,11 +197,11 @@ bool OSystem_IPHONE::handleEvent_secondMouseUp(Common::Event &event, int x, int } else if (!_mouseClickAndDragEnabled) { //printf("Rightclick!\n"); event.type = Common::EVENT_RBUTTONDOWN; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; _queuedInputEvent.type = Common::EVENT_RBUTTONUP; - _queuedInputEvent.mouse.x = _mouseX; - _queuedInputEvent.mouse.y = _mouseY; + _queuedInputEvent.mouse.x = _videoContext->mouseX; + _queuedInputEvent.mouse.y = _videoContext->mouseY; _lastSecondaryTap = curTime; _queuedEventTime = curTime + kQueuedInputEventDelay; } else { @@ -245,8 +211,8 @@ bool OSystem_IPHONE::handleEvent_secondMouseUp(Common::Event &event, int x, int } if (_mouseClickAndDragEnabled) { event.type = Common::EVENT_RBUTTONUP; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; } return true; @@ -262,17 +228,17 @@ bool OSystem_IPHONE::handleEvent_mouseDragged(Common::Event &event, int x, int y //printf("Mouse dragged at (%u, %u)\n", x, y); int mouseNewPosX; int mouseNewPosY; - if (_touchpadModeEnabled ) { + if (_touchpadModeEnabled) { int deltaX = _lastPadX - x; int deltaY = _lastPadY - y; _lastPadX = x; _lastPadY = y; - mouseNewPosX = (int)(_mouseX - deltaX / 0.5f); - mouseNewPosY = (int)(_mouseY - deltaY / 0.5f); + mouseNewPosX = (int)(_videoContext->mouseX - deltaX / 0.5f); + mouseNewPosY = (int)(_videoContext->mouseY - deltaY / 0.5f); - int widthCap = _overlayVisible ? _overlayWidth : _screenWidth; - int heightCap = _overlayVisible ? _overlayHeight : _screenHeight; + int widthCap = _videoContext->overlayVisible ? _videoContext->overlayWidth : _videoContext->screenWidth; + int heightCap = _videoContext->overlayVisible ? _videoContext->overlayHeight : _videoContext->screenHeight; if (mouseNewPosX < 0) mouseNewPosX = 0; @@ -319,12 +285,9 @@ bool OSystem_IPHONE::handleEvent_mouseSecondDragged(Common::Event &event, int x, if (absX < kMaxDeviation && vecY >= kNeededLength) { // Swipe down - event.type = Common::EVENT_KEYDOWN; - _queuedInputEvent.type = Common::EVENT_KEYUP; + event.type = Common::EVENT_MAINMENU; + _queuedInputEvent.type = Common::EVENT_INVALID; - event.kbd.flags = _queuedInputEvent.kbd.flags = 0; - event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_F5; - event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_F5; _queuedEventTime = getMillis() + kQueuedInputEventDelay; return true; } @@ -371,26 +334,26 @@ void OSystem_IPHONE::handleEvent_orientationChanged(int orientation) { ScreenOrientation newOrientation; switch (orientation) { - case 1: - newOrientation = kScreenOrientationPortrait; - break; - case 3: - newOrientation = kScreenOrientationLandscape; - break; - case 4: - newOrientation = kScreenOrientationFlippedLandscape; - break; - default: - return; + case 1: + newOrientation = kScreenOrientationPortrait; + break; + case 3: + newOrientation = kScreenOrientationLandscape; + break; + case 4: + newOrientation = kScreenOrientationFlippedLandscape; + break; + default: + return; } if (_screenOrientation != newOrientation) { _screenOrientation = newOrientation; - iPhone_initSurface(_screenWidth, _screenHeight); + updateOutputSurface(); dirtyFullScreen(); - if (_overlayVisible) + if (_videoContext->overlayVisible) dirtyFullOverlayScreen(); updateScreen(); } @@ -403,50 +366,50 @@ void OSystem_IPHONE::handleEvent_keyPressed(Common::Event &event, int keyPresse // 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; + 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; @@ -460,60 +423,60 @@ void OSystem_IPHONE::handleEvent_keyPressed(Common::Event &event, int keyPresse bool OSystem_IPHONE::handleEvent_swipe(Common::Event &event, int direction) { 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; - } + case kScreenOrientationPortrait: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_UP; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_DOWN; 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; - } + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_LEFT; 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; - } + 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; diff --git a/backends/platform/iphone/osys_main.cpp b/backends/platform/iphone/osys_main.cpp index 4bc567c39d..9a33cd8968 100644 --- a/backends/platform/iphone/osys_main.cpp +++ b/backends/platform/iphone/osys_main.cpp @@ -45,7 +45,9 @@ const OSystem::GraphicsMode OSystem_IPHONE::s_supportedGraphicsModes[] = { - {0, 0, 0} + { "linear", "Linear filtering", kGraphicsModeLinear }, + { "none", "No filtering", kGraphicsModeNone }, + { 0, 0, 0 } }; AQCallbackStruct OSystem_IPHONE::s_AudioQueue; @@ -53,28 +55,28 @@ SoundProc OSystem_IPHONE::s_soundCallback = NULL; void *OSystem_IPHONE::s_soundParam = NULL; OSystem_IPHONE::OSystem_IPHONE() : - _mixer(NULL), _offscreen(NULL), - _overlayVisible(false), _fullscreen(NULL), - _mouseHeight(0), _mouseWidth(0), _mouseBuf(NULL), _lastMouseTap(0), _queuedEventTime(0), - _secondaryTapped(false), _lastSecondaryTap(0), + _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), - _overlayHeight(0), _overlayWidth(0), _overlayBuffer(0) -{ - _queuedInputEvent.type = (Common::EventType)0; - _lastDrawnMouseRect = Common::Rect(0, 0, 0, 0); - + _mouseCursorPaletteEnabled(false), _gfxTransactionError(kTransactionSuccess) { + _queuedInputEvent.type = Common::EVENT_INVALID; _touchpadModeEnabled = !iPhone_isHighResDevice(); _fsFactory = new POSIXFilesystemFactory(); + initVideoContext(); } OSystem_IPHONE::~OSystem_IPHONE() { AudioQueueDispose(s_AudioQueue.queue, true); delete _mixer; - delete _offscreen; - delete _fullscreen; + // 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. + if (_framebuffer.pixels == _videoContext->screenTexture.pixels) + _framebuffer.free(); + _mouseBuffer.free(); } int OSystem_IPHONE::timerHandler(int t) { @@ -102,26 +104,55 @@ void OSystem_IPHONE::initBackend() { } bool OSystem_IPHONE::hasFeature(Feature f) { - return false; + 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) { - return false; + switch (f) { + case kFeatureCursorPalette: + return _mouseCursorPaletteEnabled; + case kFeatureAspectRatioCorrection: + return _videoContext->asprectRatioCorrection; + + default: + return false; + } } void OSystem_IPHONE::suspendLoop() { bool done = false; int eventType; - float xUnit, yUnit; + int x, y; uint32 startTime = getMillis(); stopSoundsystem(); while (!done) { - if (iPhone_fetchEvent(&eventType, &xUnit, &yUnit)) + if (iPhone_fetchEvent(&eventType, &x, &y)) if ((InputEvent)eventType == kInputApplicationResumed) done = true; usleep(100000); @@ -226,7 +257,6 @@ Common::String OSystem_IPHONE::getDefaultConfigFileName() { #endif } - void OSystem_IPHONE::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { // Get URL of the Resource directory of the .app bundle CFURLRef fileUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); @@ -272,7 +302,7 @@ void iphone_main(int argc, char *argv[]) { } #ifdef IPHONE_OFFICIAL - chdir( iPhone_getDocumentsDir() ); + chdir(iPhone_getDocumentsDir()); #else system("mkdir " SCUMMVM_ROOT_PATH); system("mkdir " SCUMMVM_SAVE_PATH); diff --git a/backends/platform/iphone/osys_main.h b/backends/platform/iphone/osys_main.h index 37896cceeb..b443e22f56 100644 --- a/backends/platform/iphone/osys_main.h +++ b/backends/platform/iphone/osys_main.h @@ -20,6 +20,9 @@ * */ +#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" @@ -42,16 +45,15 @@ typedef void (*SoundProc)(void *param, byte *buf, int len); typedef int (*TimerProc)(int interval); -typedef struct AQCallbackStruct { - AudioQueueRef queue; - uint32 frameCount; - AudioQueueBufferRef buffers[AUDIO_BUFFERS]; - AudioStreamBasicDescription dataFormat; -} AQCallbackStruct; +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; @@ -59,33 +61,31 @@ protected: Audio::MixerImpl *_mixer; + VideoContext *_videoContext; + Graphics::Surface _framebuffer; - byte *_offscreen; - OverlayColor *_overlayBuffer; - uint16 _overlayHeight; - uint16 _overlayWidth; - uint16 *_fullscreen; + // For signaling that screen format set up might have failed. + TransactionError _gfxTransactionError; - uint16 _palette[256]; - bool _overlayVisible; - uint16 _screenWidth; - uint16 _screenHeight; + // For use with the game texture + uint16 _gamePalette[256]; + // For use with the mouse texture + uint16 _gamePaletteRGBA5551[256]; struct timeval _startTime; uint32 _timeSuspended; - bool _mouseVisible; - byte *_mouseBuf; - byte _mouseKeyColor; - uint _mouseWidth, _mouseHeight; - uint _mouseX, _mouseY; - int _mouseHotspotX, _mouseHotspotY; + bool _mouseCursorPaletteEnabled; + uint16 _mouseCursorPalette[256]; + Graphics::Surface _mouseBuffer; + uint16 _mouseKeyColor; bool _mouseDirty; + bool _mouseNeedTextureUpdate; + long _lastMouseDown; long _lastMouseTap; long _queuedEventTime; - Common::Rect _lastDrawnMouseRect; Common::Event _queuedInputEvent; bool _secondaryTapped; long _lastSecondaryDown; @@ -121,13 +121,21 @@ public: virtual bool getFeatureState(Feature f); virtual const GraphicsMode *getSupportedGraphicsModes() const; virtual int getDefaultGraphicsMode() const; - bool setGraphicsMode(const char *name); 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(); +#ifdef USE_RGB_COLOR + virtual Graphics::PixelFormat getScreenFormat() const { return _framebuffer.format; } + virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const; +#endif + virtual PaletteManager *getPaletteManager() { return this; } protected: // PaletteManager API @@ -154,6 +162,7 @@ public: virtual void warpMouse(int x, int y); virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 255, int cursorTargetScale = 1, const Graphics::PixelFormat *format = NULL); + virtual void setCursorPalette(const byte *colors, uint start, uint num); virtual bool pollEvent(Common::Event &event); virtual uint32 getMillis(); @@ -167,7 +176,7 @@ public: 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 int getScreenChangeID() const { return _screenChangeCount; } virtual void quit(); virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); @@ -183,15 +192,15 @@ public: virtual void logMessage(LogMessageType::Type type, const char *message); protected: + void initVideoContext(); + void updateOutputSurface(); + void internUpdateScreen(); void dirtyFullScreen(); void dirtyFullOverlayScreen(); - void clipRectToScreen(int16 &x, int16 &y, int16 &w, int16 &h); void suspendLoop(); - void drawDirtyRect(const Common::Rect& dirtyRect); - void drawDirtyOverlayRect(const Common::Rect& dirtyRect); - void drawMouseCursorOnRectUpdate(const Common::Rect& updatedRect, const Common::Rect& mouseRect); - void updateHardwareSurfaceForRect(const Common::Rect& updatedRect); + void drawDirtyRect(const Common::Rect &dirtyRect); + void updateMouseTexture(); static void AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB); static int timerHandler(int t); @@ -208,3 +217,5 @@ protected: 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/iphone/osys_video.cpp b/backends/platform/iphone/osys_video.cpp deleted file mode 100644 index fa425b108a..0000000000 --- a/backends/platform/iphone/osys_video.cpp +++ /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" - -const OSystem::GraphicsMode* OSystem_IPHONE::getSupportedGraphicsModes() const { - return s_supportedGraphicsModes; -} - - -int OSystem_IPHONE::getDefaultGraphicsMode() const { - return -1; -} - -bool OSystem_IPHONE::setGraphicsMode(const char *mode) { - return true; -} - -bool OSystem_IPHONE::setGraphicsMode(int mode) { - return true; -} - -int OSystem_IPHONE::getGraphicsMode() const { - return -1; -} - -void OSystem_IPHONE::initSize(uint width, uint height, const Graphics::PixelFormat *format) { - //printf("initSize(%i, %i)\n", width, height); - - _screenWidth = width; - _screenHeight = height; - - free(_offscreen); - - _offscreen = (byte *)malloc(width * height); - bzero(_offscreen, width * height); - - //free(_overlayBuffer); - - int fullSize = _screenWidth * _screenHeight * sizeof(OverlayColor); - //_overlayBuffer = (OverlayColor *)malloc(fullSize); - clearOverlay(); - - free(_fullscreen); - - _fullscreen = (uint16 *)malloc(fullSize); - bzero(_fullscreen, fullSize); - - iPhone_initSurface(width, height); - - if (_overlayBuffer == NULL) { - _overlayHeight = iPhone_getScreenHeight(); - _overlayWidth = iPhone_getScreenWidth(); - - printf("Overlay: (%u x %u)\n", _overlayWidth, _overlayHeight); - _overlayBuffer = new OverlayColor[_overlayHeight * _overlayWidth]; - } - - _fullScreenIsDirty = false; - dirtyFullScreen(); - _mouseVisible = false; - _screenChangeCount++; - updateScreen(); -} - -int16 OSystem_IPHONE::getHeight() { - return _screenHeight; -} - -int16 OSystem_IPHONE::getWidth() { - return _screenWidth; -} - -void OSystem_IPHONE::setPalette(const byte *colors, uint start, uint num) { - assert(start + num <= 256); - const byte *b = colors; - - for (uint i = start; i < start + num; ++i) { - _palette[i] = Graphics::RGBToColor<Graphics::ColorMasks<565> >(b[0], b[1], b[2]); - b += 3; - } - - dirtyFullScreen(); -} - -void OSystem_IPHONE::grabPalette(byte *colors, uint start, uint num) { - assert(start + num <= 256); - byte *b = colors; - - for (uint i = start; i < start + num; ++i) { - Graphics::colorToRGB<Graphics::ColorMasks<565> >(_palette[i], b[0], b[1], b[2]); - b += 3; - } -} - -void OSystem_IPHONE::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { - //printf("copyRectToScreen(%i, %i, %i, %i)\n", x, y, w, h); - //Clip the coordinates - if (x < 0) { - w += x; - buf -= x; - x = 0; - } - - if (y < 0) { - h += y; - buf -= y * pitch; - y = 0; - } - - if (w > _screenWidth - x) { - w = _screenWidth - x; - } - - if (h > _screenHeight - y) { - h = _screenHeight - y; - } - - if (w <= 0 || h <= 0) - return; - - if (!_fullScreenIsDirty) { - _dirtyRects.push_back(Common::Rect(x, y, x + w, y + h)); - } - - - byte *dst = _offscreen + y * _screenWidth + x; - if (_screenWidth == pitch && pitch == w) - memcpy(dst, buf, h * w); - else { - do { - memcpy(dst, buf, w); - buf += pitch; - dst += _screenWidth; - } while (--h); - } -} - -void OSystem_IPHONE::clipRectToScreen(int16 &x, int16 &y, int16 &w, int16 &h) { - if (x < 0) { - w += x; - x = 0; - } - - if (y < 0) { - h += y; - y = 0; - } - - if (w > _screenWidth - x) - w = _screenWidth - x; - - if (h > _screenHeight - y) - h = _screenHeight - y; - - if (w < 0) { - w = 0; - } - - if (h < 0) { - h = 0; - } -} - -void OSystem_IPHONE::updateScreen() { - //printf("updateScreen(): %i dirty rects.\n", _dirtyRects.size()); - - if (_dirtyRects.size() == 0 && _dirtyOverlayRects.size() == 0 && !_mouseDirty) - return; - - internUpdateScreen(); - _fullScreenIsDirty = false; - _fullScreenOverlayIsDirty = false; - - iPhone_updateScreen(_mouseX - _mouseHotspotX, _mouseY - _mouseHotspotY); -} - -void OSystem_IPHONE::internUpdateScreen() { - int16 mouseX = _mouseX - _mouseHotspotX; - int16 mouseY = _mouseY - _mouseHotspotY; - int16 mouseWidth = _mouseWidth; - int16 mouseHeight = _mouseHeight; - - clipRectToScreen(mouseX, mouseY, mouseWidth, mouseHeight); - - Common::Rect mouseRect(mouseX, mouseY, mouseX + mouseWidth, mouseY + mouseHeight); - - if (_mouseDirty) { - if (!_fullScreenIsDirty) { - _dirtyRects.push_back(_lastDrawnMouseRect); - _dirtyRects.push_back(mouseRect); - } - if (!_fullScreenOverlayIsDirty && _overlayVisible) { - _dirtyOverlayRects.push_back(_lastDrawnMouseRect); - _dirtyOverlayRects.push_back(mouseRect); - } - _mouseDirty = false; - _lastDrawnMouseRect = mouseRect; - } - - 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); - - if (_overlayVisible) - drawDirtyOverlayRect(dirtyRect); - else - drawMouseCursorOnRectUpdate(dirtyRect, mouseRect); - - updateHardwareSurfaceForRect(dirtyRect); - } - - if (_overlayVisible) { - 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); - //drawMouseCursorOnRectUpdate(dirtyRect, mouseRect); - //updateHardwareSurfaceForRect(dirtyRect); - } - } -} - -void OSystem_IPHONE::drawDirtyRect(const Common::Rect& dirtyRect) { - int h = dirtyRect.bottom - dirtyRect.top; - int w = dirtyRect.right - dirtyRect.left; - - byte *src = &_offscreen[dirtyRect.top * _screenWidth + dirtyRect.left]; - uint16 *dst = &_fullscreen[dirtyRect.top * _screenWidth + dirtyRect.left]; - for (int y = h; y > 0; y--) { - for (int x = w; x > 0; x--) - *dst++ = _palette[*src++]; - - dst += _screenWidth - w; - src += _screenWidth - w; - } -} - -void OSystem_IPHONE::drawDirtyOverlayRect(const Common::Rect& dirtyRect) { - // int h = dirtyRect.bottom - dirtyRect.top; - // - // uint16 *src = (uint16 *)&_overlayBuffer[dirtyRect.top * _screenWidth + dirtyRect.left]; - // uint16 *dst = &_fullscreen[dirtyRect.top * _screenWidth + dirtyRect.left]; - // int x = (dirtyRect.right - dirtyRect.left) * 2; - // for (int y = h; y > 0; y--) { - // memcpy(dst, src, x); - // src += _screenWidth; - // dst += _screenWidth; - // } - iPhone_updateOverlayRect(_overlayBuffer, dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); -} - -void OSystem_IPHONE::drawMouseCursorOnRectUpdate(const Common::Rect& updatedRect, const Common::Rect& mouseRect) { - //draw mouse on top - if (_mouseVisible && (updatedRect.intersects(mouseRect))) { - int srcX = 0; - int srcY = 0; - int left = _mouseX - _mouseHotspotX; - if (left < 0) { - srcX -= left; - left = 0; - } - int top = _mouseY - _mouseHotspotY; - if (top < 0) { - srcY -= top; - top = 0; - } - - int bottom = top + _mouseHeight; - if (bottom > _screenWidth) - bottom = _screenWidth; - - int displayWidth = _mouseWidth; - if (_mouseWidth + left > _screenWidth) - displayWidth = _screenWidth - left; - - int displayHeight = _mouseHeight; - if (_mouseHeight + top > _screenHeight) - displayHeight = _screenHeight - top; - - byte *src = &_mouseBuf[srcY * _mouseWidth + srcX]; - uint16 *dst = &_fullscreen[top * _screenWidth + left]; - for (int y = displayHeight; y > srcY; y--) { - for (int x = displayWidth; x > srcX; x--) { - if (*src != _mouseKeyColor) - *dst = _palette[*src]; - dst++; - src++; - } - dst += _screenWidth - displayWidth + srcX; - src += _mouseWidth - displayWidth + srcX; - } - } -} - -void OSystem_IPHONE::updateHardwareSurfaceForRect(const Common::Rect& updatedRect) { - iPhone_updateScreenRect(_fullscreen, updatedRect.left, updatedRect.top, updatedRect.right, updatedRect.bottom ); -} - -Graphics::Surface *OSystem_IPHONE::lockScreen() { - //printf("lockScreen()\n"); - - _framebuffer.pixels = _offscreen; - _framebuffer.w = _screenWidth; - _framebuffer.h = _screenHeight; - _framebuffer.pitch = _screenWidth; - _framebuffer.format = Graphics::PixelFormat::createFormatCLUT8(); - - return &_framebuffer; -} - -void OSystem_IPHONE::unlockScreen() { - //printf("unlockScreen()\n"); - dirtyFullScreen(); -} - -void OSystem_IPHONE::setShakePos(int shakeOffset) { - //printf("setShakePos(%i)\n", shakeOffset); -} - -void OSystem_IPHONE::showOverlay() { - //printf("showOverlay()\n"); - _overlayVisible = true; - dirtyFullOverlayScreen(); - updateScreen(); - iPhone_enableOverlay(true); -} - -void OSystem_IPHONE::hideOverlay() { - //printf("hideOverlay()\n"); - _overlayVisible = false; - _dirtyOverlayRects.clear(); - dirtyFullScreen(); - iPhone_enableOverlay(false); -} - -void OSystem_IPHONE::clearOverlay() { - //printf("clearOverlay()\n"); - bzero(_overlayBuffer, _overlayWidth * _overlayHeight * sizeof(OverlayColor)); - dirtyFullOverlayScreen(); -} - -void OSystem_IPHONE::grabOverlay(OverlayColor *buf, int pitch) { - //printf("grabOverlay()\n"); - int h = _overlayHeight; - OverlayColor *src = _overlayBuffer; - - do { - memcpy(buf, src, _overlayWidth * sizeof(OverlayColor)); - src += _overlayWidth; - buf += pitch; - } while (--h); -} - -void OSystem_IPHONE::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) { - //printf("copyRectToOverlay(buf, pitch=%i, x=%i, y=%i, w=%i, h=%i)\n", pitch, x, y, w, h); - - //Clip the coordinates - if (x < 0) { - w += x; - buf -= x; - x = 0; - } - - if (y < 0) { - h += y; - buf -= y * pitch; - y = 0; - } - - if (w > _overlayWidth - x) - w = _overlayWidth - x; - - if (h > _overlayHeight - y) - h = _overlayHeight - y; - - if (w <= 0 || h <= 0) - return; - - if (!_fullScreenOverlayIsDirty) { - _dirtyOverlayRects.push_back(Common::Rect(x, y, x + w, y + h)); - } - - OverlayColor *dst = _overlayBuffer + (y * _overlayWidth + x); - if (_overlayWidth == pitch && pitch == w) - memcpy(dst, buf, h * w * sizeof(OverlayColor)); - else { - do { - memcpy(dst, buf, w * sizeof(OverlayColor)); - buf += pitch; - dst += _overlayWidth; - } while (--h); - } -} - -int16 OSystem_IPHONE::getOverlayHeight() { - return _overlayHeight; -} - -int16 OSystem_IPHONE::getOverlayWidth() { - return _overlayWidth; -} - -bool OSystem_IPHONE::showMouse(bool visible) { - bool last = _mouseVisible; - _mouseVisible = visible; - _mouseDirty = true; - - return last; -} - -void OSystem_IPHONE::warpMouse(int x, int y) { - //printf("warpMouse()\n"); - - _mouseX = x; - _mouseY = y; - _mouseDirty = true; -} - -void OSystem_IPHONE::dirtyFullScreen() { - if (!_fullScreenIsDirty) { - _dirtyRects.clear(); - _dirtyRects.push_back(Common::Rect(0, 0, _screenWidth, _screenHeight)); - _fullScreenIsDirty = true; - } -} - -void OSystem_IPHONE::dirtyFullOverlayScreen() { - if (!_fullScreenOverlayIsDirty) { - _dirtyOverlayRects.clear(); - _dirtyOverlayRects.push_back(Common::Rect(0, 0, _overlayWidth, _overlayHeight)); - _fullScreenOverlayIsDirty = true; - } -} - -void OSystem_IPHONE::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) { - //printf("setMouseCursor(%i, %i, scale %u)\n", hotspotX, hotspotY, cursorTargetScale); - - int texWidth = getSizeNextPOT(w); - int texHeight = getSizeNextPOT(h); - int bufferSize = texWidth * texHeight * sizeof(int16); - int16* mouseBuf = (int16*)malloc(bufferSize); - memset(mouseBuf, 0, bufferSize); - - for (uint x = 0; x < w; ++x) { - for (uint y = 0; y < h; ++y) { - byte color = buf[y * w + x]; - if (color != keycolor) - mouseBuf[y * texWidth + x] = _palette[color] | 0x1; - else - mouseBuf[y * texWidth + x] = 0x0; - } - } - - iPhone_setMouseCursor(mouseBuf, w, h); - - if (_mouseBuf != NULL && (_mouseWidth != w || _mouseHeight != h)) { - free(_mouseBuf); - _mouseBuf = NULL; - } - - if (_mouseBuf == NULL) - _mouseBuf = (byte *)malloc(w * h); - - _mouseWidth = w; - _mouseHeight = h; - - _mouseHotspotX = hotspotX; - _mouseHotspotY = hotspotY; - - _mouseKeyColor = (byte)keycolor; - - memcpy(_mouseBuf, buf, w * h); - - _mouseDirty = true; -} diff --git a/backends/platform/iphone/osys_video.mm b/backends/platform/iphone/osys_video.mm new file mode 100644 index 0000000000..6f80a6cba3 --- /dev/null +++ b/backends/platform/iphone/osys_video.mm @@ -0,0 +1,491 @@ +/* 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<Graphics::PixelFormat> OSystem_IPHONE::getSupportedFormats() const { + Common::List<Graphics::PixelFormat> 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.pixels == _videoContext->screenTexture.pixels) + _framebuffer.pixels = 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) { + assert(start + num <= 256); + const byte *b = colors; + + for (uint i = start; i < start + num; ++i) { + _gamePalette[i] = Graphics::RGBToColor<Graphics::ColorMasks<565> >(b[0], b[1], b[2]); + _gamePaletteRGBA5551[i] = Graphics::RGBToColor<Graphics::ColorMasks<5551> >(b[0], b[1], b[2]); + b += 3; + } + + dirtyFullScreen(); +} + +void OSystem_IPHONE::grabPalette(byte *colors, uint start, uint num) { + assert(start + num <= 256); + byte *b = colors; + + for (uint i = start; i < start + num; ++i) { + Graphics::colorToRGB<Graphics::ColorMasks<565> >(_gamePalette[i], b[0], b[1], b[2]); + b += 3; + } +} + +void OSystem_IPHONE::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { + //printf("copyRectToScreen(%i, %i, %i, %i)\n", x, y, w, h); + //Clip the coordinates + if (x < 0) { + w += x; + buf -= x; + x = 0; + } + + if (y < 0) { + h += y; + buf -= 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, buf, h * pitch); + } else { + do { + memcpy(dst, buf, w * _framebuffer.format.bytesPerPixel); + buf += pitch; + dst += _framebuffer.pitch; + } while (--h); + } +} + +void OSystem_IPHONE::updateScreen() { + //printf("updateScreen(): %i dirty rects.\n", _dirtyRects.size()); + + if (_dirtyRects.size() == 0 && _dirtyOverlayRects.size() == 0 && !_mouseDirty) + return; + + 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.getBasePtr(0, 0), _videoContext->overlayTexture.h * _videoContext->overlayTexture.pitch); + dirtyFullOverlayScreen(); +} + +void OSystem_IPHONE::grabOverlay(OverlayColor *buf, int pitch) { + //printf("grabOverlay()\n"); + int h = _videoContext->overlayHeight; + + const byte *src = (const byte *)_videoContext->overlayTexture.getBasePtr(0, 0); + do { + memcpy(buf, src, _videoContext->overlayWidth * sizeof(OverlayColor)); + src += _videoContext->overlayTexture.pitch; + buf += pitch; + } while (--h); +} + +void OSystem_IPHONE::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) { + //printf("copyRectToOverlay(buf, pitch=%i, x=%i, y=%i, w=%i, h=%i)\n", pitch, x, y, w, h); + + //Clip the coordinates + if (x < 0) { + w += x; + buf -= x; + x = 0; + } + + if (y < 0) { + h += y; + buf -= 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, buf, w * sizeof(OverlayColor)); + buf += 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) { + bool last = _videoContext->mouseIsVisible; + _videoContext->mouseIsVisible = visible; + _mouseDirty = true; + + return last; +} + +void OSystem_IPHONE::warpMouse(int x, int y) { + //printf("warpMouse()\n"); + _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 byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) { + //printf("setMouseCursor(%i, %i, scale %u)\n", hotspotX, hotspotY, cursorTargetScale); + + 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.pixels) + _mouseBuffer.create(w, h, pixelFormat); + + _videoContext->mouseWidth = w; + _videoContext->mouseHeight = h; + + _videoContext->mouseHotspotX = hotspotX; + _videoContext->mouseHotspotY = hotspotY; + + _mouseKeyColor = keycolor; + + memcpy(_mouseBuffer.getBasePtr(0, 0), buf, h * _mouseBuffer.pitch); + + _mouseDirty = true; + _mouseNeedTextureUpdate = true; +} + +void OSystem_IPHONE::setCursorPalette(const byte *colors, uint start, uint num) { + assert(start + num <= 256); + + for (uint i = start; i < start + num; ++i, colors += 3) + _mouseCursorPalette[i] = Graphics::RGBToColor<Graphics::ColorMasks<5551> >(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.getBasePtr(0, 0); + 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.getBasePtr(0, 0), (const byte *)_mouseBuffer.getBasePtr(0, 0), 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.getBasePtr(0, 0); + uint8 *dstRaw = (uint8 *)mouseTexture.getBasePtr(0, 0); + + 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.getBasePtr(0, 0), 0, mouseTexture.h * mouseTexture.pitch); + } + } + + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateMouseCursor) withObject:nil waitUntilDone: YES]; +} |