From 5d4ddf5a8f6d8be708719c1b01915e1ec8ddf595 Mon Sep 17 00:00:00 2001 From: Albert Zeyer Date: Sun, 15 Nov 2009 12:58:36 +0100 Subject: [PATCH] exported iphone helper code from https://scummvm.svn.sf.net/svnroot/scummvm/scummvm/trunk/backends/platform/iphone (thank you, ScummVM team!) --- src/sdl/iphone/blit.cpp | 51 +++ src/sdl/iphone/blit_arm.h | 38 +++ src/sdl/iphone/blit_arm.s | 140 ++++++++ src/sdl/iphone/iphone_common.h | 72 ++++ src/sdl/iphone/iphone_keyboard.h | 39 +++ src/sdl/iphone/iphone_keyboard.m | 98 ++++++ src/sdl/iphone/iphone_main.m | 132 ++++++++ src/sdl/iphone/iphone_video.h | 83 +++++ src/sdl/iphone/iphone_video.m | 553 +++++++++++++++++++++++++++++++ src/sdl/iphone/module.mk | 17 + src/sdl/iphone/osys_events.cpp | 514 ++++++++++++++++++++++++++++ src/sdl/iphone/osys_main.cpp | 302 +++++++++++++++++ src/sdl/iphone/osys_main.h | 209 ++++++++++++ src/sdl/iphone/osys_sound.cpp | 111 +++++++ src/sdl/iphone/osys_video.cpp | 463 ++++++++++++++++++++++++++ 15 files changed, 2822 insertions(+) create mode 100644 src/sdl/iphone/blit.cpp create mode 100644 src/sdl/iphone/blit_arm.h create mode 100644 src/sdl/iphone/blit_arm.s create mode 100644 src/sdl/iphone/iphone_common.h create mode 100644 src/sdl/iphone/iphone_keyboard.h create mode 100644 src/sdl/iphone/iphone_keyboard.m create mode 100644 src/sdl/iphone/iphone_main.m create mode 100644 src/sdl/iphone/iphone_video.h create mode 100644 src/sdl/iphone/iphone_video.m create mode 100644 src/sdl/iphone/module.mk create mode 100644 src/sdl/iphone/osys_events.cpp create mode 100644 src/sdl/iphone/osys_main.cpp create mode 100644 src/sdl/iphone/osys_main.h create mode 100644 src/sdl/iphone/osys_sound.cpp create mode 100644 src/sdl/iphone/osys_video.cpp diff --git a/src/sdl/iphone/blit.cpp b/src/sdl/iphone/blit.cpp new file mode 100644 index 000000000..94c18a566 --- /dev/null +++ b/src/sdl/iphone/blit.cpp @@ -0,0 +1,51 @@ +/* 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. + * + * $URL: https://scummvm.svn.sf.net/svnroot/scummvm/scummvm/trunk/backends/platform/iphone/blit.cpp $ + * $Id: blit.cpp 40867 2009-05-24 15:17:42Z lordhoto $ + * + */ + +#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/src/sdl/iphone/blit_arm.h b/src/sdl/iphone/blit_arm.h new file mode 100644 index 000000000..2f32ee3b2 --- /dev/null +++ b/src/sdl/iphone/blit_arm.h @@ -0,0 +1,38 @@ +/* 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. + * + * $URL: https://scummvm.svn.sf.net/svnroot/scummvm/scummvm/trunk/backends/platform/iphone/blit_arm.h $ + * $Id: blit_arm.h 29718 2007-12-05 08:07:10Z vinterstum $ + * + */ + +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/src/sdl/iphone/blit_arm.s b/src/sdl/iphone/blit_arm.s new file mode 100644 index 000000000..a59f90c28 --- /dev/null +++ b/src/sdl/iphone/blit_arm.s @@ -0,0 +1,140 @@ +@ 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. +@ +@ $URL: https://scummvm.svn.sf.net/svnroot/scummvm/scummvm/trunk/backends/platform/iphone/blit_arm.s $ +@ $Id: blit_arm.s 33326 2008-07-27 10:15:57Z vinterstum $ +@ +@ @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/src/sdl/iphone/iphone_common.h b/src/sdl/iphone/iphone_common.h new file mode 100644 index 000000000..2afa95f78 --- /dev/null +++ b/src/sdl/iphone/iphone_common.h @@ -0,0 +1,72 @@ +/* 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. + * + * $URL: https://scummvm.svn.sf.net/svnroot/scummvm/scummvm/trunk/backends/platform/iphone/iphone_common.h $ + * $Id: iphone_common.h 40867 2009-05-24 15:17:42Z lordhoto $ + * + */ + + +enum InputEvent { + kInputMouseDown, + kInputMouseUp, + kInputMouseDragged, + kInputMouseSecondDragged, + kInputMouseSecondDown, + kInputMouseSecondUp, + kInputOrientationChanged, + kInputKeyPressed, + kInputApplicationSuspended, + kInputApplicationResumed, + kInputSwipe +}; + +enum ScreenOrientation { + kScreenOrientationPortrait, + kScreenOrientationLandscape, + kScreenOrientationFlippedLandscape +}; + +typedef enum +{ + kUIViewSwipeUp = 1, + kUIViewSwipeDown = 2, + kUIViewSwipeLeft = 4, + kUIViewSwipeRight = 8 +} UIViewSwipeDirection; + +// We need this to be able to call functions from/in Objective-C. +#ifdef __cplusplus +extern "C" { +#endif + +// On the C++ side +void iphone_main(int argc, char *argv[]); + +// On the ObjC side +void iPhone_updateScreen(); +void iPhone_updateScreenRect(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(); + +#ifdef __cplusplus +} +#endif diff --git a/src/sdl/iphone/iphone_keyboard.h b/src/sdl/iphone/iphone_keyboard.h new file mode 100644 index 000000000..03408fa71 --- /dev/null +++ b/src/sdl/iphone/iphone_keyboard.h @@ -0,0 +1,39 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL: https://scummvm.svn.sf.net/svnroot/scummvm/scummvm/trunk/backends/platform/iphone/iphone_keyboard.h $ + * $Id: iphone_keyboard.h 39020 2009-03-01 08:41:03Z vinterstum $ + * + */ + +#import +#import + +@interface SoftKeyboard : UIView { + id inputDelegate; + UITextView* inputView; +} + +- (id)initWithFrame:(CGRect)frame; +- (UITextView*)inputView; +- (void)setInputDelegate:(id)delegate; +- (void)handleKeyPress:(unichar)c; + +@end diff --git a/src/sdl/iphone/iphone_keyboard.m b/src/sdl/iphone/iphone_keyboard.m new file mode 100644 index 000000000..d7850236e --- /dev/null +++ b/src/sdl/iphone/iphone_keyboard.m @@ -0,0 +1,98 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL: https://scummvm.svn.sf.net/svnroot/scummvm/scummvm/trunk/backends/platform/iphone/iphone_keyboard.m $ + * $Id: iphone_keyboard.m 40872 2009-05-24 21:53:29Z lordhoto $ + * + */ + +#import "iphone_keyboard.h" + +@interface UITextInputTraits +- (void)setAutocorrectionType:(int)type; +- (void)setAutocapitalizationType:(int)type; +- (void)setEnablesReturnKeyAutomatically:(BOOL)val; +@end + +@interface TextInputHandler : UITextView { + SoftKeyboard* softKeyboard; +} + +- (id)initWithKeyboard:(SoftKeyboard*)keyboard; + +@end + + +@implementation TextInputHandler + +- (id)initWithKeyboard:(SoftKeyboard*)keyboard; { + self = [super initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.0f)]; + softKeyboard = keyboard; + + [[self textInputTraits] setAutocorrectionType:1]; + [[self textInputTraits] setAutocapitalizationType:0]; + [[self textInputTraits] setEnablesReturnKeyAutomatically:NO]; + + return self; +} + +- (void) keyboardInputShouldDelete:(id)input { + [softKeyboard handleKeyPress:0x08]; +} + +- (BOOL)webView:(id)fp8 shouldInsertText:(id)character + replacingDOMRange:(id)fp16 + givenAction:(int)fp20 { + + if ([character length] != 1) { + [NSException raise:@"Unsupported" format:@"Unhandled multi-char insert!"]; + return NO; + } + + [softKeyboard handleKeyPress:[character characterAtIndex:0]]; + + return NO; +} + +@end + + +@implementation SoftKeyboard + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + inputDelegate = nil; + inputView = [[TextInputHandler alloc] initWithKeyboard:self]; + return self; +} + +- (UITextView*)inputView { + return inputView; +} + +- (void)setInputDelegate:(id)delegate { + inputDelegate = delegate; +} + +- (void)handleKeyPress:(unichar)c { + [inputDelegate handleKeyPress:c]; +} + +@end diff --git a/src/sdl/iphone/iphone_main.m b/src/sdl/iphone/iphone_main.m new file mode 100644 index 000000000..a62a0adcc --- /dev/null +++ b/src/sdl/iphone/iphone_main.m @@ -0,0 +1,132 @@ +/* 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. + * + * $URL: https://scummvm.svn.sf.net/svnroot/scummvm/scummvm/trunk/backends/platform/iphone/iphone_main.m $ + * $Id: iphone_main.m 40872 2009-05-24 21:53:29Z lordhoto $ + * + */ + +#import +#import + +#include "iphone_video.h" + +void iphone_main(int argc, char *argv[]); + +@interface iPhoneMain : UIApplication { + UIWindow* _window; + iPhoneView* _view; +} + +- (void) mainLoop: (id)param; +- (iPhoneView*) getView; +- (UIWindow*) getWindow; +- (void)didRotate:(NSNotification *)notification; +@end + +static int gArgc; +static char** gArgv; + +int main(int argc, char** argv) { + gArgc = argc; + gArgv = argv; + + NSAutoreleasePool *autoreleasePool = [ + [ NSAutoreleasePool alloc ] init + ]; + + int returnCode = UIApplicationMain(argc, argv, @"iPhoneMain", @"iPhoneMain"); + [ autoreleasePool release ]; + return returnCode; +} + +@implementation iPhoneMain + +-(id) init { + [super init]; + _window = nil; + _view = nil; + return self; +} + +- (void) mainLoop: (id)param { + [[NSAutoreleasePool alloc] init]; + + iphone_main(gArgc, gArgv); + exit(0); +} + +- (iPhoneView*) getView { + return _view; +} + +- (void)applicationDidFinishLaunching:(UIApplication *)application { + CGRect rect = [[UIScreen mainScreen] bounds]; + + // hide the status bar + [application setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:NO]; + [application setStatusBarHidden:YES animated:YES]; + + _window = [[UIWindow alloc] initWithFrame:rect]; + [_window retain]; + + _view = [[iPhoneView alloc] initWithFrame: rect]; + _view.multipleTouchEnabled = YES; + + [_window setContentView: _view]; + + [_window addSubview:_view]; + [_window makeKeyAndVisible]; + + [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didRotate:) + name:@"UIDeviceOrientationDidChangeNotification" object:nil]; + + [NSThread detachNewThreadSelector:@selector(mainLoop:) toTarget:self withObject:nil]; +} + +- (void)applicationSuspend:(struct __GSEvent *)event { + //[self setApplicationBadge:NSLocalizedString(@"ON", nil)]; + [_view applicationSuspend]; +} + +- (void)applicationResume:(struct __GSEvent *)event { + [self removeApplicationBadge]; + [_view applicationResume]; + + // 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]; +} + +- (void)didRotate:(NSNotification *)notification { + int screenOrientation = [[UIDevice currentDevice] orientation]; + [_view deviceOrientationChanged: screenOrientation]; +} + +- (UIWindow*) getWindow { + return _window; +} + +@end + diff --git a/src/sdl/iphone/iphone_video.h b/src/sdl/iphone/iphone_video.h new file mode 100644 index 000000000..ed8806b2a --- /dev/null +++ b/src/sdl/iphone/iphone_video.h @@ -0,0 +1,83 @@ +/* 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. + * + * $URL: https://scummvm.svn.sf.net/svnroot/scummvm/scummvm/trunk/backends/platform/iphone/iphone_video.h $ + * $Id: iphone_video.h 40867 2009-05-24 15:17:42Z lordhoto $ + * + */ + +#ifndef _IPHONE_VIDEO__H +#define _IPHONE_VIDEO__H + +#import +#import +#import + +#import +#import +#import + +#import "iphone_keyboard.h" + +@interface iPhoneView : UIView +{ + void* _screenSurface; + NSMutableArray* _events; + SoftKeyboard* _keyboardView; + CALayer* _screenLayer; + + int _fullWidth; + int _fullHeight; + int _widthOffset; + int _heightOffset; + + EAGLContext* _context; + GLuint _viewRenderbuffer; + GLuint _viewFramebuffer; + GLint _backingWidth; + GLint _backingHeight; + GLint _visibleWidth; + GLint _visibleHeight; + GLuint _screenTexture; +} + +- (id)initWithFrame:(struct CGRect)frame; + +- (void)drawRect:(CGRect)frame; + +- (void *)getSurface; + +- (void)initSurface; + +- (void)updateSurface; + +- (id)getEvent; + +- (void)deviceOrientationChanged:(int)orientation; + +- (void)applicationSuspend; + +- (void)applicationResume; + +@end + + + +#endif /* _IPHONE_VIDEO__H */ diff --git a/src/sdl/iphone/iphone_video.m b/src/sdl/iphone/iphone_video.m new file mode 100644 index 000000000..11a903aa8 --- /dev/null +++ b/src/sdl/iphone/iphone_video.m @@ -0,0 +1,553 @@ +/* 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. + * + * $URL: https://scummvm.svn.sf.net/svnroot/scummvm/scummvm/trunk/backends/platform/iphone/iphone_video.m $ + * $Id: iphone_video.m 44495 2009-09-30 16:16:53Z fingolfin $ + * + */ + +#include "iphone_video.h" +#include "iphone_common.h" + +static iPhoneView *sharedInstance = nil; +static int _width = 0; +static int _height = 0; +static CGRect _screenRect; +static char* _textureBuffer = 0; +static int _textureWidth = 0; +static int _textureHeight = 0; +NSLock* _lock = nil; +static int _needsScreenUpdate = 0; + +static UITouch* _firstTouch = NULL; +static UITouch* _secondTouch = NULL; + +// static long lastTick = 0; +// static int frames = 0; + +void iPhone_updateScreen() { + 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) { + //[_lock lock]; + + int y; + for (y = y1; y < y2; ++y) { + memcpy(&_textureBuffer[(y * _textureWidth + x1 )* 2], &screen[y * _width + x1], (x2 - x1) * 2); + } + + //[_lock unlock]; +} + + +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; +} + +const char* iPhone_getDocumentsDir() { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + return [documentsDirectory UTF8String]; +} + +bool getLocalMouseCoords(CGPoint *point) { + 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; +} + +uint getSizeNextPOT(uint size) { + if ((size & (size - 1)) || !size) { + int log = 0; + + while (size >>= 1) + ++log; + + size = (2 << log); + } + + return size; +} + +@implementation iPhoneView + ++ (Class) layerClass +{ + return [CAEAGLLayer class]; +} + +- (id)initWithFrame:(struct CGRect)frame { + [super initWithFrame: frame]; + + _fullWidth = frame.size.width; + _fullHeight = frame.size.height; + _screenLayer = nil; + + sharedInstance = self; + + _lock = [NSLock new]; + _keyboardView = nil; + _context = nil; + _screenTexture = 0; + + return self; +} + +-(void) dealloc { + [super dealloc]; + + if (_keyboardView != nil) { + [_keyboardView dealloc]; + } + + if (_screenTexture) + free(_textureBuffer); +} + +- (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; + + 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); + glTexCoordPointer(2, GL_FLOAT, 0, texCoords); + + //[_lock lock]; + // 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); + //[_lock unlock]; + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); + [_context presentRenderbuffer:GL_RENDERBUFFER_OES]; + +} + +- (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); + glGenRenderbuffersOES(1, &_viewRenderbuffer); + + glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); + [_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id)self.layer]; + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _viewRenderbuffer); + + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &_backingWidth); + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &_backingHeight); + + if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { + NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); + return; + } + + glViewport(0, 0, _backingWidth, _backingHeight); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + + glEnable(GL_TEXTURE_2D); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + } + } + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + if (orientation == UIDeviceOrientationLandscapeRight) { + glRotatef(-90, 0, 0, 1); + } else if (orientation == UIDeviceOrientationLandscapeLeft) { + glRotatef(90, 0, 0, 1); + } else { + glRotatef(180, 0, 0, 1); + } + + glOrthof(0, _backingWidth, 0, _backingHeight, 0, 1); + + if (_screenTexture > 0) { + glDeleteTextures(1, &_screenTexture); + } + + glGenTextures(1, &_screenTexture); + glBindTexture(GL_TEXTURE_2D, _screenTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + if (_textureBuffer) { + free(_textureBuffer); + } + + int textureSize = _textureWidth * _textureHeight * 2; + _textureBuffer = (char*)malloc(textureSize); + memset(_textureBuffer, 0, textureSize); + + glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); + + // 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); + [_context presentRenderbuffer:GL_RENDERBUFFER_OES]; + } + + 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); + } 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]; + } +} + +- (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/src/sdl/iphone/module.mk b/src/sdl/iphone/module.mk new file mode 100644 index 000000000..28bc8d3ac --- /dev/null +++ b/src/sdl/iphone/module.mk @@ -0,0 +1,17 @@ +MODULE := backends/platform/iphone + +MODULE_OBJS := \ + osys_main.o \ + osys_events.o \ + osys_sound.o \ + osys_video.o \ + iphone_main.o \ + iphone_video.o \ + iphone_keyboard.o \ + blit_arm.o + +MODULE_DIRS += \ + backends/platform/iphone/ + +# We don't use the rules.mk here on purpose +OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) $(OBJS) diff --git a/src/sdl/iphone/osys_events.cpp b/src/sdl/iphone/osys_events.cpp new file mode 100644 index 000000000..4b70627f1 --- /dev/null +++ b/src/sdl/iphone/osys_events.cpp @@ -0,0 +1,514 @@ +/* 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. + * + * $URL: https://scummvm.svn.sf.net/svnroot/scummvm/scummvm/trunk/backends/platform/iphone/osys_events.cpp $ + * $Id: osys_events.cpp 42479 2009-07-14 13:52:11Z vinterstum $ + * + */ + +#include "gui/message.h" + +#include "osys_main.h" + + +bool OSystem_IPHONE::pollEvent(Common::Event &event) { + //printf("pollEvent()\n"); + + long curTime = getMillis(); + + if (_timerCallback && (curTime >= _timerCallbackNext)) { + _timerCallback(_timerCallbackTimer); + _timerCallbackNext = curTime + _timerCallbackTimer; + } + + if (_needEventRestPeriod) { + // Workaround: Some engines can't handle mouse-down and mouse-up events + // appearing right after each other, without a call returning no input in between. + _needEventRestPeriod = false; + return false; + } + + if (_queuedInputEvent.type != (Common::EventType)0) { + event = _queuedInputEvent; + _queuedInputEvent.type = (Common::EventType)0; + return true; + } + + int eventType; + float xUnit, yUnit; + + if (iPhone_fetchEvent(&eventType, &xUnit, &yUnit)) { + int x = 0; + int y = 0; + switch (_screenOrientation) { + case kScreenOrientationPortrait: + x = (int)(xUnit * _screenWidth); + y = (int)(yUnit * _screenHeight); + break; + case kScreenOrientationLandscape: + x = (int)(yUnit * _screenWidth); + y = (int)((1.0 - xUnit) * _screenHeight); + break; + case kScreenOrientationFlippedLandscape: + x = (int)((1.0 - yUnit) * _screenWidth); + y = (int)(xUnit * _screenHeight); + break; + } + + switch ((InputEvent)eventType) { + case kInputMouseDown: + if (!handleEvent_mouseDown(event, x, y)) + return false; + break; + + 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; + + case kInputApplicationSuspended: + suspendLoop(); + return false; + break; + + case kInputKeyPressed: + handleEvent_keyPressed(event, (int)xUnit); + break; + + case kInputSwipe: + if (!handleEvent_swipe(event, (int)xUnit)) + return false; + break; + + default: + break; + } + + return true; + } + return false; +} + +bool OSystem_IPHONE::handleEvent_mouseDown(Common::Event &event, int x, int y) { + //printf("Mouse down at (%u, %u)\n", x, y); + + // Workaround: kInputMouseSecondToggled isn't always sent when the + // secondary finger is lifted. Need to make sure we get out of that mode. + _secondaryTapped = false; + + if (_touchpadModeEnabled) { + _lastPadX = x; + _lastPadY = y; + } else + warpMouse(x, y); + + if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_LBUTTONDOWN; + event.mouse.x = _mouseX; + event.mouse.y = _mouseY; + return true; + } else { + _lastMouseDown = getMillis(); + } + return false; +} + +bool OSystem_IPHONE::handleEvent_mouseUp(Common::Event &event, int x, int y) { + //printf("Mouse up at (%u, %u)\n", x, y); + + if (_secondaryTapped) { + _secondaryTapped = false; + if (!handleEvent_secondMouseUp(event, x, y)) + return false; + } + else if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_LBUTTONUP; + event.mouse.x = _mouseX; + event.mouse.y = _mouseY; + } else { + if (getMillis() - _lastMouseDown < 250) { + event.type = Common::EVENT_LBUTTONDOWN; + event.mouse.x = _mouseX; + event.mouse.y = _mouseY; + + _queuedInputEvent.type = Common::EVENT_LBUTTONUP; + _queuedInputEvent.mouse.x = _mouseX; + _queuedInputEvent.mouse.y = _mouseY; + _lastMouseTap = getMillis(); + _needEventRestPeriod = true; + } else + return false; + } + + return true; +} + +bool OSystem_IPHONE::handleEvent_secondMouseDown(Common::Event &event, int x, int y) { + _lastSecondaryDown = getMillis(); + _gestureStartX = x; + _gestureStartY = y; + + if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_LBUTTONUP; + event.mouse.x = _mouseX; + event.mouse.y = _mouseY; + + _queuedInputEvent.type = Common::EVENT_RBUTTONDOWN; + _queuedInputEvent.mouse.x = _mouseX; + _queuedInputEvent.mouse.y = _mouseY; + } + else + return false; + + return true; +} + +bool OSystem_IPHONE::handleEvent_secondMouseUp(Common::Event &event, int x, int y) { + int curTime = getMillis(); + + if (curTime - _lastSecondaryDown < 400 ) { + //printf("Right tap!\n"); + if (curTime - _lastSecondaryTap < 400 && !_overlayVisible) { + //printf("Right escape!\n"); + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE; + _needEventRestPeriod = true; + _lastSecondaryTap = 0; + } else if (!_mouseClickAndDragEnabled) { + //printf("Rightclick!\n"); + event.type = Common::EVENT_RBUTTONDOWN; + event.mouse.x = _mouseX; + event.mouse.y = _mouseY; + _queuedInputEvent.type = Common::EVENT_RBUTTONUP; + _queuedInputEvent.mouse.x = _mouseX; + _queuedInputEvent.mouse.y = _mouseY; + _lastSecondaryTap = curTime; + _needEventRestPeriod = true; + } else { + //printf("Right nothing!\n"); + return false; + } + } + if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_RBUTTONUP; + event.mouse.x = _mouseX; + event.mouse.y = _mouseY; + } + + return true; +} + +bool OSystem_IPHONE::handleEvent_mouseDragged(Common::Event &event, int x, int y) { + if (_lastDragPosX == x && _lastDragPosY == y) + return false; + + _lastDragPosX = x; + _lastDragPosY = y; + + //printf("Mouse dragged at (%u, %u)\n", x, y); + int mouseNewPosX; + int mouseNewPosY; + if (_touchpadModeEnabled ) { + int deltaX = _lastPadX - x; + int deltaY = _lastPadY - y; + _lastPadX = x; + _lastPadY = y; + + mouseNewPosX = (int)(_mouseX - deltaX / 0.5f); + mouseNewPosY = (int)(_mouseY - deltaY / 0.5f); + + if (mouseNewPosX < 0) + mouseNewPosX = 0; + else if (mouseNewPosX > _screenWidth) + mouseNewPosX = _screenWidth; + + if (mouseNewPosY < 0) + mouseNewPosY = 0; + else if (mouseNewPosY > _screenHeight) + mouseNewPosY = _screenHeight; + + } else { + mouseNewPosX = x; + mouseNewPosY = y; + } + + event.type = Common::EVENT_MOUSEMOVE; + event.mouse.x = mouseNewPosX; + event.mouse.y = mouseNewPosY; + warpMouse(mouseNewPosX, mouseNewPosY); + + return true; +} + +bool OSystem_IPHONE::handleEvent_mouseSecondDragged(Common::Event &event, int x, int y) { + if (_gestureStartX == -1 || _gestureStartY == -1) { + return false; + } + + static const int kNeededLength = 100; + static const int kMaxDeviation = 20; + + int vecX = (x - _gestureStartX); + int vecY = (y - _gestureStartY); + + int absX = abs(vecX); + int absY = abs(vecY); + + //printf("(%d, %d)\n", vecX, vecY); + + if (absX >= kNeededLength || absY >= kNeededLength) { // Long enough gesture to react upon. + _gestureStartX = -1; + _gestureStartY = -1; + + if (absX < kMaxDeviation && vecY >= kNeededLength) { + // Swipe down + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + + 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; + _needEventRestPeriod = true; + return true; + } + + if (absX < kMaxDeviation && -vecY >= kNeededLength) { + // Swipe up + _mouseClickAndDragEnabled = !_mouseClickAndDragEnabled; + const char *dialogMsg; + if (_mouseClickAndDragEnabled) { + _touchpadModeEnabled = false; + dialogMsg = "Mouse-click-and-drag mode enabled."; + } else + dialogMsg = "Mouse-click-and-drag mode disabled."; + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return false; + } + + if (absY < kMaxDeviation && vecX >= kNeededLength) { + // Swipe right + _touchpadModeEnabled = !_touchpadModeEnabled; + const char *dialogMsg; + if (_touchpadModeEnabled) + dialogMsg = "Touchpad mode enabled."; + else + dialogMsg = "Touchpad mode disabled."; + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return false; + + } + + if (absY < kMaxDeviation && -vecX >= kNeededLength) { + // Swipe left + return false; + } + } + + return false; +} + +void OSystem_IPHONE::handleEvent_orientationChanged(int orientation) { + //printf("Orientation: %i\n", orientation); + + ScreenOrientation newOrientation; + switch (orientation) { + case 1: + newOrientation = kScreenOrientationPortrait; + break; + case 3: + newOrientation = kScreenOrientationLandscape; + break; + case 4: + newOrientation = kScreenOrientationFlippedLandscape; + break; + default: + return; + } + + + if (_screenOrientation != newOrientation) { + _screenOrientation = newOrientation; + iPhone_initSurface(_screenWidth, _screenHeight); + + dirtyFullScreen(); + if (_overlayVisible) + dirtyFullOverlayScreen(); + updateScreen(); + } +} + +void OSystem_IPHONE::handleEvent_keyPressed(Common::Event &event, int keyPressed) { + int ascii = keyPressed; + //printf("key: %i\n", keyPressed); + + // We remap some of the iPhone keyboard keys. + // The first ten here are the row of symbols below the numeric keys. + switch (keyPressed) { + case 45: + keyPressed = Common::KEYCODE_F1; + ascii = Common::ASCII_F1; + break; + case 47: + keyPressed = Common::KEYCODE_F2; + ascii = Common::ASCII_F2; + break; + case 58: + keyPressed = Common::KEYCODE_F3; + ascii = Common::ASCII_F3; + break; + case 59: + keyPressed = Common::KEYCODE_F4; + ascii = Common::ASCII_F4; + break; + case 40: + keyPressed = Common::KEYCODE_F5; + ascii = Common::ASCII_F5; + break; + case 41: + keyPressed = Common::KEYCODE_F6; + ascii = Common::ASCII_F6; + break; + case 36: + keyPressed = Common::KEYCODE_F7; + ascii = Common::ASCII_F7; + break; + case 38: + keyPressed = Common::KEYCODE_F8; + ascii = Common::ASCII_F8; + break; + case 64: + keyPressed = Common::KEYCODE_F9; + ascii = Common::ASCII_F9; + break; + case 34: + keyPressed = Common::KEYCODE_F10; + ascii = Common::ASCII_F10; + break; + case 10: + keyPressed = Common::KEYCODE_RETURN; + ascii = Common::ASCII_RETURN; + break; + } + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + event.kbd.keycode = _queuedInputEvent.kbd.keycode = (Common::KeyCode)keyPressed; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = ascii; + _needEventRestPeriod = true; +} + +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; + } + break; + case kScreenOrientationLandscape: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_RIGHT; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_DOWN; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_UP; + break; + default: + return false; + } + break; + case kScreenOrientationFlippedLandscape: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_RIGHT; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_UP; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_DOWN; + break; + default: + return false; + } + break; + } + + event.kbd.keycode = _queuedInputEvent.kbd.keycode = keycode; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = 0; + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + _needEventRestPeriod = true; + + return true; +} diff --git a/src/sdl/iphone/osys_main.cpp b/src/sdl/iphone/osys_main.cpp new file mode 100644 index 000000000..27ec7f7b6 --- /dev/null +++ b/src/sdl/iphone/osys_main.cpp @@ -0,0 +1,302 @@ +/* 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. + * + * $URL: https://scummvm.svn.sf.net/svnroot/scummvm/scummvm/trunk/backends/platform/iphone/osys_main.cpp $ + * $Id: osys_main.cpp 44793 2009-10-08 19:41:38Z fingolfin $ + * + */ + +#include +#include + +#include + +#include "common/scummsys.h" +#include "common/util.h" +#include "common/rect.h" +#include "common/file.h" +#include "common/fs.h" + +#include "base/main.h" + +#include "backends/saves/default/default-saves.h" +#include "backends/timer/default/default-timer.h" +#include "sound/mixer.h" +#include "sound/mixer_intern.h" + +#include "osys_main.h" + + +const OSystem::GraphicsMode OSystem_IPHONE::s_supportedGraphicsModes[] = { + {0, 0, 0} +}; + +AQCallbackStruct OSystem_IPHONE::s_AudioQueue; +SoundProc OSystem_IPHONE::s_soundCallback = NULL; +void *OSystem_IPHONE::s_soundParam = NULL; + +OSystem_IPHONE::OSystem_IPHONE() : + _savefile(NULL), _mixer(NULL), _timer(NULL), _offscreen(NULL), + _overlayVisible(false), _overlayBuffer(NULL), _fullscreen(NULL), + _mouseHeight(0), _mouseWidth(0), _mouseBuf(NULL), _lastMouseTap(0), + _secondaryTapped(false), _lastSecondaryTap(0), _screenOrientation(kScreenOrientationFlippedLandscape), + _needEventRestPeriod(false), _mouseClickAndDragEnabled(false), _touchpadModeEnabled(true), + _gestureStartX(-1), _gestureStartY(-1), _fullScreenIsDirty(false), _fullScreenOverlayIsDirty(false), + _mouseDirty(false), _timeSuspended(0), _lastDragPosX(-1), _lastDragPosY(-1), _screenChangeCount(0) + +{ + _queuedInputEvent.type = (Common::EventType)0; + _lastDrawnMouseRect = Common::Rect(0, 0, 0, 0); + + _fsFactory = new POSIXFilesystemFactory(); +} + +OSystem_IPHONE::~OSystem_IPHONE() { + AudioQueueDispose(s_AudioQueue.queue, true); + + delete _fsFactory; + delete _savefile; + delete _mixer; + delete _timer; + delete _offscreen; + delete _fullscreen; +} + +int OSystem_IPHONE::timerHandler(int t) { + DefaultTimerManager *tm = (DefaultTimerManager *)g_system->getTimerManager(); + tm->handler(); + return t; +} + +void OSystem_IPHONE::initBackend() { +#ifdef IPHONE_OFFICIAL + _savefile = new DefaultSaveFileManager(iPhone_getDocumentsDir()); +#else + _savefile = new DefaultSaveFileManager(SCUMMVM_SAVE_PATH); +#endif + + _timer = new DefaultTimerManager(); + + gettimeofday(&_startTime, NULL); + + setupMixer(); + + setTimerCallback(&OSystem_IPHONE::timerHandler, 10); + + OSystem::initBackend(); +} + +bool OSystem_IPHONE::hasFeature(Feature f) { + return false; +} + +void OSystem_IPHONE::setFeatureState(Feature f, bool enable) { +} + +bool OSystem_IPHONE::getFeatureState(Feature f) { + return false; +} + +void OSystem_IPHONE::suspendLoop() { + bool done = false; + int eventType; + float xUnit, yUnit; + uint32 startTime = getMillis(); + + stopSoundsystem(); + + while (!done) { + if (iPhone_fetchEvent(&eventType, &xUnit, &yUnit)) + if ((InputEvent)eventType == kInputApplicationResumed) + done = true; + usleep(100000); + } + + startSoundsystem(); + + _timeSuspended += getMillis() - startTime; +} + +uint32 OSystem_IPHONE::getMillis() { + //printf("getMillis()\n"); + + struct timeval currentTime; + gettimeofday(¤tTime, NULL); + return (uint32)(((currentTime.tv_sec - _startTime.tv_sec) * 1000) + + ((currentTime.tv_usec - _startTime.tv_usec) / 1000)) - _timeSuspended; +} + +void OSystem_IPHONE::delayMillis(uint msecs) { + //printf("delayMillis(%d)\n", msecs); + usleep(msecs * 1000); +} + +OSystem::MutexRef OSystem_IPHONE::createMutex(void) { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + + pthread_mutex_t *mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t)); + if (pthread_mutex_init(mutex, &attr) != 0) { + printf("pthread_mutex_init() failed!\n"); + free(mutex); + return NULL; + } + + return (MutexRef)mutex; +} + +void OSystem_IPHONE::lockMutex(MutexRef mutex) { + if (pthread_mutex_lock((pthread_mutex_t *) mutex) != 0) { + printf("pthread_mutex_lock() failed!\n"); + } +} + +void OSystem_IPHONE::unlockMutex(MutexRef mutex) { + if (pthread_mutex_unlock((pthread_mutex_t *) mutex) != 0) { + printf("pthread_mutex_unlock() failed!\n"); + } +} + +void OSystem_IPHONE::deleteMutex(MutexRef mutex) { + if (pthread_mutex_destroy((pthread_mutex_t *) mutex) != 0) { + printf("pthread_mutex_destroy() failed!\n"); + } else { + free(mutex); + } +} + + +void OSystem_IPHONE::setTimerCallback(TimerProc callback, int interval) { + //printf("setTimerCallback()\n"); + + if (callback != NULL) { + _timerCallbackTimer = interval; + _timerCallbackNext = getMillis() + interval; + _timerCallback = callback; + } else + _timerCallback = NULL; +} + +void OSystem_IPHONE::quit() { +} + +void OSystem_IPHONE::getTimeAndDate(TimeDate &td) const { + time_t curTime = time(0); + struct tm t = *localtime(&curTime); + td.tm_sec = t.tm_sec; + td.tm_min = t.tm_min; + td.tm_hour = t.tm_hour; + td.tm_mday = t.tm_mday; + td.tm_mon = t.tm_mon; + td.tm_year = t.tm_year; +} + +Common::SaveFileManager *OSystem_IPHONE::getSavefileManager() { + assert(_savefile); + return _savefile; +} + +Audio::Mixer *OSystem_IPHONE::getMixer() { + assert(_mixer); + return _mixer; +} + +Common::TimerManager *OSystem_IPHONE::getTimerManager() { + assert(_timer); + return _timer; +} + +OSystem *OSystem_IPHONE_create() { + return new OSystem_IPHONE(); +} + +Common::SeekableReadStream *OSystem_IPHONE::createConfigReadStream() { +#ifdef IPHONE_OFFICIAL + char buf[256]; + strncpy(buf, iPhone_getDocumentsDir(), 256); + strncat(buf, "/Preferences", 256 - strlen(buf) ); + Common::FSNode file(buf); +#else + Common::FSNode file(SCUMMVM_PREFS_PATH); +#endif + return file.createReadStream(); +} + +Common::WriteStream *OSystem_IPHONE::createConfigWriteStream() { +#ifdef IPHONE_OFFICIAL + char buf[256]; + strncpy(buf, iPhone_getDocumentsDir(), 256); + strncat(buf, "/Preferences", 256 - strlen(buf) ); + Common::FSNode file(buf); +#else + Common::FSNode file(SCUMMVM_PREFS_PATH); +#endif + return file.createWriteStream(); +} + +void OSystem_IPHONE::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { + // Get URL of the Resource directory of the .app bundle + CFURLRef fileUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); + if (fileUrl) { + // Try to convert the URL to an absolute path + UInt8 buf[MAXPATHLEN]; + if (CFURLGetFileSystemRepresentation(fileUrl, true, buf, sizeof(buf))) { + // Success: Add it to the search path + Common::String bundlePath((const char *)buf); + s.add("__OSX_BUNDLE__", new Common::FSDirectory(bundlePath), priority); + } + CFRelease(fileUrl); + } +} + +void iphone_main(int argc, char *argv[]) { + + //OSystem_IPHONE::migrateApp(); + + FILE *newfp = fopen("/var/mobile/.scummvm.log", "a"); + if (newfp != NULL) { + fclose(stdout); + fclose(stderr); + *stdout = *newfp; + *stderr = *newfp; + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + //extern int gDebugLevel; + //gDebugLevel = 10; + } + +#ifdef IPHONE_OFFICIAL + chdir( iPhone_getDocumentsDir() ); +#else + system("mkdir " SCUMMVM_ROOT_PATH); + system("mkdir " SCUMMVM_SAVE_PATH); + + chdir("/var/mobile/"); +#endif + + g_system = OSystem_IPHONE_create(); + assert(g_system); + + // Invoke the actual ScummVM main entry point: + scummvm_main(argc, argv); + g_system->quit(); // TODO: Consider removing / replacing this! +} diff --git a/src/sdl/iphone/osys_main.h b/src/sdl/iphone/osys_main.h new file mode 100644 index 000000000..d0eb460c9 --- /dev/null +++ b/src/sdl/iphone/osys_main.h @@ -0,0 +1,209 @@ +/* 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. + * + * $URL: https://scummvm.svn.sf.net/svnroot/scummvm/scummvm/trunk/backends/platform/iphone/osys_main.h $ + * $Id: osys_main.h 44793 2009-10-08 19:41:38Z fingolfin $ + * + */ + +#include "graphics/surface.h" +#include "iphone_common.h" +#include "backends/base-backend.h" +#include "common/events.h" +#include "sound/mixer_intern.h" +#include "backends/fs/posix/posix-fs-factory.h" +#include "graphics/colormasks.h" + +#include + +#define AUDIO_BUFFERS 3 +#define WAVE_BUFFER_SIZE 2048 +#define AUDIO_SAMPLE_RATE 44100 + +#define SCUMMVM_ROOT_PATH "/var/mobile/Library/ScummVM" +#define SCUMMVM_SAVE_PATH SCUMMVM_ROOT_PATH "/Savegames" +#define SCUMMVM_PREFS_PATH SCUMMVM_ROOT_PATH "/Preferences" + +typedef void (*SoundProc)(void *param, byte *buf, int len); +typedef int (*TimerProc)(int interval); + +typedef struct AQCallbackStruct { + AudioQueueRef queue; + uint32 frameCount; + AudioQueueBufferRef buffers[AUDIO_BUFFERS]; + AudioStreamBasicDescription dataFormat; +} AQCallbackStruct; + +class OSystem_IPHONE : public BaseBackend { +protected: + + static const OSystem::GraphicsMode s_supportedGraphicsModes[]; + static AQCallbackStruct s_AudioQueue; + static SoundProc s_soundCallback; + static void *s_soundParam; + + Common::SaveFileManager *_savefile; + Audio::MixerImpl *_mixer; + Common::TimerManager *_timer; + + Graphics::Surface _framebuffer; + byte *_offscreen; + OverlayColor *_overlayBuffer; + uint16 *_fullscreen; + + uint16 _palette[256]; + bool _overlayVisible; + uint16 _screenWidth; + uint16 _screenHeight; + + struct timeval _startTime; + uint32 _timeSuspended; + + bool _mouseVisible; + byte *_mouseBuf; + byte _mouseKeyColour; + uint _mouseWidth, _mouseHeight; + uint _mouseX, _mouseY; + int _mouseHotspotX, _mouseHotspotY; + bool _mouseDirty; + long _lastMouseDown; + long _lastMouseTap; + Common::Rect _lastDrawnMouseRect; + Common::Event _queuedInputEvent; + bool _needEventRestPeriod; + bool _secondaryTapped; + long _lastSecondaryDown; + long _lastSecondaryTap; + int _gestureStartX, _gestureStartY; + bool _mouseClickAndDragEnabled; + bool _touchpadModeEnabled; + int _lastPadX; + int _lastPadY; + int _lastDragPosX; + int _lastDragPosY; + + int _timerCallbackNext; + int _timerCallbackTimer; + TimerProc _timerCallback; + + Common::Array _dirtyRects; + Common::Array _dirtyOverlayRects; + ScreenOrientation _screenOrientation; + bool _fullScreenIsDirty; + bool _fullScreenOverlayIsDirty; + int _screenChangeCount; + FilesystemFactory *_fsFactory; + +public: + + OSystem_IPHONE(); + virtual ~OSystem_IPHONE(); + + virtual void initBackend(); + + virtual bool hasFeature(Feature f); + virtual void setFeatureState(Feature f, bool enable); + virtual bool getFeatureState(Feature f); + virtual const GraphicsMode *getSupportedGraphicsModes() const; + virtual int getDefaultGraphicsMode() const; + 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 int16 getHeight(); + virtual int16 getWidth(); + virtual void setPalette(const byte *colors, uint start, uint num); + virtual void grabPalette(byte *colors, uint start, uint num); + virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h); + virtual void updateScreen(); + virtual Graphics::Surface *lockScreen(); + virtual void unlockScreen(); + virtual void setShakePos(int shakeOffset); + + virtual void showOverlay(); + virtual void hideOverlay(); + virtual void clearOverlay(); + virtual void grabOverlay(OverlayColor *buf, int pitch); + virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); + virtual int16 getOverlayHeight(); + virtual int16 getOverlayWidth(); + virtual Graphics::PixelFormat getOverlayFormat() const { return Graphics::createPixelFormat<565>(); } + + virtual bool showMouse(bool visible); + + 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 bool pollEvent(Common::Event &event); + virtual uint32 getMillis(); + virtual void delayMillis(uint msecs); + + virtual MutexRef createMutex(void); + virtual void lockMutex(MutexRef mutex); + virtual void unlockMutex(MutexRef mutex); + virtual void deleteMutex(MutexRef mutex); + + static void mixCallback(void *sys, byte *samples, int len); + virtual void setupMixer(void); + virtual int getOutputSampleRate() const; + virtual void setTimerCallback(TimerProc callback, int interval); + virtual int getScreenChangeID() const { return _screenChangeCount; } + virtual void quit(); + + FilesystemFactory *getFilesystemFactory() { return _fsFactory; } + virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); + virtual void getTimeAndDate(TimeDate &t) const; + + virtual Common::SaveFileManager *getSavefileManager(); + virtual Audio::Mixer *getMixer(); + virtual Common::TimerManager *getTimerManager(); + + void startSoundsystem(); + void stopSoundsystem(); + + virtual Common::SeekableReadStream *createConfigReadStream(); + virtual Common::WriteStream *createConfigWriteStream(); + +protected: + 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); + static void AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB); + static int timerHandler(int t); + + bool handleEvent_swipe(Common::Event &event, int direction); + void handleEvent_keyPressed(Common::Event &event, int keyPressed); + void handleEvent_orientationChanged(int orientation); + + bool handleEvent_mouseDown(Common::Event &event, int x, int y); + bool handleEvent_mouseUp(Common::Event &event, int x, int y); + + bool handleEvent_secondMouseDown(Common::Event &event, int x, int y); + bool handleEvent_secondMouseUp(Common::Event &event, int x, int y); + + bool handleEvent_mouseDragged(Common::Event &event, int x, int y); + bool handleEvent_mouseSecondDragged(Common::Event &event, int x, int y); +}; diff --git a/src/sdl/iphone/osys_sound.cpp b/src/sdl/iphone/osys_sound.cpp new file mode 100644 index 000000000..44625cf93 --- /dev/null +++ b/src/sdl/iphone/osys_sound.cpp @@ -0,0 +1,111 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL: https://scummvm.svn.sf.net/svnroot/scummvm/scummvm/trunk/backends/platform/iphone/osys_sound.cpp $ + * $Id: osys_sound.cpp 42479 2009-07-14 13:52:11Z vinterstum $ + * + */ + +#include "osys_main.h" + +void OSystem_IPHONE::AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB) { + //printf("AQBufferCallback()\n"); + if (s_AudioQueue.frameCount > 0 && s_soundCallback != NULL) { + outQB->mAudioDataByteSize = 4 * s_AudioQueue.frameCount; + s_soundCallback(s_soundParam, (byte *)outQB->mAudioData, outQB->mAudioDataByteSize); + AudioQueueEnqueueBuffer(inQ, outQB, 0, NULL); + } else { + AudioQueueStop(s_AudioQueue.queue, false); + } +} + +void OSystem_IPHONE::mixCallback(void *sys, byte *samples, int len) { + OSystem_IPHONE *this_ = (OSystem_IPHONE *)sys; + assert(this_); + + if (this_->_mixer) { + this_->_mixer->mixCallback(samples, len); + } +} + +void OSystem_IPHONE::setupMixer() { + //printf("setSoundCallback()\n"); + _mixer = new Audio::MixerImpl(this); + + s_soundCallback = mixCallback; + s_soundParam = this; + + startSoundsystem(); +} + +void OSystem_IPHONE::startSoundsystem() { + s_AudioQueue.dataFormat.mSampleRate = AUDIO_SAMPLE_RATE; + s_AudioQueue.dataFormat.mFormatID = kAudioFormatLinearPCM; + s_AudioQueue.dataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; + s_AudioQueue.dataFormat.mBytesPerPacket = 4; + s_AudioQueue.dataFormat.mFramesPerPacket = 1; + s_AudioQueue.dataFormat.mBytesPerFrame = 4; + s_AudioQueue.dataFormat.mChannelsPerFrame = 2; + s_AudioQueue.dataFormat.mBitsPerChannel = 16; + s_AudioQueue.frameCount = WAVE_BUFFER_SIZE; + + if (AudioQueueNewOutput(&s_AudioQueue.dataFormat, AQBufferCallback, &s_AudioQueue, 0, kCFRunLoopCommonModes, 0, &s_AudioQueue.queue)) { + printf("Couldn't set the AudioQueue callback!\n"); + _mixer->setReady(false); + return; + } + + uint32 bufferBytes = s_AudioQueue.frameCount * s_AudioQueue.dataFormat.mBytesPerFrame; + + for (int i = 0; i < AUDIO_BUFFERS; i++) { + if (AudioQueueAllocateBuffer(s_AudioQueue.queue, bufferBytes, &s_AudioQueue.buffers[i])) { + printf("Error allocating AudioQueue buffer!\n"); + _mixer->setReady(false); + return; + } + + AQBufferCallback(&s_AudioQueue, s_AudioQueue.queue, s_AudioQueue.buffers[i]); + } + + AudioQueueSetParameter(s_AudioQueue.queue, kAudioQueueParam_Volume, 1.0); + if (AudioQueueStart(s_AudioQueue.queue, NULL)) { + printf("Error starting the AudioQueue!\n"); + _mixer->setReady(false); + return; + } + + _mixer->setOutputRate(AUDIO_SAMPLE_RATE); + _mixer->setReady(true); +} + +void OSystem_IPHONE::stopSoundsystem() { + AudioQueueStop(s_AudioQueue.queue, true); + + for (int i = 0; i < AUDIO_BUFFERS; i++) { + AudioQueueFreeBuffer(s_AudioQueue.queue, s_AudioQueue.buffers[i]); + } + + AudioQueueDispose(s_AudioQueue.queue, true); + _mixer->setReady(false); +} + +int OSystem_IPHONE::getOutputSampleRate() const { + return AUDIO_SAMPLE_RATE; +} diff --git a/src/sdl/iphone/osys_video.cpp b/src/sdl/iphone/osys_video.cpp new file mode 100644 index 000000000..b262315f7 --- /dev/null +++ b/src/sdl/iphone/osys_video.cpp @@ -0,0 +1,463 @@ +/* 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. + * + * $URL: https://scummvm.svn.sf.net/svnroot/scummvm/scummvm/trunk/backends/platform/iphone/osys_video.cpp $ + * $Id: osys_video.cpp 43651 2009-08-22 14:52:26Z sev $ + * + */ + +#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); + + _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) { + //printf("setPalette()\n"); + const byte *b = colors; + + for (uint i = start; i < start + num; ++i) { + _palette[i] = Graphics::RGBToColor >(b[0], b[1], b[2]); + b += 4; + } + + dirtyFullScreen(); +} + +void OSystem_IPHONE::grabPalette(byte *colors, uint start, uint num) { + //printf("grabPalette()\n"); +} + +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(); +} + +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); + + 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; + } +} + +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 right = left + _mouseWidth; + 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 != _mouseKeyColour) + *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.bytesPerPixel = 1; + + 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(); +} + +void OSystem_IPHONE::hideOverlay() { + //printf("hideOverlay()\n"); + _overlayVisible = false; + _dirtyOverlayRects.clear(); + dirtyFullScreen(); +} + +void OSystem_IPHONE::clearOverlay() { + //printf("clearOverlay()\n"); + bzero(_overlayBuffer, _screenWidth * _screenHeight * sizeof(OverlayColor)); + dirtyFullOverlayScreen(); +} + +void OSystem_IPHONE::grabOverlay(OverlayColor *buf, int pitch) { + //printf("grabOverlay()\n"); + int h = _screenHeight; + OverlayColor *src = _overlayBuffer; + + do { + memcpy(buf, src, _screenWidth * sizeof(OverlayColor)); + src += _screenWidth; + 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 > _screenWidth - x) + w = _screenWidth - x; + + if (h > _screenHeight - y) + h = _screenHeight - y; + + if (w <= 0 || h <= 0) + return; + + if (!_fullScreenOverlayIsDirty) { + _dirtyOverlayRects.push_back(Common::Rect(x, y, x + w, y + h)); + } + + OverlayColor *dst = _overlayBuffer + (y * _screenWidth + x); + if (_screenWidth == pitch && pitch == w) + memcpy(dst, buf, h * w * sizeof(OverlayColor)); + else { + do { + memcpy(dst, buf, w * sizeof(OverlayColor)); + buf += pitch; + dst += _screenWidth; + } while (--h); + } +} + +int16 OSystem_IPHONE::getOverlayHeight() { + return _screenHeight; +} + +int16 OSystem_IPHONE::getOverlayWidth() { + return _screenWidth; +} + +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, _screenWidth, _screenHeight)); + _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)\n", hotspotX, hotspotY); + + 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; + + _mouseKeyColour = (byte)keycolor; + + memcpy(_mouseBuf, buf, w * h); + + _mouseDirty = true; +}