diff options
author | Johannes Schickel | 2016-01-07 10:38:31 +0100 |
---|---|---|
committer | Johannes Schickel | 2016-01-07 10:38:31 +0100 |
commit | bd1039b93ef3cb1541e9df91879c704aa894ddd9 (patch) | |
tree | 06aad88a939836932c53c27681507283376ad159 | |
parent | cf5856492c6ce1820339dd76f9d3175f9f457215 (diff) | |
parent | b5ef98637c54a453a6f0ac0ca8c501ceb59924d5 (diff) | |
download | scummvm-rg350-bd1039b93ef3cb1541e9df91879c704aa894ddd9.tar.gz scummvm-rg350-bd1039b93ef3cb1541e9df91879c704aa894ddd9.tar.bz2 scummvm-rg350-bd1039b93ef3cb1541e9df91879c704aa894ddd9.zip |
Merge pull request #630 from bSr43/ios-fix
IOS: Fixes the iOS port
68 files changed, 4955 insertions, 335 deletions
@@ -287,8 +287,9 @@ ScummVM Team GPH Devices (GP2X, GP2XWiz & Caanoo): John Willis - iPhone: + iPhone / iPad: Oystein Eftevaag + Vincent Benony LinuxMoto: Lubomyr Lisen diff --git a/audio/softsynth/fluidsynth.cpp b/audio/softsynth/fluidsynth.cpp index 9b64d70f2b..4dc43499d3 100644 --- a/audio/softsynth/fluidsynth.cpp +++ b/audio/softsynth/fluidsynth.cpp @@ -31,6 +31,11 @@ #include "audio/musicplugin.h" #include "audio/mpu401.h" #include "audio/softsynth/emumidi.h" +#if defined(IPHONE_IOS7) && defined(IPHONE_SANDBOXED) +#include <string.h> +#include <sys/syslimits.h> +#include "backends/platform/ios7/ios7_common.h" +#endif #include <fluidsynth.h> @@ -179,7 +184,17 @@ int MidiDriver_FluidSynth::open() { const char *soundfont = ConfMan.get("soundfont").c_str(); +#if defined(IPHONE_IOS7) && defined(IPHONE_SANDBOXED) + // HACK: Due to the sandbox on non-jailbroken iOS devices, we need to deal with the chroot filesystem. + // All the path selected by the user are relative to the Document directory. So, we need to adjust + // the path to reflect that. + Common::String soundfont_fullpath = iOS7_getDocumentsDir(); + soundfont_fullpath += soundfont; + _soundFont = fluid_synth_sfload(_synth, soundfont_fullpath.c_str(), 1); +#else _soundFont = fluid_synth_sfload(_synth, soundfont, 1); +#endif + if (_soundFont == -1) error("Failed loading custom sound font '%s'", soundfont); diff --git a/backends/fs/chroot/chroot-fs-factory.cpp b/backends/fs/chroot/chroot-fs-factory.cpp new file mode 100644 index 0000000000..fa98ab75d3 --- /dev/null +++ b/backends/fs/chroot/chroot-fs-factory.cpp @@ -0,0 +1,60 @@ +/* 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. + * + */ + +#if defined(POSIX) + +#define FORBIDDEN_SYMBOL_EXCEPTION_time_h +#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h +#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir +#define FORBIDDEN_SYMBOL_EXCEPTION_exit //Needed for IRIX's unistd.h + +#include "chroot-fs-factory.h" +#include "backends/fs/chroot/chroot-fs.h" +#include "backends/fs/posix/posix-fs-factory.h" + +ChRootFilesystemFactory::ChRootFilesystemFactory(Common::String root) { + _root = root; +} + +AbstractFSNode *ChRootFilesystemFactory::makeRootFileNode() const { + return new ChRootFilesystemNode(_root, "/"); +} + +AbstractFSNode *ChRootFilesystemFactory::makeCurrentDirectoryFileNode() const { + char buf[MAXPATHLEN]; + if (getcwd(buf, MAXPATHLEN) == NULL) { + return NULL; + } + + if (Common::String(buf).hasPrefix(_root + Common::String("/"))) { + return new ChRootFilesystemNode(_root, buf + _root.size()); + } + + return new ChRootFilesystemNode(_root, "/"); +} + +AbstractFSNode *ChRootFilesystemFactory::makeFileNodePath(const Common::String &path) const { + assert(!path.empty()); + return new ChRootFilesystemNode(_root, path); +} + +#endif diff --git a/backends/fs/chroot/chroot-fs-factory.h b/backends/fs/chroot/chroot-fs-factory.h new file mode 100644 index 0000000000..23b3c8f44a --- /dev/null +++ b/backends/fs/chroot/chroot-fs-factory.h @@ -0,0 +1,45 @@ +/* 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. + * + */ + +/* + * FIXME: Warning, using this factory in your backend may silently breaks some features. Instances are, for example, the FluidSynth code, and the POSIX plugin code. + */ + +#ifndef BACKENDS_FS_CHROOT_CHROOT_FS_FACTORY_H +#define BACKENDS_FS_CHROOT_CHROOT_FS_FACTORY_H + +#include "backends/fs/fs-factory.h" + +class ChRootFilesystemFactory : public FilesystemFactory { +private: + Common::String _root; + +protected: + virtual AbstractFSNode *makeRootFileNode() const; + virtual AbstractFSNode *makeCurrentDirectoryFileNode() const; + virtual AbstractFSNode *makeFileNodePath(const Common::String &path) const; + +public: + ChRootFilesystemFactory(Common::String root); +}; + +#endif /* BACKENDS_FS_CHROOT_CHROOT_FS_FACTORY_H */ diff --git a/backends/fs/chroot/chroot-fs.cpp b/backends/fs/chroot/chroot-fs.cpp new file mode 100644 index 0000000000..2cbb4af9d6 --- /dev/null +++ b/backends/fs/chroot/chroot-fs.cpp @@ -0,0 +1,124 @@ +/* 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. + * + */ + +#if defined(POSIX) + +// Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h. +// Also with clock() in sys/time.h in some Mac OS X SDKs. +#define FORBIDDEN_SYMBOL_EXCEPTION_time_h +#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h +#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir +#define FORBIDDEN_SYMBOL_EXCEPTION_getenv +#define FORBIDDEN_SYMBOL_EXCEPTION_exit //Needed for IRIX's unistd.h + +#include "backends/fs/chroot/chroot-fs.h" + +ChRootFilesystemNode::ChRootFilesystemNode(const Common::String &root, POSIXFilesystemNode *node) { + _root = Common::normalizePath(root, '/'); + _realNode = node; +} + +ChRootFilesystemNode::ChRootFilesystemNode(const Common::String &root, const Common::String &path) { + _root = Common::normalizePath(root, '/'); + _realNode = new POSIXFilesystemNode(addPathComponent(root, path)); +} + +ChRootFilesystemNode::~ChRootFilesystemNode() { + delete _realNode; +} + +bool ChRootFilesystemNode::exists() const { + return _realNode->exists(); +} + +Common::String ChRootFilesystemNode::getDisplayName() const { + return getName(); +} + +Common::String ChRootFilesystemNode::getName() const { + return _realNode->AbstractFSNode::getDisplayName(); +} + +Common::String ChRootFilesystemNode::getPath() const { + Common::String path = _realNode->getPath(); + if (path.size() > _root.size()) { + return Common::String(path.c_str() + _root.size()); + } + return Common::String("/"); +} + +bool ChRootFilesystemNode::isDirectory() const { + return _realNode->isDirectory(); +} + +bool ChRootFilesystemNode::isReadable() const { + return _realNode->isReadable(); +} + +bool ChRootFilesystemNode::isWritable() const { + return _realNode->isWritable(); +} + +AbstractFSNode *ChRootFilesystemNode::getChild(const Common::String &n) const { + return new ChRootFilesystemNode(_root, (POSIXFilesystemNode *)_realNode->getChild(n)); +} + +bool ChRootFilesystemNode::getChildren(AbstractFSList &list, ListMode mode, bool hidden) const { + AbstractFSList tmp; + if (!_realNode->getChildren(tmp, mode, hidden)) { + return false; + } + + for (AbstractFSList::iterator i=tmp.begin(); i!=tmp.end(); ++i) { + list.push_back(new ChRootFilesystemNode(_root, (POSIXFilesystemNode *) *i)); + } + + return true; +} + +AbstractFSNode *ChRootFilesystemNode::getParent() const { + if (getPath() == "/") return 0; + return new ChRootFilesystemNode(_root, (POSIXFilesystemNode *)_realNode->getParent()); +} + +Common::SeekableReadStream *ChRootFilesystemNode::createReadStream() { + return _realNode->createReadStream(); +} + +Common::WriteStream *ChRootFilesystemNode::createWriteStream() { + return _realNode->createWriteStream(); +} + +Common::String ChRootFilesystemNode::addPathComponent(const Common::String &path, const Common::String &component) { + const char sep = '/'; + if (path.lastChar() == sep && component.firstChar() == sep) { + return Common::String::format("%s%s", path.c_str(), component.c_str() + 1); + } + + if (path.lastChar() == sep || component.firstChar() == sep) { + return Common::String::format("%s%s", path.c_str(), component.c_str()); + } + + return Common::String::format("%s%c%s", path.c_str(), sep, component.c_str()); +} + +#endif diff --git a/backends/fs/chroot/chroot-fs.h b/backends/fs/chroot/chroot-fs.h new file mode 100644 index 0000000000..9ff913be31 --- /dev/null +++ b/backends/fs/chroot/chroot-fs.h @@ -0,0 +1,57 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef BACKENDS_FS_CHROOT_CHROOT_FS_H +#define BACKENDS_FS_CHROOT_CHROOT_FS_H + +#include "backends/fs/posix/posix-fs.h" + +class ChRootFilesystemNode : public AbstractFSNode { + Common::String _root; + POSIXFilesystemNode *_realNode; + + ChRootFilesystemNode(const Common::String &root, POSIXFilesystemNode *); + +public: + ChRootFilesystemNode(const Common::String &root, const Common::String &path); + virtual ~ChRootFilesystemNode(); + + virtual bool exists() const; + virtual Common::String getDisplayName() const; + virtual Common::String getName() const; + virtual Common::String getPath() const; + virtual bool isDirectory() const; + virtual bool isReadable() const; + virtual bool isWritable() const; + + virtual AbstractFSNode *getChild(const Common::String &n) const; + virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; + virtual AbstractFSNode *getParent() const; + + virtual Common::SeekableReadStream *createReadStream(); + virtual Common::WriteStream *createWriteStream(); + +private: + static Common::String addPathComponent(const Common::String &path, const Common::String &component); +}; + +#endif /* BACKENDS_FS_CHROOT_CHROOT_FS_H */ diff --git a/backends/module.mk b/backends/module.mk index 3d7dea1f26..3d412c031a 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -88,6 +88,8 @@ ifdef POSIX MODULE_OBJS += \ fs/posix/posix-fs.o \ fs/posix/posix-fs-factory.o \ + fs/chroot/chroot-fs-factory.o \ + fs/chroot/chroot-fs.o \ plugins/posix/posix-provider.o \ saves/posix/posix-saves.o \ taskbar/unity/unity-taskbar.o diff --git a/backends/platform/ios7/README.md b/backends/platform/ios7/README.md new file mode 100644 index 0000000000..1f34c15cc6 --- /dev/null +++ b/backends/platform/ios7/README.md @@ -0,0 +1,150 @@ +# ScummVM for iOS 7.1+ # + +This is a quick fix of the latest ScummVM (1.8.0) for iOS 7.1. It has been tested on real iPhone 6S+, and iPad Pro, and also on all the available Xcode simulators. + +I tried to use all the latest iOS features to replace the old code. For instance, it uses gesture recognizers most of the time, it supports the new iPhones 6 / 6+ / 6s / 6s+ resolution, and you can copy your game files using iTunes. + +## Compilation ## + +First, clone the repository: +``` +$ git clone -b ios-fix --recursive https://github.com/bSr43/scummvm.git +``` + +### Compilation from Xcode ### + +This is the recommended way to compile ScummVM, and the only one which makes it possible to run ScummVM on a non-jailbroken device! + +The next step is to compile the **create_project** tool. Open the Xcode project you'll found in the **devtools/create\_project/xcode/** directory. Once compiled, copy the binary somewhere in your *PATH*, and create a **build** directory somewhere on your harddisk. It is recommended to create this directory next to the cloned repository (they share the same parent). + +Execute the following commands in a terminal: +``` +$ cd path_to_the_build_directory +$ create_project path_to_scummvm_repository --xcode --enable-fluidsynth --disable-jpeg --disable-bink --disable-16bit --disable-mt32emu --disable-nasm --disable-opengl --disable-theora --disable-taskbar +``` + +This will create an Xcode project for ScummVM, for both the OS X, and the iOS target. + +Now, download the external libraries from http://bsr43.free.fr/scummvm/ScummVM-iOS-libraries.zip. Unzip the archive in your **build** directory. Please make sure that the **lib**, and **include** directories are at the root of the **build** directory, not in a subdirectory. + +Now, your **build** directory should contain: +* a generated **engines** directory, +* a generated **scummvm.xcodeproj** project, +* an **include** directory, +* a **lib** directory. + +You are ready to compile ScummVM: open the **scummvm.xcodeproj** project, and build it. + +### Compilation from command line ### + +For jailbroken devices, it is also possible to compile the project from command line. You'll need a working toolchain, and some tools, like **ldid**, to fake the code signature. + +Here is a script to download, and compile all the required tools. This script has been wrote for Debian 8.2, and should be run as root. + +``` +#!/bin/bash + +if [ $UID -ne 0 ]; then + echo "This script should be run by the root user" + exit 1 +fi + +# Install the Clang compiler +apt-get install -y clang-3.4 libclang-3.4-dev llvm-3.4 libtool bison flex automake subversion git pkg-config wget libssl-dev uuid-dev libxml2-dev || exit 1 + +# Add LLVM to the linker library path +echo /usr/lib/llvm-3.4/lib > /etc/ld.so.conf.d/libllvm-3.4.conf +ldconfig + +# Add symlinks for the LLVM headers +ln -s /usr/lib/llvm-3.4/bin/llvm-config /usr/bin/llvm-config || exit 1 +ln -s /usr/include/llvm-3.4/llvm /usr/include/llvm || exit 1 +ln -s /usr/include/llvm-c-3.4/llvm-c /usr/include/llvm-c || exit 1 +ln -s /usr/bin/clang-3.4 /usr/bin/clang || exit 1 +ln -s /usr/bin/clang++-3.4 /usr/bin/clang++ || exit 1 + +# Build the linker +svn checkout http://ios-toolchain-based-on-clang-for-linux.googlecode.com/svn/trunk/cctools-porting || exit 1 +cd cctools-porting +sed -i'' 's/proz -k=20 --no-curses/wget/g' cctools-ld64.sh +./cctools-ld64.sh || exit 1 + +cd cctools-855-ld64-236.3 +./autogen.sh || exit 1 +./configure --prefix=/usr/local --target=arm-apple-darwin11 || exit 1 +make || exit 1 +make install || exit 1 +cd ../.. + +# Install ios-tools +wget https://ios-toolchain-based-on-clang-for-linux.googlecode.com/files/iphonesdk-utils-2.0.tar.gz || exit 1 +tar xzf iphonesdk-utils-2.0.tar.gz +cd iphonesdk-utils-2.0 +patch -p0 <<_EOF +*** genLocalization2/getLocalizedStringFromFile.cpp 2015-04-02 04:45:39.309837816 +0530 +--- genLocalization2/getLocalizedStringFromFile.cpp 2015-04-02 04:45:11.525700021 +0530 +*************** +*** 113,115 **** + clang::HeaderSearch headerSearch(headerSearchOptions, +- fileManager, + *pDiagnosticsEngine, +--- 113,115 ---- + clang::HeaderSearch headerSearch(headerSearchOptions, ++ sourceManager, + *pDiagnosticsEngine, +*************** +*** 129,134 **** + false); +- clang::HeaderSearch headerSearch(fileManager, + *pDiagnosticsEngine, + languageOptions, +- pTargetInfo); + ApplyHeaderSearchOptions(headerSearch, headerSearchOptions, languageOptions, pTargetInfo->getTriple()); +--- 129,134 ---- + false); ++ clang::HeaderSearch headerSearch(fileManager);/*, + *pDiagnosticsEngine, + languageOptions, ++ pTargetInfo);*/ + ApplyHeaderSearchOptions(headerSearch, headerSearchOptions, languageOptio +_EOF + +./autogen.sh || exit 1 +CC=clang CXX=clang++ ./configure --prefix=/usr/local || exit 1 +make || exit 1 +make install || exit 1 + +# Install the iOS SDK 8.1 +mkdir -p /usr/share/ios-sdk +cd /usr/share/ios-sdk +wget http://iphone.howett.net/sdks/dl/iPhoneOS8.1.sdk.tbz2 || exit 1 +tar xjf iPhoneOS8.1.sdk.tbz2 +rm iPhoneOS8.1.sdk.tbz2 +``` + +Now, in order to compile ScummVM, execute the following commands: +``` +$ export SDKROOT=/usr/share/ios-sdk/iPhoneOS8.1.sdk +$ export CC=ios-clang +$ export CXX=ios-clang++ +$ ./configure --host=ios7 --disable-mt32emu --enable-release +$ make ios7bundle +``` + +At the end of the compilation, you'll find a **ScummVM.app** application: copy it over SSH, and reboot your device. + +## Usage ## + +The game data files can be copied on the iOS device using iTunes. Once done, add your games in ScummVM as usual. + +Here is a list of the in-game gestures: + +|Gesture|Description| +|-------|-----------| +|Two fingers swipe down|Display the ScummVM menu for loading, saving, etc.| +|Two fingers swipe right|Enable / disable the touchpad mode| +|Two fingers swipe up|Enable / disable the mouse-click-and-drag mode| +|Two fingers tap|Simulate a right click. You should tap with one finger, and then tap with another while keeping your first finger on the screen.| +|Two fingers double-tap|Skip the cinematic / video| + +The iOS keyboard is visible when the device is in portrait mode, and hidden in landscape mode. diff --git a/backends/platform/ios7/iOS7AppDelegate.h b/backends/platform/ios7/iOS7AppDelegate.h new file mode 100644 index 0000000000..7f903a692d --- /dev/null +++ b/backends/platform/ios7/iOS7AppDelegate.h @@ -0,0 +1,15 @@ +// +// Created by Vincent Bénony on 07/12/2015. +// + +#import <UIKit/UIKit.h> + +@class iPhoneView; + + +@interface iOS7AppDelegate : NSObject<UIApplicationDelegate> + ++ (iOS7AppDelegate *)iOS7AppDelegate; ++ (iPhoneView *)iPhoneView; + +@end diff --git a/backends/platform/ios7/iOS7AppDelegate.mm b/backends/platform/ios7/iOS7AppDelegate.mm new file mode 100644 index 0000000000..e9908ec146 --- /dev/null +++ b/backends/platform/ios7/iOS7AppDelegate.mm @@ -0,0 +1,95 @@ +// +// Created by Vincent Bénony on 07/12/2015. +// + +#define FORBIDDEN_SYMBOL_ALLOW_ALL +#import "iOS7AppDelegate.h" +#import "iOS7ScummVMViewController.h" +#import "ios7_video.h" + +@implementation iOS7AppDelegate { + UIWindow *_window; + iOS7ScummVMViewController *_controller; + iPhoneView *_view; +} + +- (id)init { + if (self = [super init]) { + _window = nil; + _view = nil; + } + return self; +} + +- (void)mainLoop:(id)param { + @autoreleasepool { + iOS7_main(iOS7_argc, iOS7_argv); + } + + exit(0); +} + +- (void)applicationDidFinishLaunching:(UIApplication *)application { + CGRect rect = [[UIScreen mainScreen] bounds]; + +#ifdef IPHONE_SANDBOXED + // Create the directory for savegames + NSFileManager *fm = [NSFileManager defaultManager]; + NSString *documentPath = [NSString stringWithUTF8String:iOS7_getDocumentsDir()]; + NSString *savePath = [documentPath stringByAppendingPathComponent:@"Savegames"]; + if (![fm fileExistsAtPath:savePath]) { + [fm createDirectoryAtPath:savePath withIntermediateDirectories:YES attributes:nil error:nil]; + } +#endif + + _window = [[UIWindow alloc] initWithFrame:rect]; + [_window retain]; + + _controller = [[iOS7ScummVMViewController alloc] init]; + + _view = [[iPhoneView alloc] initWithFrame:rect]; + _view.multipleTouchEnabled = YES; + _controller.view = _view; + + [_window setRootViewController:_controller]; + [_window makeKeyAndVisible]; + + [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didRotate:) + name:@"UIDeviceOrientationDidChangeNotification" + object:nil]; + + [NSThread detachNewThreadSelector:@selector(mainLoop:) toTarget:self withObject:nil]; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + [_view applicationSuspend]; +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { + [_view applicationResume]; +} + +- (void)didRotate:(NSNotification *)notification { + UIDeviceOrientation screenOrientation = [[UIDevice currentDevice] orientation]; + [_view deviceOrientationChanged:screenOrientation]; +} + ++ (iOS7AppDelegate *)iOS7AppDelegate { + UIApplication *app = [UIApplication sharedApplication]; + return (iOS7AppDelegate *) app.delegate; +} + ++ (iPhoneView *)iPhoneView { + iOS7AppDelegate *appDelegate = [self iOS7AppDelegate]; + return appDelegate->_view; +} + +@end + +const char *iOS7_getDocumentsDir() { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + return [documentsDirectory UTF8String]; +} diff --git a/backends/platform/ios7/iOS7ScummVMViewController.h b/backends/platform/ios7/iOS7ScummVMViewController.h new file mode 100644 index 0000000000..0322bc6f7f --- /dev/null +++ b/backends/platform/ios7/iOS7ScummVMViewController.h @@ -0,0 +1,28 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#import <UIKit/UIKit.h> + + +@interface iOS7ScummVMViewController : UIViewController + +@end diff --git a/backends/platform/ios7/iOS7ScummVMViewController.mm b/backends/platform/ios7/iOS7ScummVMViewController.mm new file mode 100644 index 0000000000..f92fd0115c --- /dev/null +++ b/backends/platform/ios7/iOS7ScummVMViewController.mm @@ -0,0 +1,32 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#import "iOS7ScummVMViewController.h" + + +@implementation iOS7ScummVMViewController + +- (BOOL)prefersStatusBarHidden { + return YES; +} + +@end diff --git a/backends/platform/ios7/ios7_common.h b/backends/platform/ios7/ios7_common.h new file mode 100644 index 0000000000..a32a59a541 --- /dev/null +++ b/backends/platform/ios7/ios7_common.h @@ -0,0 +1,131 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef BACKENDS_PLATFORM_IPHONE_IPHONE_COMMON_H +#define BACKENDS_PLATFORM_IPHONE_IPHONE_COMMON_H + +#include "graphics/surface.h" + +// #define ENABLE_IOS7_SCALERS + + +enum InputEvent { + kInputMouseDown, + kInputMouseUp, + kInputMouseDragged, + kInputMouseSecondDragged, + kInputMouseSecondDown, + kInputMouseSecondUp, + kInputOrientationChanged, + kInputKeyPressed, + kInputApplicationSuspended, + kInputApplicationResumed, + kInputSwipe, + kInputTap +}; + +enum ScreenOrientation { + kScreenOrientationPortrait, + kScreenOrientationLandscape, + kScreenOrientationFlippedLandscape +}; + +enum UIViewSwipeDirection { + kUIViewSwipeUp = 1, + kUIViewSwipeDown = 2, + kUIViewSwipeLeft = 4, + kUIViewSwipeRight = 8 +}; + +enum UIViewTapDescription { + kUIViewTapSingle = 1, + kUIViewTapDouble = 2 +}; + +enum GraphicsModes { + kGraphicsModeLinear = 0, + kGraphicsModeNone = 1, + + kGraphicsMode2xSaI, + kGraphicsModeSuper2xSaI, + kGraphicsModeSuperEagle, + kGraphicsModeAdvMame2x, + kGraphicsModeAdvMame3x, + kGraphicsModeHQ2x, + kGraphicsModeHQ3x, + kGraphicsModeTV2x, + kGraphicsModeDotMatrix +}; + +struct VideoContext { + VideoContext() : asprectRatioCorrection(), screenWidth(), screenHeight(), overlayVisible(false), + overlayWidth(), overlayHeight(), mouseX(), mouseY(), + mouseHotspotX(), mouseHotspotY(), mouseWidth(), mouseHeight(), + mouseIsVisible(), graphicsMode(kGraphicsModeNone), shakeOffsetY() { + } + + // Game screen state + bool asprectRatioCorrection; + uint screenWidth, screenHeight; + Graphics::Surface screenTexture; + + // Overlay state + bool overlayVisible; + uint overlayWidth, overlayHeight; + Graphics::Surface overlayTexture; + + // Mouse cursor state + uint mouseX, mouseY; + int mouseHotspotX, mouseHotspotY; + uint mouseWidth, mouseHeight; + bool mouseIsVisible; + Graphics::Surface mouseTexture; + + // Misc state + GraphicsModes graphicsMode; + int shakeOffsetY; +}; + +struct InternalEvent { + InternalEvent() : type(), value1(), value2() {} + InternalEvent(InputEvent t, int v1, int v2) : type(t), value1(v1), value2(v2) {} + + InputEvent type; + int value1, value2; +}; + +// On the ObjC side + +extern int iOS7_argc; +extern char **iOS7_argv; + +void iOS7_updateScreen(); +bool iOS7_fetchEvent(InternalEvent *event); +bool iOS7_isBigDevice(); + +void iOS7_main(int argc, char **argv); +const char *iOS7_getDocumentsDir(); +bool iOS7_touchpadModeEnabled(); + +uint getSizeNextPOT(uint size); + +#endif diff --git a/backends/platform/ios7/ios7_keyboard.h b/backends/platform/ios7/ios7_keyboard.h new file mode 100644 index 0000000000..ddd8f436e5 --- /dev/null +++ b/backends/platform/ios7/ios7_keyboard.h @@ -0,0 +1,44 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef BACKENDS_PLATFORM_IPHONE_IPHONE_KEYBOARD_H +#define BACKENDS_PLATFORM_IPHONE_IPHONE_KEYBOARD_H + +#include <UIKit/UIKit.h> +#include <UIKit/UITextView.h> + +@interface SoftKeyboard : UIView<UITextViewDelegate> { + id inputDelegate; + UITextView *inputView; +} + +- (id)initWithFrame:(CGRect)frame; +- (UITextView *)inputView; +- (void)setInputDelegate:(id)delegate; +- (void)handleKeyPress:(unichar)c; + +- (void)showKeyboard; +- (void)hideKeyboard; + +@end + +#endif diff --git a/backends/platform/ios7/ios7_keyboard.mm b/backends/platform/ios7/ios7_keyboard.mm new file mode 100644 index 0000000000..7923a1cda9 --- /dev/null +++ b/backends/platform/ios7/ios7_keyboard.mm @@ -0,0 +1,98 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "ios7_keyboard.h" + +@interface UITextInputTraits +- (void)setAutocorrectionType:(int)type; +- (void)setAutocapitalizationType:(int)type; +- (void)setEnablesReturnKeyAutomatically:(BOOL)val; +@end + +@interface TextInputHandler : UITextView { + SoftKeyboard *softKeyboard; +} + +- (id)initWithKeyboard:(SoftKeyboard *)keyboard; + +@end + + +@implementation TextInputHandler + +- (id)initWithKeyboard:(SoftKeyboard *)keyboard { + self = [super initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.0f)]; + softKeyboard = keyboard; + + [self setAutocorrectionType:UITextAutocorrectionTypeNo]; + [self setAutocapitalizationType:UITextAutocapitalizationTypeNone]; + [self setEnablesReturnKeyAutomatically:NO]; + + return self; +} + +@end + + +@implementation SoftKeyboard + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + inputDelegate = nil; + inputView = [[TextInputHandler alloc] initWithKeyboard:self]; + inputView.delegate = self; + return self; +} + +- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { + unichar c; + if (text.length) { + c = [text characterAtIndex:0]; + } + else { + c = '\b'; + } + [inputDelegate handleKeyPress:c]; + return YES; +} + +- (UITextView *)inputView { + return inputView; +} + +- (void)setInputDelegate:(id)delegate { + inputDelegate = delegate; +} + +- (void)handleKeyPress:(unichar)c { + [inputDelegate handleKeyPress:c]; +} + +- (void)showKeyboard { + [inputView becomeFirstResponder]; +} + +- (void)hideKeyboard { + [inputView endEditing:YES]; +} + +@end diff --git a/backends/platform/ios7/ios7_main.mm b/backends/platform/ios7/ios7_main.mm new file mode 100644 index 0000000000..96f41f4c02 --- /dev/null +++ b/backends/platform/ios7/ios7_main.mm @@ -0,0 +1,47 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include <UIKit/UIKit.h> +#include <Foundation/NSThread.h> + +#include "ios7_video.h" + + +int iOS7_argc; +char **iOS7_argv; + +int main(int argc, char **argv) { + int returnCode; + + @autoreleasepool { + iOS7_argc = argc; + iOS7_argv = argv; + + returnCode = UIApplicationMain(argc, argv, @"UIApplication", @"iOS7AppDelegate"); + } + + return returnCode; +} + diff --git a/backends/platform/ios7/ios7_osys_events.cpp b/backends/platform/ios7/ios7_osys_events.cpp new file mode 100644 index 0000000000..7e805f34b7 --- /dev/null +++ b/backends/platform/ios7/ios7_osys_events.cpp @@ -0,0 +1,576 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "gui/message.h" +#include "common/translation.h" + +#include "ios7_osys_main.h" + +static const int kQueuedInputEventDelay = 50; + +bool OSystem_iOS7::pollEvent(Common::Event &event) { + //printf("pollEvent()\n"); + + long curTime = getMillis(); + + if (_timerCallback && (curTime >= _timerCallbackNext)) { + _timerCallback(_timerCallbackTimer); + _timerCallbackNext = curTime + _timerCallbackTimer; + } + + if (_queuedInputEvent.type != Common::EVENT_INVALID && curTime >= _queuedEventTime) { + event = _queuedInputEvent; + _queuedInputEvent.type = Common::EVENT_INVALID; + return true; + } + + InternalEvent internalEvent; + + if (iOS7_fetchEvent(&internalEvent)) { + switch (internalEvent.type) { + case kInputMouseDown: + if (!handleEvent_mouseDown(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + + case kInputMouseUp: + if (!handleEvent_mouseUp(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + + case kInputMouseDragged: + if (!handleEvent_mouseDragged(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + + case kInputOrientationChanged: + handleEvent_orientationChanged(internalEvent.value1); + return false; + + case kInputApplicationSuspended: + handleEvent_applicationSuspended(); + return false; + + case kInputApplicationResumed: + handleEvent_applicationResumed(); + return false; + + case kInputMouseSecondDragged: + if (!handleEvent_mouseSecondDragged(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + case kInputMouseSecondDown: + _secondaryTapped = true; + if (!handleEvent_secondMouseDown(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + case kInputMouseSecondUp: + _secondaryTapped = false; + if (!handleEvent_secondMouseUp(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + + case kInputKeyPressed: + handleEvent_keyPressed(event, internalEvent.value1); + break; + + case kInputSwipe: + if (!handleEvent_swipe(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + + case kInputTap: + if (!handleEvent_tap(event, (UIViewTapDescription) internalEvent.value1, internalEvent.value2)) + return false; + break; + + default: + break; + } + + return true; + } + return false; +} + +bool OSystem_iOS7::handleEvent_mouseDown(Common::Event &event, int x, int y) { + //printf("Mouse down at (%u, %u)\n", x, y); + + // Workaround: kInputMouseSecondToggled isn't always sent when the + // secondary finger is lifted. Need to make sure we get out of that mode. + _secondaryTapped = false; + + if (_touchpadModeEnabled) { + _lastPadX = x; + _lastPadY = y; + } else + warpMouse(x, y); + + if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_LBUTTONDOWN; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + return true; + } else { + _lastMouseDown = getMillis(); + } + return false; +} + +bool OSystem_iOS7::handleEvent_mouseUp(Common::Event &event, int x, int y) { + //printf("Mouse up at (%u, %u)\n", x, y); + + if (_secondaryTapped) { + _secondaryTapped = false; + if (!handleEvent_secondMouseUp(event, x, y)) + return false; + } else if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_LBUTTONUP; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + } else { + if (getMillis() - _lastMouseDown < 250) { + event.type = Common::EVENT_LBUTTONDOWN; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + + _queuedInputEvent.type = Common::EVENT_LBUTTONUP; + _queuedInputEvent.mouse.x = _videoContext->mouseX; + _queuedInputEvent.mouse.y = _videoContext->mouseY; + _lastMouseTap = getMillis(); + _queuedEventTime = _lastMouseTap + kQueuedInputEventDelay; + } else + return false; + } + + return true; +} + +bool OSystem_iOS7::handleEvent_secondMouseDown(Common::Event &event, int x, int y) { + _lastSecondaryDown = getMillis(); + _gestureStartX = x; + _gestureStartY = y; + + if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_LBUTTONUP; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + + _queuedInputEvent.type = Common::EVENT_RBUTTONDOWN; + _queuedInputEvent.mouse.x = _videoContext->mouseX; + _queuedInputEvent.mouse.y = _videoContext->mouseY; + } else + return false; + + return true; +} + +bool OSystem_iOS7::handleEvent_secondMouseUp(Common::Event &event, int x, int y) { + int curTime = getMillis(); + + if (curTime - _lastSecondaryDown < 400) { + //printf("Right tap!\n"); + if (curTime - _lastSecondaryTap < 400 && !_videoContext->overlayVisible) { + //printf("Right escape!\n"); + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE; + _queuedEventTime = curTime + kQueuedInputEventDelay; + _lastSecondaryTap = 0; + } else if (!_mouseClickAndDragEnabled) { + //printf("Rightclick!\n"); + event.type = Common::EVENT_RBUTTONDOWN; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + _queuedInputEvent.type = Common::EVENT_RBUTTONUP; + _queuedInputEvent.mouse.x = _videoContext->mouseX; + _queuedInputEvent.mouse.y = _videoContext->mouseY; + _lastSecondaryTap = curTime; + _queuedEventTime = curTime + kQueuedInputEventDelay; + } else { + //printf("Right nothing!\n"); + return false; + } + } + if (_mouseClickAndDragEnabled) { + event.type = Common::EVENT_RBUTTONUP; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; + } + + return true; +} + +bool OSystem_iOS7::handleEvent_mouseDragged(Common::Event &event, int x, int y) { + if (_lastDragPosX == x && _lastDragPosY == y) + return false; + + _lastDragPosX = x; + _lastDragPosY = y; + + //printf("Mouse dragged at (%u, %u)\n", x, y); + int mouseNewPosX; + int mouseNewPosY; + if (_touchpadModeEnabled) { + int deltaX = _lastPadX - x; + int deltaY = _lastPadY - y; + _lastPadX = x; + _lastPadY = y; + + mouseNewPosX = (int)(_videoContext->mouseX - deltaX / 0.5f); + mouseNewPosY = (int)(_videoContext->mouseY - deltaY / 0.5f); + + int widthCap = _videoContext->overlayVisible ? _videoContext->overlayWidth : _videoContext->screenWidth; + int heightCap = _videoContext->overlayVisible ? _videoContext->overlayHeight : _videoContext->screenHeight; + + if (mouseNewPosX < 0) + mouseNewPosX = 0; + else if (mouseNewPosX > widthCap) + mouseNewPosX = widthCap; + + if (mouseNewPosY < 0) + mouseNewPosY = 0; + else if (mouseNewPosY > heightCap) + mouseNewPosY = heightCap; + + } else { + mouseNewPosX = x; + mouseNewPosY = y; + } + + event.type = Common::EVENT_MOUSEMOVE; + event.mouse.x = mouseNewPosX; + event.mouse.y = mouseNewPosY; + warpMouse(mouseNewPosX, mouseNewPosY); + + return true; +} + +bool OSystem_iOS7::handleEvent_mouseSecondDragged(Common::Event &event, int x, int y) { + if (_gestureStartX == -1 || _gestureStartY == -1) { + return false; + } + + static const int kNeededLength = 100; + static const int kMaxDeviation = 20; + + int vecX = (x - _gestureStartX); + int vecY = (y - _gestureStartY); + + int absX = abs(vecX); + int absY = abs(vecY); + + //printf("(%d, %d)\n", vecX, vecY); + + if (absX >= kNeededLength || absY >= kNeededLength) { // Long enough gesture to react upon. + _gestureStartX = -1; + _gestureStartY = -1; + + if (absX < kMaxDeviation && vecY >= kNeededLength) { + // Swipe down + event.type = Common::EVENT_MAINMENU; + _queuedInputEvent.type = Common::EVENT_INVALID; + + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + return true; + } + + if (absX < kMaxDeviation && -vecY >= kNeededLength) { + // Swipe up + _mouseClickAndDragEnabled = !_mouseClickAndDragEnabled; + const char *dialogMsg; + if (_mouseClickAndDragEnabled) { + _touchpadModeEnabled = false; + dialogMsg = _("Mouse-click-and-drag mode enabled."); + } else + dialogMsg = _("Mouse-click-and-drag mode disabled."); + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return false; + } + + if (absY < kMaxDeviation && vecX >= kNeededLength) { + // Swipe right + _touchpadModeEnabled = !_touchpadModeEnabled; + const char *dialogMsg; + if (_touchpadModeEnabled) + dialogMsg = _("Touchpad mode enabled."); + else + dialogMsg = _("Touchpad mode disabled."); + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return false; + + } + + if (absY < kMaxDeviation && -vecX >= kNeededLength) { + // Swipe left + return false; + } + } + + return false; +} + +void OSystem_iOS7::handleEvent_orientationChanged(int orientation) { + //printf("Orientation: %i\n", orientation); + + ScreenOrientation newOrientation; + switch (orientation) { + case 1: + newOrientation = kScreenOrientationPortrait; + break; + case 3: + newOrientation = kScreenOrientationLandscape; + break; + case 4: + newOrientation = kScreenOrientationFlippedLandscape; + break; + default: + return; + } + + if (_screenOrientation != newOrientation) { + _screenOrientation = newOrientation; + rebuildSurface(); + } +} + +void OSystem_iOS7::rebuildSurface() { + updateOutputSurface(); + + dirtyFullScreen(); + if (_videoContext->overlayVisible) { + dirtyFullOverlayScreen(); + } + updateScreen(); +} + +void OSystem_iOS7::handleEvent_applicationSuspended() { + suspendLoop(); +} + +void OSystem_iOS7::handleEvent_applicationResumed() { + rebuildSurface(); +} + +void OSystem_iOS7::handleEvent_keyPressed(Common::Event &event, int keyPressed) { + int ascii = keyPressed; + //printf("key: %i\n", keyPressed); + + // We remap some of the iPhone keyboard keys. + // The first ten here are the row of symbols below the numeric keys. + switch (keyPressed) { + case 45: + keyPressed = Common::KEYCODE_F1; + ascii = Common::ASCII_F1; + break; + case 47: + keyPressed = Common::KEYCODE_F2; + ascii = Common::ASCII_F2; + break; + case 58: + keyPressed = Common::KEYCODE_F3; + ascii = Common::ASCII_F3; + break; + case 59: + keyPressed = Common::KEYCODE_F4; + ascii = Common::ASCII_F4; + break; + case 40: + keyPressed = Common::KEYCODE_F5; + ascii = Common::ASCII_F5; + break; + case 41: + keyPressed = Common::KEYCODE_F6; + ascii = Common::ASCII_F6; + break; + case 36: + keyPressed = Common::KEYCODE_F7; + ascii = Common::ASCII_F7; + break; + case 38: + keyPressed = Common::KEYCODE_F8; + ascii = Common::ASCII_F8; + break; + case 64: + keyPressed = Common::KEYCODE_F9; + ascii = Common::ASCII_F9; + break; + case 34: + keyPressed = Common::KEYCODE_F10; + ascii = Common::ASCII_F10; + break; + case 10: + keyPressed = Common::KEYCODE_RETURN; + ascii = Common::ASCII_RETURN; + break; + } + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + event.kbd.keycode = _queuedInputEvent.kbd.keycode = (Common::KeyCode)keyPressed; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = ascii; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; +} + +bool OSystem_iOS7::handleEvent_swipe(Common::Event &event, int direction, int touches) { + if (touches == 1) { + Common::KeyCode keycode = Common::KEYCODE_INVALID; + switch (_screenOrientation) { + case kScreenOrientationPortrait: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_UP; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_DOWN; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_RIGHT; + break; + default: + return false; + } + break; + case kScreenOrientationLandscape: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_RIGHT; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_DOWN; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_UP; + break; + default: + return false; + } + break; + case kScreenOrientationFlippedLandscape: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_RIGHT; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_UP; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_DOWN; + break; + default: + return false; + } + break; + } + + event.kbd.keycode = _queuedInputEvent.kbd.keycode = keycode; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = 0; + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + + return true; + } + else if (touches == 2) { + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: { + _mouseClickAndDragEnabled = !_mouseClickAndDragEnabled; + const char *dialogMsg; + if (_mouseClickAndDragEnabled) { + _touchpadModeEnabled = false; + dialogMsg = _("Mouse-click-and-drag mode enabled."); + } else + dialogMsg = _("Mouse-click-and-drag mode disabled."); + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return false; + } + + case kUIViewSwipeDown: { + // Swipe down + event.type = Common::EVENT_MAINMENU; + _queuedInputEvent.type = Common::EVENT_INVALID; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + return true; + } + + case kUIViewSwipeRight: { + // Swipe right + _touchpadModeEnabled = !_touchpadModeEnabled; + const char *dialogMsg; + if (_touchpadModeEnabled) + dialogMsg = _("Touchpad mode enabled."); + else + dialogMsg = _("Touchpad mode disabled."); + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return false; + } + + default: + break; + } + } + return false; +} + +bool OSystem_iOS7::handleEvent_tap(Common::Event &event, UIViewTapDescription type, int touches) { + if (touches == 1) { + if (type == kUIViewTapDouble) { + event.type = Common::EVENT_RBUTTONDOWN; + _queuedInputEvent.type = Common::EVENT_RBUTTONUP; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + return true; + } + } + else if (touches == 2) { + if (type == kUIViewTapDouble) { + event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE; + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + return true; + } + } + return false; +} diff --git a/backends/platform/ios7/ios7_osys_main.cpp b/backends/platform/ios7/ios7_osys_main.cpp new file mode 100644 index 0000000000..37fa34ce33 --- /dev/null +++ b/backends/platform/ios7/ios7_osys_main.cpp @@ -0,0 +1,368 @@ +/* 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 <unistd.h> +#include <pthread.h> +#include <string.h> + +#include <sys/time.h> +#include <QuartzCore/QuartzCore.h> + +#include "common/scummsys.h" +#include "common/util.h" +#include "common/rect.h" +#include "common/file.h" +#include "common/fs.h" + +#include "base/main.h" + +#include "backends/saves/default/default-saves.h" +#include "backends/timer/default/default-timer.h" +#include "backends/fs/chroot/chroot-fs-factory.h" +#include "backends/fs/posix/posix-fs.h" +#include "audio/mixer.h" +#include "audio/mixer_intern.h" + +#include "graphics/scaler.h" +#include "graphics/scaler/aspect.h" + +#include "ios7_osys_main.h" + + +const OSystem::GraphicsMode OSystem_iOS7::s_supportedGraphicsModes[] = { + { "none", "No filtering", kGraphicsModeNone }, + { "linear", "Linear filtering", kGraphicsModeLinear }, + +#ifdef ENABLE_IOS7_SCALERS +#ifdef USE_SCALERS +// {"2x", "2x", GFX_DOUBLESIZE}, +// {"3x", "3x", GFX_TRIPLESIZE}, + { "2xsai", "2xSAI", kGraphicsMode2xSaI}, + {"super2xsai", "Super2xSAI", kGraphicsModeSuper2xSaI}, + {"supereagle", "SuperEagle", kGraphicsModeSuperEagle}, + {"advmame2x", "AdvMAME2x", kGraphicsModeAdvMame2x}, + {"advmame3x", "AdvMAME3x", kGraphicsModeAdvMame3x}, +#ifdef USE_HQ_SCALERS + {"hq2x", "HQ2x", kGraphicsModeHQ2x}, + {"hq3x", "HQ3x", kGraphicsModeHQ3x}, +#endif + {"tv2x", "TV2x", kGraphicsModeTV2x}, + {"dotmatrix", "DotMatrix", kGraphicsModeDotMatrix}, +#endif +#endif + { 0, 0, 0 } +}; + +AQCallbackStruct OSystem_iOS7::s_AudioQueue; +SoundProc OSystem_iOS7::s_soundCallback = NULL; +void *OSystem_iOS7::s_soundParam = NULL; + +OSystem_iOS7::OSystem_iOS7() : + _mixer(NULL), _lastMouseTap(0), _queuedEventTime(0), + _mouseNeedTextureUpdate(false), _secondaryTapped(false), _lastSecondaryTap(0), + _screenOrientation(kScreenOrientationFlippedLandscape), _mouseClickAndDragEnabled(false), + _gestureStartX(-1), _gestureStartY(-1), _fullScreenIsDirty(false), _fullScreenOverlayIsDirty(false), + _mouseDirty(false), _timeSuspended(0), _lastDragPosX(-1), _lastDragPosY(-1), _screenChangeCount(0), + _lastErrorMessage(NULL), _mouseCursorPaletteEnabled(false), _gfxTransactionError(kTransactionSuccess) { + _queuedInputEvent.type = Common::EVENT_INVALID; + _touchpadModeEnabled = !iOS7_isBigDevice(); +#ifdef IPHONE_SANDBOXED + _fsFactory = new ChRootFilesystemFactory(iOS7_getDocumentsDir()); +#else + _fsFactory = new POSIXFilesystemFactory(); +#endif + initVideoContext(); + + memset(_gamePalette, 0, sizeof(_gamePalette)); + memset(_gamePaletteRGBA5551, 0, sizeof(_gamePaletteRGBA5551)); + memset(_mouseCursorPalette, 0, sizeof(_mouseCursorPalette)); +} + +OSystem_iOS7::~OSystem_iOS7() { + AudioQueueDispose(s_AudioQueue.queue, true); + + delete _mixer; + // Prevent accidental freeing of the screen texture here. This needs to be + // checked since we might use the screen texture as framebuffer in the case + // of hi-color games for example. Otherwise this can lead to a double free. + if (_framebuffer.getPixels() != _videoContext->screenTexture.getPixels()) + _framebuffer.free(); + _mouseBuffer.free(); +} + +bool OSystem_iOS7::touchpadModeEnabled() const { + return _touchpadModeEnabled; +} + +int OSystem_iOS7::timerHandler(int t) { + DefaultTimerManager *tm = (DefaultTimerManager *)g_system->getTimerManager(); + tm->handler(); + return t; +} + +void OSystem_iOS7::initBackend() { +#ifdef IPHONE_SANDBOXED + _savefileManager = new DefaultSaveFileManager("/Savegames"); +#else + _savefileManager = new DefaultSaveFileManager(SCUMMVM_SAVE_PATH); +#endif + + _timerManager = new DefaultTimerManager(); + + gettimeofday(&_startTime, NULL); + + setupMixer(); + + setTimerCallback(&OSystem_iOS7::timerHandler, 10); + + EventsBaseBackend::initBackend(); +} + +bool OSystem_iOS7::hasFeature(Feature f) { + switch (f) { + case kFeatureCursorPalette: + return true; + + default: + return false; + } +} + +void OSystem_iOS7::setFeatureState(Feature f, bool enable) { + switch (f) { + case kFeatureCursorPalette: + if (_mouseCursorPaletteEnabled != enable) { + _mouseNeedTextureUpdate = true; + _mouseDirty = true; + _mouseCursorPaletteEnabled = enable; + } + break; + case kFeatureAspectRatioCorrection: + _videoContext->asprectRatioCorrection = enable; + break; + + default: + break; + } +} + +bool OSystem_iOS7::getFeatureState(Feature f) { + switch (f) { + case kFeatureCursorPalette: + return _mouseCursorPaletteEnabled; + case kFeatureAspectRatioCorrection: + return _videoContext->asprectRatioCorrection; + + default: + return false; + } +} + +void OSystem_iOS7::suspendLoop() { + bool done = false; + uint32 startTime = getMillis(); + + stopSoundsystem(); + + InternalEvent event; + while (!done) { + if (iOS7_fetchEvent(&event)) + if (event.type == kInputApplicationResumed) + done = true; + usleep(100000); + } + + startSoundsystem(); + + _timeSuspended += getMillis() - startTime; +} + +uint32 OSystem_iOS7::getMillis(bool skipRecord) { + CFTimeInterval timeInSeconds = CACurrentMediaTime(); + return (uint32) (timeInSeconds * 1000.0); +} + +void OSystem_iOS7::delayMillis(uint msecs) { + //printf("delayMillis(%d)\n", msecs); + usleep(msecs * 1000); +} + +OSystem::MutexRef OSystem_iOS7::createMutex(void) { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + + pthread_mutex_t *mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t)); + if (pthread_mutex_init(mutex, &attr) != 0) { + printf("pthread_mutex_init() failed!\n"); + free(mutex); + return NULL; + } + + return (MutexRef)mutex; +} + +void OSystem_iOS7::lockMutex(MutexRef mutex) { + if (pthread_mutex_lock((pthread_mutex_t *) mutex) != 0) { + printf("pthread_mutex_lock() failed!\n"); + } +} + +void OSystem_iOS7::unlockMutex(MutexRef mutex) { + if (pthread_mutex_unlock((pthread_mutex_t *) mutex) != 0) { + printf("pthread_mutex_unlock() failed!\n"); + } +} + +void OSystem_iOS7::deleteMutex(MutexRef mutex) { + if (pthread_mutex_destroy((pthread_mutex_t *) mutex) != 0) { + printf("pthread_mutex_destroy() failed!\n"); + } else { + free(mutex); + } +} + + +void OSystem_iOS7::setTimerCallback(TimerProc callback, int interval) { + //printf("setTimerCallback()\n"); + + if (callback != NULL) { + _timerCallbackTimer = interval; + _timerCallbackNext = getMillis() + interval; + _timerCallback = callback; + } else + _timerCallback = NULL; +} + +void OSystem_iOS7::quit() { +} + +void OSystem_iOS7::getTimeAndDate(TimeDate &td) const { + time_t curTime = time(0); + struct tm t = *localtime(&curTime); + td.tm_sec = t.tm_sec; + td.tm_min = t.tm_min; + td.tm_hour = t.tm_hour; + td.tm_mday = t.tm_mday; + td.tm_mon = t.tm_mon; + td.tm_year = t.tm_year; + td.tm_wday = t.tm_wday; +} + +Audio::Mixer *OSystem_iOS7::getMixer() { + assert(_mixer); + return _mixer; +} + +OSystem_iOS7 *OSystem_iOS7::sharedInstance() { + static OSystem_iOS7 *instance = new OSystem_iOS7(); + return instance; +} + +Common::String OSystem_iOS7::getDefaultConfigFileName() { +#ifdef IPHONE_SANDBOXED + Common::String path = "/Preferences"; + return path; +#else + return SCUMMVM_PREFS_PATH; +#endif +} + +void OSystem_iOS7::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { + // Get URL of the Resource directory of the .app bundle + CFURLRef fileUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); + if (fileUrl) { + // Try to convert the URL to an absolute path + UInt8 buf[MAXPATHLEN]; + if (CFURLGetFileSystemRepresentation(fileUrl, true, buf, sizeof(buf))) { + // Success: Add it to the search path + Common::String bundlePath((const char *)buf); +#ifdef IPHONE_SANDBOXED + POSIXFilesystemNode *posixNode = new POSIXFilesystemNode(bundlePath); + Common::FSNode *node = new Common::FSNode(posixNode); + s.add("__IOS_BUNDLE__", new Common::FSDirectory(*node), priority); +#else + s.add("__IOS_BUNDLE__", new Common::FSDirectory(bundlePath), priority); +#endif + } + CFRelease(fileUrl); + } +} + +void OSystem_iOS7::logMessage(LogMessageType::Type type, const char *message) { + FILE *output = 0; + + if (type == LogMessageType::kInfo || type == LogMessageType::kDebug) + output = stdout; + else + output = stderr; + + if (type == LogMessageType::kError) { + free(_lastErrorMessage); + _lastErrorMessage = strdup(message); + } + + fputs(message, output); + fflush(output); +} + +bool iOS7_touchpadModeEnabled() { + OSystem_iOS7 *sys = (OSystem_iOS7 *) g_system; + return sys && sys->touchpadModeEnabled(); +} + +void iOS7_main(int argc, char **argv) { + + //OSystem_iOS7::migrateApp(); + + FILE *newfp = fopen("/var/mobile/.scummvm.log", "a"); + if (newfp != NULL) { + fclose(stdout); + fclose(stderr); + *stdout = *newfp; + *stderr = *newfp; + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + //extern int gDebugLevel; + //gDebugLevel = 10; + } + +#ifdef IPHONE_SANDBOXED + chdir(iOS7_getDocumentsDir()); +#else + system("mkdir " SCUMMVM_ROOT_PATH); + system("mkdir " SCUMMVM_SAVE_PATH); + + chdir("/var/mobile/"); +#endif + + g_system = OSystem_iOS7::sharedInstance(); + assert(g_system); + + // Invoke the actual ScummVM main entry point: + scummvm_main(argc, (const char *const *) argv); + g_system->quit(); // TODO: Consider removing / replacing this! +} diff --git a/backends/platform/ios7/ios7_osys_main.h b/backends/platform/ios7/ios7_osys_main.h new file mode 100644 index 0000000000..eadb49e5ac --- /dev/null +++ b/backends/platform/ios7/ios7_osys_main.h @@ -0,0 +1,233 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef BACKENDS_PLATFORM_IPHONE_OSYS_MAIN_H +#define BACKENDS_PLATFORM_IPHONE_OSYS_MAIN_H + +#include "graphics/surface.h" +#include "ios7_common.h" +#include "backends/base-backend.h" +#include "common/events.h" +#include "audio/mixer_intern.h" +#include "backends/fs/posix/posix-fs-factory.h" +#include "graphics/colormasks.h" +#include "graphics/palette.h" + +#include <AudioToolbox/AudioQueue.h> + +#define AUDIO_BUFFERS 3 +#define WAVE_BUFFER_SIZE 2048 +#define AUDIO_SAMPLE_RATE 44100 + +#define SCUMMVM_ROOT_PATH "/var/mobile/Library/ScummVM" +#define SCUMMVM_SAVE_PATH SCUMMVM_ROOT_PATH "/Savegames" +#define SCUMMVM_PREFS_PATH SCUMMVM_ROOT_PATH "/Preferences" + +typedef void (*SoundProc)(void *param, byte *buf, int len); +typedef int (*TimerProc)(int interval); + +struct AQCallbackStruct { + AudioQueueRef queue; + uint32 frameCount; + AudioQueueBufferRef buffers[AUDIO_BUFFERS]; + AudioStreamBasicDescription dataFormat; +}; + +class OSystem_iOS7 : public EventsBaseBackend, public PaletteManager { +protected: + static const OSystem::GraphicsMode s_supportedGraphicsModes[]; + static AQCallbackStruct s_AudioQueue; + static SoundProc s_soundCallback; + static void *s_soundParam; + + Audio::MixerImpl *_mixer; + + VideoContext *_videoContext; + + Graphics::Surface _framebuffer; + + // For signaling that screen format set up might have failed. + TransactionError _gfxTransactionError; + + // For use with the game texture + uint16 _gamePalette[256]; + // For use with the mouse texture + uint16 _gamePaletteRGBA5551[256]; + + struct timeval _startTime; + uint32 _timeSuspended; + + bool _mouseCursorPaletteEnabled; + uint16 _mouseCursorPalette[256]; + Graphics::Surface _mouseBuffer; + uint16 _mouseKeyColor; + bool _mouseDirty; + bool _mouseNeedTextureUpdate; + + long _lastMouseDown; + long _lastMouseTap; + long _queuedEventTime; + Common::Event _queuedInputEvent; + bool _secondaryTapped; + long _lastSecondaryDown; + long _lastSecondaryTap; + int _gestureStartX, _gestureStartY; + bool _mouseClickAndDragEnabled; + bool _touchpadModeEnabled; + int _lastPadX; + int _lastPadY; + int _lastDragPosX; + int _lastDragPosY; + + int _timerCallbackNext; + int _timerCallbackTimer; + TimerProc _timerCallback; + + Common::Array<Common::Rect> _dirtyRects; + Common::Array<Common::Rect> _dirtyOverlayRects; + ScreenOrientation _screenOrientation; + bool _fullScreenIsDirty; + bool _fullScreenOverlayIsDirty; + int _screenChangeCount; + + char *_lastErrorMessage; + +public: + + OSystem_iOS7(); + virtual ~OSystem_iOS7(); + + static OSystem_iOS7 *sharedInstance(); + + virtual void initBackend(); + + virtual bool hasFeature(Feature f); + virtual void setFeatureState(Feature f, bool enable); + virtual bool getFeatureState(Feature f); + virtual const GraphicsMode *getSupportedGraphicsModes() const; + virtual int getDefaultGraphicsMode() const; + virtual bool setGraphicsMode(int mode); + virtual int getGraphicsMode() const; + virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format); + + virtual void beginGFXTransaction(); + virtual TransactionError endGFXTransaction(); + + virtual int16 getHeight(); + virtual int16 getWidth(); + + bool touchpadModeEnabled() const; + +#ifdef USE_RGB_COLOR + virtual Graphics::PixelFormat getScreenFormat() const { return _framebuffer.format; } + virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const; +#endif + + virtual PaletteManager *getPaletteManager() { return this; } +protected: + // PaletteManager API + virtual void setPalette(const byte *colors, uint start, uint num); + virtual void grabPalette(byte *colors, uint start, uint num); + +public: + virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h); + virtual void updateScreen(); + virtual Graphics::Surface *lockScreen(); + virtual void unlockScreen(); + virtual void setShakePos(int shakeOffset); + + virtual void showOverlay(); + virtual void hideOverlay(); + virtual void clearOverlay(); + virtual void grabOverlay(void *buf, int pitch); + virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h); + virtual int16 getOverlayHeight(); + virtual int16 getOverlayWidth(); + virtual Graphics::PixelFormat getOverlayFormat() const { return Graphics::createPixelFormat<5551>(); } + + virtual bool showMouse(bool visible); + + virtual void warpMouse(int x, int y); + virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor = 255, bool dontScale = false, const Graphics::PixelFormat *format = NULL); + virtual void setCursorPalette(const byte *colors, uint start, uint num); + + virtual bool pollEvent(Common::Event &event); + virtual uint32 getMillis(bool skipRecord = false); + virtual void delayMillis(uint msecs); + + virtual MutexRef createMutex(void); + virtual void lockMutex(MutexRef mutex); + virtual void unlockMutex(MutexRef mutex); + virtual void deleteMutex(MutexRef mutex); + + static void mixCallback(void *sys, byte *samples, int len); + virtual void setupMixer(void); + virtual void setTimerCallback(TimerProc callback, int interval); + virtual int getScreenChangeID() const { return _screenChangeCount; } + virtual void quit(); + + virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); + virtual void getTimeAndDate(TimeDate &t) const; + + virtual Audio::Mixer *getMixer(); + + void startSoundsystem(); + void stopSoundsystem(); + + virtual Common::String getDefaultConfigFileName(); + + virtual void logMessage(LogMessageType::Type type, const char *message); + virtual void fatalError() override; + +protected: + void initVideoContext(); + void updateOutputSurface(); + + void internUpdateScreen(); + void dirtyFullScreen(); + void dirtyFullOverlayScreen(); + void suspendLoop(); + void drawDirtyRect(const Common::Rect &dirtyRect); + void updateMouseTexture(); + static void AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB); + static int timerHandler(int t); + + bool handleEvent_swipe(Common::Event &event, int direction, int touches); + bool handleEvent_tap(Common::Event &event, UIViewTapDescription type, int touches); + void handleEvent_keyPressed(Common::Event &event, int keyPressed); + void handleEvent_orientationChanged(int orientation); + void handleEvent_applicationSuspended(); + void handleEvent_applicationResumed(); + + bool handleEvent_mouseDown(Common::Event &event, int x, int y); + bool handleEvent_mouseUp(Common::Event &event, int x, int y); + + 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); + + void rebuildSurface(); +}; + +#endif diff --git a/backends/platform/ios7/ios7_osys_sound.cpp b/backends/platform/ios7/ios7_osys_sound.cpp new file mode 100644 index 0000000000..0dc81a9385 --- /dev/null +++ b/backends/platform/ios7/ios7_osys_sound.cpp @@ -0,0 +1,105 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "ios7_osys_main.h" + +void OSystem_iOS7::AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB) { + //printf("AQBufferCallback()\n"); + if (s_AudioQueue.frameCount > 0 && s_soundCallback != NULL) { + outQB->mAudioDataByteSize = 4 * s_AudioQueue.frameCount; + s_soundCallback(s_soundParam, (byte *)outQB->mAudioData, outQB->mAudioDataByteSize); + AudioQueueEnqueueBuffer(inQ, outQB, 0, NULL); + } else { + AudioQueueStop(s_AudioQueue.queue, false); + } +} + +void OSystem_iOS7::mixCallback(void *sys, byte *samples, int len) { + OSystem_iOS7 *this_ = (OSystem_iOS7 *)sys; + assert(this_); + + if (this_->_mixer) { + this_->_mixer->mixCallback(samples, len); + } +} + +void OSystem_iOS7::setupMixer() { + _mixer = new Audio::MixerImpl(this, AUDIO_SAMPLE_RATE); + + s_soundCallback = mixCallback; + s_soundParam = this; + + startSoundsystem(); +} + +void OSystem_iOS7::startSoundsystem() { + s_AudioQueue.dataFormat.mSampleRate = AUDIO_SAMPLE_RATE; + s_AudioQueue.dataFormat.mFormatID = kAudioFormatLinearPCM; + s_AudioQueue.dataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; + s_AudioQueue.dataFormat.mBytesPerPacket = 4; + s_AudioQueue.dataFormat.mFramesPerPacket = 1; + s_AudioQueue.dataFormat.mBytesPerFrame = 4; + s_AudioQueue.dataFormat.mChannelsPerFrame = 2; + s_AudioQueue.dataFormat.mBitsPerChannel = 16; + s_AudioQueue.frameCount = WAVE_BUFFER_SIZE; + + if (AudioQueueNewOutput(&s_AudioQueue.dataFormat, AQBufferCallback, &s_AudioQueue, 0, kCFRunLoopCommonModes, 0, &s_AudioQueue.queue)) { + printf("Couldn't set the AudioQueue callback!\n"); + _mixer->setReady(false); + return; + } + + uint32 bufferBytes = s_AudioQueue.frameCount * s_AudioQueue.dataFormat.mBytesPerFrame; + + for (int i = 0; i < AUDIO_BUFFERS; i++) { + if (AudioQueueAllocateBuffer(s_AudioQueue.queue, bufferBytes, &s_AudioQueue.buffers[i])) { + printf("Error allocating AudioQueue buffer!\n"); + _mixer->setReady(false); + return; + } + + AQBufferCallback(&s_AudioQueue, s_AudioQueue.queue, s_AudioQueue.buffers[i]); + } + + AudioQueueSetParameter(s_AudioQueue.queue, kAudioQueueParam_Volume, 1.0); + if (AudioQueueStart(s_AudioQueue.queue, NULL)) { + printf("Error starting the AudioQueue!\n"); + _mixer->setReady(false); + return; + } + + _mixer->setReady(true); +} + +void OSystem_iOS7::stopSoundsystem() { + AudioQueueStop(s_AudioQueue.queue, true); + + for (int i = 0; i < AUDIO_BUFFERS; i++) { + AudioQueueFreeBuffer(s_AudioQueue.queue, s_AudioQueue.buffers[i]); + } + + AudioQueueDispose(s_AudioQueue.queue, true); + _mixer->setReady(false); +} diff --git a/backends/platform/ios7/ios7_osys_video.mm b/backends/platform/ios7/ios7_osys_video.mm new file mode 100644 index 0000000000..0d183ce834 --- /dev/null +++ b/backends/platform/ios7/ios7_osys_video.mm @@ -0,0 +1,545 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "ios7_osys_main.h" +#include "ios7_video.h" + +#include "graphics/conversion.h" +#import "iOS7AppDelegate.h" + +@interface iOS7AlertHandler : NSObject<UIAlertViewDelegate> +@end + +@implementation iOS7AlertHandler + +- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex { + OSystem_iOS7::sharedInstance()->quit(); + exit(1); +} + +@end + +static void displayAlert(void *ctx) { + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Fatal Error" + message:[NSString stringWithCString:(const char *)ctx encoding:NSUTF8StringEncoding] + delegate:[[iOS7AlertHandler alloc] init] + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; + [alert show]; + [alert autorelease]; +} + +void OSystem_iOS7::fatalError() { + if (_lastErrorMessage) { + dispatch_async_f(dispatch_get_main_queue(), _lastErrorMessage, displayAlert); + for(;;); + } + else { + OSystem::fatalError(); + } +} + +void OSystem_iOS7::initVideoContext() { + _videoContext = [[iOS7AppDelegate iPhoneView] getVideoContext]; +} + +const OSystem::GraphicsMode *OSystem_iOS7::getSupportedGraphicsModes() const { + return s_supportedGraphicsModes; +} + +int OSystem_iOS7::getDefaultGraphicsMode() const { + return kGraphicsModeNone; +} + +bool OSystem_iOS7::setGraphicsMode(int mode) { + switch (mode) { + case kGraphicsModeNone: + case kGraphicsModeLinear: + case kGraphicsMode2xSaI: + case kGraphicsModeSuper2xSaI: + case kGraphicsModeSuperEagle: + case kGraphicsModeAdvMame2x: + case kGraphicsModeAdvMame3x: + case kGraphicsModeHQ2x: + case kGraphicsModeHQ3x: + case kGraphicsModeTV2x: + case kGraphicsModeDotMatrix: + _videoContext->graphicsMode = (GraphicsModes)mode; + return true; + + default: + return false; + } +} + +int OSystem_iOS7::getGraphicsMode() const { + return _videoContext->graphicsMode; +} + +#ifdef USE_RGB_COLOR +Common::List<Graphics::PixelFormat> OSystem_iOS7::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_iOS7::initSize(uint width, uint height, const Graphics::PixelFormat *format) { + //printf("initSize(%u, %u, %p)\n", width, height, (const void *)format); + + _videoContext->screenWidth = width; + _videoContext->screenHeight = height; + _videoContext->shakeOffsetY = 0; + + // In case we use the screen texture as frame buffer we reset the pixels + // pointer here to avoid freeing the screen texture. + if (_framebuffer.getPixels() == _videoContext->screenTexture.getPixels()) + _framebuffer.setPixels(0); + + // Create the screen texture right here. We need to do this here, since + // when a game requests hi-color mode, we actually set the framebuffer + // to the texture buffer to avoid an additional copy step. + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(createScreenTexture) withObject:nil waitUntilDone: YES]; + + // In case the client code tries to set up a non supported mode, we will + // fall back to CLUT8 and set the transaction error accordingly. + if (format && format->bytesPerPixel != 1 && *format != _videoContext->screenTexture.format) { + format = 0; + _gfxTransactionError = kTransactionFormatNotSupported; + } + + if (!format || format->bytesPerPixel == 1) { + _framebuffer.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + } else { +#if 0 + printf("bytesPerPixel: %u RGBAlosses: %u,%u,%u,%u RGBAshifts: %u,%u,%u,%u\n", format->bytesPerPixel, + format->rLoss, format->gLoss, format->bLoss, format->aLoss, + format->rShift, format->gShift, format->bShift, format->aShift); +#endif + // We directly draw on the screen texture in hi-color mode. Thus + // we copy over its settings here and just replace the width and + // height to avoid any problems. + _framebuffer = _videoContext->screenTexture; + _framebuffer.w = width; + _framebuffer.h = height; + } + + _fullScreenIsDirty = false; + dirtyFullScreen(); + _mouseCursorPaletteEnabled = false; +} + +void OSystem_iOS7::beginGFXTransaction() { + _gfxTransactionError = kTransactionSuccess; +} + +OSystem::TransactionError OSystem_iOS7::endGFXTransaction() { + _screenChangeCount++; + updateOutputSurface(); + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(setGraphicsMode) withObject:nil waitUntilDone: YES]; + + return _gfxTransactionError; +} + +void OSystem_iOS7::updateOutputSurface() { + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(initSurface) withObject:nil waitUntilDone: YES]; +} + +int16 OSystem_iOS7::getHeight() { + return _videoContext->screenHeight; +} + +int16 OSystem_iOS7::getWidth() { + return _videoContext->screenWidth; +} + +void OSystem_iOS7::setPalette(const byte *colors, uint start, uint num) { + //printf("setPalette(%p, %u, %u)\n", colors, start, num); + assert(start + num <= 256); + const byte *b = colors; + + for (uint i = start; i < start + num; ++i) { + _gamePalette[i] = Graphics::RGBToColor<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(); + + // Automatically update the mouse texture when the palette changes while the + // cursor palette is disabled. + if (!_mouseCursorPaletteEnabled && _mouseBuffer.format.bytesPerPixel == 1) + _mouseDirty = _mouseNeedTextureUpdate = true; +} + +void OSystem_iOS7::grabPalette(byte *colors, uint start, uint num) { + //printf("grabPalette(%p, %u, %u)\n", colors, start, num); + assert(start + num <= 256); + byte *b = colors; + + for (uint i = start; i < start + num; ++i) { + Graphics::colorToRGB<Graphics::ColorMasks<565> >(_gamePalette[i], b[0], b[1], b[2]); + b += 3; + } +} + +void OSystem_iOS7::copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) { + //printf("copyRectToScreen(%p, %d, %i, %i, %i, %i)\n", buf, pitch, x, y, w, h); + //Clip the coordinates + const byte *src = (const byte *)buf; + if (x < 0) { + w += x; + src -= x; + x = 0; + } + + if (y < 0) { + h += y; + src -= y * pitch; + y = 0; + } + + if (w > (int)_framebuffer.w - x) { + w = _framebuffer.w - x; + } + + if (h > (int)_framebuffer.h - y) { + h = _framebuffer.h - y; + } + + if (w <= 0 || h <= 0) + return; + + if (!_fullScreenIsDirty) { + _dirtyRects.push_back(Common::Rect(x, y, x + w, y + h)); + } + + byte *dst = (byte *)_framebuffer.getBasePtr(x, y); + if (_framebuffer.pitch == pitch && _framebuffer.w == w) { + memcpy(dst, src, h * pitch); + } else { + do { + memcpy(dst, src, w * _framebuffer.format.bytesPerPixel); + src += pitch; + dst += _framebuffer.pitch; + } while (--h); + } +} + +void OSystem_iOS7::updateScreen() { + if (_dirtyRects.size() == 0 && _dirtyOverlayRects.size() == 0 && !_mouseDirty) + return; + + //printf("updateScreen(): %i dirty rects.\n", _dirtyRects.size()); + + internUpdateScreen(); + _mouseDirty = false; + _fullScreenIsDirty = false; + _fullScreenOverlayIsDirty = false; + + iOS7_updateScreen(); +} + +void OSystem_iOS7::internUpdateScreen() { + if (_mouseNeedTextureUpdate) { + updateMouseTexture(); + _mouseNeedTextureUpdate = false; + } + + while (_dirtyRects.size()) { + Common::Rect dirtyRect = _dirtyRects.remove_at(_dirtyRects.size() - 1); + + //printf("Drawing: (%i, %i) -> (%i, %i)\n", dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); + drawDirtyRect(dirtyRect); + // TODO: Implement dirty rect code + //updateHardwareSurfaceForRect(dirtyRect); + } + + if (_videoContext->overlayVisible) { + // TODO: Implement dirty rect code + _dirtyOverlayRects.clear(); + /*while (_dirtyOverlayRects.size()) { + Common::Rect dirtyRect = _dirtyOverlayRects.remove_at(_dirtyOverlayRects.size() - 1); + + //printf("Drawing: (%i, %i) -> (%i, %i)\n", dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); + drawDirtyOverlayRect(dirtyRect); + }*/ + } +} + +void OSystem_iOS7::drawDirtyRect(const Common::Rect &dirtyRect) { + // We only need to do a color look up for CLUT8 + if (_framebuffer.format.bytesPerPixel != 1) + return; + + int h = dirtyRect.bottom - dirtyRect.top; + int w = dirtyRect.right - dirtyRect.left; + + const byte *src = (const byte *)_framebuffer.getBasePtr(dirtyRect.left, dirtyRect.top); + byte *dstRaw = (byte *)_videoContext->screenTexture.getBasePtr(dirtyRect.left, dirtyRect.top); + + // When we use CLUT8 do a color look up + for (int y = h; y > 0; y--) { + uint16 *dst = (uint16 *)dstRaw; + for (int x = w; x > 0; x--) + *dst++ = _gamePalette[*src++]; + + dstRaw += _videoContext->screenTexture.pitch; + src += _framebuffer.pitch - w; + } +} + +Graphics::Surface *OSystem_iOS7::lockScreen() { + //printf("lockScreen()\n"); + return &_framebuffer; +} + +void OSystem_iOS7::unlockScreen() { + //printf("unlockScreen()\n"); + dirtyFullScreen(); +} + +void OSystem_iOS7::setShakePos(int shakeOffset) { + //printf("setShakePos(%i)\n", shakeOffset); + _videoContext->shakeOffsetY = shakeOffset; + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(setViewTransformation) withObject:nil waitUntilDone: YES]; + // HACK: We use this to force a redraw. + _mouseDirty = true; +} + +void OSystem_iOS7::showOverlay() { + //printf("showOverlay()\n"); + _videoContext->overlayVisible = true; + dirtyFullOverlayScreen(); + updateScreen(); + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(updateMouseCursorScaling) withObject:nil waitUntilDone: YES]; + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES]; +} + +void OSystem_iOS7::hideOverlay() { + //printf("hideOverlay()\n"); + _videoContext->overlayVisible = false; + _dirtyOverlayRects.clear(); + dirtyFullScreen(); + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(updateMouseCursorScaling) withObject:nil waitUntilDone: YES]; + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES]; +} + +void OSystem_iOS7::clearOverlay() { + //printf("clearOverlay()\n"); + bzero(_videoContext->overlayTexture.getPixels(), _videoContext->overlayTexture.h * _videoContext->overlayTexture.pitch); + dirtyFullOverlayScreen(); +} + +void OSystem_iOS7::grabOverlay(void *buf, int pitch) { + //printf("grabOverlay()\n"); + int h = _videoContext->overlayHeight; + + byte *dst = (byte *)buf; + const byte *src = (const byte *)_videoContext->overlayTexture.getPixels(); + do { + memcpy(dst, src, _videoContext->overlayWidth * sizeof(uint16)); + src += _videoContext->overlayTexture.pitch; + dst += pitch; + } while (--h); +} + +void OSystem_iOS7::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) { + //printf("copyRectToOverlay(%p, pitch=%i, x=%i, y=%i, w=%i, h=%i)\n", (const void *)buf, pitch, x, y, w, h); + const byte *src = (const byte *)buf; + + //Clip the coordinates + if (x < 0) { + w += x; + src -= x * sizeof(uint16); + x = 0; + } + + if (y < 0) { + h += y; + src -= y * pitch; + y = 0; + } + + if (w > (int)_videoContext->overlayWidth - x) + w = _videoContext->overlayWidth - x; + + if (h > (int)_videoContext->overlayHeight - y) + h = _videoContext->overlayHeight - y; + + if (w <= 0 || h <= 0) + return; + + if (!_fullScreenOverlayIsDirty) { + _dirtyOverlayRects.push_back(Common::Rect(x, y, x + w, y + h)); + } + + byte *dst = (byte *)_videoContext->overlayTexture.getBasePtr(x, y); + do { + memcpy(dst, src, w * sizeof(uint16)); + src += pitch; + dst += _videoContext->overlayTexture.pitch; + } while (--h); +} + +int16 OSystem_iOS7::getOverlayHeight() { + return _videoContext->overlayHeight; +} + +int16 OSystem_iOS7::getOverlayWidth() { + return _videoContext->overlayWidth; +} + +bool OSystem_iOS7::showMouse(bool visible) { + //printf("showMouse(%d)\n", visible); + bool last = _videoContext->mouseIsVisible; + _videoContext->mouseIsVisible = visible; + _mouseDirty = true; + + return last; +} + +void OSystem_iOS7::warpMouse(int x, int y) { + //printf("warpMouse(%d, %d)\n", x, y); + _videoContext->mouseX = x; + _videoContext->mouseY = y; + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(notifyMouseMove) withObject:nil waitUntilDone: YES]; + _mouseDirty = true; +} + +void OSystem_iOS7::dirtyFullScreen() { + if (!_fullScreenIsDirty) { + _dirtyRects.clear(); + _dirtyRects.push_back(Common::Rect(0, 0, _videoContext->screenWidth, _videoContext->screenHeight)); + _fullScreenIsDirty = true; + } +} + +void OSystem_iOS7::dirtyFullOverlayScreen() { + if (!_fullScreenOverlayIsDirty) { + _dirtyOverlayRects.clear(); + _dirtyOverlayRects.push_back(Common::Rect(0, 0, _videoContext->overlayWidth, _videoContext->overlayHeight)); + _fullScreenOverlayIsDirty = true; + } +} + +void OSystem_iOS7::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { + //printf("setMouseCursor(%p, %u, %u, %i, %i, %u, %d, %p)\n", (const void *)buf, w, h, hotspotX, hotspotY, keycolor, dontScale, (const void *)format); + + const Graphics::PixelFormat pixelFormat = format ? *format : Graphics::PixelFormat::createFormatCLUT8(); +#if 0 + printf("bytesPerPixel: %u RGBAlosses: %u,%u,%u,%u RGBAshifts: %u,%u,%u,%u\n", pixelFormat.bytesPerPixel, + pixelFormat.rLoss, pixelFormat.gLoss, pixelFormat.bLoss, pixelFormat.aLoss, + pixelFormat.rShift, pixelFormat.gShift, pixelFormat.bShift, pixelFormat.aShift); +#endif + assert(pixelFormat.bytesPerPixel == 1 || pixelFormat.bytesPerPixel == 2); + + if (_mouseBuffer.w != w || _mouseBuffer.h != h || _mouseBuffer.format != pixelFormat || !_mouseBuffer.getPixels()) + _mouseBuffer.create(w, h, pixelFormat); + + _videoContext->mouseWidth = w; + _videoContext->mouseHeight = h; + + _videoContext->mouseHotspotX = hotspotX; + _videoContext->mouseHotspotY = hotspotY; + + _mouseKeyColor = keycolor; + + memcpy(_mouseBuffer.getPixels(), buf, h * _mouseBuffer.pitch); + + _mouseDirty = true; + _mouseNeedTextureUpdate = true; +} + +void OSystem_iOS7::setCursorPalette(const byte *colors, uint start, uint num) { + //printf("setCursorPalette(%p, %u, %u)\n", (const void *)colors, start, num); + assert(start + num <= 256); + + for (uint i = start; i < start + num; ++i, colors += 3) + _mouseCursorPalette[i] = Graphics::RGBToColor<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_iOS7::updateMouseTexture() { + uint texWidth = getSizeNextPOT(_videoContext->mouseWidth); + uint texHeight = getSizeNextPOT(_videoContext->mouseHeight); + + Graphics::Surface &mouseTexture = _videoContext->mouseTexture; + if (mouseTexture.w != texWidth || mouseTexture.h != texHeight) + mouseTexture.create(texWidth, texHeight, Graphics::createPixelFormat<5551>()); + + if (_mouseBuffer.format.bytesPerPixel == 1) { + const uint16 *palette; + if (_mouseCursorPaletteEnabled) + palette = _mouseCursorPalette; + else + palette = _gamePaletteRGBA5551; + + uint16 *mouseBuf = (uint16 *)mouseTexture.getPixels(); + for (uint x = 0; x < _videoContext->mouseWidth; ++x) { + for (uint y = 0; y < _videoContext->mouseHeight; ++y) { + const byte color = *(const byte *)_mouseBuffer.getBasePtr(x, y); + if (color != _mouseKeyColor) + mouseBuf[y * texWidth + x] = palette[color] | 0x1; + else + mouseBuf[y * texWidth + x] = 0x0; + } + } + } else { + if (crossBlit((byte *)mouseTexture.getPixels(), (const byte *)_mouseBuffer.getPixels(), mouseTexture.pitch, + _mouseBuffer.pitch, _mouseBuffer.w, _mouseBuffer.h, mouseTexture.format, _mouseBuffer.format)) { + if (!_mouseBuffer.format.aBits()) { + // Apply color keying since the original cursor had no alpha channel. + const uint16 *src = (const uint16 *)_mouseBuffer.getPixels(); + uint8 *dstRaw = (uint8 *)mouseTexture.getPixels(); + + for (uint y = 0; y < _mouseBuffer.h; ++y, dstRaw += mouseTexture.pitch) { + uint16 *dst = (uint16 *)dstRaw; + for (uint x = 0; x < _mouseBuffer.w; ++x, ++dst) { + if (*src++ == _mouseKeyColor) + *dst &= ~1; + else + *dst |= 1; + } + } + } + } else { + // TODO: Log this! + // Make the cursor all transparent... we really need a better fallback ;-). + memset(mouseTexture.getPixels(), 0, mouseTexture.h * mouseTexture.pitch); + } + } + + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(updateMouseCursor) withObject:nil waitUntilDone: YES]; +} diff --git a/backends/platform/ios7/ios7_video.h b/backends/platform/ios7/ios7_video.h new file mode 100644 index 0000000000..ab261a977b --- /dev/null +++ b/backends/platform/ios7/ios7_video.h @@ -0,0 +1,131 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef BACKENDS_PLATFORM_IPHONE_IPHONE_VIDEO_H +#define BACKENDS_PLATFORM_IPHONE_IPHONE_VIDEO_H + +#include <UIKit/UIKit.h> +#include <Foundation/Foundation.h> +#include <QuartzCore/QuartzCore.h> + +#include <OpenGLES/EAGL.h> +#include <OpenGLES/ES2/gl.h> +#include <OpenGLES/ES2/glext.h> + +#include "ios7_keyboard.h" +#include "ios7_common.h" + +#include "common/list.h" +#import "graphics/scaler.h" + +typedef struct { + GLfloat x, y; + GLfloat u,v; +} GLVertex; + +@interface iPhoneView : UIView { + VideoContext _videoContext; + + Common::List<InternalEvent> _events; + NSLock *_eventLock; + SoftKeyboard *_keyboardView; + + EAGLContext *_context; + GLuint _viewRenderbuffer; + GLuint _viewFramebuffer; + GLuint _screenTexture; + GLuint _overlayTexture; + GLuint _mouseCursorTexture; + + GLuint _vertexShader; + GLuint _fragmentShader; + + GLuint _vertexBuffer; + + GLuint _screenSizeSlot; + GLuint _textureSlot; + GLuint _shakeSlot; + + GLuint _positionSlot; + GLuint _textureCoordSlot; + + GLint _renderBufferWidth; + GLint _renderBufferHeight; + + GLVertex _gameScreenCoords[4]; + CGRect _gameScreenRect; + + GLVertex _overlayCoords[4]; + CGRect _overlayRect; + + GLVertex _mouseCoords[4]; + + GLint _mouseHotspotX, _mouseHotspotY; + GLint _mouseWidth, _mouseHeight; + GLfloat _mouseScaleX, _mouseScaleY; + + int _scaledShakeOffsetY; + + UITouch *_firstTouch; + UITouch *_secondTouch; + +#ifdef ENABLE_IOS7_SCALERS + uint8_t *_scalerMemorySrc; + uint8_t *_scalerMemoryDst; + size_t _scalerMemorySrcSize; + size_t _scalerMemoryDstSize; + int _scalerScale; + ScalerProc *_scaler; +#endif +} + +- (id)initWithFrame:(struct CGRect)frame; + +- (VideoContext *)getVideoContext; + +- (void)createScreenTexture; +- (void)initSurface; +- (void)setViewTransformation; + +- (void)setGraphicsMode; + +- (void)updateSurface; +- (void)updateMainSurface; +- (void)updateOverlaySurface; +- (void)updateMouseSurface; +- (void)clearColorBuffer; + +- (void)notifyMouseMove; +- (void)updateMouseCursorScaling; +- (void)updateMouseCursor; + +- (void)deviceOrientationChanged:(UIDeviceOrientation)orientation; + +- (void)applicationSuspend; + +- (void)applicationResume; + +- (bool)fetchEvent:(InternalEvent *)event; + +@end + +#endif diff --git a/backends/platform/ios7/ios7_video.mm b/backends/platform/ios7/ios7_video.mm new file mode 100644 index 0000000000..2cfc3e05f7 --- /dev/null +++ b/backends/platform/ios7/ios7_video.mm @@ -0,0 +1,1002 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "ios7_video.h" + +#include "graphics/colormasks.h" +#include "common/system.h" +#import "iOS7AppDelegate.h" + +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 iOS7_isBigDevice() { + return UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad; +} + +void iOS7_updateScreen() { + //printf("Mouse: (%i, %i)\n", mouseX, mouseY); + if (!g_needsScreenUpdate) { + g_needsScreenUpdate = 1; + [[iOS7AppDelegate iPhoneView] performSelectorOnMainThread:@selector(updateSurface) withObject:nil waitUntilDone: NO]; + } +} + +bool iOS7_fetchEvent(InternalEvent *event) { + return [[iOS7AppDelegate iPhoneView] fetchEvent:event]; +} + +uint getSizeNextPOT(uint size) { + if ((size & (size - 1)) || !size) { + int log = 0; + + while (size >>= 1) + ++log; + + size = (2 << log); + } + + return size; +} + +@implementation iPhoneView + ++ (Class)layerClass { + return [CAEAGLLayer class]; +} + +- (VideoContext *)getVideoContext { + return &_videoContext; +} + +- (void)createContext { + CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; + + eaglLayer.opaque = YES; + eaglLayer.drawableProperties = @{ + kEAGLDrawablePropertyRetainedBacking: @NO, + kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGB565 + }; + + _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + + // 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]) { + // glEnableClientState(GL_TEXTURE_COORD_ARRAY); printOpenGLError(); + // glEnableClientState(GL_VERTEX_ARRAY); printOpenGLError(); + [self setupOpenGL]; + } +} + +- (void)setupOpenGL { + [self setupFramebuffer]; + [self createOverlaySurface]; + [self compileShaders]; + [self setupVBOs]; + [self setupTextures]; + + [self finishGLSetup]; +} + +- (void)finishGLSetup { + glViewport(0, 0, _renderBufferWidth, _renderBufferHeight); printOpenGLError(); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); printOpenGLError(); + + glUniform2f(_screenSizeSlot, _renderBufferWidth, _renderBufferHeight); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +} + +- (void)freeOpenGL { + [self deleteTextures]; + [self deleteVBOs]; + [self deleteShaders]; + [self deleteFramebuffer]; +} + +- (void)rebuildFrameBuffer { + [self deleteFramebuffer]; + [self setupFramebuffer]; + [self finishGLSetup]; +} + +- (void)setupFramebuffer { + glGenRenderbuffers(1, &_viewRenderbuffer); + printOpenGLError(); + glBindRenderbuffer(GL_RENDERBUFFER, _viewRenderbuffer); + printOpenGLError(); + [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(id <EAGLDrawable>) self.layer]; + + glGenFramebuffers(1, &_viewFramebuffer); + printOpenGLError(); + glBindFramebuffer(GL_FRAMEBUFFER, _viewFramebuffer); + printOpenGLError(); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _viewRenderbuffer); + printOpenGLError(); + + // Retrieve the render buffer size. This *should* match the frame size, + // i.e. g_fullWidth and g_fullHeight. + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_renderBufferWidth); + printOpenGLError(); + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_renderBufferHeight); + printOpenGLError(); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatus(GL_FRAMEBUFFER)); + return; + } +} + +- (void)createOverlaySurface { + uint overlayWidth = (uint) MAX(_renderBufferWidth, _renderBufferHeight); + uint overlayHeight = (uint) MIN(_renderBufferWidth, _renderBufferHeight); + + if (iOS7_isBigDevice()) { + // On really big displays, like the iPad Pro, we scale the interface down + // so that the controls are not too small.. + while (overlayHeight > 1024) { + overlayWidth /= 2; + overlayHeight /= 2; + } + } + else { + // On small devices, we force the user interface to use the small theme + while (overlayHeight > 480) { + overlayWidth /= 2; + overlayHeight /= 2; + } + } + + _videoContext.overlayWidth = overlayWidth; + _videoContext.overlayHeight = overlayHeight; + + uint overlayTextureWidthPOT = getSizeNextPOT(overlayWidth); + uint overlayTextureHeightPOT = getSizeNextPOT(overlayHeight); + + // Since the overlay size won't change the whole run, we can + // precalculate the texture coordinates for the overlay texture here + // and just use it later on. + GLfloat u = _videoContext.overlayWidth / (GLfloat) overlayTextureWidthPOT; + GLfloat v = _videoContext.overlayHeight / (GLfloat) overlayTextureHeightPOT; + _overlayCoords[0].x = 0; _overlayCoords[0].y = 0; _overlayCoords[0].u = 0; _overlayCoords[0].v = 0; + _overlayCoords[1].x = 0; _overlayCoords[1].y = 0; _overlayCoords[1].u = u; _overlayCoords[1].v = 0; + _overlayCoords[2].x = 0; _overlayCoords[2].y = 0; _overlayCoords[2].u = 0; _overlayCoords[2].v = v; + _overlayCoords[3].x = 0; _overlayCoords[3].y = 0; _overlayCoords[3].u = u; _overlayCoords[3].v = v; + + _videoContext.overlayTexture.create((uint16) overlayTextureWidthPOT, (uint16) overlayTextureHeightPOT, Graphics::createPixelFormat<5551>()); +} + +- (void)deleteFramebuffer { + glDeleteRenderbuffers(1, &_viewRenderbuffer); + glDeleteFramebuffers(1, &_viewFramebuffer); +} + +- (void)setupVBOs { + glGenBuffers(1, &_vertexBuffer); + glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); +} + +- (void)deleteVBOs { + glDeleteBuffers(1, &_vertexBuffer); +} + +- (GLuint)compileShader:(const char*)shaderPrg withType:(GLenum)shaderType { + GLuint shaderHandle = glCreateShader(shaderType); + + int shaderPrgLength = strlen(shaderPrg); + glShaderSource(shaderHandle, 1, &shaderPrg, &shaderPrgLength); + + glCompileShader(shaderHandle); + + GLint compileSuccess; + glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess); + if (compileSuccess == GL_FALSE) { + GLchar messages[256]; + glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]); + NSString *messageString = [NSString stringWithUTF8String:messages]; + NSLog(@"%@", messageString); + exit(1); + } + + return shaderHandle; +} + +- (void)compileShaders { + const char *vertexPrg = + "uniform vec2 ScreenSize;" + "uniform float Shake;" + "" + "attribute vec2 Position;" + "attribute vec2 TexCoord;" + "" + "varying vec4 DestColor;" + "varying vec2 o_TexCoord;" + "" + "void main(void) {" + " DestColor = vec4(Position.x, Position.y, 0, 1);" + " o_TexCoord = TexCoord;" + " gl_Position = vec4((Position.x / ScreenSize.x) * 2.0 - 1.0, (1.0 - (Position.y + Shake) / ScreenSize.y) * 2.0 - 1.0, 0, 1);" + "}"; + + const char *fragmentPrg = + "uniform sampler2D Texture;" + "" + "varying lowp vec4 DestColor;" + "varying lowp vec2 o_TexCoord;" + "" + "void main(void) {" + " gl_FragColor = texture2D(Texture, o_TexCoord);" + "}"; + + _vertexShader = [self compileShader:vertexPrg withType:GL_VERTEX_SHADER]; + _fragmentShader = [self compileShader:fragmentPrg withType:GL_FRAGMENT_SHADER]; + + GLuint programHandle = glCreateProgram(); + glAttachShader(programHandle, _vertexShader); + glAttachShader(programHandle, _fragmentShader); + glLinkProgram(programHandle); + + GLint linkSuccess; + glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess); + if (linkSuccess == GL_FALSE) { + printOpenGLError(); + exit(1); + } + + glUseProgram(programHandle); + + _screenSizeSlot = (GLuint) glGetUniformLocation(programHandle, "ScreenSize"); + _textureSlot = (GLuint) glGetUniformLocation(programHandle, "Texture"); + _shakeSlot = (GLuint) glGetUniformLocation(programHandle, "Shake"); + + _positionSlot = (GLuint) glGetAttribLocation(programHandle, "Position"); + _textureCoordSlot = (GLuint) glGetAttribLocation(programHandle, "TexCoord"); + + glEnableVertexAttribArray(_positionSlot); + glEnableVertexAttribArray(_textureCoordSlot); + + glUniform1i(_textureSlot, 0); printOpenGLError(); +} + +- (void)deleteShaders { + glDeleteShader(_vertexShader); + glDeleteShader(_fragmentShader); +} + +- (void)setupTextures { + glGenTextures(1, &_screenTexture); printOpenGLError(); + glGenTextures(1, &_overlayTexture); printOpenGLError(); + glGenTextures(1, &_mouseCursorTexture); printOpenGLError(); + + [self setGraphicsMode]; +} + +- (void)deleteTextures { + if (_screenTexture) { + glDeleteTextures(1, &_screenTexture); printOpenGLError(); + _screenTexture = 0; + } + if (_overlayTexture) { + glDeleteTextures(1, &_overlayTexture); printOpenGLError(); + _overlayTexture = 0; + } + if (_mouseCursorTexture) { + glDeleteTextures(1, &_mouseCursorTexture); printOpenGLError(); + _mouseCursorTexture = 0; + } +} + +- (void)setupGestureRecognizers { + UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeRight:)]; + swipeRight.direction = UISwipeGestureRecognizerDirectionRight; + swipeRight.numberOfTouchesRequired = 2; + swipeRight.delaysTouchesBegan = NO; + swipeRight.delaysTouchesEnded = NO; + + UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeLeft:)]; + swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft; + swipeLeft.numberOfTouchesRequired = 2; + swipeLeft.delaysTouchesBegan = NO; + swipeLeft.delaysTouchesEnded = NO; + + UISwipeGestureRecognizer *swipeUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeUp:)]; + swipeUp.direction = UISwipeGestureRecognizerDirectionUp; + swipeUp.numberOfTouchesRequired = 2; + swipeUp.delaysTouchesBegan = NO; + swipeUp.delaysTouchesEnded = NO; + + UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeDown:)]; + swipeDown.direction = UISwipeGestureRecognizerDirectionDown; + swipeDown.numberOfTouchesRequired = 2; + swipeDown.delaysTouchesBegan = NO; + swipeDown.delaysTouchesEnded = NO; + + UITapGestureRecognizer *doubleTapTwoFingers = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersDoubleTap:)]; + doubleTapTwoFingers.numberOfTapsRequired = 2; + doubleTapTwoFingers.numberOfTouchesRequired = 2; + doubleTapTwoFingers.delaysTouchesBegan = NO; + doubleTapTwoFingers.delaysTouchesEnded = NO; + + [self addGestureRecognizer:swipeRight]; + [self addGestureRecognizer:swipeLeft]; + [self addGestureRecognizer:swipeUp]; + [self addGestureRecognizer:swipeDown]; + [self addGestureRecognizer:doubleTapTwoFingers]; + + [swipeRight release]; + [swipeLeft release]; + [swipeUp release]; + [swipeDown release]; + [doubleTapTwoFingers release]; +} + +- (id)initWithFrame:(struct CGRect)frame { + self = [super initWithFrame: frame]; + +#if defined(USE_SCALERS) || defined(USE_HQ_SCALERS) + InitScalers(565); +#endif + + [self setupGestureRecognizers]; + + [self setContentScaleFactor:[[UIScreen mainScreen] scale]]; + +#ifdef ENABLE_IOS7_SCALERS + _scalerMemorySrc = NULL; + _scalerMemoryDst = NULL; + _scalerMemorySrcSize = 0; + _scalerMemoryDstSize = 0; + _scaler = NULL; + _scalerScale = 1; +#endif + + _keyboardView = nil; + _screenTexture = 0; + _overlayTexture = 0; + _mouseCursorTexture = 0; + + _scaledShakeOffsetY = 0; + + _firstTouch = NULL; + _secondTouch = NULL; + + _eventLock = [[NSLock alloc] init]; + + memset(_gameScreenCoords, 0, sizeof(GLVertex) * 4); + memset(_overlayCoords, 0, sizeof(GLVertex) * 4); + memset(_mouseCoords, 0, sizeof(GLVertex) * 4); + + // Initialize the OpenGL ES context + [self createContext]; + + return self; +} + +- (void)dealloc { + [_keyboardView release]; + + _videoContext.screenTexture.free(); + _videoContext.overlayTexture.free(); + _videoContext.mouseTexture.free(); + +#ifdef ENABLE_IOS7_SCALERS + free(_scalerMemorySrc); + free(_scalerMemoryDst); +#endif + + [_eventLock release]; + [super dealloc]; +} + +- (void)setFilterModeForTexture:(GLuint)tex { + if (!tex) + return; + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, tex); printOpenGLError(); + + GLint filter = GL_LINEAR; + + switch (_videoContext.graphicsMode) { + case kGraphicsModeNone: + filter = GL_NEAREST; + break; + + case kGraphicsModeLinear: + case kGraphicsMode2xSaI: + case kGraphicsModeSuper2xSaI: + case kGraphicsModeSuperEagle: + case kGraphicsModeAdvMame2x: + case kGraphicsModeAdvMame3x: + case kGraphicsModeHQ2x: + case kGraphicsModeHQ3x: + case kGraphicsModeTV2x: + case kGraphicsModeDotMatrix: + filter = GL_LINEAR; + break; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); printOpenGLError(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); printOpenGLError(); + // We use GL_CLAMP_TO_EDGE here to avoid artifacts when linear filtering + // is used. If we would not use this for example the cursor in Loom would + // have a line/border artifact on the right side of the covered rect. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); printOpenGLError(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); printOpenGLError(); +} + +#ifdef ENABLE_IOS7_SCALERS +- (void)setScaler { + ScalerProc *scaler = NULL; + int scalerScale = 1; + + switch (_videoContext.graphicsMode) { + case kGraphicsModeLinear: + break; + + case kGraphicsModeNone: + break; +#ifdef USE_SCALERS + case kGraphicsMode2xSaI: + scaler = _2xSaI; + scalerScale = 2; + break; + + case kGraphicsModeSuper2xSaI: + scaler = Super2xSaI; + scalerScale = 2; + break; + + case kGraphicsModeSuperEagle: + scaler = SuperEagle; + scalerScale = 2; + break; + + case kGraphicsModeAdvMame2x: + scaler = AdvMame2x; + scalerScale = 2; + break; + + case kGraphicsModeAdvMame3x: + scaler = AdvMame3x; + scalerScale = 3; + break; + +#ifdef USE_HQ_SCALERS + case kGraphicsModeHQ2x: + scaler = HQ2x; + scalerScale = 2; + break; + + case kGraphicsModeHQ3x: + scaler = HQ3x; + scalerScale = 3; + break; +#endif + + case kGraphicsModeTV2x: + scaler = TV2x; + scalerScale = 2; + break; + + case kGraphicsModeDotMatrix: + scaler = DotMatrix; + scalerScale = 2; + break; +#endif + + default: + break; + } + + _scaler = scaler; + _scalerScale = scalerScale; +} +#endif + +- (void)setGraphicsMode { + [self setFilterModeForTexture:_screenTexture]; + [self setFilterModeForTexture:_overlayTexture]; + [self setFilterModeForTexture:_mouseCursorTexture]; +#ifdef ENABLE_IOS7_SCALERS + [self setScaler]; +#endif +} + +- (void)updateSurface { + 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]; + + [_context presentRenderbuffer:GL_RENDERBUFFER]; + glFinish(); +} + +- (void)notifyMouseMove { + const GLint mouseX = (GLint)(_videoContext.mouseX * _mouseScaleX) - _mouseHotspotX; + const GLint mouseY = (GLint)(_videoContext.mouseY * _mouseScaleY) - _mouseHotspotY; + + _mouseCoords[0].x = _mouseCoords[2].x = mouseX; + _mouseCoords[0].y = _mouseCoords[1].y = mouseY; + _mouseCoords[1].x = _mouseCoords[3].x = mouseX + _mouseWidth; + _mouseCoords[2].y = _mouseCoords[3].y = mouseY + _mouseHeight; +} + +- (void)updateMouseCursorScaling { + 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 { + [self updateMouseCursorScaling]; + + _mouseCoords[1].u = _mouseCoords[3].u = (_videoContext.mouseWidth - 1) / (GLfloat)_videoContext.mouseTexture.w; + _mouseCoords[2].v = _mouseCoords[3].v = (_videoContext.mouseHeight - 1) / (GLfloat)_videoContext.mouseTexture.h; + + [self setFilterModeForTexture:_mouseCursorTexture]; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.mouseTexture.w, _videoContext.mouseTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.mouseTexture.getPixels()); printOpenGLError(); +} + +- (void)updateMainSurface { + glBufferData(GL_ARRAY_BUFFER, sizeof(GLVertex) * 4, _gameScreenCoords, GL_STATIC_DRAW); + glVertexAttribPointer(_positionSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), 0); + glVertexAttribPointer(_textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), (GLvoid *) (sizeof(GLfloat) * 2)); + + [self setFilterModeForTexture:_screenTexture]; + + // Unfortunately we have to update the whole texture every frame, since glTexSubImage2D is actually slower in all cases + // due to the iPhone internals having to convert the whole texture back from its internal format when used. + // In the future we could use several tiled textures instead. +#ifdef ENABLE_IOS7_SCALERS + if (_scaler) { + size_t neededSrcMemorySize = (size_t) (_videoContext.screenTexture.pitch * (_videoContext.screenTexture.h + 4)); + size_t neededDstMemorySize = (size_t) (_videoContext.screenTexture.pitch * (_videoContext.screenTexture.h + 4) * _scalerScale * _scalerScale); + if (neededSrcMemorySize != _scalerMemorySrcSize) { + _scalerMemorySrc = (uint8_t *) realloc(_scalerMemorySrc, neededSrcMemorySize); + _scalerMemorySrcSize = neededSrcMemorySize; + } + if (neededDstMemorySize != _scalerMemoryDstSize) { + _scalerMemoryDst = (uint8_t *) realloc(_scalerMemoryDst, neededDstMemorySize); + _scalerMemoryDstSize = neededDstMemorySize; + } + + // Clear two lines before + memset(_scalerMemorySrc, 0, (size_t) (_videoContext.screenTexture.pitch * 2)); + // Copy original buffer + memcpy(_scalerMemorySrc + _videoContext.screenTexture.pitch * 2, _videoContext.screenTexture.getPixels(), _videoContext.screenTexture.pitch * _videoContext.screenTexture.h); + // Clear two lines after + memset(_scalerMemorySrc + _videoContext.screenTexture.pitch * (2 + _videoContext.screenTexture.h), 0, (size_t) (_videoContext.screenTexture.pitch * 2)); + // Apply scaler + _scaler(_scalerMemorySrc + _videoContext.screenTexture.pitch * 2, + _videoContext.screenTexture.pitch, + _scalerMemoryDst, + (uint32) (_videoContext.screenTexture.pitch * _scalerScale), + _videoContext.screenTexture.w, + _videoContext.screenTexture.h); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w * _scalerScale, _videoContext.screenTexture.h * _scalerScale, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _scalerMemoryDst); printOpenGLError(); + } + else { +#endif + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w, _videoContext.screenTexture.h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _videoContext.screenTexture.getPixels()); printOpenGLError(); +#ifdef ENABLE_IOS7_SCALERS + } +#endif + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); +} + +- (void)updateOverlaySurface { + glBufferData(GL_ARRAY_BUFFER, sizeof(GLVertex) * 4, _overlayCoords, GL_STATIC_DRAW); + glVertexAttribPointer(_positionSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), 0); + glVertexAttribPointer(_textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), (GLvoid *) (sizeof(GLfloat) * 2)); + + [self setFilterModeForTexture:_overlayTexture]; + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.overlayTexture.w, _videoContext.overlayTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.overlayTexture.getPixels()); printOpenGLError(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); +} + +- (void)updateMouseSurface { + glBufferData(GL_ARRAY_BUFFER, sizeof(GLVertex) * 4, _mouseCoords, GL_STATIC_DRAW); + glVertexAttribPointer(_positionSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), 0); + glVertexAttribPointer(_textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLVertex), (GLvoid *) (sizeof(GLfloat) * 2)); + + glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); +} + +- (void)createScreenTexture { + const uint screenTexWidth = getSizeNextPOT(_videoContext.screenWidth); + const uint screenTexHeight = getSizeNextPOT(_videoContext.screenHeight); + + _gameScreenCoords[1].u = _gameScreenCoords[3].u = _videoContext.screenWidth / (GLfloat)screenTexWidth; + _gameScreenCoords[2].v = _gameScreenCoords[3].v = _videoContext.screenHeight / (GLfloat)screenTexHeight; + + _videoContext.screenTexture.create((uint16) screenTexWidth, (uint16) screenTexHeight, Graphics::createPixelFormat<565>()); +} + +- (void)initSurface { + if (_context) { + [self rebuildFrameBuffer]; + } + + BOOL isLandscape = (self.bounds.size.width > self.bounds.size.height); // UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]); + + int screenWidth, screenHeight; + if (isLandscape) { + screenWidth = MAX(_renderBufferWidth, _renderBufferHeight); + screenHeight = MIN(_renderBufferWidth, _renderBufferHeight); + } + else { + screenWidth = MIN(_renderBufferWidth, _renderBufferHeight); + screenHeight = MAX(_renderBufferWidth, _renderBufferHeight); + } + + glBindRenderbuffer(GL_RENDERBUFFER, _viewRenderbuffer); printOpenGLError(); + + [self clearColorBuffer]; + + GLfloat adjustedWidth = _videoContext.screenWidth; + GLfloat adjustedHeight = _videoContext.screenHeight; + if (_videoContext.asprectRatioCorrection) { + if (_videoContext.screenWidth == 320 && _videoContext.screenHeight == 200) + adjustedHeight = 240; + else if (_videoContext.screenWidth == 640 && _videoContext.screenHeight == 400) + adjustedHeight = 480; + } + + float overlayPortraitRatio; + + if (isLandscape) { + GLfloat gameScreenRatio = adjustedWidth / adjustedHeight; + GLfloat screenRatio = (GLfloat)screenWidth / (GLfloat)screenHeight; + + // These are the width/height according to the portrait layout! + int rectWidth, rectHeight; + int xOffset, yOffset; + + if (gameScreenRatio < screenRatio) { + // When the game screen ratio is less than the screen ratio + // we need to scale the width, since the game screen was higher + // compared to the width than our output screen is. + rectWidth = (int)(screenHeight * gameScreenRatio); + rectHeight = screenHeight; + xOffset = (screenWidth - rectWidth) / 2; + yOffset = 0; + } else { + // When the game screen ratio is bigger than the screen ratio + // we need to scale the height, since the game screen was wider + // compared to the height than our output screen is. + rectWidth = screenWidth; + rectHeight = (int)(screenWidth / gameScreenRatio); + xOffset = 0; + yOffset = (screenHeight - rectHeight) / 2; + } + + [_keyboardView hideKeyboard]; + + //printf("Rect: %i, %i, %i, %i\n", xOffset, yOffset, rectWidth, rectHeight); + _gameScreenRect = CGRectMake(xOffset, yOffset, rectWidth, rectHeight); + overlayPortraitRatio = 1.0f; + } else { + GLfloat ratio = adjustedHeight / adjustedWidth; + int height = (int)(screenWidth * ratio); + //printf("Making rect (%u, %u)\n", screenWidth, height); + _gameScreenRect = CGRectMake(0, 0, screenWidth, height); + + CGRect keyFrame = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f); + if (_keyboardView == nil) { + _keyboardView = [[SoftKeyboard alloc] initWithFrame:keyFrame]; + [_keyboardView setInputDelegate:self]; + [self addSubview:[_keyboardView inputView]]; + [self addSubview: _keyboardView]; + } + + [_keyboardView showKeyboard]; + overlayPortraitRatio = (_videoContext.overlayHeight * ratio) / _videoContext.overlayWidth; + } + _overlayRect = CGRectMake(0, 0, screenWidth, screenHeight * overlayPortraitRatio); + + _gameScreenCoords[0].x = _gameScreenCoords[2].x = CGRectGetMinX(_gameScreenRect); + _gameScreenCoords[0].y = _gameScreenCoords[1].y = CGRectGetMinY(_gameScreenRect); + _gameScreenCoords[1].x = _gameScreenCoords[3].x = CGRectGetMaxX(_gameScreenRect); + _gameScreenCoords[2].y = _gameScreenCoords[3].y = CGRectGetMaxY(_gameScreenRect); + + _overlayCoords[1].x = _overlayCoords[3].x = CGRectGetMaxX(_overlayRect); + _overlayCoords[2].y = _overlayCoords[3].y = CGRectGetMaxY(_overlayRect); + + [self setViewTransformation]; + [self updateMouseCursorScaling]; +} + +- (void)setViewTransformation { + // 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)); + + glUniform1f(_shakeSlot, _scaledShakeOffsetY); +} + +- (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]; + glFinish(); + } +} + +- (void)addEvent:(InternalEvent)event { + [_eventLock lock]; + _events.push_back(event); + [_eventLock unlock]; +} + +- (bool)fetchEvent:(InternalEvent *)event { + [_eventLock lock]; + if (_events.empty()) { + [_eventLock unlock]; + return false; + } + + *event = *_events.begin(); + _events.pop_front(); + [_eventLock unlock]; + return true; +} + +- (bool)getMouseCoords:(CGPoint)point eventX:(int *)x eventY:(int *)y { + // We scale the input according to our scale factor to get actual screen + // coordinates. + point.x *= self.contentScaleFactor; + point.y *= self.contentScaleFactor; + + CGRect *area; + int width, height, offsetY; + if (_videoContext.overlayVisible) { + area = &_overlayRect; + width = _videoContext.overlayWidth; + height = _videoContext.overlayHeight; + offsetY = _scaledShakeOffsetY; + } else { + area = &_gameScreenRect; + width = _videoContext.screenWidth; + height = _videoContext.screenHeight; + offsetY = _videoContext.shakeOffsetY; + } + + point.x = (point.x - CGRectGetMinX(*area)) / CGRectGetWidth(*area); + point.y = (point.y - CGRectGetMinY(*area)) / CGRectGetHeight(*area); + + *x = (int)(point.x * width); + // offsetY describes the translation of the screen in the upward direction, + // thus we need to add it here. + *y = (int)(point.y * height + offsetY); + + if (!iOS7_touchpadModeEnabled()) { + // Clip coordinates + if (*x < 0 || *x > width || *y < 0 || *y > height) + return false; + } + + return true; +} + +- (void)deviceOrientationChanged:(UIDeviceOrientation)orientation { + [self addEvent:InternalEvent(kInputOrientationChanged, orientation, 0)]; +} + +- (UITouch *)secondTouchOtherTouchThan:(UITouch *)touch in:(NSSet *)set { + NSArray *all = [set allObjects]; + for (UITouch *t in all) { + if (t != touch) { + return t; + } + } + return nil; +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + int x, y; + + NSSet *allTouches = [event allTouches]; + if (allTouches.count == 1) { + _firstTouch = [allTouches anyObject]; + CGPoint point = [_firstTouch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent:InternalEvent(kInputMouseDown, x, y)]; + } + else if (allTouches.count == 2) { + _secondTouch = [self secondTouchOtherTouchThan:_firstTouch in:allTouches]; + if (_secondTouch) { + CGPoint point = [_secondTouch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent:InternalEvent(kInputMouseSecondDown, x, y)]; + } + } +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + int x, y; + + NSSet *allTouches = [event allTouches]; + for (UITouch *touch in allTouches) { + if (touch == _firstTouch) { + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent:InternalEvent(kInputMouseDragged, x, y)]; + } else if (touch == _secondTouch) { + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent:InternalEvent(kInputMouseSecondDragged, x, y)]; + } + } +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + int x, y; + + NSSet *allTouches = [event allTouches]; + if (allTouches.count == 1) { + UITouch *touch = [allTouches anyObject]; + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) { + return; + } + + [self addEvent:InternalEvent(kInputMouseUp, x, y)]; + } + else if (allTouches.count == 2) { + UITouch *touch = [[allTouches allObjects] objectAtIndex:1]; + CGPoint point = [touch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; + + [self addEvent:InternalEvent(kInputMouseSecondUp, x, y)]; + } + _firstTouch = nil; + _secondTouch = nil; +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + _firstTouch = nil; + _secondTouch = nil; +} + +- (void)twoFingersSwipeRight:(UISwipeGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeRight, 2)]; +} + +- (void)twoFingersSwipeLeft:(UISwipeGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeLeft, 2)]; +} + +- (void)twoFingersSwipeUp:(UISwipeGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeUp, 2)]; +} + +- (void)twoFingersSwipeDown:(UISwipeGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeDown, 2)]; +} + +- (void)twoFingersDoubleTap:(UITapGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputTap, kUIViewTapDouble, 2)]; +} + +- (void)handleKeyPress:(unichar)c { + [self addEvent:InternalEvent(kInputKeyPressed, c, 0)]; +} + +- (void)applicationSuspend { + [self addEvent:InternalEvent(kInputApplicationSuspended, 0, 0)]; +} + +- (void)applicationResume { + [self addEvent:InternalEvent(kInputApplicationResumed, 0, 0)]; +} + +@end diff --git a/backends/platform/ios7/module.mk b/backends/platform/ios7/module.mk new file mode 100644 index 0000000000..5ee4c7a601 --- /dev/null +++ b/backends/platform/ios7/module.mk @@ -0,0 +1,17 @@ +MODULE := backends/platform/ios7 + +MODULE_OBJS := \ + ios7_osys_main.o \ + ios7_osys_events.o \ + ios7_osys_sound.o \ + ios7_osys_video.o \ + ios7_main.o \ + ios7_video.o \ + ios7_keyboard.o \ + iOS7ScummVMViewController.o \ + iOS7AppDelegate.o + +# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS. +MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) +OBJS := $(MODULE_OBJS) $(OBJS) +MODULE_DIRS += $(sort $(dir $(MODULE_OBJS))) diff --git a/backends/platform/iphone/osys_main.cpp b/backends/platform/iphone/osys_main.cpp index 0ce21b44c1..3f5e7692c7 100644 --- a/backends/platform/iphone/osys_main.cpp +++ b/backends/platform/iphone/osys_main.cpp @@ -90,7 +90,7 @@ int OSystem_IPHONE::timerHandler(int t) { } void OSystem_IPHONE::initBackend() { -#ifdef IPHONE_OFFICIAL +#ifdef IPHONE_SANDBOXED _savefileManager = new DefaultSaveFileManager(iPhone_getDocumentsDir()); #else _savefileManager = new DefaultSaveFileManager(SCUMMVM_SAVE_PATH); @@ -252,7 +252,7 @@ OSystem *OSystem_IPHONE_create() { } Common::String OSystem_IPHONE::getDefaultConfigFileName() { -#ifdef IPHONE_OFFICIAL +#ifdef IPHONE_SANDBOXED Common::String path = iPhone_getDocumentsDir(); path += "/Preferences"; return path; @@ -305,7 +305,7 @@ void iphone_main(int argc, char *argv[]) { //gDebugLevel = 10; } -#ifdef IPHONE_OFFICIAL +#ifdef IPHONE_SANDBOXED chdir(iPhone_getDocumentsDir()); #else system("mkdir " SCUMMVM_ROOT_PATH); diff --git a/common/fs.h b/common/fs.h index b5b88ba8cb..66e98444d6 100644 --- a/common/fs.h +++ b/common/fs.h @@ -58,9 +58,11 @@ class FSList : public Array<FSNode> {}; class FSNode : public ArchiveMember { private: SharedPtr<AbstractFSNode> _realNode; - FSNode(AbstractFSNode *realNode); public: + // WARNING: Use this constructor with care! FSNode takes the ownership of the pointer and will delete it at some point. + FSNode(AbstractFSNode *realNode); + /** * Flag to tell listDir() which kind of files to list. */ diff --git a/common/str.h b/common/str.h index dede87a005..a30dae3513 100644 --- a/common/str.h +++ b/common/str.h @@ -180,6 +180,7 @@ public: inline uint size() const { return _size; } inline bool empty() const { return (_size == 0); } + char firstChar() const { return (_size > 0) ? _str[0] : 0; } char lastChar() const { return (_size > 0) ? _str[_size - 1] : 0; } char operator[](int idx) const { @@ -834,7 +834,7 @@ Usage: $0 [OPTIONS]... Configuration: -h, --help display this help and exit --backend=BACKEND backend to build (android, tizen, dc, dingux, ds, gcw0, - gph, iphone, linuxmoto, maemo, n64, null, openpandora, + gph, iphone, ios7, linuxmoto, maemo, n64, null, openpandora, ps2, psp, samsungtv, sdl, webos, wii, wince) [sdl] Installation directories: @@ -874,7 +874,8 @@ Special configuration feature: gcw0 for GCW Zero gp2x for GP2X gp2xwiz for GP2X Wiz - iphone for Apple iPhone + iphone for Apple iPhone (iOS <= 6) + ios7 for Apple iPhone / iPad (iOS >= 7) linupy for Yopy PDA maemo for Nokia Maemo motoezx for MotoEZX @@ -1359,6 +1360,11 @@ iphone) _host_cpu=arm _host_alias=arm-apple-darwin9 ;; +ios7) + _host_os=iphone + _host_cpu=arm + _host_alias=arm-apple-darwin11 + ;; linupy) _host_os=linux _host_cpu=arm @@ -2062,21 +2068,28 @@ define_in_config_h_if_yes $_need_memalign 'SCUMM_NEED_ALIGNMENT' echo_n "Checking host CPU architecture... " case $_host_cpu in arm*) - echo "ARM" - define_in_config_if_yes yes 'USE_ARM_SCALER_ASM' - # FIXME: The following feature exhibits a bug. It produces distorted - # sound since 9003ce517ff9906b0288f9f7c02197fd091d4554. The ARM - # assembly will need to be properly adapted to the changes to the C - # code in 8f5a7cde2f99de9fef849b0ff688906f05f4643e. - # See bug #6957: "AUDIO: ARM ASM sound code causes distorted audio on 32 bit armv6" - #define_in_config_if_yes yes 'USE_ARM_SOUND_ASM' - define_in_config_if_yes yes 'USE_ARM_SMUSH_ASM' - define_in_config_if_yes yes 'USE_ARM_GFX_ASM' - # FIXME: The following feature exhibits a bug during the intro scene of Indy 4 - # (on Pandora and iPhone at least) - #define_in_config_if_yes yes 'USE_ARM_COSTUME_ASM' - - append_var DEFINES "-DARM_TARGET" + case $_host_alias in + arm-apple-darwin11) + echo "Apple iOS 7+ - ARM assembly disabled" + ;; + *) + echo "ARM" + define_in_config_if_yes yes 'USE_ARM_SCALER_ASM' + # FIXME: The following feature exhibits a bug. It produces distorted + # sound since 9003ce517ff9906b0288f9f7c02197fd091d4554. The ARM + # assembly will need to be properly adapted to the changes to the C + # code in 8f5a7cde2f99de9fef849b0ff688906f05f4643e. + # See bug #6957: "AUDIO: ARM ASM sound code causes distorted audio on 32 bit armv6" + #define_in_config_if_yes yes 'USE_ARM_SOUND_ASM' + define_in_config_if_yes yes 'USE_ARM_SMUSH_ASM' + define_in_config_if_yes yes 'USE_ARM_GFX_ASM' + # FIXME: The following feature exhibits a bug during the intro scene of Indy 4 + # (on Pandora and iPhone at least) + #define_in_config_if_yes yes 'USE_ARM_COSTUME_ASM' + + append_var DEFINES "-DARM_TARGET" + ;; + esac ;; i[3-6]86) echo "x86" @@ -2722,6 +2735,16 @@ if test -n "$_host"; then _seq_midi=no _timidity=no ;; + ios7) + append_var DEFINES "-DIPHONE" + append_var CFLAGS "-Wno-shift-count-overflow" + append_var CXXFLAGS "-Wno-shift-count-overflow" + _backend="ios7" + _build_scalers=no + _mt32emu=no + _seq_midi=no + _timidity=no + ;; m68k-atari-mint) append_var DEFINES "-DSYSTEM_NOT_SUPPORTING_D_TYPE" _ranlib=m68k-atari-mint-ranlib @@ -3015,6 +3038,19 @@ case $_backend in append_var LIBS "-framework QuartzCore -framework CoreFoundation -framework Foundation" append_var LIBS "-framework AudioToolbox -framework CoreAudio" ;; + ios7) + append_var LIBS "-lobjc -framework UIKit -framework CoreGraphics -framework OpenGLES" + append_var LIBS "-framework QuartzCore -framework CoreFoundation -framework Foundation" + append_var LIBS "-framework AudioToolbox -framework CoreAudio" + append_var LDFLAGS "-miphoneos-version-min=7.1 -arch armv7" + append_var CFLAGS "-miphoneos-version-min=7.1 -arch armv7" + append_var CXXFLAGS "-miphoneos-version-min=7.1 -arch armv7" + if test -n "$SDKROOT"; then + append_var LDFLAGS "-mlinker-version=134.9 -B/usr/local/bin/arm-apple-darwin11-" + append_var CFLAGS "-isysroot $SDKROOT -F$SDKROOT/System/Library/Frameworks" + append_var CXXFLAGS "-isysroot $SDKROOT -I$SDKROOT/usr/include/c++/4.2.1 -F$SDKROOT/System/Library/Frameworks" + fi + ;; linuxmoto) append_var DEFINES "-DLINUXMOTO" ;; @@ -3146,7 +3182,7 @@ esac # Enable 16bit support only for backends which support it # case $_backend in - android | dingux | dc | gph | iphone | maemo | openpandora | psp | samsungtv | sdl | tizen | webos | wii) + android | dingux | dc | gph | iphone | ios7 | maemo | openpandora | psp | samsungtv | sdl | tizen | webos | wii) if test "$_16bit" = auto ; then _16bit=yes else @@ -3205,7 +3241,7 @@ case $_host_os in amigaos* | cygwin* | dreamcast | ds | gamecube | mingw* | n64 | ps2 | ps3 | psp | wii | wince) _posix=no ;; - android | beos* | bsd* | darwin* | freebsd* | gnu* | gph-linux | haiku* | hpux* | iphone | irix*| k*bsd*-gnu* | linux* | maemo | mint* | netbsd* | openbsd* | solaris* | sunos* | uclinux* | webos) + android | beos* | bsd* | darwin* | freebsd* | gnu* | gph-linux | haiku* | hpux* | iphone | ios7 | irix*| k*bsd*-gnu* | linux* | maemo | mint* | netbsd* | openbsd* | solaris* | sunos* | uclinux* | webos) _posix=yes ;; os2-emx*) diff --git a/devtools/create_project/codeblocks.cpp b/devtools/create_project/codeblocks.cpp index 442a2b0025..e9dc8bf234 100644 --- a/devtools/create_project/codeblocks.cpp +++ b/devtools/create_project/codeblocks.cpp @@ -200,6 +200,11 @@ void CodeBlocksProvider::createProjectFile(const std::string &name, const std::s } +void CodeBlocksProvider::addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) { + includeList.push_back(setup.srcDir + "/icons/" + setup.projectName + ".ico"); + includeList.push_back(setup.srcDir + "/dists/" + setup.projectName + ".rc"); +} + void CodeBlocksProvider::writeWarnings(const std::string &name, std::ofstream &output) const { // Global warnings diff --git a/devtools/create_project/codeblocks.h b/devtools/create_project/codeblocks.h index f65604d925..5baa21c242 100644 --- a/devtools/create_project/codeblocks.h +++ b/devtools/create_project/codeblocks.h @@ -37,6 +37,8 @@ protected: void createOtherBuildFiles(const BuildSetup &) {} + void addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList); + void createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir, const StringList &includeList, const StringList &excludeList); diff --git a/devtools/create_project/create_project.cpp b/devtools/create_project/create_project.cpp index 0aba511491..65b7601a54 100644 --- a/devtools/create_project/create_project.cpp +++ b/devtools/create_project/create_project.cpp @@ -340,7 +340,13 @@ int main(int argc, char *argv[]) { setup.defines.push_back("WIN32"); } else { setup.defines.push_back("POSIX"); - setup.defines.push_back("MACOSX"); // This will break iOS, but allows OS X to catch up on browser_osx. + // Define both MACOSX, and IPHONE, but only one of them will be associated to the + // correct target by the Xcode project provider. + // This define will help catching up target dependend files, like "browser_osx.mm" + // The suffix ("_osx", or "_ios") will be used by the project provider to filter out + // the files, according to the target. + setup.defines.push_back("MACOSX"); + setup.defines.push_back("IPHONE"); } setup.defines.push_back("SDL_BACKEND"); if (!useSDL2) { @@ -929,16 +935,17 @@ TokenList tokenize(const std::string &input, char separator) { namespace { const Feature s_features[] = { // Libraries - { "libz", "USE_ZLIB", "zlib", true, "zlib (compression) support" }, - { "mad", "USE_MAD", "libmad", true, "libmad (MP3) support" }, - { "vorbis", "USE_VORBIS", "libvorbisfile_static libvorbis_static libogg_static", true, "Ogg Vorbis support" }, - { "flac", "USE_FLAC", "libFLAC_static win_utf8_io_static", true, "FLAC support" }, - { "png", "USE_PNG", "libpng", true, "libpng support" }, - { "faad", "USE_FAAD", "libfaad", false, "AAC support" }, - { "mpeg2", "USE_MPEG2", "libmpeg2", false, "MPEG-2 support" }, - { "theora", "USE_THEORADEC", "libtheora_static", true, "Theora decoding support" }, - {"freetype", "USE_FREETYPE2", "freetype", true, "FreeType support" }, - { "jpeg", "USE_JPEG", "jpeg-static", true, "libjpeg support" }, + { "libz", "USE_ZLIB", "zlib", true, "zlib (compression) support" }, + { "mad", "USE_MAD", "libmad", true, "libmad (MP3) support" }, + { "vorbis", "USE_VORBIS", "libvorbisfile_static libvorbis_static libogg_static", true, "Ogg Vorbis support" }, + { "flac", "USE_FLAC", "libFLAC_static win_utf8_io_static", true, "FLAC support" }, + { "png", "USE_PNG", "libpng", true, "libpng support" }, + { "faad", "USE_FAAD", "libfaad", false, "AAC support" }, + { "mpeg2", "USE_MPEG2", "libmpeg2", false, "MPEG-2 support" }, + { "theora", "USE_THEORADEC", "libtheora_static", true, "Theora decoding support" }, + { "freetype", "USE_FREETYPE2", "freetype", true, "FreeType support" }, + { "jpeg", "USE_JPEG", "jpeg-static", true, "libjpeg support" }, + {"fluidsynth", "USE_FLUIDSYNTH", "libfluidsynth", true, "FluidSynth support" }, // Feature flags { "bink", "USE_BINK", "", true, "Bink video support" }, @@ -1050,6 +1057,12 @@ void splitFilename(const std::string &fileName, std::string &name, std::string & ext = (dot == std::string::npos) ? std::string() : fileName.substr(dot + 1); } +std::string basename(const std::string &fileName) { + const std::string::size_type slash = fileName.find_last_of('/'); + if (slash == std::string::npos) return fileName; + return fileName.substr(slash + 1); +} + bool producesObjectFile(const std::string &fileName) { std::string n, ext; splitFilename(fileName, n, ext); @@ -1334,8 +1347,7 @@ void ProjectProvider::createProject(BuildSetup &setup) { createModuleList(setup.srcDir + "/image", setup.defines, setup.testDirs, in, ex); // Resource files - in.push_back(setup.srcDir + "/icons/" + setup.projectName + ".ico"); - in.push_back(setup.srcDir + "/dists/" + setup.projectName + ".rc"); + addResourceFiles(setup, in, ex); // Various text files in.push_back(setup.srcDir + "/AUTHORS"); diff --git a/devtools/create_project/create_project.h b/devtools/create_project/create_project.h index 1a28946315..fb207f3f59 100644 --- a/devtools/create_project/create_project.h +++ b/devtools/create_project/create_project.h @@ -316,6 +316,17 @@ std::string convertPathToWin(const std::string &path); void splitFilename(const std::string &fileName, std::string &name, std::string &ext); /** + * Returns the basename of a path. + * examples: + * a/b/c/d.ext -> d.ext + * d.ext -> d.ext + * + * @param fileName Filename + * @return The basename + */ +std::string basename(const std::string &fileName); + +/** * Checks whether the given file will produce an object file or not. * * @param fileName Name of the file. @@ -419,6 +430,13 @@ protected: virtual void createOtherBuildFiles(const BuildSetup &setup) = 0; /** + * Add resources to the project + * + * @param setup Description of the desired build setup. + */ + virtual void addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) = 0; + + /** * Create a project file for the specified list of files. * * @param name Name of the project file. diff --git a/devtools/create_project/msvc.cpp b/devtools/create_project/msvc.cpp index dbfbcc128d..e6b47fe724 100644 --- a/devtools/create_project/msvc.cpp +++ b/devtools/create_project/msvc.cpp @@ -130,6 +130,11 @@ void MSVCProvider::createOtherBuildFiles(const BuildSetup &setup) { createBuildProp(setup, false, true, "LLVM"); } +void MSVCProvider::addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) { + includeList.push_back(setup.srcDir + "/icons/" + setup.projectName + ".ico"); + includeList.push_back(setup.srcDir + "/dists/" + setup.projectName + ".rc"); +} + void MSVCProvider::createGlobalProp(const BuildSetup &setup) { std::ofstream properties((setup.outputDir + '/' + setup.projectDescription + "_Global" + getPropertiesExtension()).c_str()); if (!properties) diff --git a/devtools/create_project/msvc.h b/devtools/create_project/msvc.h index e75e131bd1..178ba8e216 100644 --- a/devtools/create_project/msvc.h +++ b/devtools/create_project/msvc.h @@ -39,6 +39,8 @@ protected: void createOtherBuildFiles(const BuildSetup &setup); + void addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList); + /** * Create the global project properties. * diff --git a/devtools/create_project/xcode.cpp b/devtools/create_project/xcode.cpp index c5c433c82e..8274875ec5 100644 --- a/devtools/create_project/xcode.cpp +++ b/devtools/create_project/xcode.cpp @@ -26,26 +26,33 @@ #include <fstream> #include <algorithm> +#ifdef MACOSX +#include <sstream> +#include <iomanip> +#include <CommonCrypto/CommonCrypto.h> +#endif + namespace CreateProjectTool { #define DEBUG_XCODE_HASH 0 -#ifdef ENABLE_IOS #define IOS_TARGET 0 #define OSX_TARGET 1 -#define SIM_TARGET 2 -#else -#define OSX_TARGET 0 -#endif #define ADD_DEFINE(defines, name) \ defines.push_back(name); +#define REMOVE_DEFINE(defines, name) \ + { ValueList::iterator i = std::find(defines.begin(), defines.end(), name); if (i != defines.end()) defines.erase(i); } + +#define CONTAINS_DEFINE(defines, name) \ + (std::find(defines.begin(), defines.end(), name) != defines.end()) + #define ADD_SETTING(config, key, value) \ config._settings[key] = Setting(value, "", kSettingsNoQuote); #define ADD_SETTING_ORDER(config, key, value, order) \ - config._settings[key] = Setting(value, "", kSettingsNoQuote, 0, order); + config.settings[key] = Setting(value, "", kSettingsNoQuote, 0, order); #define ADD_SETTING_ORDER_NOVALUE(config, key, comment, order) \ config._settings[key] = Setting("", comment, kSettingsNoValue, 0, order); @@ -69,6 +76,17 @@ namespace CreateProjectTool { _buildFile._flags = kSettingsSingleItem; \ } +#define ADD_FILE_REFERENCE(id, name, properties) { \ + Object *fileRef = new Object(this, id, name, "PBXFileReference", "PBXFileReference", name); \ + if (!properties._fileEncoding.empty()) fileRef->addProperty("fileEncoding", properties._fileEncoding, "", kSettingsNoValue); \ + if (!properties._lastKnownFileType.empty()) fileRef->addProperty("lastKnownFileType", properties._lastKnownFileType, "", kSettingsNoValue|kSettingsQuoteVariable); \ + if (!properties._fileName.empty()) fileRef->addProperty("name", properties._fileName, "", kSettingsNoValue|kSettingsQuoteVariable); \ + if (!properties._filePath.empty()) fileRef->addProperty("path", properties._filePath, "", kSettingsNoValue|kSettingsQuoteVariable); \ + if (!properties._sourceTree.empty()) fileRef->addProperty("sourceTree", properties._sourceTree, "", kSettingsNoValue); \ + _fileReference.add(fileRef); \ + _fileReference._flags = kSettingsSingleItem; \ +} + bool producesObjectFileOnOSX(const std::string &fileName) { std::string n, ext; splitFilename(fileName, n, ext); @@ -81,9 +99,61 @@ bool producesObjectFileOnOSX(const std::string &fileName) { return false; } +bool targetIsIOS(const std::string &targetName) { + return targetName.length() > 4 && targetName.substr(targetName.length() - 4) == "-iOS"; +} + +bool shouldSkipFileForTarget(const std::string &fileID, const std::string &targetName, const std::string &fileName) { + // Rules: + // - if the parent directory is "backends/platform/ios7", the file belongs to the iOS target. + // - if the parent directory is "/sdl", the file belongs to the OS X target. + // - if the file has a suffix, like "_osx", or "_ios", the file belongs to one of the target. + // - if the file is an OS X icon file (icns), it belongs to the OS X target. + std::string name, ext; + splitFilename(fileName, name, ext); + if (targetIsIOS(targetName)) { + // iOS target: we skip all files with the "_osx" suffix + if (name.length() > 4 && name.substr(name.length() - 4) == "_osx") { + return true; + } + // We don't need SDL for the iOS target + static const std::string sdl_directory = "/sdl/"; + static const std::string surfacesdl_directory = "/surfacesdl/"; + static const std::string doublebufferdl_directory = "/doublebuffersdl/"; + if (fileID.find(sdl_directory) != std::string::npos + || fileID.find(surfacesdl_directory) != std::string::npos + || fileID.find(doublebufferdl_directory) != std::string::npos) { + return true; + } + if (ext == "icns") { + return true; + } + } + else { + // Ugly hack: explicitly remove the browser.cpp file. + // The problem is that we have only one project for two different targets, + // and the parsing of the "mk" files added this file for both targets... + if (fileID.length() > 12 && fileID.substr(fileID.length() - 12) == "/browser.cpp") { + return true; + } + // OS X target: we skip all files with the "_ios" suffix + if (name.length() > 4 && name.substr(name.length() - 4) == "_ios") { + return true; + } + // parent directory + const std::string directory = fileID.substr(0, fileID.length() - fileName.length()); + static const std::string iphone_directory = "backends/platform/ios7"; + if (directory.length() > iphone_directory.length() && directory.substr(directory.length() - iphone_directory.length()) == iphone_directory) { + return true; + } + } + return false; +} + XcodeProvider::Group::Group(XcodeProvider *objectParent, const std::string &groupName, const std::string &uniqueName, const std::string &path) : Object(objectParent, uniqueName, groupName, "PBXGroup", "", groupName) { + bool path_is_absolute = (path.length() > 0 && path.at(0) == '/'); addProperty("name", _name, "", kSettingsNoValue | kSettingsQuoteVariable); - addProperty("sourceTree", "<group>", "", kSettingsNoValue | kSettingsQuoteVariable); + addProperty("sourceTree", path_is_absolute ? "<absolute>" : "<group>", "", kSettingsNoValue | kSettingsQuoteVariable); if (path != "") { addProperty("path", path, "", kSettingsNoValue | kSettingsQuoteVariable); @@ -93,7 +163,7 @@ XcodeProvider::Group::Group(XcodeProvider *objectParent, const std::string &grou } void XcodeProvider::Group::ensureChildExists(const std::string &name) { - std::map<std::string, Group *>::iterator it = _childGroups.find(name); + std::map<std::string, Group*>::iterator it = _childGroups.find(name); if (it == _childGroups.end()) { Group *child = new Group(_parent, name, this->_treeName + '/' + name, name); _childGroups[name] = child; @@ -180,7 +250,7 @@ void XcodeProvider::addFileReference(const std::string &id, const std::string &n void XcodeProvider::addProductFileReference(const std::string &id, const std::string &name) { Object *fileRef = new Object(this, id, name, "PBXFileReference", "PBXFileReference", name); - fileRef->addProperty("explicitFileType", "compiled.mach-o.executable", "", kSettingsNoValue | kSettingsQuoteVariable); + fileRef->addProperty("explicitFileType", "wrapper.application", "", kSettingsNoValue | kSettingsQuoteVariable); fileRef->addProperty("includeInIndex", "0", "", kSettingsNoValue); fileRef->addProperty("path", name, "", kSettingsNoValue | kSettingsQuoteVariable); fileRef->addProperty("sourceTree", "BUILT_PRODUCTS_DIR", "", kSettingsNoValue); @@ -201,6 +271,18 @@ XcodeProvider::XcodeProvider(StringList &global_warnings, std::map<std::string, _rootSourceGroup = NULL; } +void XcodeProvider::addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) { + includeList.push_back(setup.srcDir + "/dists/ios7/Info.plist"); + + ValueList &resources = getResourceFiles(); + for (ValueList::iterator it = resources.begin(); it != resources.end(); ++it) { + includeList.push_back(setup.srcDir + "/" + *it); + } + + StringList td; + createModuleList(setup.srcDir + "/backends/platform/ios7", setup.defines, td, includeList, excludeList); +} + void XcodeProvider::createWorkspace(const BuildSetup &setup) { // Create project folder std::string workspace = setup.outputDir + '/' + PROJECT_NAME ".xcodeproj"; @@ -210,19 +292,15 @@ void XcodeProvider::createWorkspace(const BuildSetup &setup) { // Setup global objects setupDefines(setup); -#ifdef ENABLE_IOS - _targets.push_back(PROJECT_DESCRIPTION "-iPhone"); -#endif + _targets.push_back(PROJECT_DESCRIPTION "-iOS"); _targets.push_back(PROJECT_DESCRIPTION "-OS X"); -#ifdef ENABLE_IOS - _targets.push_back(PROJECT_DESCRIPTION "-Simulator"); -#endif setupCopyFilesBuildPhase(); - setupFrameworksBuildPhase(); + setupFrameworksBuildPhase(setup); setupNativeTarget(); setupProject(); setupResourcesBuildPhase(); - setupBuildConfiguration(); + setupBuildConfiguration(setup); + setupImageAssetCatalog(setup); } // We are done with constructing all the object graph and we got through every project, output the main project file @@ -323,15 +401,21 @@ void XcodeProvider::setupCopyFilesBuildPhase() { #define DEF_SYSFRAMEWORK(framework) properties[framework".framework"] = FileProperty("wrapper.framework", framework".framework", "System/Library/Frameworks/" framework ".framework", "SDKROOT"); \ ADD_SETTING_ORDER_NOVALUE(children, getHash(framework".framework"), framework".framework", fwOrder++); -#define DEF_LOCALLIB_STATIC(lib) properties[lib".a"] = FileProperty("archive.ar", lib".a", "/opt/local/lib/" lib ".a", "\"<group>\""); \ +#define DEF_SYSTBD(lib) properties[lib".tbd"] = FileProperty("sourcecode.text-based-dylib-definition", lib".tbd", "usr/lib/" lib ".tbd", "SDKROOT"); \ + ADD_SETTING_ORDER_NOVALUE(children, getHash(lib".tbd"), lib".tbd", fwOrder++); + +#define DEF_LOCALLIB_STATIC_PATH(path,lib,absolute) properties[lib".a"] = FileProperty("archive.ar", lib ".a", path, (absolute ? "\"<absolute>\"" : "\"<group>\"")); \ ADD_SETTING_ORDER_NOVALUE(children, getHash(lib".a"), lib".a", fwOrder++); +#define DEF_LOCALLIB_STATIC(lib) DEF_LOCALLIB_STATIC_PATH("/opt/local/lib/" lib ".a", lib, true) + + /** * Sets up the frameworks build phase. * * (each native target has different build rules) */ -void XcodeProvider::setupFrameworksBuildPhase() { +void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { _frameworksBuildPhase._comment = "PBXFrameworksBuildPhase"; // Just use a hardcoded id for the Frameworks-group @@ -351,6 +435,8 @@ void XcodeProvider::setupFrameworksBuildPhase() { DEF_SYSFRAMEWORK("Carbon"); DEF_SYSFRAMEWORK("Cocoa"); DEF_SYSFRAMEWORK("CoreAudio"); + DEF_SYSFRAMEWORK("CoreMIDI"); + DEF_SYSFRAMEWORK("CoreGraphics"); DEF_SYSFRAMEWORK("CoreFoundation"); DEF_SYSFRAMEWORK("CoreMIDI"); DEF_SYSFRAMEWORK("Foundation"); @@ -359,6 +445,8 @@ void XcodeProvider::setupFrameworksBuildPhase() { DEF_SYSFRAMEWORK("QuartzCore"); DEF_SYSFRAMEWORK("QuickTime"); DEF_SYSFRAMEWORK("UIKit"); + DEF_SYSTBD("libiconv"); + // Optionals: DEF_SYSFRAMEWORK("OpenGL"); @@ -369,53 +457,92 @@ void XcodeProvider::setupFrameworksBuildPhase() { DEF_LOCALLIB_STATIC("libfreetype"); // DEF_LOCALLIB_STATIC("libmpeg2"); + std::string absoluteOutputDir; +#ifdef POSIX + char *c_path = realpath(setup.outputDir.c_str(), NULL); + absoluteOutputDir = c_path; + absoluteOutputDir += "/lib"; + free(c_path); +#else + absoluteOutputDir = "lib"; +#endif + + DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libFLACiOS.a", "libFLACiOS", true); + DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libFreetype2.a", "libFreetype2", true); + DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libogg.a", "libogg", true); + DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libpng.a", "libpng", true); + DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libvorbis.a", "libvorbis", true); + DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libmad.a", "libmad", true); + DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libfluidsynth.a", "libfluidsynth", true); + DEF_LOCALLIB_STATIC_PATH(absoluteOutputDir + "/libglib.a", "libglib", true); + frameworksGroup->_properties["children"] = children; _groups.add(frameworksGroup); // Force this to be added as a sub-group in the root. _rootSourceGroup->addChildGroup(frameworksGroup); - // Declare this here, as it's used across the three targets + // Declare this here, as it's used across all the targets int order = 0; -#ifdef ENABLE_IOS + ////////////////////////////////////////////////////////////////////////// - // iPhone + // ScummVM-iOS Object *framework_iPhone = new Object(this, "PBXFrameworksBuildPhase_" + _targets[IOS_TARGET], "PBXFrameworksBuildPhase", "PBXFrameworksBuildPhase", "", "Frameworks"); framework_iPhone->addProperty("buildActionMask", "2147483647", "", kSettingsNoValue); framework_iPhone->addProperty("runOnlyForDeploymentPostprocessing", "0", "", kSettingsNoValue); // List of frameworks - Property iPhone_files; - iPhone_files._hasOrder = true; - iPhone_files._flags = kSettingsAsList; - - ValueList frameworks_iPhone; - frameworks_iPhone.push_back("CoreAudio.framework"); - frameworks_iPhone.push_back("CoreFoundation.framework"); - frameworks_iPhone.push_back("Foundation.framework"); - frameworks_iPhone.push_back("UIKit.framework"); - frameworks_iPhone.push_back("AudioToolbox.framework"); - frameworks_iPhone.push_back("QuartzCore.framework"); - frameworks_iPhone.push_back("libmad.a"); - //frameworks_iPhone.push_back("libmpeg2.a"); - frameworks_iPhone.push_back("libFLAC.a"); - frameworks_iPhone.push_back("libvorbisidec.a"); - frameworks_iPhone.push_back("OpenGLES.framework"); - - for (ValueList::iterator framework = frameworks_iPhone.begin(); framework != frameworks_iPhone.end(); framework++) { + Property iOS_files; + iOS_files._hasOrder = true; + iOS_files._flags = kSettingsAsList; + + ValueList frameworks_iOS; + frameworks_iOS.push_back("CoreAudio.framework"); + frameworks_iOS.push_back("CoreGraphics.framework"); + frameworks_iOS.push_back("CoreFoundation.framework"); + frameworks_iOS.push_back("Foundation.framework"); + frameworks_iOS.push_back("UIKit.framework"); + frameworks_iOS.push_back("AudioToolbox.framework"); + frameworks_iOS.push_back("QuartzCore.framework"); + frameworks_iOS.push_back("OpenGLES.framework"); + + if (CONTAINS_DEFINE(setup.defines, "USE_FLAC")) { + frameworks_iOS.push_back("libFLACiOS.a"); + } + if (CONTAINS_DEFINE(setup.defines, "USE_FREETYPE2")) { + frameworks_iOS.push_back("libFreetype2.a"); + } + if (CONTAINS_DEFINE(setup.defines, "USE_PNG")) { + frameworks_iOS.push_back("libpng.a"); + } + if (CONTAINS_DEFINE(setup.defines, "USE_VORBIS")) { + frameworks_iOS.push_back("libogg.a"); + frameworks_iOS.push_back("libvorbis.a"); + } + if (CONTAINS_DEFINE(setup.defines, "USE_MAD")) { + frameworks_iOS.push_back("libmad.a"); + } + if (CONTAINS_DEFINE(setup.defines, "USE_FLUIDSYNTH")) { + frameworks_iOS.push_back("libfluidsynth.a"); + frameworks_iOS.push_back("libglib.a"); + frameworks_iOS.push_back("CoreMIDI.framework"); + frameworks_iOS.push_back("libiconv.tbd"); + } + + for (ValueList::iterator framework = frameworks_iOS.begin(); framework != frameworks_iOS.end(); framework++) { std::string id = "Frameworks_" + *framework + "_iphone"; std::string comment = *framework + " in Frameworks"; - ADD_SETTING_ORDER_NOVALUE(iPhone_files, getHash(id), comment, order++); + ADD_SETTING_ORDER_NOVALUE(iOS_files, getHash(id), comment, order++); ADD_BUILD_FILE(id, *framework, getHash(*framework), comment); - addFileReference(*framework, *framework, properties[*framework]); + ADD_FILE_REFERENCE(*framework, *framework, properties[*framework]); } - framework_iPhone->_properties["files"] = iPhone_files; + framework_iPhone->_properties["files"] = iOS_files; _frameworksBuildPhase.add(framework_iPhone); -#endif + ////////////////////////////////////////////////////////////////////////// // ScummVM-OS X Object *framework_OSX = new Object(this, "PBXFrameworksBuildPhase_" + _targets[OSX_TARGET], "PBXFrameworksBuildPhase", "PBXFrameworksBuildPhase", "", "Frameworks"); @@ -451,48 +578,12 @@ void XcodeProvider::setupFrameworksBuildPhase() { ADD_SETTING_ORDER_NOVALUE(osx_files, getHash(id), comment, order++); ADD_BUILD_FILE(id, *framework, getHash(*framework), comment); - addFileReference(*framework, *framework, properties[*framework]); + ADD_FILE_REFERENCE(*framework, *framework, properties[*framework]); } framework_OSX->_properties["files"] = osx_files; _frameworksBuildPhase.add(framework_OSX); -#ifdef ENABLE_IOS - ////////////////////////////////////////////////////////////////////////// - // Simulator - Object *framework_simulator = new Object(this, "PBXFrameworksBuildPhase_" + _targets[SIM_TARGET], "PBXFrameworksBuildPhase", "PBXFrameworksBuildPhase", "", "Frameworks"); - - framework_simulator->addProperty("buildActionMask", "2147483647", "", kSettingsNoValue); - framework_simulator->addProperty("runOnlyForDeploymentPostprocessing", "0", "", kSettingsNoValue); - - // List of frameworks - Property simulator_files; - simulator_files._hasOrder = true; - simulator_files._flags = kSettingsAsList; - - ValueList frameworks_simulator; - frameworks_simulator.push_back("CoreAudio.framework"); - frameworks_simulator.push_back("CoreFoundation.framework"); - frameworks_simulator.push_back("Foundation.framework"); - frameworks_simulator.push_back("UIKit.framework"); - frameworks_simulator.push_back("AudioToolbox.framework"); - frameworks_simulator.push_back("QuartzCore.framework"); - frameworks_simulator.push_back("OpenGLES.framework"); - - order = 0; - for (ValueList::iterator framework = frameworks_simulator.begin(); framework != frameworks_simulator.end(); framework++) { - std::string id = "Frameworks_" + *framework + "_simulator"; - std::string comment = *framework + " in Frameworks"; - - ADD_SETTING_ORDER_NOVALUE(simulator_files, getHash(id), comment, order++); - ADD_BUILD_FILE(id, *framework, getHash(*framework), comment); - addFileReference(*framework, *framework, properties[*framework]); - } - - framework_simulator->_properties["files"] = simulator_files; - - _frameworksBuildPhase.add(framework_simulator); -#endif } void XcodeProvider::setupNativeTarget() { @@ -502,11 +593,6 @@ void XcodeProvider::setupNativeTarget() { Group *productsGroup = new Group(this, "Products", "PBXGroup_CustomTemplate_Products_" , ""); // Output native target section for (unsigned int i = 0; i < _targets.size(); i++) { -#ifndef ENABLE_IOS - if (i != OSX_TARGET) { // TODO: Fix iOS-targets, for now just disable them. - continue; - } -#endif Object *target = new Object(this, "PBXNativeTarget_" + _targets[i], "PBXNativeTarget", "PBXNativeTarget", "", _targets[i]); target->addProperty("buildConfigurationList", getHash("XCConfigurationList_" + _targets[i]), "Build configuration list for PBXNativeTarget \"" + _targets[i] + "\"", kSettingsNoValue); @@ -556,49 +642,51 @@ void XcodeProvider::setupProject() { project->_properties["knownRegions"] = regions; project->addProperty("mainGroup", _rootSourceGroup->getHashRef(), "CustomTemplate", kSettingsNoValue); + project->addProperty("productRefGroup", getHash("PBXGroup_CustomTemplate_Products_"), "" , kSettingsNoValue); project->addProperty("projectDirPath", _projectRoot, "", kSettingsNoValue | kSettingsQuoteVariable); project->addProperty("projectRoot", "", "", kSettingsNoValue | kSettingsQuoteVariable); // List of targets Property targets; targets._flags = kSettingsAsList; -#ifdef ENABLE_IOS targets._settings[getHash("PBXNativeTarget_" + _targets[IOS_TARGET])] = Setting("", _targets[IOS_TARGET], kSettingsNoValue, 0, 0); -#endif targets._settings[getHash("PBXNativeTarget_" + _targets[OSX_TARGET])] = Setting("", _targets[OSX_TARGET], kSettingsNoValue, 0, 1); -#ifdef ENABLE_IOS - targets._settings[getHash("PBXNativeTarget_" + _targets[SIM_TARGET])] = Setting("", _targets[SIM_TARGET], kSettingsNoValue, 0, 2); -#endif project->_properties["targets"] = targets; -#ifndef ENABLE_IOS + // Force list even when there is only a single target project->_properties["targets"]._flags |= kSettingsSingleItem; -#endif _project.add(project); } +XcodeProvider::ValueList& XcodeProvider::getResourceFiles() const { + static ValueList files; + if (files.empty()) { + files.push_back("gui/themes/scummclassic.zip"); + files.push_back("gui/themes/scummmodern.zip"); + files.push_back("gui/themes/translations.dat"); + files.push_back("dists/engine-data/drascula.dat"); + files.push_back("dists/engine-data/hugo.dat"); + files.push_back("dists/engine-data/kyra.dat"); + files.push_back("dists/engine-data/lure.dat"); + files.push_back("dists/engine-data/mort.dat"); + files.push_back("dists/engine-data/neverhood.dat"); + files.push_back("dists/engine-data/queen.tbl"); + files.push_back("dists/engine-data/sky.cpt"); + files.push_back("dists/engine-data/teenagent.dat"); + files.push_back("dists/engine-data/tony.dat"); + files.push_back("dists/engine-data/toon.dat"); + files.push_back("dists/engine-data/wintermute.zip"); + files.push_back("dists/pred.dic"); + files.push_back("icons/scummvm.icns"); + } + return files; +} + void XcodeProvider::setupResourcesBuildPhase() { _resourcesBuildPhase._comment = "PBXResourcesBuildPhase"; - // Setup resource file properties - std::map<std::string, FileProperty> properties; - properties["scummclassic.zip"] = FileProperty("archive.zip", "", "scummclassic.zip", "\"<group>\""); - properties["scummmodern.zip"] = FileProperty("archive.zip", "", "scummmodern.zip", "\"<group>\""); - - properties["kyra.dat"] = FileProperty("file", "", "kyra.dat", "\"<group>\""); - properties["lure.dat"] = FileProperty("file", "", "lure.dat", "\"<group>\""); - properties["queen.tbl"] = FileProperty("file", "", "queen.tbl", "\"<group>\""); - properties["sky.cpt"] = FileProperty("file", "", "sky.cpt", "\"<group>\""); - properties["drascula.dat"] = FileProperty("file", "", "drascula.dat", "\"<group>\""); - properties["hugo.dat"] = FileProperty("file", "", "hugo.dat", "\"<group>\""); - properties["teenagent.dat"] = FileProperty("file", "", "teenagent.dat", "\"<group>\""); - properties["toon.dat"] = FileProperty("file", "", "toon.dat", "\"<group>\""); - - properties["Default.png"] = FileProperty("image.png", "", "Default.png", "\"<group>\""); - properties["icon.png"] = FileProperty("image.png", "", "icon.png", "\"<group>\""); - properties["icon-72.png"] = FileProperty("image.png", "", "icon-72.png", "\"<group>\""); - properties["icon4.png"] = FileProperty("image.png", "", "icon4.png", "\"<group>\""); + ValueList &files_list = getResourceFiles(); // Same as for containers: a rule for each native target for (unsigned int i = 0; i < _targets.size(); i++) { @@ -611,40 +699,17 @@ void XcodeProvider::setupResourcesBuildPhase() { files._hasOrder = true; files._flags = kSettingsAsList; - ValueList files_list; - files_list.push_back("scummclassic.zip"); - files_list.push_back("scummmodern.zip"); - files_list.push_back("kyra.dat"); - files_list.push_back("lure.dat"); - files_list.push_back("queen.tbl"); - files_list.push_back("sky.cpt"); - files_list.push_back("Default.png"); - files_list.push_back("icon.png"); - files_list.push_back("icon-72.png"); - files_list.push_back("icon4.png"); - files_list.push_back("drascula.dat"); - files_list.push_back("hugo.dat"); - files_list.push_back("teenagent.dat"); - files_list.push_back("toon.dat"); - int order = 0; for (ValueList::iterator file = files_list.begin(); file != files_list.end(); file++) { - std::string id = "PBXResources_" + *file; - std::string comment = *file + " in Resources"; - - ADD_SETTING_ORDER_NOVALUE(files, getHash(id), comment, order++); - // TODO Fix crash when adding build file for data - //ADD_BUILD_FILE(id, *file, comment); - addFileReference(*file, *file, properties[*file]); - } - - // Add custom files depending on the target - if (_targets[i] == PROJECT_DESCRIPTION "-OS X") { - files._settings[getHash("PBXResources_" PROJECT_NAME ".icns")] = Setting("", PROJECT_NAME ".icns in Resources", kSettingsNoValue, 0, 6); - - // Remove 2 iphone icon files - files._settings.erase(getHash("PBXResources_Default.png")); - files._settings.erase(getHash("PBXResources_icon.png")); + if (shouldSkipFileForTarget(*file, _targets[i], *file)) { + continue; + } + std::string resourceAbsolutePath = _projectRoot + "/" + *file; + std::string file_id = "FileReference_" + resourceAbsolutePath; + std::string base = basename(*file); + std::string comment = base + " in Resources"; + addBuildFile(resourceAbsolutePath, base, getHash(file_id), comment); + ADD_SETTING_ORDER_NOVALUE(files, getHash(resourceAbsolutePath), comment, order++); } resource->_properties["files"] = files; @@ -658,11 +723,9 @@ void XcodeProvider::setupResourcesBuildPhase() { void XcodeProvider::setupSourcesBuildPhase() { _sourcesBuildPhase._comment = "PBXSourcesBuildPhase"; - // Setup source file properties - std::map<std::string, FileProperty> properties; - // Same as for containers: a rule for each native target for (unsigned int i = 0; i < _targets.size(); i++) { + const std::string &targetName = _targets[i]; Object *source = new Object(this, "PBXSourcesBuildPhase_" + _targets[i], "PBXSourcesBuildPhase", "PBXSourcesBuildPhase", "", "Sources"); source->addProperty("buildActionMask", "2147483647", "", kSettingsNoValue); @@ -673,13 +736,19 @@ void XcodeProvider::setupSourcesBuildPhase() { int order = 0; for (std::vector<Object *>::iterator file = _buildFile._objects.begin(); file != _buildFile._objects.end(); ++file) { - if (!producesObjectFileOnOSX((*file)->_name)) { + const std::string &fileName = (*file)->_name; + if (shouldSkipFileForTarget((*file)->_id, targetName, fileName)) { + continue; + } + if (!producesObjectFileOnOSX(fileName)) { continue; } - std::string comment = (*file)->_name + " in Sources"; + std::string comment = fileName + " in Sources"; ADD_SETTING_ORDER_NOVALUE(files, getHash((*file)->_id), comment, order++); } + setupAdditionalSources(targetName, files, order); + source->_properties["files"] = files; source->addProperty("runOnlyForDeploymentPostprocessing", "0", "", kSettingsNoValue); @@ -689,73 +758,20 @@ void XcodeProvider::setupSourcesBuildPhase() { } // Setup all build configurations -void XcodeProvider::setupBuildConfiguration() { +void XcodeProvider::setupBuildConfiguration(const BuildSetup &setup) { _buildConfiguration._comment = "XCBuildConfiguration"; _buildConfiguration._flags = kSettingsAsList; - ///**************************************** - // * iPhone - // ****************************************/ -#ifdef ENABLE_IOS - // Debug - Object *iPhone_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-iPhone_Debug", _targets[IOS_TARGET] /* ScummVM-iPhone */, "XCBuildConfiguration", "PBXNativeTarget", "Debug"); - Property iPhone_Debug; - ADD_SETTING_QUOTE(iPhone_Debug, "ARCHS", "$(ARCHS_UNIVERSAL_IPHONE_OS)"); - ADD_SETTING_QUOTE(iPhone_Debug, "CODE_SIGN_IDENTITY", "iPhone Developer"); - ADD_SETTING_QUOTE_VAR(iPhone_Debug, "CODE_SIGN_IDENTITY[sdk=iphoneos*]", "iPhone Developer"); - ADD_SETTING(iPhone_Debug, "COMPRESS_PNG_FILES", "NO"); - ADD_SETTING(iPhone_Debug, "COPY_PHASE_STRIP", "NO"); - ADD_SETTING_QUOTE(iPhone_Debug, "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym"); - ValueList iPhone_FrameworkSearchPaths; - iPhone_FrameworkSearchPaths.push_back("$(inherited)"); - iPhone_FrameworkSearchPaths.push_back("\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\""); - ADD_SETTING_LIST(iPhone_Debug, "FRAMEWORK_SEARCH_PATHS", iPhone_FrameworkSearchPaths, kSettingsAsList, 5); - ADD_SETTING(iPhone_Debug, "GCC_DYNAMIC_NO_PIC", "NO"); - ADD_SETTING(iPhone_Debug, "GCC_ENABLE_CPP_EXCEPTIONS", "NO"); - ADD_SETTING(iPhone_Debug, "GCC_ENABLE_FIX_AND_CONTINUE", "NO"); - ADD_SETTING(iPhone_Debug, "GCC_OPTIMIZATION_LEVEL", "0"); - ADD_SETTING(iPhone_Debug, "GCC_PRECOMPILE_PREFIX_HEADER", "NO"); - ADD_SETTING_QUOTE(iPhone_Debug, "GCC_PREFIX_HEADER", ""); - ADD_SETTING(iPhone_Debug, "GCC_THUMB_SUPPORT", "NO"); - ADD_SETTING(iPhone_Debug, "GCC_UNROLL_LOOPS", "YES"); - ValueList iPhone_HeaderSearchPaths; - iPhone_HeaderSearchPaths.push_back("$(SRCROOT)/engines/"); - iPhone_HeaderSearchPaths.push_back("$(SRCROOT)"); - iPhone_HeaderSearchPaths.push_back("include/"); - ADD_SETTING_LIST(iPhone_Debug, "HEADER_SEARCH_PATHS", iPhone_HeaderSearchPaths, kSettingsAsList | kSettingsQuoteVariable, 5); - ADD_SETTING(iPhone_Debug, "INFOPLIST_FILE", "Info.plist"); - ValueList iPhone_LibPaths; - iPhone_LibPaths.push_back("$(inherited)"); - iPhone_LibPaths.push_back("\"$(SRCROOT)/lib\""); - ADD_SETTING_LIST(iPhone_Debug, "LIBRARY_SEARCH_PATHS", iPhone_LibPaths, kSettingsAsList, 5); - ADD_SETTING(iPhone_Debug, "ONLY_ACTIVE_ARCH", "YES"); - ADD_SETTING(iPhone_Debug, "PREBINDING", "NO"); - ADD_SETTING(iPhone_Debug, "PRODUCT_NAME", PROJECT_DESCRIPTION); - ADD_SETTING_QUOTE(iPhone_Debug, "PROVISIONING_PROFILE", "EF590570-5FAC-4346-9071-D609DE2B28D8"); - ADD_SETTING_QUOTE_VAR(iPhone_Debug, "PROVISIONING_PROFILE[sdk=iphoneos*]", ""); - ADD_SETTING(iPhone_Debug, "SDKROOT", "iphoneos4.0"); - ADD_SETTING_QUOTE(iPhone_Debug, "TARGETED_DEVICE_FAMILY", "1,2"); - - iPhone_Debug_Object->addProperty("name", "Debug", "", kSettingsNoValue); - iPhone_Debug_Object->_properties["buildSettings"] = iPhone_Debug; - - // Release - Object *iPhone_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-iPhone_Release", _targets[IOS_TARGET] /* ScummVM-iPhone */, "XCBuildConfiguration", "PBXNativeTarget", "Release"); - Property iPhone_Release(iPhone_Debug); - ADD_SETTING(iPhone_Release, "GCC_OPTIMIZATION_LEVEL", "3"); - ADD_SETTING(iPhone_Release, "COPY_PHASE_STRIP", "YES"); - REMOVE_SETTING(iPhone_Release, "GCC_DYNAMIC_NO_PIC"); - ADD_SETTING(iPhone_Release, "WRAPPER_EXTENSION", "app"); - - iPhone_Release_Object->addProperty("name", "Release", "", kSettingsNoValue); - iPhone_Release_Object->_properties["buildSettings"] = iPhone_Release; - - _buildConfiguration.add(iPhone_Debug_Object); - _buildConfiguration.add(iPhone_Release_Object); + std::string projectOutputDirectory; +#ifdef POSIX + char *rp = realpath(setup.outputDir.c_str(), NULL); + projectOutputDirectory = rp; + free(rp); #endif + /**************************************** - * scummvm + * ScummVM - Project Level ****************************************/ // Debug @@ -763,7 +779,6 @@ void XcodeProvider::setupBuildConfiguration() { Property scummvm_Debug; ADD_SETTING(scummvm_Debug, "ALWAYS_SEARCH_USER_PATHS", "NO"); ADD_SETTING_QUOTE(scummvm_Debug, "USER_HEADER_SEARCH_PATHS", "$(SRCROOT) $(SRCROOT)/engines"); - ADD_SETTING_QUOTE(scummvm_Debug, "ARCHS", "$(ARCHS_STANDARD_32_BIT)"); ADD_SETTING_QUOTE(scummvm_Debug, "CODE_SIGN_IDENTITY", "Don't Code Sign"); ADD_SETTING_QUOTE_VAR(scummvm_Debug, "CODE_SIGN_IDENTITY[sdk=iphoneos*]", "Don't Code Sign"); ADD_SETTING_QUOTE(scummvm_Debug, "FRAMEWORK_SEARCH_PATHS", ""); @@ -773,9 +788,11 @@ void XcodeProvider::setupBuildConfiguration() { ADD_SETTING(scummvm_Debug, "GCC_INPUT_FILETYPE", "automatic"); ADD_SETTING(scummvm_Debug, "GCC_OPTIMIZATION_LEVEL", "0"); ValueList scummvm_defines(_defines); - ADD_DEFINE(scummvm_defines, "IPHONE"); - ADD_DEFINE(scummvm_defines, "XCODE"); - ADD_DEFINE(scummvm_defines, "IPHONE_OFFICIAL"); + REMOVE_DEFINE(scummvm_defines, "MACOSX"); + REMOVE_DEFINE(scummvm_defines, "IPHONE"); + REMOVE_DEFINE(scummvm_defines, "IPHONE_IOS7"); + REMOVE_DEFINE(scummvm_defines, "IPHONE_SANDBOXED"); + REMOVE_DEFINE(scummvm_defines, "SDL_BACKEND"); ADD_SETTING_LIST(scummvm_Debug, "GCC_PREPROCESSOR_DEFINITIONS", scummvm_defines, kSettingsNoQuote | kSettingsAsList, 5); ADD_SETTING(scummvm_Debug, "GCC_THUMB_SUPPORT", "NO"); ADD_SETTING(scummvm_Debug, "GCC_USE_GCC3_PFE_SUPPORT", "NO"); @@ -791,7 +808,7 @@ void XcodeProvider::setupBuildConfiguration() { ADD_SETTING_QUOTE(scummvm_Debug, "OTHER_CFLAGS", ""); ADD_SETTING_QUOTE(scummvm_Debug, "OTHER_LDFLAGS", "-lz"); ADD_SETTING(scummvm_Debug, "PREBINDING", "NO"); - ADD_SETTING(scummvm_Debug, "SDKROOT", "macosx"); + ADD_SETTING(scummvm_Debug, "ENABLE_TESTABILITY", "YES"); scummvm_Debug_Object->addProperty("name", "Debug", "", kSettingsNoValue); scummvm_Debug_Object->_properties["buildSettings"] = scummvm_Debug; @@ -803,6 +820,7 @@ void XcodeProvider::setupBuildConfiguration() { REMOVE_SETTING(scummvm_Release, "GCC_WARN_ABOUT_RETURN_TYPE"); REMOVE_SETTING(scummvm_Release, "GCC_WARN_UNUSED_VARIABLE"); REMOVE_SETTING(scummvm_Release, "ONLY_ACTIVE_ARCH"); + REMOVE_SETTING(scummvm_Release, "ENABLE_TESTABILITY"); scummvm_Release_Object->addProperty("name", "Release", "", kSettingsNoValue); scummvm_Release_Object->_properties["buildSettings"] = scummvm_Release; @@ -810,17 +828,92 @@ void XcodeProvider::setupBuildConfiguration() { _buildConfiguration.add(scummvm_Debug_Object); _buildConfiguration.add(scummvm_Release_Object); + ///**************************************** + // * ScummVM - iOS Target + // ****************************************/ + + // Debug + Object *iPhone_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-iPhone_Debug", _targets[IOS_TARGET] /* ScummVM-iPhone */, "XCBuildConfiguration", "PBXNativeTarget", "Debug"); + Property iPhone_Debug; + ADD_SETTING_QUOTE(iPhone_Debug, "CODE_SIGN_IDENTITY", "iPhone Developer"); + ADD_SETTING_QUOTE_VAR(iPhone_Debug, "CODE_SIGN_IDENTITY[sdk=iphoneos*]", "iPhone Developer"); + ADD_SETTING(iPhone_Debug, "COMPRESS_PNG_FILES", "NO"); + ADD_SETTING(iPhone_Debug, "COPY_PHASE_STRIP", "NO"); + ADD_SETTING_QUOTE(iPhone_Debug, "DEBUG_INFORMATION_FORMAT", "dwarf"); + ValueList iPhone_FrameworkSearchPaths; + iPhone_FrameworkSearchPaths.push_back("$(inherited)"); + iPhone_FrameworkSearchPaths.push_back("\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\""); + ADD_SETTING_LIST(iPhone_Debug, "FRAMEWORK_SEARCH_PATHS", iPhone_FrameworkSearchPaths, kSettingsAsList, 5); + ADD_SETTING(iPhone_Debug, "GCC_DYNAMIC_NO_PIC", "NO"); + ADD_SETTING(iPhone_Debug, "GCC_ENABLE_CPP_EXCEPTIONS", "NO"); + ADD_SETTING(iPhone_Debug, "GCC_ENABLE_FIX_AND_CONTINUE", "NO"); + ADD_SETTING(iPhone_Debug, "GCC_OPTIMIZATION_LEVEL", "0"); + ADD_SETTING(iPhone_Debug, "GCC_PRECOMPILE_PREFIX_HEADER", "NO"); + ADD_SETTING(iPhone_Debug, "GCC_WARN_64_TO_32_BIT_CONVERSION", "NO"); + ADD_SETTING(iPhone_Debug, "WARNING_CFLAGS", "-Wno-multichar"); + ADD_SETTING_QUOTE(iPhone_Debug, "GCC_PREFIX_HEADER", ""); + ADD_SETTING(iPhone_Debug, "GCC_THUMB_SUPPORT", "NO"); + ADD_SETTING(iPhone_Debug, "GCC_UNROLL_LOOPS", "YES"); + ValueList iPhone_HeaderSearchPaths; + iPhone_HeaderSearchPaths.push_back("$(SRCROOT)/engines/"); + iPhone_HeaderSearchPaths.push_back("$(SRCROOT)"); + iPhone_HeaderSearchPaths.push_back("\"" + projectOutputDirectory + "\""); + iPhone_HeaderSearchPaths.push_back("\"" + projectOutputDirectory + "/include\""); + ADD_SETTING_LIST(iPhone_Debug, "HEADER_SEARCH_PATHS", iPhone_HeaderSearchPaths, kSettingsAsList | kSettingsQuoteVariable, 5); + ADD_SETTING_QUOTE(iPhone_Debug, "INFOPLIST_FILE", "$(SRCROOT)/dists/ios7/Info.plist"); + ValueList iPhone_LibPaths; + iPhone_LibPaths.push_back("$(inherited)"); + iPhone_LibPaths.push_back("\"" + projectOutputDirectory + "/lib\""); + ADD_SETTING_LIST(iPhone_Debug, "LIBRARY_SEARCH_PATHS", iPhone_LibPaths, kSettingsAsList, 5); + ADD_SETTING(iPhone_Debug, "ONLY_ACTIVE_ARCH", "YES"); + ADD_SETTING(iPhone_Debug, "PREBINDING", "NO"); + ADD_SETTING(iPhone_Debug, "PRODUCT_NAME", PROJECT_NAME); + ADD_SETTING(iPhone_Debug, "PRODUCT_BUNDLE_IDENTIFIER", "\"org.scummvm.${PRODUCT_NAME}\""); + ADD_SETTING(iPhone_Debug, "IPHONEOS_DEPLOYMENT_TARGET", "7.1"); + //ADD_SETTING_QUOTE(iPhone_Debug, "PROVISIONING_PROFILE", "EF590570-5FAC-4346-9071-D609DE2B28D8"); + ADD_SETTING_QUOTE_VAR(iPhone_Debug, "PROVISIONING_PROFILE[sdk=iphoneos*]", ""); + ADD_SETTING(iPhone_Debug, "SDKROOT", "iphoneos"); + ADD_SETTING_QUOTE(iPhone_Debug, "TARGETED_DEVICE_FAMILY", "1,2"); + ValueList scummvmIOS_defines; + ADD_DEFINE(scummvmIOS_defines, "\"$(inherited)\""); + ADD_DEFINE(scummvmIOS_defines, "IPHONE"); + ADD_DEFINE(scummvmIOS_defines, "IPHONE_IOS7"); + ADD_DEFINE(scummvmIOS_defines, "IPHONE_SANDBOXED"); + ADD_SETTING_LIST(iPhone_Debug, "GCC_PREPROCESSOR_DEFINITIONS", scummvmIOS_defines, kSettingsNoQuote | kSettingsAsList, 5); + ADD_SETTING(iPhone_Debug, "ASSETCATALOG_COMPILER_APPICON_NAME", "AppIcon"); + ADD_SETTING(iPhone_Debug, "ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME", "LaunchImage"); + + iPhone_Debug_Object->addProperty("name", "Debug", "", kSettingsNoValue); + iPhone_Debug_Object->_properties["buildSettings"] = iPhone_Debug; + + // Release + Object *iPhone_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-iPhone_Release", _targets[IOS_TARGET] /* ScummVM-iPhone */, "XCBuildConfiguration", "PBXNativeTarget", "Release"); + Property iPhone_Release(iPhone_Debug); + ADD_SETTING(iPhone_Release, "GCC_OPTIMIZATION_LEVEL", "3"); + ADD_SETTING(iPhone_Release, "COPY_PHASE_STRIP", "YES"); + REMOVE_SETTING(iPhone_Release, "GCC_DYNAMIC_NO_PIC"); + ADD_SETTING(iPhone_Release, "WRAPPER_EXTENSION", "app"); + REMOVE_SETTING(iPhone_Release, "DEBUG_INFORMATION_FORMAT"); + ADD_SETTING_QUOTE(iPhone_Release, "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym"); + + iPhone_Release_Object->addProperty("name", "Release", "", kSettingsNoValue); + iPhone_Release_Object->_properties["buildSettings"] = iPhone_Release; + + _buildConfiguration.add(iPhone_Debug_Object); + _buildConfiguration.add(iPhone_Release_Object); + /**************************************** - * ScummVM-OS X + * ScummVM - OS X Target ****************************************/ // Debug Object *scummvmOSX_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-OSX_Debug", _targets[OSX_TARGET] /* ScummVM-OS X */, "XCBuildConfiguration", "PBXNativeTarget", "Debug"); Property scummvmOSX_Debug; - ADD_SETTING_QUOTE(scummvmOSX_Debug, "ARCHS", "$(NATIVE_ARCH)"); + ADD_SETTING(scummvmOSX_Debug, "COMBINE_HIDPI_IMAGES", "YES"); + ADD_SETTING(scummvmOSX_Debug, "SDKROOT", "macosx"); ADD_SETTING(scummvmOSX_Debug, "COMPRESS_PNG_FILES", "NO"); ADD_SETTING(scummvmOSX_Debug, "COPY_PHASE_STRIP", "NO"); - ADD_SETTING_QUOTE(scummvmOSX_Debug, "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym"); + ADD_SETTING_QUOTE(scummvmOSX_Debug, "DEBUG_INFORMATION_FORMAT", "dwarf"); ADD_SETTING_QUOTE(scummvmOSX_Debug, "FRAMEWORK_SEARCH_PATHS", ""); ADD_SETTING(scummvmOSX_Debug, "GCC_C_LANGUAGE_STANDARD", "c99"); ADD_SETTING(scummvmOSX_Debug, "GCC_ENABLE_CPP_EXCEPTIONS", "NO"); @@ -830,7 +923,8 @@ void XcodeProvider::setupBuildConfiguration() { ADD_SETTING(scummvmOSX_Debug, "GCC_OPTIMIZATION_LEVEL", "0"); ADD_SETTING(scummvmOSX_Debug, "GCC_PRECOMPILE_PREFIX_HEADER", "NO"); ADD_SETTING_QUOTE(scummvmOSX_Debug, "GCC_PREFIX_HEADER", ""); - ValueList scummvmOSX_defines(_defines); + ValueList scummvmOSX_defines; + ADD_DEFINE(scummvmOSX_defines, "\"$(inherited)\""); ADD_DEFINE(scummvmOSX_defines, "SDL_BACKEND"); ADD_DEFINE(scummvmOSX_defines, "MACOSX"); ADD_SETTING_LIST(scummvmOSX_Debug, "GCC_PREPROCESSOR_DEFINITIONS", scummvmOSX_defines, kSettingsNoQuote | kSettingsAsList, 5); @@ -866,7 +960,7 @@ void XcodeProvider::setupBuildConfiguration() { scummvmOSX_LdFlags.push_back("-lz"); ADD_SETTING_LIST(scummvmOSX_Debug, "OTHER_LDFLAGS", scummvmOSX_LdFlags, kSettingsAsList, 5); ADD_SETTING(scummvmOSX_Debug, "PREBINDING", "NO"); - ADD_SETTING(scummvmOSX_Debug, "PRODUCT_NAME", PROJECT_DESCRIPTION); + ADD_SETTING(scummvmOSX_Debug, "PRODUCT_NAME", PROJECT_NAME); scummvmOSX_Debug_Object->addProperty("name", "Debug", "", kSettingsNoValue); scummvmOSX_Debug_Object->_properties["buildSettings"] = scummvmOSX_Debug; @@ -878,48 +972,15 @@ void XcodeProvider::setupBuildConfiguration() { REMOVE_SETTING(scummvmOSX_Release, "GCC_DYNAMIC_NO_PIC"); REMOVE_SETTING(scummvmOSX_Release, "GCC_OPTIMIZATION_LEVEL"); ADD_SETTING(scummvmOSX_Release, "WRAPPER_EXTENSION", "app"); + REMOVE_SETTING(scummvmOSX_Release, "DEBUG_INFORMATION_FORMAT"); + ADD_SETTING_QUOTE(scummvmOSX_Release, "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym"); scummvmOSX_Release_Object->addProperty("name", "Release", "", kSettingsNoValue); scummvmOSX_Release_Object->_properties["buildSettings"] = scummvmOSX_Release; _buildConfiguration.add(scummvmOSX_Debug_Object); _buildConfiguration.add(scummvmOSX_Release_Object); -#ifdef ENABLE_IOS - /**************************************** - * ScummVM-Simulator - ****************************************/ - // Debug - Object *scummvmSimulator_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-Simulator_Debug", _targets[SIM_TARGET] /* ScummVM-Simulator */, "XCBuildConfiguration", "PBXNativeTarget", "Debug"); - Property scummvmSimulator_Debug(iPhone_Debug); - ADD_SETTING_QUOTE(scummvmSimulator_Debug, "FRAMEWORK_SEARCH_PATHS", "$(inherited)"); - ADD_SETTING_LIST(scummvmSimulator_Debug, "GCC_PREPROCESSOR_DEFINITIONS", scummvm_defines, kSettingsNoQuote | kSettingsAsList, 5); - ADD_SETTING(scummvmSimulator_Debug, "SDKROOT", "iphonesimulator3.2"); - ADD_SETTING_QUOTE(scummvmSimulator_Debug, "VALID_ARCHS", "i386 x86_64"); - REMOVE_SETTING(scummvmSimulator_Debug, "TARGETED_DEVICE_FAMILY"); - - scummvmSimulator_Debug_Object->addProperty("name", "Debug", "", kSettingsNoValue); - scummvmSimulator_Debug_Object->_properties["buildSettings"] = scummvmSimulator_Debug; - - // Release - Object *scummvmSimulator_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-Simulator_Release", _targets[SIM_TARGET] /* ScummVM-Simulator */, "XCBuildConfiguration", "PBXNativeTarget", "Release"); - Property scummvmSimulator_Release(scummvmSimulator_Debug); - ADD_SETTING(scummvmSimulator_Release, "COPY_PHASE_STRIP", "YES"); - ADD_SETTING(scummvmSimulator_Release, "GCC_OPTIMIZATION_LEVEL", "3"); - REMOVE_SETTING(scummvmSimulator_Release, "GCC_DYNAMIC_NO_PIC"); - ADD_SETTING(scummvmSimulator_Release, "WRAPPER_EXTENSION", "app"); - - scummvmSimulator_Release_Object->addProperty("name", "Release", "", kSettingsNoValue); - scummvmSimulator_Release_Object->_properties["buildSettings"] = scummvmSimulator_Release; - - _buildConfiguration.add(scummvmSimulator_Debug_Object); - _buildConfiguration.add(scummvmSimulator_Release_Object); - - ////////////////////////////////////////////////////////////////////////// - // Configuration List - _configurationList._comment = "XCConfigurationList"; - _configurationList._flags = kSettingsAsList; -#endif // Warning: This assumes we have all configurations with a Debug & Release pair for (std::vector<Object *>::iterator config = _buildConfiguration._objects.begin(); config != _buildConfiguration._objects.end(); config++) { @@ -940,6 +1001,22 @@ void XcodeProvider::setupBuildConfiguration() { } } +void XcodeProvider::setupImageAssetCatalog(const BuildSetup &setup) { + const std::string filename = "Images.xcassets"; + const std::string absoluteCatalogPath = _projectRoot + "/dists/ios7/" + filename; + const std::string id = "FileReference_" + absoluteCatalogPath; + Group *group = touchGroupsForPath(absoluteCatalogPath); + group->addChildFile(filename); + addBuildFile(absoluteCatalogPath, filename, getHash(id), "Image Asset Catalog"); +} + +void XcodeProvider::setupAdditionalSources(std::string targetName, Property &files, int &order) { + if (targetIsIOS(targetName)) { + const std::string absoluteCatalogPath = _projectRoot + "/dists/ios7/Images.xcassets"; + ADD_SETTING_ORDER_NOVALUE(files, getHash(absoluteCatalogPath), "Image Asset Catalog", order++); + } +} + ////////////////////////////////////////////////////////////////////////// // Misc ////////////////////////////////////////////////////////////////////////// @@ -954,9 +1031,12 @@ void XcodeProvider::setupDefines(const BuildSetup &setup) { ADD_DEFINE(_defines, *i); } // Add special defines for Mac support + REMOVE_DEFINE(_defines, "MACOSX"); + REMOVE_DEFINE(_defines, "IPHONE"); + REMOVE_DEFINE(_defines, "IPHONE_IOS7"); + REMOVE_DEFINE(_defines, "IPHONE_SANDBOXED"); + REMOVE_DEFINE(_defines, "SDL_BACKEND"); ADD_DEFINE(_defines, "CONFIG_H"); - ADD_DEFINE(_defines, "SCUMM_NEED_ALIGNMENT"); - ADD_DEFINE(_defines, "SCUMM_LITTLE_ENDIAN"); ADD_DEFINE(_defines, "UNIX"); ADD_DEFINE(_defines, "SCUMMVM"); } @@ -965,7 +1045,6 @@ void XcodeProvider::setupDefines(const BuildSetup &setup) { // Object hash ////////////////////////////////////////////////////////////////////////// -// TODO use md5 to compute a file hash (and fall back to standard key generation if not passed a file) std::string XcodeProvider::getHash(std::string key) { #if DEBUG_XCODE_HASH @@ -977,7 +1056,12 @@ std::string XcodeProvider::getHash(std::string key) { return hashIterator->second; // Generate a new key from the file hash and insert it into the dictionary +#ifdef MACOSX + std::string hash = md5(key); +#else std::string hash = newHash(); +#endif + _hashDictionnary[key] = hash; return hash; @@ -986,6 +1070,19 @@ std::string XcodeProvider::getHash(std::string key) { bool isSeparator(char s) { return (s == '-'); } +#ifdef MACOSX +std::string XcodeProvider::md5(std::string key) { + unsigned char md[CC_MD5_DIGEST_LENGTH]; + CC_MD5(key.c_str(), (CC_LONG) key.length(), md); + std::stringstream stream; + stream << std::hex << std::setfill('0') << std::setw(2); + for (int i=0; i<CC_MD5_DIGEST_LENGTH; i++) { + stream << (unsigned int) md[i]; + } + return stream.str(); +} +#endif + std::string XcodeProvider::newHash() const { std::string hash = createUUID(); @@ -1070,7 +1167,6 @@ std::string XcodeProvider::writeSetting(const std::string &variable, const Setti // Output a list if (setting._flags & kSettingsAsList) { - output += var + ((setting._flags & kSettingsNoValue) ? "(" : " = (") + newline; for (unsigned int i = 0, count = 0; i < setting._entries.size(); ++i) { diff --git a/devtools/create_project/xcode.h b/devtools/create_project/xcode.h index d48f11cb19..d495dd0dfd 100644 --- a/devtools/create_project/xcode.h +++ b/devtools/create_project/xcode.h @@ -40,6 +40,8 @@ protected: void createOtherBuildFiles(const BuildSetup &setup); + void addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList); + void createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir, const StringList &includeList, const StringList &excludeList); @@ -63,7 +65,7 @@ private: std::string _sourceTree; FileProperty(std::string fileType = "", std::string name = "", std::string path = "", std::string source = "") - : _fileEncoding(""), _lastKnownFileType(fileType), _fileName(name), _filePath(path), _sourceTree(source) { + : _fileEncoding(""), _lastKnownFileType(fileType), _fileName(name), _filePath(path), _sourceTree(source) { } }; @@ -208,6 +210,7 @@ private: assert(!_properties["isa"]._settings.empty()); SettingList::iterator it = _properties["isa"]._settings.begin(); + return it->first; } }; @@ -230,6 +233,15 @@ private: _objectMap[obj->_id] = true; } + Object *find(std::string id) { + for (std::vector<Object *>::iterator it = _objects.begin(); it != _objects.end(); ++it) { + if ((*it)->_id == id) { + return *it; + } + } + return NULL; + } + std::string toString() { std::string output; @@ -300,18 +312,26 @@ private: // Setup objects void setupCopyFilesBuildPhase(); - void setupFrameworksBuildPhase(); + void setupFrameworksBuildPhase(const BuildSetup &setup); void setupNativeTarget(); void setupProject(); void setupResourcesBuildPhase(); void setupSourcesBuildPhase(); - void setupBuildConfiguration(); + void setupBuildConfiguration(const BuildSetup &setup); + void setupImageAssetCatalog(const BuildSetup &setup); + void setupAdditionalSources(std::string targetName, Property &files, int &order); // Misc void setupDefines(const BuildSetup &setup); // Setup the list of defines to be used on build configurations + // Retrieve information + ValueList& getResourceFiles() const; + // Hash generation std::string getHash(std::string key); +#ifdef MACOSX + std::string md5(std::string key); +#endif std::string newHash() const; // Output diff --git a/devtools/create_project/xcode/create_project.xcodeproj/project.pbxproj b/devtools/create_project/xcode/create_project.xcodeproj/project.pbxproj index f13bcf6969..4f06a5e469 100644 --- a/devtools/create_project/xcode/create_project.xcodeproj/project.pbxproj +++ b/devtools/create_project/xcode/create_project.xcodeproj/project.pbxproj @@ -140,6 +140,9 @@ /* Begin PBXProject section */ F9A66C1E1396D36100CEE494 /* Project object */ = { isa = PBXProject; + attributes = { + LastUpgradeCheck = 0720; + }; buildConfigurationList = F9A66C211396D36100CEE494 /* Build configuration list for PBXProject "create_project" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; @@ -177,12 +180,14 @@ F9A66C2E1396D36100CEE494 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = DEBUG; + GCC_PREPROCESSOR_DEFINITIONS = ( + POSIX, + MACOSX, + ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; @@ -195,9 +200,11 @@ F9A66C2F1396D36100CEE494 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_PREPROCESSOR_DEFINITIONS = ( + POSIX, + MACOSX, + ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; @@ -213,6 +220,10 @@ COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + DEBUG, + ); PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -224,6 +235,7 @@ COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; diff --git a/devtools/credits.pl b/devtools/credits.pl index 1a038c7dee..6201fc1052 100755 --- a/devtools/credits.pl +++ b/devtools/credits.pl @@ -826,8 +826,9 @@ begin_credits("Credits"); add_person("John Willis", "DJWillis", ""); end_section(); - begin_section("iPhone"); + begin_section("iPhone / iPad"); add_person("Oystein Eftevaag", "vinterstum", ""); + add_person("Vincent Bénony", "bSr43", ""); end_section(); begin_section("LinuxMoto"); diff --git a/devtools/update-version.pl b/devtools/update-version.pl index b313846ab3..3e44198d31 100755 --- a/devtools/update-version.pl +++ b/devtools/update-version.pl @@ -38,6 +38,7 @@ my @subs_files = qw( dists/slackware/scummvm.SlackBuild dists/macosx/Info.plist dists/iphone/Info.plist + dists/ios7/Info.plist dists/irix/scummvm.spec dists/win32/scummvm.nsi dists/wii/meta.xml diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/Contents.json b/dists/ios7/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..c37df59806 --- /dev/null +++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,86 @@ +{ + "images" : [ + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon4-29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon4-29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon4-40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon4-40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon4-60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon4-60@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon4-29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon4-29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon4-40.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon4-40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon4-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon4-76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "icon4-83.5@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +}
\ No newline at end of file diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29.png Binary files differnew file mode 100644 index 0000000000..9b89d07046 --- /dev/null +++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29.png diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@2x.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@2x.png Binary files differnew file mode 100644 index 0000000000..0de0984ed7 --- /dev/null +++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@2x.png diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@3x.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@3x.png Binary files differnew file mode 100644 index 0000000000..db6089dcf6 --- /dev/null +++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@3x.png diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40.png Binary files differnew file mode 100644 index 0000000000..9a7575b404 --- /dev/null +++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40.png diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@2x.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@2x.png Binary files differnew file mode 100644 index 0000000000..5cd982d0e1 --- /dev/null +++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@2x.png diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@3x.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@3x.png Binary files differnew file mode 100644 index 0000000000..22580b0ac6 --- /dev/null +++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@3x.png diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@2x.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@2x.png Binary files differnew file mode 100644 index 0000000000..22580b0ac6 --- /dev/null +++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@2x.png diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@3x.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@3x.png Binary files differnew file mode 100644 index 0000000000..c5f39976bb --- /dev/null +++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@3x.png diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76.png Binary files differnew file mode 100644 index 0000000000..0609594553 --- /dev/null +++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76.png diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76@2x.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76@2x.png Binary files differnew file mode 100644 index 0000000000..7bc1ae1de1 --- /dev/null +++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76@2x.png diff --git a/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-83.5@2x.png b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-83.5@2x.png Binary files differnew file mode 100644 index 0000000000..acaf12f435 --- /dev/null +++ b/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-83.5@2x.png diff --git a/dists/ios7/Images.xcassets/Contents.json b/dists/ios7/Images.xcassets/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/dists/ios7/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +}
\ No newline at end of file diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/Contents.json b/dists/ios7/Images.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 0000000000..40e3b1e3dd --- /dev/null +++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,150 @@ +{ + "images" : [ + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "736h", + "filename" : "ScummVM-splash-1242x2208.png", + "minimum-system-version" : "8.0", + "orientation" : "portrait", + "scale" : "3x" + }, + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "736h", + "filename" : "ScummVM-splash-2208x1242.png", + "minimum-system-version" : "8.0", + "orientation" : "landscape", + "scale" : "3x" + }, + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "667h", + "filename" : "ScummVM-splash-750x1334.png", + "minimum-system-version" : "8.0", + "orientation" : "portrait", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "retina4", + "filename" : "ScummVM-splash-640x1136-1.png", + "minimum-system-version" : "7.0", + "orientation" : "portrait", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "filename" : "ScummVM-splash-768x1024.png", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "filename" : "ScummVM-splash-1024x768.png", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "filename" : "ScummVM-splash-1536x2048.png", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "filename" : "ScummVM-splash-2048x1536.png", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "subtype" : "retina4", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "to-status-bar", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "to-status-bar", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "to-status-bar", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "to-status-bar", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +}
\ No newline at end of file diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1024x768.png b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1024x768.png Binary files differnew file mode 100644 index 0000000000..6fb6c9bf4b --- /dev/null +++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1024x768.png diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1242x2208.png b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1242x2208.png Binary files differnew file mode 100644 index 0000000000..c70153b1f7 --- /dev/null +++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1242x2208.png diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1536x2048.png b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1536x2048.png Binary files differnew file mode 100644 index 0000000000..8d6e588226 --- /dev/null +++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1536x2048.png diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2048x1536.png b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2048x1536.png Binary files differnew file mode 100644 index 0000000000..988122bce8 --- /dev/null +++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2048x1536.png diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2208x1242.png b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2208x1242.png Binary files differnew file mode 100644 index 0000000000..33b3740092 --- /dev/null +++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2208x1242.png diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-640x1136-1.png b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-640x1136-1.png Binary files differnew file mode 100644 index 0000000000..91641cf91f --- /dev/null +++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-640x1136-1.png diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-750x1334.png b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-750x1334.png Binary files differnew file mode 100644 index 0000000000..630502974a --- /dev/null +++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-750x1334.png diff --git a/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-768x1024.png b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-768x1024.png Binary files differnew file mode 100644 index 0000000000..6a33b63110 --- /dev/null +++ b/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-768x1024.png diff --git a/dists/ios7/Info.plist b/dists/ios7/Info.plist new file mode 100644 index 0000000000..84885d9232 --- /dev/null +++ b/dists/ios7/Info.plist @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleExecutable</key> + <string>ScummVM</string> + <key>CFBundleIcons</key> + <dict/> + <key>CFBundleIcons~ipad</key> + <dict/> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>ScummVM</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.8.0git</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1.8.0git</string> + <key>UIApplicationExitsOnSuspend</key> + <false/> + <key>UIFileSharingEnabled</key> + <true/> + <key>UILaunchImages</key> + <array/> + <key>UIPrerenderedIcon</key> + <true/> + <key>UIRequiresFullScreen</key> + <true/> + <key>UIStatusBarHidden</key> + <true/> + <key>UISupportedInterfaceOrientations</key> + <array> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + <string>UIInterfaceOrientationPortrait</string> + </array> + <key>UISupportedInterfaceOrientations~ipad</key> + <array> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + <string>UIInterfaceOrientationPortrait</string> + </array> +</dict> +</plist> diff --git a/dists/ios7/Info.plist.in b/dists/ios7/Info.plist.in new file mode 100644 index 0000000000..33094f4df9 --- /dev/null +++ b/dists/ios7/Info.plist.in @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleExecutable</key> + <string>ScummVM</string> + <key>CFBundleIcons</key> + <dict/> + <key>CFBundleIcons~ipad</key> + <dict/> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>ScummVM</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>@VERSION@</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>@VERSION@</string> + <key>UIApplicationExitsOnSuspend</key> + <false/> + <key>UIFileSharingEnabled</key> + <true/> + <key>UILaunchImages</key> + <array/> + <key>UIPrerenderedIcon</key> + <true/> + <key>UIRequiresFullScreen</key> + <true/> + <key>UIStatusBarHidden</key> + <true/> + <key>UISupportedInterfaceOrientations</key> + <array> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + <string>UIInterfaceOrientationPortrait</string> + </array> + <key>UISupportedInterfaceOrientations~ipad</key> + <array> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + <string>UIInterfaceOrientationPortrait</string> + </array> +</dict> +</plist> diff --git a/dists/macosx/Info.plist b/dists/macosx/Info.plist index b872febd60..ef504751a7 100644 --- a/dists/macosx/Info.plist +++ b/dists/macosx/Info.plist @@ -4,6 +4,18 @@ <dict> <key>CFBundleDevelopmentRegion</key> <string>English</string> + <key>CFBundleDisplayName</key> + <string>ScummVM</string> + <key>CFBundleExecutable</key> + <string>scummvm</string> + <key>CFBundleGetInfoString</key> + <string>1.8.0git, Copyright 2001-2016 The ScummVM Team</string> + <key>CFBundleIconFile</key> + <string>scummvm.icns</string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> <key>CFBundleLocalizations</key> <array> <string>en</string> @@ -28,18 +40,6 @@ <string>se</string> <string>uk</string> </array> - <key>CFBundleDisplayName</key> - <string>ScummVM</string> - <key>CFBundleExecutable</key> - <string>scummvm</string> - <key>CFBundleGetInfoString</key> - <string>1.8.0git, Copyright 2001-2016 The ScummVM Team</string> - <key>CFBundleIconFile</key> - <string>scummvm.icns</string> - <key>CFBundleIdentifier</key> - <string>org.scummvm.scummvm</string> - <key>CFBundleInfoDictionaryVersion</key> - <string>6.0</string> <key>CFBundleName</key> <string>ScummVM</string> <key>CFBundlePackageType</key> @@ -48,10 +48,10 @@ <string>1.8.0git</string> <key>CFBundleVersion</key> <string>1.8.0git</string> - <key>NSPrincipalClass</key> - <string>NSApplication</string> <key>NSHumanReadableCopyright</key> <string>Copyright 2001-2016 The ScummVM Team</string> + <key>NSPrincipalClass</key> + <string>NSApplication</string> <key>SUFeedURL</key> <string>http://www.scummvm.org/appcasts/macosx/release.xml</string> <key>SUPublicDSAKeyFile</key> diff --git a/dists/macosx/Info.plist.in b/dists/macosx/Info.plist.in index 1a83447e26..55be27d77b 100644 --- a/dists/macosx/Info.plist.in +++ b/dists/macosx/Info.plist.in @@ -4,6 +4,18 @@ <dict> <key>CFBundleDevelopmentRegion</key> <string>English</string> + <key>CFBundleDisplayName</key> + <string>ScummVM</string> + <key>CFBundleExecutable</key> + <string>scummvm</string> + <key>CFBundleGetInfoString</key> + <string>@VERSION@, Copyright 2001-2016 The ScummVM Team</string> + <key>CFBundleIconFile</key> + <string>scummvm.icns</string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> <key>CFBundleLocalizations</key> <array> <string>en</string> @@ -28,18 +40,6 @@ <string>se</string> <string>uk</string> </array> - <key>CFBundleDisplayName</key> - <string>ScummVM</string> - <key>CFBundleExecutable</key> - <string>scummvm</string> - <key>CFBundleGetInfoString</key> - <string>@VERSION@, Copyright 2001-2016 The ScummVM Team</string> - <key>CFBundleIconFile</key> - <string>scummvm.icns</string> - <key>CFBundleIdentifier</key> - <string>org.scummvm.scummvm</string> - <key>CFBundleInfoDictionaryVersion</key> - <string>6.0</string> <key>CFBundleName</key> <string>ScummVM</string> <key>CFBundlePackageType</key> @@ -48,10 +48,10 @@ <string>@VERSION@</string> <key>CFBundleVersion</key> <string>@VERSION@</string> - <key>NSPrincipalClass</key> - <string>NSApplication</string> <key>NSHumanReadableCopyright</key> <string>Copyright 2001-2016 The ScummVM Team</string> + <key>NSPrincipalClass</key> + <string>NSApplication</string> <key>SUFeedURL</key> <string>http://www.scummvm.org/appcasts/macosx/release.xml</string> <key>SUPublicDSAKeyFile</key> diff --git a/gui/credits.h b/gui/credits.h index 72fe3fa951..b084935cbb 100644 --- a/gui/credits.h +++ b/gui/credits.h @@ -351,8 +351,10 @@ static const char *credits[] = { "C1""GPH Devices (GP2X, GP2XWiz & Caanoo)", "C0""John Willis", "", -"C1""iPhone", +"C1""iPhone / iPad", "C0""Oystein Eftevaag", +"A0""Vincent Benony", +"C0""Vincent B\351nony", "", "C1""LinuxMoto", "C0""Lubomyr Lisen", diff --git a/gui/module.mk b/gui/module.mk index e355212620..fb7c968c34 100644 --- a/gui/module.mk +++ b/gui/module.mk @@ -32,6 +32,15 @@ MODULE_OBJS := \ widgets/scrollbar.o \ widgets/tab.o +# HACK: Even if it seems redundant, please keep these directives in that order! +# This is needed by the "create_project" tool, for the OS X / iOS Xcode project. +# The main problem is that the create_project tool scans the files for both OS X, and iOS targets. +# It must be able to collect all the files for both targets, so that the backend can later filter +# them for its own targets (in the Xcode terminology) +ifdef IPHONE +MODULE_OBJS += \ + browser.o +else ifdef MACOSX MODULE_OBJS += \ browser_osx.o @@ -39,6 +48,7 @@ else MODULE_OBJS += \ browser.o endif +endif ifdef ENABLE_EVENTRECORDER MODULE_OBJS += \ @@ -58,7 +58,7 @@ bundle: scummvm-static mkdir -p $(bundle_name)/Contents/MacOS mkdir -p $(bundle_name)/Contents/Resources echo "APPL????" > $(bundle_name)/Contents/PkgInfo - cp $(srcdir)/dists/macosx/Info.plist $(bundle_name)/Contents/ + sed -e 's/$$(PRODUCT_BUNDLE_IDENTIFIER)/org.scummvm.scummvm/' $(srcdir)/dists/macosx/Info.plist >$(bundle_name)/Contents/Info.plist ifdef USE_SPARKLE mkdir -p $(bundle_name)/Contents/Frameworks cp $(srcdir)/dists/macosx/dsa_pub.pem $(bundle_name)/Contents/Resources/ @@ -92,11 +92,139 @@ endif cp $(srcdir)/dists/iphone/icon-72.png $(bundle_name)/ cp $(srcdir)/dists/iphone/Default.png $(bundle_name)/ +ios7bundle: ios7 + mkdir -p $(bundle_name) + awk 'BEGIN {s=0}\ + /<key>CFBundleIcons<\/key>/ {\ + print $$0;\ + print "\t<dict>";\ + print "\t\t<key>CFBundlePrimaryIcon</key>";\ + print "\t\t<dict>";\ + print "\t\t\t<key>CFBundleIconFiles</key>";\ + print "\t\t\t<array>";\ + print "\t\t\t\t<string>AppIcon29x29</string>";\ + print "\t\t\t\t<string>AppIcon40x40</string>";\ + print "\t\t\t\t<string>AppIcon60x60</string>";\ + print "\t\t\t</array>";\ + print "\t\t</dict>";\ + print "\t</dict>";\ + s=2}\ + /<key>CFBundleIcons~ipad<\/key>/ {\ + print $$0;\ + print "\t<dict>";\ + print "\t\t<key>CFBundlePrimaryIcon</key>";\ + print "\t\t<dict>";\ + print "\t\t\t<key>CFBundleIconFiles</key>";\ + print "\t\t\t<array>";\ + print "\t\t\t\t<string>AppIcon29x29</string>";\ + print "\t\t\t\t<string>AppIcon40x40</string>";\ + print "\t\t\t\t<string>AppIcon60x60</string>";\ + print "\t\t\t\t<string>AppIcon76x76</string>";\ + print "\t\t\t\t<string>AppIcon83.5x83.5</string>";\ + print "\t\t\t</array>";\ + print "\t\t</dict>";\ + print "\t</dict>";\ + s=2}\ + /<key>UILaunchImages<\/key>/ {\ + print $$0;\ + print "\t<array>";\ + print "\t\t<dict>";\ + print "\t\t\t<key>UILaunchImageMinimumOSVersion</key>";\ + print "\t\t\t<string>8.0</string>";\ + print "\t\t\t<key>UILaunchImageName</key>";\ + print "\t\t\t<string>LaunchImage-800-Portrait-736h</string>";\ + print "\t\t\t<key>UILaunchImageOrientation</key>";\ + print "\t\t\t<string>Portrait</string>";\ + print "\t\t\t<key>UILaunchImageSize</key>";\ + print "\t\t\t<string>{414, 736}</string>";\ + print "\t\t\t<key>UILaunchImageMinimumOSVersion</key>";\ + print "\t\t\t<string>8.0</string>";\ + print "\t\t\t<key>UILaunchImageName</key>";\ + print "\t\t\t<string>LaunchImage-800-Landscape-736h</string>";\ + print "\t\t\t<key>UILaunchImageOrientation</key>";\ + print "\t\t\t<string>Landscape</string>";\ + print "\t\t\t<key>UILaunchImageSize</key>";\ + print "\t\t\t<string>{414, 736}</string>";\ + print "\t\t\t<key>UILaunchImageMinimumOSVersion</key>";\ + print "\t\t\t<string>8.0</string>";\ + print "\t\t\t<key>UILaunchImageName</key>";\ + print "\t\t\t<string>LaunchImage-800-667h</string>";\ + print "\t\t\t<key>UILaunchImageOrientation</key>";\ + print "\t\t\t<string>Portrait</string>";\ + print "\t\t\t<key>UILaunchImageSize</key>";\ + print "\t\t\t<string>{375, 667}</string>";\ + print "\t\t\t<key>UILaunchImageMinimumOSVersion</key>";\ + print "\t\t\t<string>7.0</string>";\ + print "\t\t\t<key>UILaunchImageName</key>";\ + print "\t\t\t<string>LaunchImage-700-568h</string>";\ + print "\t\t\t<key>UILaunchImageOrientation</key>";\ + print "\t\t\t<string>Portrait</string>";\ + print "\t\t\t<key>UILaunchImageSize</key>";\ + print "\t\t\t<string>{320, 568}</string>";\ + print "\t\t</dict>";\ + print "\t\t<dict>";\ + print "\t\t\t<key>UILaunchImageMinimumOSVersion</key>";\ + print "\t\t\t<string>7.0</string>";\ + print "\t\t\t<key>UILaunchImageName</key>";\ + print "\t\t\t<string>LaunchImage-700-Portrait</string>";\ + print "\t\t\t<key>UILaunchImageOrientation</key>";\ + print "\t\t\t<string>Portrait</string>";\ + print "\t\t\t<key>UILaunchImageSize</key>";\ + print "\t\t\t<string>{768, 1024}</string>";\ + print "\t\t</dict>";\ + print "\t\t<dict>";\ + print "\t\t\t<key>UILaunchImageMinimumOSVersion</key>";\ + print "\t\t\t<string>7.0</string>";\ + print "\t\t\t<key>UILaunchImageName</key>";\ + print "\t\t\t<string>LaunchImage-700-Landscape</string>";\ + print "\t\t\t<key>UILaunchImageOrientation</key>";\ + print "\t\t\t<string>Landscape</string>";\ + print "\t\t\t<key>UILaunchImageSize</key>";\ + print "\t\t\t<string>{768, 1024}</string>";\ + print "\t\t</dict>";\ + print "\t</array>";\ + s=2}\ + s==0 {print $$0}\ + s > 0 { s-- }' $(srcdir)/dists/ios7/Info.plist >$(bundle_name)/Info.plist + sed -i'' -e 's/$$(PRODUCT_BUNDLE_IDENTIFIER)/org.scummvm.scummvm/' $(bundle_name)/Info.plist + cp $(DIST_FILES_DOCS) $(bundle_name)/ + cp $(DIST_FILES_THEMES) $(bundle_name)/ +ifdef DIST_FILES_ENGINEDATA + cp $(DIST_FILES_ENGINEDATA) $(bundle_name)/ +endif + $(STRIP) scummvm + ldid -S scummvm + chmod 755 scummvm + cp scummvm $(bundle_name)/ScummVM + cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@2x.png $(bundle_name)/AppIcon29x29@2x.png + cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@2x.png $(bundle_name)/AppIcon29x29@2x~ipad.png + cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29@3x.png $(bundle_name)/AppIcon29x29@3x.png + cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-29.png $(bundle_name)/AppIcon29x29~ipad.png + cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@2x.png $(bundle_name)/AppIcon40x40@2x.png + cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@2x.png $(bundle_name)/AppIcon40x40@2x~ipad.png + cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40@3x.png $(bundle_name)/AppIcon40x40@3x.png + cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-40.png $(bundle_name)/AppIcon40x40~ipad.png + cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@2x.png $(bundle_name)/AppIcon60x60@2x.png + cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-60@3x.png $(bundle_name)/AppIcon60x60@3x.png + cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76@2x.png $(bundle_name)/AppIcon76x76@2x~ipad.png + cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-76.png $(bundle_name)/AppIcon76x76~ipad.png + cp $(srcdir)/dists/ios7/Images.xcassets/AppIcon.appiconset/icon4-83.5@2x.png $(bundle_name)/AppIcon83.5x83.5@2x~ipad.png + cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-640x1136-1.png $(bundle_name)/LaunchImage-700-568h@2x.png + cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2048x1536.png $(bundle_name)/LaunchImage-700-Landscape@2x~ipad.png + cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1024x768.png $(bundle_name)/LaunchImage-700-Landscape~ipad.png + cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1536x2048.png $(bundle_name)/LaunchImage-700-Portrait@2x~ipad.png + cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-768x1024.png $(bundle_name)/LaunchImage-700-Portrait~ipad.png + cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-1242x2208.png $(bundle_name)/LaunchImage-800-Portrait-736h@3x.png + cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-2208x1242.png $(bundle_name)/LaunchImage-800-Landscape-736h@3x.png + cp $(srcdir)/dists/ios7/Images.xcassets/LaunchImage.launchimage/ScummVM-splash-750x1334.png $(bundle_name)/LaunchImage-800-667h@2x.png + # Location of static libs for the iPhone ifneq ($(BACKEND), iphone) +ifneq ($(BACKEND), ios7) # Static libaries, used for the scummvm-static and iphone targets OSX_STATIC_LIBS := `$(SDLCONFIG) --static-libs` endif +endif ifdef USE_FREETYPE2 OSX_STATIC_LIBS += $(STATICLIBPATH)/lib/libfreetype.a $(STATICLIBPATH)/lib/libbz2.a @@ -164,7 +292,7 @@ scummvm-static: $(OBJS) $(OSX_STATIC_LIBS) \ $(OSX_ZLIB) -# Special target to create a static linked binary for the iPhone +# Special target to create a static linked binary for the iPhone (legacy, and iOS 7+) iphone: $(OBJS) $(CXX) $(LDFLAGS) -o scummvm $(OBJS) \ $(OSX_STATIC_LIBS) \ |