diff --git a/Cores/DeltaCore b/Cores/DeltaCore index 92a390d..026b22b 160000 --- a/Cores/DeltaCore +++ b/Cores/DeltaCore @@ -1 +1 @@ -Subproject commit 92a390d01eaafbce5852531d8e072ae29752dedb +Subproject commit 026b22be17246068f7e333437545db490882521f diff --git a/Cores/SNESDeltaCore b/Cores/SNESDeltaCore index e591a53..746632e 160000 --- a/Cores/SNESDeltaCore +++ b/Cores/SNESDeltaCore @@ -1 +1 @@ -Subproject commit e591a53f115fc3a8b9dcdfea677e6f14d788f04f +Subproject commit 746632eee940d597777d2c32d5e031807fd788fb diff --git a/Delta.xcodeproj/project.pbxproj b/Delta.xcodeproj/project.pbxproj index 5b71699..014b08c 100644 --- a/Delta.xcodeproj/project.pbxproj +++ b/Delta.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + BF090CF41B490D8300DCAB45 /* UIDevice+Vibration.m in Sources */ = {isa = PBXBuildFile; fileRef = BF090CF31B490D8300DCAB45 /* UIDevice+Vibration.m */; }; BF46894F1AAC46EF00A2586D /* DirectoryContentsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF46894E1AAC46EF00A2586D /* DirectoryContentsDataSource.swift */; }; BF9F4FCF1AAD7B87004C9500 /* DeltaCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF9F4FCE1AAD7B87004C9500 /* DeltaCore.framework */; }; BF9F4FD01AAD7B87004C9500 /* DeltaCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BF9F4FCE1AAD7B87004C9500 /* DeltaCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -40,6 +41,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + BF090CF11B490D8300DCAB45 /* Delta-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Delta-Bridging-Header.h"; sourceTree = ""; }; + BF090CF21B490D8300DCAB45 /* UIDevice+Vibration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIDevice+Vibration.h"; sourceTree = ""; }; + BF090CF31B490D8300DCAB45 /* UIDevice+Vibration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIDevice+Vibration.m"; sourceTree = ""; }; BF46894E1AAC46EF00A2586D /* DirectoryContentsDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DirectoryContentsDataSource.swift; sourceTree = ""; }; BF9F4FCE1AAD7B87004C9500 /* DeltaCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DeltaCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BFC134E01AAD82460087AD7B /* SNESDeltaCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SNESDeltaCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -69,6 +73,15 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + BF090CEE1B490C1A00DCAB45 /* Extensions */ = { + isa = PBXGroup; + children = ( + BF090CF21B490D8300DCAB45 /* UIDevice+Vibration.h */, + BF090CF31B490D8300DCAB45 /* UIDevice+Vibration.m */, + ); + name = Extensions; + sourceTree = ""; + }; BF46894D1AAC469800A2586D /* Game Selection */ = { isa = PBXGroup; children = ( @@ -120,6 +133,7 @@ BFFA71E01AAC406100EE9DD1 /* Main.storyboard */, BF46894D1AAC469800A2586D /* Game Selection */, BFFB709D1AF99ACA00DE56FE /* Emulation */, + BF090CEE1B490C1A00DCAB45 /* Extensions */, BFEC732F1AAECCBD00650035 /* Resources */, BFFA71DA1AAC406100EE9DD1 /* Supporting Files */, ); @@ -129,6 +143,7 @@ BFFA71DA1AAC406100EE9DD1 /* Supporting Files */ = { isa = PBXGroup; children = ( + BF090CF11B490D8300DCAB45 /* Delta-Bridging-Header.h */, BFFA71E51AAC406100EE9DD1 /* LaunchScreen.xib */, BFFA71DB1AAC406100EE9DD1 /* Info.plist */, ); @@ -221,6 +236,7 @@ BFFB709F1AF99B1700DE56FE /* EmulationViewController.swift in Sources */, BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */, BF46894F1AAC46EF00A2586D /* DirectoryContentsDataSource.swift in Sources */, + BF090CF41B490D8300DCAB45 /* UIDevice+Vibration.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -333,15 +349,15 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Delta-cubiloonxwcpqtawcqdjabbtttfl/Build/Products/Debug-iphoneos", - ); + CLANG_ENABLE_MODULES = YES; INFOPLIST_FILE = Delta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_CFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.rileytestut.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Delta/Delta-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; @@ -349,15 +365,14 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Delta-cubiloonxwcpqtawcqdjabbtttfl/Build/Products/Debug-iphoneos", - ); + CLANG_ENABLE_MODULES = YES; INFOPLIST_FILE = Delta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_CFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.rileytestut.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Delta/Delta-Bridging-Header.h"; }; name = Release; }; diff --git a/Delta/Delta-Bridging-Header.h b/Delta/Delta-Bridging-Header.h new file mode 100644 index 0000000..a65050d --- /dev/null +++ b/Delta/Delta-Bridging-Header.h @@ -0,0 +1,5 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#import "UIDevice+Vibration.h" \ No newline at end of file diff --git a/Delta/EmulationViewController.swift b/Delta/EmulationViewController.swift index 425f6cb..0bf5a31 100644 --- a/Delta/EmulationViewController.swift +++ b/Delta/EmulationViewController.swift @@ -7,21 +7,26 @@ // import UIKit + import DeltaCore -import SNESDeltaCore class EmulationViewController: UIViewController { + //MARK: - Properties - + /** Properties **/ let game: Game let emulatorCore: EmulatorCore @IBOutlet private(set) var controllerView: ControllerView! + //MARK: - Private Properties @IBOutlet private var controllerViewHeightConstraint: NSLayoutConstraint! + //MARK: - Initializers - + /** Initializers **/ required init(game: Game) { self.game = game - self.emulatorCore = SNESEmulatorCore(game: game) + self.emulatorCore = EmulatorCore(game: game) super.init(nibName: "EmulationViewController", bundle: nil) } @@ -30,18 +35,20 @@ class EmulationViewController: UIViewController fatalError("initWithCoder: not implemented.") } - //MARK: UIViewController + //MARK: - Overrides - + /** Overrides **/ + //MARK: - UIViewController + /// UIViewController override func viewDidLoad() { super.viewDidLoad() - let skinURL = self.game.URL.URLByDeletingLastPathComponent?.URLByAppendingPathComponent("Standard.deltaskin") - let controllerSkin = ControllerSkin(URL: skinURL!) + let controllerSkin = ControllerSkin.defaultControllerSkinForGameUTI(self.game.UTI) self.controllerView.controllerSkin = controllerSkin - - print(self.controllerView.intrinsicContentSize()) + self.controllerView.addReceiver(self) + self.emulatorCore.setGameController(self.controllerView, atIndex: 0) } override func viewDidAppear(animated: Bool) @@ -59,6 +66,12 @@ class EmulationViewController: UIViewController self.controllerViewHeightConstraint.constant = self.controllerView.intrinsicContentSize().height * scale } + override func prefersStatusBarHidden() -> Bool + { + return true + } + + /// override func willTransitionToTraitCollection(newCollection: UITraitCollection, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { super.willTransitionToTraitCollection(newCollection, withTransitionCoordinator: coordinator) @@ -69,9 +82,28 @@ class EmulationViewController: UIViewController self.controllerView.finishAnimatingUpdateControllerSkin() } } - - override func prefersStatusBarHidden() -> Bool +} + +//MARK: - - +/// +extension EmulationViewController: GameControllerReceiverType +{ + func gameController(gameController: GameControllerType, didActivateInput input: InputType) { - return true + if UIDevice.currentDevice().supportsVibration + { + UIDevice.currentDevice().vibrate() + } + + guard let input = input as? ControllerInput else { return } + + print("Activated \(input)") + } + + func gameController(gameController: GameControllerType, didDeactivateInput input: InputType) + { + guard let input = input as? ControllerInput else { return } + + print("Deactivated \(input)") } } diff --git a/Delta/UIDevice+Vibration.h b/Delta/UIDevice+Vibration.h new file mode 100644 index 0000000..d313447 --- /dev/null +++ b/Delta/UIDevice+Vibration.h @@ -0,0 +1,21 @@ +// +// UIDevice+Vibration.h +// Delta +// +// Created by Riley Testut on 7/5/15. +// Copyright © 2015 Riley Testut. All rights reserved. +// + +@import UIKit; + +NS_ASSUME_NONNULL_BEGIN + +@interface UIDevice (Vibration) + +@property (nonatomic, readonly, getter=isVibrationSupported) BOOL supportsVibration; + +- (void)vibrate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Delta/UIDevice+Vibration.m b/Delta/UIDevice+Vibration.m new file mode 100644 index 0000000..9a905b8 --- /dev/null +++ b/Delta/UIDevice+Vibration.m @@ -0,0 +1,78 @@ +// +// UIDevice+Vibration.m +// Delta +// +// Created by Riley Testut on 7/5/15. +// Copyright © 2015 Riley Testut. All rights reserved. +// + +#import "UIDevice+Vibration.h" + +#include + +@import AudioToolbox; + +// Private vibration API declarations +#if !APP_STORE_BUILD +void AudioServicesStopSystemSound(int); +void AudioServicesPlaySystemSoundWithVibration(int, id, NSDictionary *); +#endif + +@implementation UIDevice (Vibration) + +#pragma mark - Vibration - + +- (void)vibrate +{ +#if !APP_STORE_BUILD + AudioServicesStopSystemSound(kSystemSoundID_Vibrate); + + int64_t vibrationLength = 30; + + if ([[self modelGeneration] hasPrefix:@"iPhone6"]) + { + // iPhone 5S has a weaker vibration motor, so we vibrate for 10ms longer to compensate + vibrationLength = 40; + } + + NSArray *pattern = @[@NO, @0, @YES, @(vibrationLength)]; + + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + dictionary[@"VibePattern"] = pattern; + dictionary[@"Intensity"] = @1; + + AudioServicesPlaySystemSoundWithVibration(kSystemSoundID_Vibrate, nil, dictionary); +#endif +} + +#pragma mark - Device Info - + +- (NSString *)modelGeneration +{ + char *type = "hw.machine"; + + size_t size; + sysctlbyname(type, NULL, &size, NULL, 0); + + char *name = malloc(size); + sysctlbyname(type, name, &size, NULL, 0); + + NSString *modelName = [NSString stringWithCString:name encoding:NSUTF8StringEncoding]; + free(name); + + return modelName; +} + +#pragma mark - Getters/Setters - + +- (BOOL)isVibrationSupported +{ +#if APP_STORE_BUILD || TARGET_IPHONE_SIMULATOR + return NO; +#else + // No way to detect if hardware supports vibration, so we assume if it's not an iPhone, it doesn't have a vibration motor + return [self.model hasPrefix:@"iPhone"]; +#endif +} + +@end