diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj index 9a1143a21a5b..d8da520ed718 100644 --- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj +++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj @@ -386,7 +386,7 @@ CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"; DEVELOPMENT_TEAM = $team_id; INFOPLIST_FILE = "$binary/$binary-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -416,7 +416,7 @@ CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"; DEVELOPMENT_TEAM = $team_id; INFOPLIST_FILE = "$binary/$binary-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/modules/arkit/arkit_interface.h b/modules/arkit/arkit_interface.h index 5a2c50e2131e..29e09411ff1e 100644 --- a/modules/arkit/arkit_interface.h +++ b/modules/arkit/arkit_interface.h @@ -44,6 +44,15 @@ // forward declaration for some needed objects class ARKitShader; +#ifdef __OBJC__ + +typedef ARAnchor GodotARAnchor; + +#else + +typedef void GodotARAnchor; +#endif + class ARKitInterface : public XRInterface { GDCLASS(ARKitInterface, XRInterface); @@ -115,8 +124,8 @@ class ARKitInterface : public XRInterface { virtual void process() override; // called by delegate (void * because C++ and Obj-C don't always mix, should really change all platform/iphone/*.cpp files to .mm) - void _add_or_update_anchor(void *p_anchor); - void _remove_anchor(void *p_anchor); + void _add_or_update_anchor(GodotARAnchor *p_anchor); + void _remove_anchor(GodotARAnchor *p_anchor); ARKitInterface(); ~ARKitInterface(); diff --git a/modules/arkit/arkit_interface.mm b/modules/arkit/arkit_interface.mm index 3fb2cc933d2b..e8fa023ac7eb 100644 --- a/modules/arkit/arkit_interface.mm +++ b/modules/arkit/arkit_interface.mm @@ -306,12 +306,10 @@ remove_all_anchors(); if (@available(iOS 11.0, *)) { - [ar_session release]; - ar_session = NULL; + ar_session = nil; } - [ar_delegate release]; - ar_delegate = NULL; + ar_delegate = nil; initialized = false; session_was_started = false; } @@ -687,7 +685,7 @@ } } -void ARKitInterface::_add_or_update_anchor(void *p_anchor) { +void ARKitInterface::_add_or_update_anchor(GodotARAnchor *p_anchor) { // _THREAD_SAFE_METHOD_ if (@available(iOS 11.0, *)) { @@ -749,7 +747,7 @@ } } -void ARKitInterface::_remove_anchor(void *p_anchor) { +void ARKitInterface::_remove_anchor(GodotARAnchor *p_anchor) { // _THREAD_SAFE_METHOD_ if (@available(iOS 11.0, *)) { @@ -768,7 +766,7 @@ plane_detection_is_enabled = false; light_estimation_is_enabled = false; if (@available(iOS 11.0, *)) { - ar_session = NULL; + ar_session = nil; } z_near = 0.01; z_far = 1000.0; diff --git a/modules/camera/camera_ios.mm b/modules/camera/camera_ios.mm index c10b13b2afc9..e4cb92880504 100644 --- a/modules/camera/camera_ios.mm +++ b/modules/camera/camera_ios.mm @@ -124,18 +124,12 @@ - (void)cleanup { if (output) { [self removeOutput:output]; [output setSampleBufferDelegate:nil queue:NULL]; - [output release]; output = nil; } [self commitConfiguration]; } -- (void)dealloc { - // bye bye - [super dealloc]; -} - - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { // This gets called every time our camera has a new image for us to process. // May need to investigate in a way to throttle this if we get more images then we're rendering frames.. @@ -272,7 +266,6 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM void CameraFeedIOS::set_device(AVCaptureDevice *p_device) { device = p_device; - [device retain]; // get some info NSString *device_name = p_device.localizedName; @@ -286,14 +279,12 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM }; CameraFeedIOS::~CameraFeedIOS() { - if (capture_session != NULL) { - [capture_session release]; - capture_session = NULL; + if (capture_session) { + capture_session = nil; }; - if (device != NULL) { - [device release]; - device = NULL; + if (device) { + device = nil; }; }; @@ -312,8 +303,7 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM // end camera capture if we have one if (capture_session) { [capture_session cleanup]; - [capture_session release]; - capture_session = NULL; + capture_session = nil; }; }; @@ -347,8 +337,6 @@ - (void)dealloc { // remove notifications [[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceWasConnectedNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceWasDisconnectedNotification object:nil]; - - [super dealloc]; } @end @@ -453,5 +441,5 @@ - (void)dealloc { }; CameraIOS::~CameraIOS() { - [device_notifications release]; + device_notifications = nil; }; diff --git a/modules/mono/mono_gd/support/ios_support.mm b/modules/mono/mono_gd/support/ios_support.mm index e3d1a647fd28..dc23c06ebaaf 100644 --- a/modules/mono/mono_gd/support/ios_support.mm +++ b/modules/mono/mono_gd/support/ios_support.mm @@ -131,8 +131,7 @@ GD_PINVOKE_EXPORT void xamarin_log(const uint16_t *p_unicode_message) { NSTimeZone *tz = nil; if (p_name) { NSString *n = [[NSString alloc] initWithUTF8String:p_name]; - tz = [[[NSTimeZone alloc] initWithName:n] autorelease]; - [n release]; + tz = [[NSTimeZone alloc] initWithName:n]; } else { tz = [NSTimeZone localTimeZone]; } diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub index 848fd9713a7b..1dd37dabe579 100644 --- a/platform/iphone/SCsub +++ b/platform/iphone/SCsub @@ -19,6 +19,8 @@ iphone_lib = [ "display_layer.mm", "godot_view_renderer.mm", "godot_view_gesture_recognizer.mm", + "device_metrics.m", + "native_video_view.m", ] env_ios = env.Clone() diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm index 7edbcc4667df..40a63d7ad2b6 100644 --- a/platform/iphone/app_delegate.mm +++ b/platform/iphone/app_delegate.mm @@ -62,7 +62,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( CGRect windowBounds = [[UIScreen mainScreen] bounds]; // Create a full-screen window - self.window = [[[UIWindow alloc] initWithFrame:windowBounds] autorelease]; + self.window = [[UIWindow alloc] initWithFrame:windowBounds]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; @@ -140,7 +140,6 @@ - (void)applicationDidBecomeActive:(UIApplication *)application { - (void)dealloc { self.window = nil; - [super dealloc]; } @end diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index 66579c1ad770..5ebabdd3dcfc 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -129,7 +129,7 @@ def configure(env): detect_darwin_sdk_path("iphone", env) env.Append( CCFLAGS=( - "-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing" + "-fobjc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing" " -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits" " -fpascal-strings -fblocks -isysroot $IPHONESDK -fvisibility=hidden -mthumb" ' "-DIBOutlet=__attribute__((iboutlet))"' @@ -141,7 +141,7 @@ def configure(env): detect_darwin_sdk_path("iphone", env) env.Append( CCFLAGS=( - "-fno-objc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing" + "-fobjc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing" " -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits" " -fpascal-strings -fblocks -fvisibility=hidden -MMD -MT dependencies -miphoneos-version-min=11.0" " -isysroot $IPHONESDK".split() diff --git a/platform/iphone/device_metrics.h b/platform/iphone/device_metrics.h new file mode 100644 index 000000000000..6d0ff49077dd --- /dev/null +++ b/platform/iphone/device_metrics.h @@ -0,0 +1,37 @@ +/*************************************************************************/ +/* device_metrics.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#import + +@interface GodotDeviceMetrics : NSObject + +@property(nonatomic, class, readonly, strong) NSDictionary *dpiList; + +@end diff --git a/platform/iphone/device_metrics.m b/platform/iphone/device_metrics.m new file mode 100644 index 000000000000..747872bc490d --- /dev/null +++ b/platform/iphone/device_metrics.m @@ -0,0 +1,152 @@ +/*************************************************************************/ +/* device_metrics.m */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#import "device_metrics.h" + +@implementation GodotDeviceMetrics + ++ (NSDictionary *)dpiList { + return @{ + @[ + @"iPad1,1", + @"iPad2,1", + @"iPad2,2", + @"iPad2,3", + @"iPad2,4", + ] : @132, + @[ + @"iPhone1,1", + @"iPhone1,2", + @"iPhone2,1", + @"iPad2,5", + @"iPad2,6", + @"iPad2,7", + @"iPod1,1", + @"iPod2,1", + @"iPod3,1", + ] : @163, + @[ + @"iPad3,1", + @"iPad3,2", + @"iPad3,3", + @"iPad3,4", + @"iPad3,5", + @"iPad3,6", + @"iPad4,1", + @"iPad4,2", + @"iPad4,3", + @"iPad5,3", + @"iPad5,4", + @"iPad6,3", + @"iPad6,4", + @"iPad6,7", + @"iPad6,8", + @"iPad6,11", + @"iPad6,12", + @"iPad7,1", + @"iPad7,2", + @"iPad7,3", + @"iPad7,4", + @"iPad7,5", + @"iPad7,6", + @"iPad7,11", + @"iPad7,12", + @"iPad8,1", + @"iPad8,2", + @"iPad8,3", + @"iPad8,4", + @"iPad8,5", + @"iPad8,6", + @"iPad8,7", + @"iPad8,8", + @"iPad8,9", + @"iPad8,10", + @"iPad8,11", + @"iPad8,12", + @"iPad11,3", + @"iPad11,4", + ] : @264, + @[ + @"iPhone3,1", + @"iPhone3,2", + @"iPhone3,3", + @"iPhone4,1", + @"iPhone5,1", + @"iPhone5,2", + @"iPhone5,3", + @"iPhone5,4", + @"iPhone6,1", + @"iPhone6,2", + @"iPhone7,2", + @"iPhone8,1", + @"iPhone8,4", + @"iPhone9,1", + @"iPhone9,3", + @"iPhone10,1", + @"iPhone10,4", + @"iPhone11,8", + @"iPhone12,1", + @"iPhone12,8", + @"iPad4,4", + @"iPad4,5", + @"iPad4,6", + @"iPad4,7", + @"iPad4,8", + @"iPad4,9", + @"iPad5,1", + @"iPad5,2", + @"iPad11,1", + @"iPad11,2", + @"iPod4,1", + @"iPod5,1", + @"iPod7,1", + @"iPod9,1", + ] : @326, + @[ + @"iPhone7,1", + @"iPhone8,2", + @"iPhone9,2", + @"iPhone9,4", + @"iPhone10,2", + @"iPhone10,5", + ] : @401, + @[ + @"iPhone10,3", + @"iPhone10,6", + @"iPhone11,2", + @"iPhone11,4", + @"iPhone11,6", + @"iPhone12,3", + @"iPhone12,5", + ] : @458, + }; +} + +@end diff --git a/platform/iphone/display_layer.mm b/platform/iphone/display_layer.mm index 5ec94fb47168..2716538b89be 100644 --- a/platform/iphone/display_layer.mm +++ b/platform/iphone/display_layer.mm @@ -124,11 +124,8 @@ - (void)dealloc { } if (context) { - [context release]; context = nil; } - - [super dealloc]; } - (BOOL)createFramebuffer { diff --git a/platform/iphone/display_server_iphone.mm b/platform/iphone/display_server_iphone.mm index eea87cecc922..d456f9cbf6ec 100644 --- a/platform/iphone/display_server_iphone.mm +++ b/platform/iphone/display_server_iphone.mm @@ -32,8 +32,10 @@ #import "app_delegate.h" #include "core/io/file_access_pack.h" #include "core/project_settings.h" +#import "device_metrics.h" #import "godot_view.h" #include "ios.h" +#import "native_video_view.h" #include "os_iphone.h" #import "view_controller.h" @@ -41,120 +43,6 @@ #import static const float kDisplayServerIPhoneAcceleration = 1; -static NSDictionary *iOSModelToDPI = @{ - @[ - @"iPad1,1", - @"iPad2,1", - @"iPad2,2", - @"iPad2,3", - @"iPad2,4", - ] : @132, - @[ - @"iPhone1,1", - @"iPhone1,2", - @"iPhone2,1", - @"iPad2,5", - @"iPad2,6", - @"iPad2,7", - @"iPod1,1", - @"iPod2,1", - @"iPod3,1", - ] : @163, - @[ - @"iPad3,1", - @"iPad3,2", - @"iPad3,3", - @"iPad3,4", - @"iPad3,5", - @"iPad3,6", - @"iPad4,1", - @"iPad4,2", - @"iPad4,3", - @"iPad5,3", - @"iPad5,4", - @"iPad6,3", - @"iPad6,4", - @"iPad6,7", - @"iPad6,8", - @"iPad6,11", - @"iPad6,12", - @"iPad7,1", - @"iPad7,2", - @"iPad7,3", - @"iPad7,4", - @"iPad7,5", - @"iPad7,6", - @"iPad7,11", - @"iPad7,12", - @"iPad8,1", - @"iPad8,2", - @"iPad8,3", - @"iPad8,4", - @"iPad8,5", - @"iPad8,6", - @"iPad8,7", - @"iPad8,8", - @"iPad8,9", - @"iPad8,10", - @"iPad8,11", - @"iPad8,12", - @"iPad11,3", - @"iPad11,4", - ] : @264, - @[ - @"iPhone3,1", - @"iPhone3,2", - @"iPhone3,3", - @"iPhone4,1", - @"iPhone5,1", - @"iPhone5,2", - @"iPhone5,3", - @"iPhone5,4", - @"iPhone6,1", - @"iPhone6,2", - @"iPhone7,2", - @"iPhone8,1", - @"iPhone8,4", - @"iPhone9,1", - @"iPhone9,3", - @"iPhone10,1", - @"iPhone10,4", - @"iPhone11,8", - @"iPhone12,1", - @"iPhone12,8", - @"iPad4,4", - @"iPad4,5", - @"iPad4,6", - @"iPad4,7", - @"iPad4,8", - @"iPad4,9", - @"iPad5,1", - @"iPad5,2", - @"iPad11,1", - @"iPad11,2", - @"iPod4,1", - @"iPod5,1", - @"iPod7,1", - @"iPod9,1", - ] : @326, - @[ - @"iPhone7,1", - @"iPhone8,2", - @"iPhone9,2", - @"iPhone9,4", - @"iPhone10,2", - @"iPhone10,5", - ] : @401, - @[ - @"iPhone10,3", - @"iPhone10,6", - @"iPhone11,2", - @"iPhone11,4", - @"iPhone11,6", - @"iPhone12,3", - @"iPhone12,5", - ] : @458, -}; DisplayServerIPhone *DisplayServerIPhone::get_singleton() { return (DisplayServerIPhone *)DisplayServer::get_singleton(); @@ -383,8 +271,7 @@ Input::get_singleton()->set_gravity(Vector3(p_x, p_y, p_z)); }; -void DisplayServerIPhone::update_accelerometer(float p_x, float p_y, - float p_z) { +void DisplayServerIPhone::update_accelerometer(float p_x, float p_y, float p_z) { // Found out the Z should not be negated! Pass as is! Vector3 v_accelerometer = Vector3( p_x / kDisplayServerIPhoneAcceleration, @@ -392,39 +279,6 @@ p_z / kDisplayServerIPhoneAcceleration); Input::get_singleton()->set_accelerometer(v_accelerometer); - - /* - if (p_x != last_accel.x) { - //printf("updating accel x %f\n", p_x); - InputEvent ev; - ev.type = InputEvent::JOYPAD_MOTION; - ev.device = 0; - ev.joy_motion.axis = JOY_ANALOG_0; - ev.joy_motion.axis_value = (p_x / (float)ACCEL_RANGE); - last_accel.x = p_x; - queue_event(ev); - }; - if (p_y != last_accel.y) { - //printf("updating accel y %f\n", p_y); - InputEvent ev; - ev.type = InputEvent::JOYPAD_MOTION; - ev.device = 0; - ev.joy_motion.axis = JOY_ANALOG_1; - ev.joy_motion.axis_value = (p_y / (float)ACCEL_RANGE); - last_accel.y = p_y; - queue_event(ev); - }; - if (p_z != last_accel.z) { - //printf("updating accel z %f\n", p_z); - InputEvent ev; - ev.type = InputEvent::JOYPAD_MOTION; - ev.device = 0; - ev.joy_motion.axis = JOY_ANALOG_2; - ev.joy_motion.axis_value = ( (1.0 - p_z) / (float)ACCEL_RANGE); - last_accel.z = p_z; - queue_event(ev); - }; - */ }; void DisplayServerIPhone::update_magnetometer(float p_x, float p_y, float p_z) { @@ -516,6 +370,8 @@ NSString *string = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; + NSDictionary *iOSModelToDPI = [GodotDeviceMetrics dpiList]; + for (NSArray *keyArray in iOSModelToDPI) { if ([keyArray containsObject:string]) { NSNumber *value = iOSModelToDPI[keyArray]; @@ -523,7 +379,26 @@ } } - return 163; + // If device wasn't found in dictionary + // make a best guess from device metrics. + CGFloat scale = [UIScreen mainScreen].scale; + + UIUserInterfaceIdiom idiom = [UIDevice currentDevice].userInterfaceIdiom; + + switch (idiom) { + case UIUserInterfaceIdiomPad: + return scale == 2 ? 264 : 132; + case UIUserInterfaceIdiomPhone: { + if (scale == 3) { + CGFloat nativeScale = [UIScreen mainScreen].nativeScale; + return nativeScale == 3 ? 458 : 401; + } + + return 326; + } + default: + return 72; + } } float DisplayServerIPhone::screen_get_scale(int p_screen) const { @@ -716,7 +591,7 @@ String file_path = ProjectSettings::get_singleton()->globalize_path(p_path); - NSString *filePath = [[[NSString alloc] initWithUTF8String:file_path.utf8().get_data()] autorelease]; + NSString *filePath = [[NSString alloc] initWithUTF8String:file_path.utf8().get_data()]; NSString *audioTrack = [NSString stringWithUTF8String:p_audio_track.utf8()]; NSString *subtitleTrack = [NSString stringWithUTF8String:p_subtitle_track.utf8()]; @@ -731,22 +606,22 @@ } bool DisplayServerIPhone::native_video_is_playing() const { - return [AppDelegate.viewController isVideoPlaying]; + return [AppDelegate.viewController.videoView isVideoPlaying]; } void DisplayServerIPhone::native_video_pause() { if (native_video_is_playing()) { - [AppDelegate.viewController pauseVideo]; + [AppDelegate.viewController.videoView pauseVideo]; } } void DisplayServerIPhone::native_video_unpause() { - [AppDelegate.viewController unpauseVideo]; + [AppDelegate.viewController.videoView unpauseVideo]; }; void DisplayServerIPhone::native_video_stop() { if (native_video_is_playing()) { - [AppDelegate.viewController stopVideo]; + [AppDelegate.viewController.videoView stopVideo]; } } diff --git a/platform/iphone/game_center.mm b/platform/iphone/game_center.mm index b237ba6bb62c..0f8c0100c3bc 100644 --- a/platform/iphone/game_center.mm +++ b/platform/iphone/game_center.mm @@ -83,7 +83,12 @@ // after the view is cancelled or the user logs in. Or if the user's already logged in, it's // called just once to confirm they're authenticated. This is why no result needs to be specified // in the presentViewController phase. In this case, more calls to this function will follow. + _weakify(root_controller); + _weakify(player); player.authenticateHandler = (^(UIViewController *controller, NSError *error) { + _strongify(root_controller); + _strongify(player); + if (controller) { [root_controller presentViewController:controller animated:YES completion:nil]; } else { @@ -123,8 +128,8 @@ float score = p_score["score"]; String category = p_score["category"]; - NSString *cat_str = [[[NSString alloc] initWithUTF8String:category.utf8().get_data()] autorelease]; - GKScore *reporter = [[[GKScore alloc] initWithLeaderboardIdentifier:cat_str] autorelease]; + NSString *cat_str = [[NSString alloc] initWithUTF8String:category.utf8().get_data()]; + GKScore *reporter = [[GKScore alloc] initWithLeaderboardIdentifier:cat_str]; reporter.value = score; ERR_FAIL_COND_V([GKScore respondsToSelector:@selector(reportScores)], ERR_UNAVAILABLE); @@ -152,8 +157,8 @@ String name = p_params["name"]; float progress = p_params["progress"]; - NSString *name_str = [[[NSString alloc] initWithUTF8String:name.utf8().get_data()] autorelease]; - GKAchievement *achievement = [[[GKAchievement alloc] initWithIdentifier:name_str] autorelease]; + NSString *name_str = [[NSString alloc] initWithUTF8String:name.utf8().get_data()]; + GKAchievement *achievement = [[GKAchievement alloc] initWithIdentifier:name_str]; ERR_FAIL_COND_V(!achievement, FAILED); ERR_FAIL_COND_V([GKAchievement respondsToSelector:@selector(reportAchievements)], ERR_UNAVAILABLE); @@ -297,7 +302,7 @@ } } - GKGameCenterViewController *controller = [[[GKGameCenterViewController alloc] init] autorelease]; + GKGameCenterViewController *controller = [[GKGameCenterViewController alloc] init]; ERR_FAIL_COND_V(!controller, FAILED); ViewController *root_controller = (ViewController *)((AppDelegate *)[[UIApplication sharedApplication] delegate]).window.rootViewController; @@ -309,7 +314,7 @@ controller.leaderboardIdentifier = nil; if (p_params.has("leaderboard_name")) { String name = p_params["leaderboard_name"]; - NSString *name_str = [[[NSString alloc] initWithUTF8String:name.utf8().get_data()] autorelease]; + NSString *name_str = [[NSString alloc] initWithUTF8String:name.utf8().get_data()]; controller.leaderboardIdentifier = name_str; } } diff --git a/platform/iphone/godot_iphone.mm b/platform/iphone/godot_iphone.mm index 090b77294791..6d95276f379a 100644 --- a/platform/iphone/godot_iphone.mm +++ b/platform/iphone/godot_iphone.mm @@ -49,10 +49,8 @@ int add_path(int p_argc, char **p_args) { } p_args[p_argc++] = (char *)"--path"; - [str retain]; // memory leak lol (maybe make it static here and delete it in ViewController destructor? @todo p_args[p_argc++] = (char *)[str cStringUsingEncoding:NSUTF8StringEncoding]; p_args[p_argc] = NULL; - [str release]; return p_argc; }; @@ -68,9 +66,7 @@ int add_cmdline(int p_argc, char **p_args) { if (!str) { continue; } - [str retain]; // @todo delete these at some point p_args[p_argc++] = (char *)[str cStringUsingEncoding:NSUTF8StringEncoding]; - [str release]; }; p_args[p_argc] = NULL; diff --git a/platform/iphone/godot_view.mm b/platform/iphone/godot_view.mm index c0a31549c4ac..3b4344c46dbb 100644 --- a/platform/iphone/godot_view.mm +++ b/platform/iphone/godot_view.mm @@ -145,8 +145,6 @@ - (void)dealloc { if (self.delayGestureRecognizer) { self.delayGestureRecognizer = nil; } - - [super dealloc]; } - (void)godot_commonInit { @@ -156,7 +154,7 @@ - (void)godot_commonInit { // Configure and start accelerometer if (!self.motionManager) { - self.motionManager = [[[CMMotionManager alloc] init] autorelease]; + self.motionManager = [[CMMotionManager alloc] init]; if (self.motionManager.deviceMotionAvailable) { self.motionManager.deviceMotionUpdateInterval = 1.0 / 70.0; [self.motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXMagneticNorthZVertical]; @@ -169,7 +167,6 @@ - (void)godot_commonInit { GodotViewGestureRecognizer *gestureRecognizer = [[GodotViewGestureRecognizer alloc] init]; self.delayGestureRecognizer = gestureRecognizer; [self addGestureRecognizer:self.delayGestureRecognizer]; - [gestureRecognizer release]; } - (void)stopRendering { @@ -204,14 +201,11 @@ - (void)startRendering { if (self.useCADisplayLink) { self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawView)]; - // if (@available(iOS 10, *)) { - self.displayLink.preferredFramesPerSecond = (NSInteger)(1.0 / self.renderingInterval); - // } else { - // // Approximate frame rate - // // assumes device refreshes at 60 fps - // int frameInterval = (int)floor(self.renderingInterval * 60.0f); - // [self.displayLink setFrameInterval:frameInterval]; - // } + // Approximate frame rate + // assumes device refreshes at 60 fps + int displayFPS = (NSInteger)(1.0 / self.renderingInterval); + + self.displayLink.preferredFramesPerSecond = displayFPS; // Setup DisplayLink in main thread [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; diff --git a/platform/iphone/godot_view_gesture_recognizer.mm b/platform/iphone/godot_view_gesture_recognizer.mm index 99ee42ecb317..71367a629c17 100644 --- a/platform/iphone/godot_view_gesture_recognizer.mm +++ b/platform/iphone/godot_view_gesture_recognizer.mm @@ -83,8 +83,6 @@ - (void)dealloc { if (self.delayedEvent) { self.delayedEvent = nil; } - - [super dealloc]; } - (void)delayTouches:(NSSet *)touches andEvent:(UIEvent *)event { @@ -116,7 +114,6 @@ - (void)fireDelayedTouches:(id)timer { - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSSet *cleared = [self copyClearedTouches:touches phase:UITouchPhaseBegan]; [self delayTouches:cleared andEvent:event]; - [cleared release]; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { @@ -137,17 +134,14 @@ - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { if (distance > kGLGestureMovementDistance) { [self.delayTimer fire]; [self.view touchesMoved:cleared withEvent:event]; - [cleared release]; return; } } - [cleared release]; return; } [self.view touchesMoved:cleared withEvent:event]; - [cleared release]; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { @@ -155,7 +149,6 @@ - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { NSSet *cleared = [self copyClearedTouches:touches phase:UITouchPhaseEnded]; [self.view touchesEnded:cleared withEvent:event]; - [cleared release]; } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { diff --git a/platform/iphone/icloud.mm b/platform/iphone/icloud.mm index d3086e6cea03..3d8134988347 100644 --- a/platform/iphone/icloud.mm +++ b/platform/iphone/icloud.mm @@ -150,7 +150,7 @@ Variant nsobject_to_variant(NSObject *object) { NSObject *variant_to_nsobject(Variant v) { if (v.get_type() == Variant::STRING) { - return [[[NSString alloc] initWithUTF8String:((String)v).utf8().get_data()] autorelease]; + return [[NSString alloc] initWithUTF8String:((String)v).utf8().get_data()]; } else if (v.get_type() == Variant::FLOAT) { return [NSNumber numberWithDouble:(double)v]; } else if (v.get_type() == Variant::INT) { @@ -158,11 +158,11 @@ Variant nsobject_to_variant(NSObject *object) { } else if (v.get_type() == Variant::BOOL) { return [NSNumber numberWithBool:BOOL((bool)v)]; } else if (v.get_type() == Variant::DICTIONARY) { - NSMutableDictionary *result = [[[NSMutableDictionary alloc] init] autorelease]; + NSMutableDictionary *result = [[NSMutableDictionary alloc] init]; Dictionary dic = v; Array keys = dic.keys(); for (int i = 0; i < keys.size(); ++i) { - NSString *key = [[[NSString alloc] initWithUTF8String:((String)(keys[i])).utf8().get_data()] autorelease]; + NSString *key = [[NSString alloc] initWithUTF8String:((String)(keys[i])).utf8().get_data()]; NSObject *value = variant_to_nsobject(dic[keys[i]]); if (key == NULL || value == NULL) { @@ -173,7 +173,7 @@ Variant nsobject_to_variant(NSObject *object) { } return result; } else if (v.get_type() == Variant::ARRAY) { - NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease]; + NSMutableArray *result = [[NSMutableArray alloc] init]; Array arr = v; for (int i = 0; i < arr.size(); ++i) { NSObject *value = variant_to_nsobject(arr[i]); @@ -195,7 +195,7 @@ Variant nsobject_to_variant(NSObject *object) { } Error ICloud::remove_key(String p_param) { - NSString *key = [[[NSString alloc] initWithUTF8String:p_param.utf8().get_data()] autorelease]; + NSString *key = [[NSString alloc] initWithUTF8String:p_param.utf8().get_data()]; NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore]; @@ -217,7 +217,7 @@ Variant nsobject_to_variant(NSObject *object) { String variant_key = keys[i]; Variant variant_value = p_params[variant_key]; - NSString *key = [[[NSString alloc] initWithUTF8String:variant_key.utf8().get_data()] autorelease]; + NSString *key = [[NSString alloc] initWithUTF8String:variant_key.utf8().get_data()]; if (key == NULL) { error_keys.push_back(variant_key); continue; @@ -238,7 +238,7 @@ Variant nsobject_to_variant(NSObject *object) { } Variant ICloud::get_key_value(String p_param) { - NSString *key = [[[NSString alloc] initWithUTF8String:p_param.utf8().get_data()] autorelease]; + NSString *key = [[NSString alloc] initWithUTF8String:p_param.utf8().get_data()]; NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore]; if (![[store dictionaryRepresentation] objectForKey:key]) { diff --git a/platform/iphone/in_app_store.mm b/platform/iphone/in_app_store.mm index 1477f92200a4..2b973dfbcf3f 100644 --- a/platform/iphone/in_app_store.mm +++ b/platform/iphone/in_app_store.mm @@ -56,7 +56,6 @@ - (NSString *)localizedPrice { [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; [numberFormatter setLocale:self.priceLocale]; NSString *formattedString = [numberFormatter stringFromNumber:self.price]; - [numberFormatter release]; return formattedString; } @@ -124,8 +123,6 @@ - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProdu ret["invalid_ids"] = invalid_ids; InAppStore::get_singleton()->_post_event(ret); - - [request release]; }; @end @@ -136,14 +133,14 @@ - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProdu PackedStringArray pids = p_params["product_ids"]; printf("************ request product info! %i\n", pids.size()); - NSMutableArray *array = [[[NSMutableArray alloc] initWithCapacity:pids.size()] autorelease]; + NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:pids.size()]; for (int i = 0; i < pids.size(); i++) { printf("******** adding %s to product list\n", pids[i].utf8().get_data()); - NSString *pid = [[[NSString alloc] initWithUTF8String:pids[i].utf8().get_data()] autorelease]; + NSString *pid = [[NSString alloc] initWithUTF8String:pids[i].utf8().get_data()]; [array addObject:pid]; }; - NSSet *products = [[[NSSet alloc] initWithArray:array] autorelease]; + NSSet *products = [[NSSet alloc] initWithArray:array]; SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:products]; ProductsDelegate *delegate = [[ProductsDelegate alloc] init]; @@ -183,30 +180,14 @@ - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)tran ret["transaction_id"] = transactionId; NSData *receipt = nil; - int sdk_version = 6; - - if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) { - NSURL *receiptFileURL = nil; - NSBundle *bundle = [NSBundle mainBundle]; - if ([bundle respondsToSelector:@selector(appStoreReceiptURL)]) { - // Get the transaction receipt file path location in the app bundle. - receiptFileURL = [bundle appStoreReceiptURL]; - - // Read in the contents of the transaction file. - receipt = [NSData dataWithContentsOfURL:receiptFileURL]; - sdk_version = 7; + int sdk_version = [[[UIDevice currentDevice] systemVersion] intValue]; - } else { - // Fall back to deprecated transaction receipt, - // which is still available in iOS 7. + NSBundle *bundle = [NSBundle mainBundle]; + // Get the transaction receipt file path location in the app bundle. + NSURL *receiptFileURL = [bundle appStoreReceiptURL]; - // Use SKPaymentTransaction's transactionReceipt. - receipt = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]]; - } - - } else { - receipt = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]]; - } + // Read in the contents of the transaction file. + receipt = [NSData dataWithContentsOfURL:receiptFileURL]; NSString *receipt_to_send = nil; if (receipt != nil) { @@ -265,7 +246,7 @@ - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)tran printf("purchasing!\n"); ERR_FAIL_COND_V(!p_params.has("product_id"), ERR_INVALID_PARAMETER); - NSString *pid = [[[NSString alloc] initWithUTF8String:String(p_params["product_id"]).utf8().get_data()] autorelease]; + NSString *pid = [[NSString alloc] initWithUTF8String:String(p_params["product_id"]).utf8().get_data()]; SKProduct *product = nil; @@ -307,7 +288,7 @@ - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)tran void InAppStore::_record_purchase(String product_id) { String skey = "purchased/" + product_id; - NSString *key = [[[NSString alloc] initWithUTF8String:skey.utf8().get_data()] autorelease]; + NSString *key = [[NSString alloc] initWithUTF8String:skey.utf8().get_data()]; [[NSUserDefaults standardUserDefaults] setBool:YES forKey:key]; [[NSUserDefaults standardUserDefaults] synchronize]; }; diff --git a/platform/iphone/ios.mm b/platform/iphone/ios.mm index 6d7699c0c946..d4e099063f24 100644 --- a/platform/iphone/ios.mm +++ b/platform/iphone/ios.mm @@ -30,6 +30,7 @@ #include "ios.h" #import "app_delegate.h" +#import "view_controller.h" #import #include @@ -68,23 +69,9 @@ } String iOS::get_rate_url(int p_app_id) const { - String templ = "itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=APP_ID"; - String templ_iOS7 = "itms-apps://itunes.apple.com/app/idAPP_ID"; - String templ_iOS8 = "itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?id=APP_ID&onlyLatestVersion=true&pageNumber=0&sortOrdering=1&type=Purple+Software"; + String app_url_path = "itms-apps://itunes.apple.com/app/idAPP_ID"; - //ios7 before - String ret = templ; - - if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0 && [[[UIDevice currentDevice] systemVersion] floatValue] < 7.1) { - // iOS 7 needs a different templateReviewURL @see https://github.com/arashpayan/appirater/issues/131 - ret = templ_iOS7; - } else if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) { - // iOS 8 needs a different templateReviewURL also @see https://github.com/arashpayan/appirater/issues/182 - ret = templ_iOS8; - } - - // ios7 for everything? - ret = templ_iOS7.replace("APP_ID", String::num(p_app_id)); + String ret = app_url_path.replace("APP_ID", String::num(p_app_id)); printf("returning rate url %s\n", ret.utf8().get_data()); return ret; diff --git a/platform/iphone/joypad_iphone.mm b/platform/iphone/joypad_iphone.mm index 6088f1c25c18..b0a8076b5677 100644 --- a/platform/iphone/joypad_iphone.mm +++ b/platform/iphone/joypad_iphone.mm @@ -131,8 +131,6 @@ - (void)finishObserving { - (void)dealloc { [self finishObserving]; - - [super dealloc]; } - (int)getJoyIdForController:(GCController *)controller { @@ -251,8 +249,13 @@ - (void)setControllerInputHandler:(GCController *)controller { // The extended gamepad profile has all the input you could possibly find on // a gamepad but will only be active if your gamepad actually has all of // these... - controller.extendedGamepad.valueChangedHandler = ^( - GCExtendedGamepad *gamepad, GCControllerElement *element) { + _weakify(self); + _weakify(controller); + + controller.extendedGamepad.valueChangedHandler = ^(GCExtendedGamepad *gamepad, GCControllerElement *element) { + _strongify(self); + _strongify(controller); + int joy_id = [self getJoyIdForController:controller]; if (element == gamepad.buttonA) { @@ -304,71 +307,33 @@ - (void)setControllerInputHandler:(GCController *)controller { Input::get_singleton()->joy_axis(joy_id, JOY_AXIS_TRIGGER_RIGHT, jx); }; }; + } else if (controller.microGamepad != nil) { + // micro gamepads were added in OS 9 and feature just 2 buttons and a d-pad + _weakify(self); + _weakify(controller); + + controller.microGamepad.valueChangedHandler = ^(GCMicroGamepad *gamepad, GCControllerElement *element) { + _strongify(self); + _strongify(controller); + + int joy_id = [self getJoyIdForController:controller]; + + if (element == gamepad.buttonA) { + Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_A, + gamepad.buttonA.isPressed); + } else if (element == gamepad.buttonX) { + Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_X, + gamepad.buttonX.isPressed); + } else if (element == gamepad.dpad) { + Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_UP, + gamepad.dpad.up.isPressed); + Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_DOWN, + gamepad.dpad.down.isPressed); + Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_LEFT, gamepad.dpad.left.isPressed); + Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_RIGHT, gamepad.dpad.right.isPressed); + }; + }; } - // else if (controller.gamepad != nil) { - // // gamepad is the standard profile with 4 buttons, shoulder buttons and a - // // D-pad - // controller.gamepad.valueChangedHandler = ^(GCGamepad *gamepad, - // GCControllerElement *element) { - // int joy_id = [self getJoyIdForController:controller]; - // - // if (element == gamepad.buttonA) { - // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_A, - // gamepad.buttonA.isPressed); - // } else if (element == gamepad.buttonB) { - // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_B, - // gamepad.buttonB.isPressed); - // } else if (element == gamepad.buttonX) { - // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_X, - // gamepad.buttonX.isPressed); - // } else if (element == gamepad.buttonY) { - // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_Y, - // gamepad.buttonY.isPressed); - // } else if (element == gamepad.leftShoulder) { - // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_LEFT_SHOULDER, - // gamepad.leftShoulder.isPressed); - // } else if (element == gamepad.rightShoulder) { - // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_RIGHT_SHOULDER, - // gamepad.rightShoulder.isPressed); - // } else if (element == gamepad.dpad) { - // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_UP, - // gamepad.dpad.up.isPressed); - // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_DOWN, - // gamepad.dpad.down.isPressed); - // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_LEFT, - // gamepad.dpad.left.isPressed); - // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_RIGHT, - // gamepad.dpad.right.isPressed); - // }; - // }; - //#ifdef ADD_MICRO_GAMEPAD // disabling this for now, only available on iOS 9+, - // // while we are setting that as the minimum, seems our - // // build environment doesn't like it - // } else if (controller.microGamepad != nil) { - // // micro gamepads were added in OS 9 and feature just 2 buttons and a d-pad - // controller.microGamepad.valueChangedHandler = - // ^(GCMicroGamepad *gamepad, GCControllerElement *element) { - // int joy_id = [self getJoyIdForController:controller]; - // - // if (element == gamepad.buttonA) { - // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_A, - // gamepad.buttonA.isPressed); - // } else if (element == gamepad.buttonX) { - // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_X, - // gamepad.buttonX.isPressed); - // } else if (element == gamepad.dpad) { - // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_UP, - // gamepad.dpad.up.isPressed); - // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_DOWN, - // gamepad.dpad.down.isPressed); - // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_LEFT, - // gamepad.dpad.left.isPressed); - // Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_RIGHT, - // gamepad.dpad.right.isPressed); - // }; - // }; - //#endif - // }; ///@TODO need to add support for controller.motion which gives us access to /// the orientation of the device (if supported) diff --git a/platform/iphone/native_video_view.h b/platform/iphone/native_video_view.h new file mode 100644 index 000000000000..d8687b35383f --- /dev/null +++ b/platform/iphone/native_video_view.h @@ -0,0 +1,41 @@ +/*************************************************************************/ +/* native_video_view.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#import + +@interface GodotNativeVideoView : UIView + +- (BOOL)playVideoAtPath:(NSString *)filePath volume:(float)videoVolume audio:(NSString *)audioTrack subtitle:(NSString *)subtitleTrack; +- (BOOL)isVideoPlaying; +- (void)pauseVideo; +- (void)unpauseVideo; +- (void)stopVideo; + +@end diff --git a/platform/iphone/native_video_view.m b/platform/iphone/native_video_view.m new file mode 100644 index 000000000000..a4e9f209f082 --- /dev/null +++ b/platform/iphone/native_video_view.m @@ -0,0 +1,260 @@ +/*************************************************************************/ +/* native_video_view.m */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#import "native_video_view.h" +#import + +@interface GodotNativeVideoView () + +@property(strong, nonatomic) AVAsset *avAsset; +@property(strong, nonatomic) AVPlayerItem *avPlayerItem; +@property(strong, nonatomic) AVPlayer *avPlayer; +@property(strong, nonatomic) AVPlayerLayer *avPlayerLayer; +@property(assign, nonatomic) CMTime videoCurrentTime; +@property(assign, nonatomic) BOOL isVideoCurrentlyPlaying; + +@end + +@implementation GodotNativeVideoView + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + + if (self) { + [self godot_commonInit]; + } + + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + + if (self) { + [self godot_commonInit]; + } + + return self; +} + +- (void)godot_commonInit { + self.isVideoCurrentlyPlaying = NO; + self.videoCurrentTime = kCMTimeZero; + + [self observeVideoAudio]; +} + +- (void)observeVideoAudio { + printf("******** adding observer for sound routing changes\n"); + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(audioRouteChangeListenerCallback:) + name:AVAudioSessionRouteChangeNotification + object:nil]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + if (object == self.avPlayerItem && [keyPath isEqualToString:@"status"]) { + [self handleVideoOrPlayerStatus]; + } + + if (object == self.avPlayer && [keyPath isEqualToString:@"rate"]) { + [self handleVideoPlayRate]; + } +} + +// MARK: Video Audio + +- (void)audioRouteChangeListenerCallback:(NSNotification *)notification { + printf("*********** route changed!\n"); + NSDictionary *interuptionDict = notification.userInfo; + + NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue]; + + switch (routeChangeReason) { + case AVAudioSessionRouteChangeReasonNewDeviceAvailable: { + NSLog(@"AVAudioSessionRouteChangeReasonNewDeviceAvailable"); + NSLog(@"Headphone/Line plugged in"); + } break; + case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: { + NSLog(@"AVAudioSessionRouteChangeReasonOldDeviceUnavailable"); + NSLog(@"Headphone/Line was pulled. Resuming video play...."); + if ([self isVideoPlaying]) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self.avPlayer play]; // NOTE: change this line according your current player implementation + NSLog(@"resumed play"); + }); + } + } break; + case AVAudioSessionRouteChangeReasonCategoryChange: { + // called at start - also when other audio wants to play + NSLog(@"AVAudioSessionRouteChangeReasonCategoryChange"); + } break; + } +} + +// MARK: Native Video Player + +- (void)handleVideoOrPlayerStatus { + if (self.avPlayerItem.status == AVPlayerItemStatusFailed || self.avPlayer.status == AVPlayerStatusFailed) { + [self stopVideo]; + } + + if (self.avPlayer.status == AVPlayerStatusReadyToPlay && self.avPlayerItem.status == AVPlayerItemStatusReadyToPlay && CMTimeCompare(self.videoCurrentTime, kCMTimeZero) == 0) { + // NSLog(@"time: %@", self.video_current_time); + [self.avPlayer seekToTime:self.videoCurrentTime]; + self.videoCurrentTime = kCMTimeZero; + } +} + +- (void)handleVideoPlayRate { + NSLog(@"Player playback rate changed: %.5f", self.avPlayer.rate); + if ([self isVideoPlaying] && self.avPlayer.rate == 0.0 && !self.avPlayer.error) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self.avPlayer play]; // NOTE: change this line according your current player implementation + NSLog(@"resumed play"); + }); + + NSLog(@" . . . PAUSED (or just started)"); + } +} + +- (BOOL)playVideoAtPath:(NSString *)filePath volume:(float)videoVolume audio:(NSString *)audioTrack subtitle:(NSString *)subtitleTrack { + self.avAsset = [AVAsset assetWithURL:[NSURL fileURLWithPath:filePath]]; + + self.avPlayerItem = [AVPlayerItem playerItemWithAsset:self.avAsset]; + [self.avPlayerItem addObserver:self forKeyPath:@"status" options:0 context:nil]; + + self.avPlayer = [AVPlayer playerWithPlayerItem:self.avPlayerItem]; + self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer]; + + [self.avPlayer addObserver:self forKeyPath:@"status" options:0 context:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(playerItemDidReachEnd:) + name:AVPlayerItemDidPlayToEndTimeNotification + object:[self.avPlayer currentItem]]; + + [self.avPlayer addObserver:self forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:0]; + + [self.avPlayerLayer setFrame:self.bounds]; + [self.layer addSublayer:self.avPlayerLayer]; + [self.avPlayer play]; + + AVMediaSelectionGroup *audioGroup = [self.avAsset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicAudible]; + + NSMutableArray *allAudioParams = [NSMutableArray array]; + for (id track in audioGroup.options) { + NSString *language = [[track locale] localeIdentifier]; + NSLog(@"subtitle lang: %@", language); + + if ([language isEqualToString:audioTrack]) { + AVMutableAudioMixInputParameters *audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters]; + [audioInputParams setVolume:videoVolume atTime:kCMTimeZero]; + [audioInputParams setTrackID:[track trackID]]; + [allAudioParams addObject:audioInputParams]; + + AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix]; + [audioMix setInputParameters:allAudioParams]; + + [self.avPlayer.currentItem selectMediaOption:track inMediaSelectionGroup:audioGroup]; + [self.avPlayer.currentItem setAudioMix:audioMix]; + + break; + } + } + + AVMediaSelectionGroup *subtitlesGroup = [self.avAsset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicLegible]; + NSArray *useableTracks = [AVMediaSelectionGroup mediaSelectionOptionsFromArray:subtitlesGroup.options withoutMediaCharacteristics:[NSArray arrayWithObject:AVMediaCharacteristicContainsOnlyForcedSubtitles]]; + + for (id track in useableTracks) { + NSString *language = [[track locale] localeIdentifier]; + NSLog(@"subtitle lang: %@", language); + + if ([language isEqualToString:subtitleTrack]) { + [self.avPlayer.currentItem selectMediaOption:track inMediaSelectionGroup:subtitlesGroup]; + break; + } + } + + self.isVideoCurrentlyPlaying = YES; + + return true; +} + +- (BOOL)isVideoPlaying { + if (self.avPlayer.error) { + printf("Error during playback\n"); + } + return (self.avPlayer.rate > 0 && !self.avPlayer.error); +} + +- (void)pauseVideo { + self.videoCurrentTime = self.avPlayer.currentTime; + [self.avPlayer pause]; + self.isVideoCurrentlyPlaying = NO; +} + +- (void)unpauseVideo { + [self.avPlayer play]; + self.isVideoCurrentlyPlaying = YES; +} + +- (void)playerItemDidReachEnd:(NSNotification *)notification { + [self stopVideo]; +} + +- (void)finishPlayingVideo { + [self.avPlayer pause]; + [self.avPlayerLayer removeFromSuperlayer]; + self.avPlayerLayer = nil; + + if (self.avPlayerItem) { + [self.avPlayerItem removeObserver:self forKeyPath:@"status"]; + self.avPlayerItem = nil; + } + + if (self.avPlayer) { + [self.avPlayer removeObserver:self forKeyPath:@"status"]; + self.avPlayer = nil; + } + + self.avAsset = nil; + + self.isVideoCurrentlyPlaying = NO; +} + +- (void)stopVideo { + [self finishPlayingVideo]; + + [self removeFromSuperview]; +} + +@end diff --git a/platform/iphone/os_iphone.mm b/platform/iphone/os_iphone.mm index 5baa5b66fc2a..e007276b4b43 100644 --- a/platform/iphone/os_iphone.mm +++ b/platform/iphone/os_iphone.mm @@ -271,7 +271,6 @@ void register_dynamic_symbol(char *name, void *address) { Error OSIPhone::shell_open(String p_uri) { NSString *urlPath = [[NSString alloc] initWithUTF8String:p_uri.utf8().get_data()]; NSURL *url = [NSURL URLWithString:urlPath]; - [urlPath release]; if (![[UIApplication sharedApplication] canOpenURL:url]) { return ERR_CANT_OPEN; @@ -279,11 +278,7 @@ void register_dynamic_symbol(char *name, void *address) { printf("opening url %s\n", p_uri.utf8().get_data()); - // if (@available(iOS 10, *)) { [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; - // } else { - // [[UIApplication sharedApplication] openURL:url]; - // } return OK; }; diff --git a/platform/iphone/platform_config.h b/platform/iphone/platform_config.h index 2bbbe47c0dad..ec39ad0ba441 100644 --- a/platform/iphone/platform_config.h +++ b/platform/iphone/platform_config.h @@ -33,3 +33,10 @@ #define PLATFORM_REFCOUNT #define PTHREAD_RENAME_SELF + +#define _weakify(var) __weak typeof(var) GDWeak_##var = var; +#define _strongify(var) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wshadow\"") \ + __strong typeof(var) var = GDWeak_##var; \ + _Pragma("clang diagnostic pop") diff --git a/platform/iphone/view_controller.h b/platform/iphone/view_controller.h index dffdc01d4a3a..b0b31ae377c7 100644 --- a/platform/iphone/view_controller.h +++ b/platform/iphone/view_controller.h @@ -32,17 +32,15 @@ #import @class GodotView; +@class GodotNativeVideoView; @interface ViewController : UIViewController -- (GodotView *)godotView; +@property(nonatomic, readonly, strong) GodotView *godotView; +@property(nonatomic, readonly, strong) GodotNativeVideoView *videoView; // MARK: Native Video Player - (BOOL)playVideoAtPath:(NSString *)filePath volume:(float)videoVolume audio:(NSString *)audioTrack subtitle:(NSString *)subtitleTrack; -- (BOOL)isVideoPlaying; -- (void)pauseVideo; -- (void)unpauseVideo; -- (void)stopVideo; @end diff --git a/platform/iphone/view_controller.mm b/platform/iphone/view_controller.mm index 31597f78569d..fb25041779e6 100644 --- a/platform/iphone/view_controller.mm +++ b/platform/iphone/view_controller.mm @@ -33,6 +33,7 @@ #include "display_server_iphone.h" #import "godot_view.h" #import "godot_view_renderer.h" +#import "native_video_view.h" #include "os_iphone.h" #import @@ -40,16 +41,7 @@ @interface ViewController () @property(strong, nonatomic) GodotViewRenderer *renderer; - -// TODO: separate view to handle video -// AVPlayer-related properties -@property(strong, nonatomic) AVAsset *avAsset; -@property(strong, nonatomic) AVPlayerItem *avPlayerItem; -@property(strong, nonatomic) AVPlayer *avPlayer; -@property(strong, nonatomic) AVPlayerLayer *avPlayerLayer; -@property(assign, nonatomic) CMTime videoCurrentTime; -@property(assign, nonatomic) BOOL isVideoCurrentlyPlaying; -@property(assign, nonatomic) BOOL videoHasFoundError; +@property(strong, nonatomic) GodotNativeVideoView *videoView; @end @@ -67,9 +59,6 @@ - (void)loadView { self.view = view; view.renderer = self.renderer; - - [renderer release]; - [view release]; } - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { @@ -93,9 +82,7 @@ - (instancetype)initWithCoder:(NSCoder *)coder { } - (void)godot_commonInit { - self.isVideoCurrentlyPlaying = NO; - self.videoCurrentTime = kCMTimeZero; - self.videoHasFoundError = false; + // Initialize view controller values. } - (void)didReceiveMemoryWarning { @@ -107,7 +94,6 @@ - (void)viewDidLoad { [super viewDidLoad]; [self observeKeyboard]; - [self observeAudio]; if (@available(iOS 11.0, *)) { [self setNeedsUpdateOfScreenEdgesDeferringSystemGestures]; @@ -128,33 +114,13 @@ - (void)observeKeyboard { object:nil]; } -- (void)observeAudio { - printf("******** adding observer for sound routing changes\n"); - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(audioRouteChangeListenerCallback:) - name:AVAudioSessionRouteChangeNotification - object:nil]; -} - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - if (object == self.avPlayerItem && [keyPath isEqualToString:@"status"]) { - [self handleVideoOrPlayerStatus]; - } - - if (object == self.avPlayer && [keyPath isEqualToString:@"rate"]) { - [self handleVideoPlayRate]; - } -} - - (void)dealloc { - [self stopVideo]; + [self.videoView stopVideo]; + self.videoView = nil; self.renderer = nil; [[NSNotificationCenter defaultCenter] removeObserver:self]; - - [super dealloc]; } // MARK: Orientation @@ -233,166 +199,19 @@ - (void)keyboardHidden:(NSNotification *)notification { } } -// MARK: Audio - -- (void)audioRouteChangeListenerCallback:(NSNotification *)notification { - printf("*********** route changed!\n"); - NSDictionary *interuptionDict = notification.userInfo; - - NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue]; - - switch (routeChangeReason) { - case AVAudioSessionRouteChangeReasonNewDeviceAvailable: { - NSLog(@"AVAudioSessionRouteChangeReasonNewDeviceAvailable"); - NSLog(@"Headphone/Line plugged in"); - } break; - case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: { - NSLog(@"AVAudioSessionRouteChangeReasonOldDeviceUnavailable"); - NSLog(@"Headphone/Line was pulled. Resuming video play...."); - if ([self isVideoPlaying]) { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - [self.avPlayer play]; // NOTE: change this line according your current player implementation - NSLog(@"resumed play"); - }); - } - } break; - case AVAudioSessionRouteChangeReasonCategoryChange: { - // called at start - also when other audio wants to play - NSLog(@"AVAudioSessionRouteChangeReasonCategoryChange"); - } break; - } -} - // MARK: Native Video Player -- (void)handleVideoOrPlayerStatus { - if (self.avPlayerItem.status == AVPlayerItemStatusFailed || self.avPlayer.status == AVPlayerStatusFailed) { - [self stopVideo]; - self.videoHasFoundError = true; - } - - if (self.avPlayer.status == AVPlayerStatusReadyToPlay && self.avPlayerItem.status == AVPlayerItemStatusReadyToPlay && CMTimeCompare(self.videoCurrentTime, kCMTimeZero) == 0) { - // NSLog(@"time: %@", self.video_current_time); - [self.avPlayer seekToTime:self.videoCurrentTime]; - self.videoCurrentTime = kCMTimeZero; - } -} - -- (void)handleVideoPlayRate { - NSLog(@"Player playback rate changed: %.5f", self.avPlayer.rate); - if ([self isVideoPlaying] && self.avPlayer.rate == 0.0 && !self.avPlayer.error) { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - [self.avPlayer play]; // NOTE: change this line according your current player implementation - NSLog(@"resumed play"); - }); - - NSLog(@" . . . PAUSED (or just started)"); - } -} - - (BOOL)playVideoAtPath:(NSString *)filePath volume:(float)videoVolume audio:(NSString *)audioTrack subtitle:(NSString *)subtitleTrack { - self.avAsset = [AVAsset assetWithURL:[NSURL fileURLWithPath:filePath]]; - - self.avPlayerItem = [AVPlayerItem playerItemWithAsset:self.avAsset]; - [self.avPlayerItem addObserver:self forKeyPath:@"status" options:0 context:nil]; - - self.avPlayer = [AVPlayer playerWithPlayerItem:self.avPlayerItem]; - self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer]; - - [self.avPlayer addObserver:self forKeyPath:@"status" options:0 context:nil]; - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(playerItemDidReachEnd:) - name:AVPlayerItemDidPlayToEndTimeNotification - object:[self.avPlayer currentItem]]; - - [self.avPlayer addObserver:self forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:0]; - - [self.avPlayerLayer setFrame:self.view.bounds]; - [self.view.layer addSublayer:self.avPlayerLayer]; - [self.avPlayer play]; - - AVMediaSelectionGroup *audioGroup = [self.avAsset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicAudible]; - - NSMutableArray *allAudioParams = [NSMutableArray array]; - for (id track in audioGroup.options) { - NSString *language = [[track locale] localeIdentifier]; - NSLog(@"subtitle lang: %@", language); - - if ([language isEqualToString:audioTrack]) { - AVMutableAudioMixInputParameters *audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters]; - [audioInputParams setVolume:videoVolume atTime:kCMTimeZero]; - [audioInputParams setTrackID:[track trackID]]; - [allAudioParams addObject:audioInputParams]; - - AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix]; - [audioMix setInputParameters:allAudioParams]; - - [self.avPlayer.currentItem selectMediaOption:track inMediaSelectionGroup:audioGroup]; - [self.avPlayer.currentItem setAudioMix:audioMix]; - - break; - } - } - - AVMediaSelectionGroup *subtitlesGroup = [self.avAsset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicLegible]; - NSArray *useableTracks = [AVMediaSelectionGroup mediaSelectionOptionsFromArray:subtitlesGroup.options withoutMediaCharacteristics:[NSArray arrayWithObject:AVMediaCharacteristicContainsOnlyForcedSubtitles]]; - - for (id track in useableTracks) { - NSString *language = [[track locale] localeIdentifier]; - NSLog(@"subtitle lang: %@", language); - - if ([language isEqualToString:subtitleTrack]) { - [self.avPlayer.currentItem selectMediaOption:track inMediaSelectionGroup:subtitlesGroup]; - break; - } - } - - self.isVideoCurrentlyPlaying = YES; - - return true; -} - -- (BOOL)isVideoPlaying { - if (self.avPlayer.error) { - printf("Error during playback\n"); - } - return (self.avPlayer.rate > 0 && !self.avPlayer.error); -} - -- (void)pauseVideo { - self.videoCurrentTime = self.avPlayer.currentTime; - [self.avPlayer pause]; - self.isVideoCurrentlyPlaying = NO; -} - -- (void)unpauseVideo { - [self.avPlayer play]; - self.isVideoCurrentlyPlaying = YES; -} - -- (void)playerItemDidReachEnd:(NSNotification *)notification { - [self stopVideo]; -} - -- (void)stopVideo { - [self.avPlayer pause]; - [self.avPlayerLayer removeFromSuperlayer]; - self.avPlayerLayer = nil; - - if (self.avPlayerItem) { - [self.avPlayerItem removeObserver:self forKeyPath:@"status"]; - self.avPlayerItem = nil; - } - - if (self.avPlayer) { - [self.avPlayer removeObserver:self forKeyPath:@"status"]; - self.avPlayer = nil; + // If we are showing some video already, reuse existing view for new video. + if (self.videoView) { + return [self.videoView playVideoAtPath:filePath volume:videoVolume audio:audioTrack subtitle:subtitleTrack]; + } else { + // Create autoresizing view for video playback. + GodotNativeVideoView *videoView = [[GodotNativeVideoView alloc] initWithFrame:self.view.bounds]; + videoView.autoresizingMask = UIViewAutoresizingFlexibleWidth & UIViewAutoresizingFlexibleHeight; + [self.view addSubview:videoView]; + return [self.videoView playVideoAtPath:filePath volume:videoVolume audio:audioTrack subtitle:subtitleTrack]; } - - self.avAsset = nil; - - self.isVideoCurrentlyPlaying = NO; } // MARK: Delegates diff --git a/platform/iphone/vulkan_context_iphone.mm b/platform/iphone/vulkan_context_iphone.mm index cb4dbe7f8527..d62e82695720 100644 --- a/platform/iphone/vulkan_context_iphone.mm +++ b/platform/iphone/vulkan_context_iphone.mm @@ -35,14 +35,12 @@ return VK_MVK_IOS_SURFACE_EXTENSION_NAME; } -Error VulkanContextIPhone::window_create(DisplayServer::WindowID p_window_id, - CALayer *p_metal_layer, int p_width, - int p_height) { +Error VulkanContextIPhone::window_create(DisplayServer::WindowID p_window_id, CALayer *p_metal_layer, int p_width, int p_height) { VkIOSSurfaceCreateInfoMVK createInfo; createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK; createInfo.pNext = NULL; createInfo.flags = 0; - createInfo.pView = p_metal_layer; + createInfo.pView = (__bridge const void *)p_metal_layer; VkSurfaceKHR surface; VkResult err =