mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 16:03:29 +00:00
Introduce 'drivers/apple_embedded' abstract platform for code reuse
This commit is contained in:
parent
34f005d810
commit
457299449d
84 changed files with 6107 additions and 5411 deletions
|
@ -647,7 +647,11 @@ if env["scu_build"]:
|
|||
# are actually handled to change compile options, etc.
|
||||
detect.configure(env)
|
||||
|
||||
print(f'Building for platform "{env["platform"]}", architecture "{env["arch"]}", target "{env["target"]}".')
|
||||
platform_string = env["platform"]
|
||||
if env.get("simulator"):
|
||||
platform_string += " (simulator)"
|
||||
print(f'Building for platform "{platform_string}", architecture "{env["arch"]}", target "{env["target"]}".')
|
||||
|
||||
if env.dev_build:
|
||||
print_info("Developer build, with debug optimization level and debug symbols (unless overridden).")
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ def make_default_controller_mappings(target, source, env):
|
|||
"Windows": "WINDOWS",
|
||||
"Mac OS X": "MACOS",
|
||||
"Android": "ANDROID",
|
||||
"iOS": "IOS",
|
||||
"iOS": "APPLE_EMBEDDED",
|
||||
"Web": "WEB",
|
||||
}
|
||||
|
||||
|
|
13
doc/classes/EditorExportPlatformAppleEmbedded.xml
Normal file
13
doc/classes/EditorExportPlatformAppleEmbedded.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="EditorExportPlatformAppleEmbedded" inherits="EditorExportPlatform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||
<brief_description>
|
||||
Base class for the Apple embedded platform exporters (iOS).
|
||||
</brief_description>
|
||||
<description>
|
||||
The base class for Apple embedded platform exporters. These include iOS, but not macOS. See the classes inheriting from this one for more details.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="Exporting for iOS">$DOCS_URL/tutorials/export/exporting_for_ios.html</link>
|
||||
<link title="iOS plugins documentation index">$DOCS_URL/tutorials/platform/ios/index.html</link>
|
||||
</tutorials>
|
||||
</class>
|
|
@ -4,7 +4,7 @@
|
|||
Base class for the desktop platform exporter (Windows and Linux/BSD).
|
||||
</brief_description>
|
||||
<description>
|
||||
The base class for the desktop platform exporters. These include Windows and Linux/BSD, but not macOS. See the classes inheriting this one for more details.
|
||||
The base class for the desktop platform exporters. These include Windows and Linux/BSD, but not macOS. See the classes inheriting from this one for more details.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="Exporting for Windows">$DOCS_URL/tutorials/export/exporting_for_windows.html</link>
|
||||
|
|
|
@ -251,6 +251,57 @@
|
|||
If no modifications are needed, then an empty [PackedByteArray] should be returned.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_apple_embedded_platform_bundle_file">
|
||||
<return type="void" />
|
||||
<param index="0" name="path" type="String" />
|
||||
<description>
|
||||
Adds an Apple embedded platform bundle file from the given [param path] to the exported project.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_apple_embedded_platform_cpp_code">
|
||||
<return type="void" />
|
||||
<param index="0" name="code" type="String" />
|
||||
<description>
|
||||
Adds C++ code to the Apple embedded platform export. The final code is created from the code appended by each active export plugin.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_apple_embedded_platform_embedded_framework">
|
||||
<return type="void" />
|
||||
<param index="0" name="path" type="String" />
|
||||
<description>
|
||||
Adds a dynamic library (*.dylib, *.framework) to the Linking Phase in the Apple embedded platform's Xcode project and embeds it into the resulting binary.
|
||||
[b]Note:[/b] For static libraries (*.a), this works in the same way as [method add_apple_embedded_platform_framework].
|
||||
[b]Note:[/b] This method should not be used for System libraries as they are already present on the device.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_apple_embedded_platform_framework">
|
||||
<return type="void" />
|
||||
<param index="0" name="path" type="String" />
|
||||
<description>
|
||||
Adds a static library (*.a) or a dynamic library (*.dylib, *.framework) to the Linking Phase to the Apple embedded platform's Xcode project.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_apple_embedded_platform_linker_flags">
|
||||
<return type="void" />
|
||||
<param index="0" name="flags" type="String" />
|
||||
<description>
|
||||
Adds linker flags for the Apple embedded platform export.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_apple_embedded_platform_plist_content">
|
||||
<return type="void" />
|
||||
<param index="0" name="plist_content" type="String" />
|
||||
<description>
|
||||
Adds additional fields to the Apple embedded platform's project Info.plist file.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_apple_embedded_platform_project_static_lib">
|
||||
<return type="void" />
|
||||
<param index="0" name="path" type="String" />
|
||||
<description>
|
||||
Adds a static library from the given [param path] to the Apple embedded platform project.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_file">
|
||||
<return type="void" />
|
||||
<param index="0" name="path" type="String" />
|
||||
|
@ -262,55 +313,55 @@
|
|||
[param file] will not be imported, so consider using [method _customize_resource] to remap imported resources.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_ios_bundle_file">
|
||||
<method name="add_ios_bundle_file" deprecated="Use [method add_apple_embedded_platform_bundle_file] instead.">
|
||||
<return type="void" />
|
||||
<param index="0" name="path" type="String" />
|
||||
<description>
|
||||
Adds an iOS bundle file from the given [param path] to the exported project.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_ios_cpp_code">
|
||||
<method name="add_ios_cpp_code" deprecated="Use [method add_apple_embedded_platform_cpp_code] instead.">
|
||||
<return type="void" />
|
||||
<param index="0" name="code" type="String" />
|
||||
<description>
|
||||
Adds a C++ code to the iOS export. The final code is created from the code appended by each active export plugin.
|
||||
Adds C++ code to the iOS export. The final code is created from the code appended by each active export plugin.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_ios_embedded_framework">
|
||||
<method name="add_ios_embedded_framework" deprecated="Use [method add_apple_embedded_platform_embedded_framework] instead.">
|
||||
<return type="void" />
|
||||
<param index="0" name="path" type="String" />
|
||||
<description>
|
||||
Adds a dynamic library (*.dylib, *.framework) to Linking Phase in iOS's Xcode project and embeds it into resulting binary.
|
||||
[b]Note:[/b] For static libraries (*.a) works in same way as [method add_ios_framework].
|
||||
[b]Note:[/b] For static libraries (*.a), this works the in same way as [method add_apple_embedded_platform_framework].
|
||||
[b]Note:[/b] This method should not be used for System libraries as they are already present on the device.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_ios_framework">
|
||||
<method name="add_ios_framework" deprecated="Use [method add_apple_embedded_platform_framework] instead.">
|
||||
<return type="void" />
|
||||
<param index="0" name="path" type="String" />
|
||||
<description>
|
||||
Adds a static library (*.a) or dynamic library (*.dylib, *.framework) to Linking Phase in iOS's Xcode project.
|
||||
Adds a static library (*.a) or a dynamic library (*.dylib, *.framework) to the Linking Phase to the iOS Xcode project.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_ios_linker_flags">
|
||||
<method name="add_ios_linker_flags" deprecated="Use [method add_apple_embedded_platform_linker_flags] instead.">
|
||||
<return type="void" />
|
||||
<param index="0" name="flags" type="String" />
|
||||
<description>
|
||||
Adds linker flags for the iOS export.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_ios_plist_content">
|
||||
<method name="add_ios_plist_content" deprecated="Use [method add_apple_embedded_platform_plist_content] instead.">
|
||||
<return type="void" />
|
||||
<param index="0" name="plist_content" type="String" />
|
||||
<description>
|
||||
Adds content for iOS Property List files.
|
||||
Adds additional fields to the iOS project Info.plist file.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_ios_project_static_lib">
|
||||
<method name="add_ios_project_static_lib" deprecated="Use [method add_apple_embedded_platform_project_static_lib] instead.">
|
||||
<return type="void" />
|
||||
<param index="0" name="path" type="String" />
|
||||
<description>
|
||||
Adds a static lib from the given [param path] to the iOS project.
|
||||
Adds a static library from the given [param path] to the iOS project.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_macos_plugin_file">
|
||||
|
|
|
@ -14,8 +14,6 @@ SConscript("windows/SCsub")
|
|||
|
||||
# Sounds drivers
|
||||
SConscript("alsa/SCsub")
|
||||
if env["platform"] == "ios" or env["platform"] == "macos":
|
||||
SConscript("coreaudio/SCsub")
|
||||
SConscript("pulseaudio/SCsub")
|
||||
if env["platform"] == "windows":
|
||||
SConscript("wasapi/SCsub")
|
||||
|
@ -30,6 +28,9 @@ if env["xaudio2"]:
|
|||
# Shared Apple platform drivers
|
||||
if env["platform"] in ["macos", "ios"]:
|
||||
SConscript("apple/SCsub")
|
||||
SConscript("coreaudio/SCsub")
|
||||
if env["platform"] in ["ios"]:
|
||||
SConscript("apple_embedded/SCsub")
|
||||
|
||||
# Accessibility
|
||||
if env["accesskit"] and env["platform"] in ["macos", "windows", "linuxbsd"]:
|
||||
|
|
16
drivers/apple_embedded/SCsub
Normal file
16
drivers/apple_embedded/SCsub
Normal file
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
|
||||
env_apple_embedded = env.Clone()
|
||||
|
||||
# Enable module support
|
||||
env_apple_embedded.Append(CCFLAGS=["-fmodules", "-fcxx-modules"])
|
||||
|
||||
# Use bundled Vulkan headers
|
||||
vulkan_dir = "#thirdparty/vulkan"
|
||||
env_apple_embedded.Prepend(CPPPATH=[vulkan_dir, vulkan_dir + "/include"])
|
||||
|
||||
# Driver source files
|
||||
env_apple_embedded.add_source_files(env.drivers_sources, "*.mm")
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* app_delegate.h */
|
||||
/* app_delegate_service.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -32,18 +32,11 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class ViewController;
|
||||
@class GDTViewController;
|
||||
|
||||
// FIXME: Add support for both OpenGL and Vulkan when OpenGL is implemented again,
|
||||
// so it can't be done with compilation time branching.
|
||||
//#if defined(GLES3_ENABLED)
|
||||
//@interface AppDelegate : NSObject <UIApplicationDelegate, GLViewDelegate> {
|
||||
//#endif
|
||||
//#if defined(VULKAN_ENABLED)
|
||||
@interface AppDelegate : NSObject <UIApplicationDelegate>
|
||||
//#endif
|
||||
@interface GDTAppDelegateService : NSObject <UIApplicationDelegate>
|
||||
|
||||
@property(strong, nonatomic) UIWindow *window;
|
||||
@property(strong, class, readonly, nonatomic) ViewController *viewController;
|
||||
@property(strong, class, readonly, nonatomic) GDTViewController *viewController;
|
||||
|
||||
@end
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* app_delegate.mm */
|
||||
/* app_delegate_service.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -28,10 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#import "app_delegate.h"
|
||||
#import "app_delegate_service.h"
|
||||
|
||||
#import "godot_view.h"
|
||||
#import "os_ios.h"
|
||||
#import "godot_view_apple_embedded.h"
|
||||
#import "os_apple_embedded.h"
|
||||
#import "view_controller.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
|
@ -46,10 +46,10 @@
|
|||
extern int gargc;
|
||||
extern char **gargv;
|
||||
|
||||
extern int ios_main(int, char **);
|
||||
extern void ios_finish();
|
||||
extern int apple_embedded_main(int, char **);
|
||||
extern void apple_embedded_finish();
|
||||
|
||||
@implementation AppDelegate
|
||||
@implementation GDTAppDelegateService
|
||||
|
||||
enum {
|
||||
SESSION_CATEGORY_AMBIENT,
|
||||
|
@ -60,9 +60,9 @@ enum {
|
|||
SESSION_CATEGORY_SOLO_AMBIENT
|
||||
};
|
||||
|
||||
static ViewController *mainViewController = nil;
|
||||
static GDTViewController *mainViewController = nil;
|
||||
|
||||
+ (ViewController *)viewController {
|
||||
+ (GDTViewController *)viewController {
|
||||
return mainViewController;
|
||||
}
|
||||
|
||||
|
@ -71,12 +71,11 @@ static ViewController *mainViewController = nil;
|
|||
// TODO: logo screen is not displayed while shaders are compiling
|
||||
// DummyViewController(Splash/LoadingViewController) -> setup -> GodotViewController
|
||||
|
||||
CGRect windowBounds = [[UIScreen mainScreen] bounds];
|
||||
|
||||
// Create a full-screen window
|
||||
CGRect windowBounds = [[UIScreen mainScreen] bounds];
|
||||
self.window = [[UIWindow alloc] initWithFrame:windowBounds];
|
||||
|
||||
int err = ios_main(gargc, gargv);
|
||||
int err = apple_embedded_main(gargc, gargv);
|
||||
|
||||
if (err != 0) {
|
||||
// bail, things did not go very well for us, should probably output a message on screen with our error code...
|
||||
|
@ -84,7 +83,7 @@ static ViewController *mainViewController = nil;
|
|||
return NO;
|
||||
}
|
||||
|
||||
ViewController *viewController = [[ViewController alloc] init];
|
||||
GDTViewController *viewController = [[GDTViewController alloc] init];
|
||||
viewController.godotView.useCADisplayLink = bool(GLOBAL_DEF("display.iOS/use_cadisplaylink", true)) ? YES : NO;
|
||||
viewController.godotView.renderingInterval = 1.0 / kRenderingFrequency;
|
||||
|
||||
|
@ -135,10 +134,10 @@ static ViewController *mainViewController = nil;
|
|||
if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) {
|
||||
if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeBegan]]) {
|
||||
NSLog(@"Audio interruption began");
|
||||
OS_IOS::get_singleton()->on_focus_out();
|
||||
OS_AppleEmbedded::get_singleton()->on_focus_out();
|
||||
} else if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeEnded]]) {
|
||||
NSLog(@"Audio interruption ended");
|
||||
OS_IOS::get_singleton()->on_focus_in();
|
||||
OS_AppleEmbedded::get_singleton()->on_focus_in();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +149,7 @@ static ViewController *mainViewController = nil;
|
|||
}
|
||||
|
||||
- (void)applicationWillTerminate:(UIApplication *)application {
|
||||
ios_finish();
|
||||
apple_embedded_finish();
|
||||
}
|
||||
|
||||
// When application goes to background (e.g. user switches to another app or presses Home),
|
||||
|
@ -164,19 +163,19 @@ static ViewController *mainViewController = nil;
|
|||
// notification panel by swiping from the upper part of the screen.
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication *)application {
|
||||
OS_IOS::get_singleton()->on_focus_out();
|
||||
OS_AppleEmbedded::get_singleton()->on_focus_out();
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
||||
OS_IOS::get_singleton()->on_focus_in();
|
||||
OS_AppleEmbedded::get_singleton()->on_focus_in();
|
||||
}
|
||||
|
||||
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
||||
OS_IOS::get_singleton()->on_enter_background();
|
||||
OS_AppleEmbedded::get_singleton()->on_enter_background();
|
||||
}
|
||||
|
||||
- (void)applicationWillEnterForeground:(UIApplication *)application {
|
||||
OS_IOS::get_singleton()->on_exit_background();
|
||||
OS_AppleEmbedded::get_singleton()->on_exit_background();
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
59
drivers/apple_embedded/apple_embedded.h
Normal file
59
drivers/apple_embedded/apple_embedded.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/**************************************************************************/
|
||||
/* apple_embedded.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
#import <CoreHaptics/CoreHaptics.h>
|
||||
|
||||
class AppleEmbedded : public Object {
|
||||
GDCLASS(AppleEmbedded, Object);
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
private:
|
||||
CHHapticEngine *haptic_engine API_AVAILABLE(ios(13)) = nullptr;
|
||||
|
||||
CHHapticEngine *get_haptic_engine_instance() API_AVAILABLE(ios(13));
|
||||
void start_haptic_engine();
|
||||
void stop_haptic_engine();
|
||||
|
||||
public:
|
||||
static void alert(const char *p_alert, const char *p_title);
|
||||
|
||||
bool supports_haptic_engine();
|
||||
void vibrate_haptic_engine(float p_duration_seconds, float p_amplitude);
|
||||
|
||||
String get_model() const;
|
||||
String get_rate_url(int p_app_id) const;
|
||||
|
||||
AppleEmbedded();
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* ios.mm */
|
||||
/* apple_embedded.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -28,23 +28,23 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#import "ios.h"
|
||||
#import "apple_embedded.h"
|
||||
|
||||
#import "app_delegate.h"
|
||||
#import "app_delegate_service.h"
|
||||
#import "view_controller.h"
|
||||
|
||||
#import <CoreHaptics/CoreHaptics.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
void iOS::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_rate_url", "app_id"), &iOS::get_rate_url);
|
||||
ClassDB::bind_method(D_METHOD("supports_haptic_engine"), &iOS::supports_haptic_engine);
|
||||
ClassDB::bind_method(D_METHOD("start_haptic_engine"), &iOS::start_haptic_engine);
|
||||
ClassDB::bind_method(D_METHOD("stop_haptic_engine"), &iOS::stop_haptic_engine);
|
||||
void AppleEmbedded::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_rate_url", "app_id"), &AppleEmbedded::get_rate_url);
|
||||
ClassDB::bind_method(D_METHOD("supports_haptic_engine"), &AppleEmbedded::supports_haptic_engine);
|
||||
ClassDB::bind_method(D_METHOD("start_haptic_engine"), &AppleEmbedded::start_haptic_engine);
|
||||
ClassDB::bind_method(D_METHOD("stop_haptic_engine"), &AppleEmbedded::stop_haptic_engine);
|
||||
}
|
||||
|
||||
bool iOS::supports_haptic_engine() {
|
||||
bool AppleEmbedded::supports_haptic_engine() {
|
||||
if (@available(iOS 13, *)) {
|
||||
id<CHHapticDeviceCapability> capabilities = [CHHapticEngine capabilitiesForHardware];
|
||||
return capabilities.supportsHaptics;
|
||||
|
@ -53,7 +53,7 @@ bool iOS::supports_haptic_engine() {
|
|||
return false;
|
||||
}
|
||||
|
||||
CHHapticEngine *iOS::get_haptic_engine_instance() API_AVAILABLE(ios(13)) {
|
||||
CHHapticEngine *AppleEmbedded::get_haptic_engine_instance() API_AVAILABLE(ios(13)) {
|
||||
if (haptic_engine == nullptr) {
|
||||
NSError *error = nullptr;
|
||||
haptic_engine = [[CHHapticEngine alloc] initAndReturnError:&error];
|
||||
|
@ -69,7 +69,7 @@ CHHapticEngine *iOS::get_haptic_engine_instance() API_AVAILABLE(ios(13)) {
|
|||
return haptic_engine;
|
||||
}
|
||||
|
||||
void iOS::vibrate_haptic_engine(float p_duration_seconds, float p_amplitude) API_AVAILABLE(ios(13)) {
|
||||
void AppleEmbedded::vibrate_haptic_engine(float p_duration_seconds, float p_amplitude) API_AVAILABLE(ios(13)) {
|
||||
if (@available(iOS 13, *)) { // We need the @available check every time to make the compiler happy...
|
||||
if (supports_haptic_engine()) {
|
||||
CHHapticEngine *cur_haptic_engine = get_haptic_engine_instance();
|
||||
|
@ -117,10 +117,10 @@ void iOS::vibrate_haptic_engine(float p_duration_seconds, float p_amplitude) API
|
|||
}
|
||||
}
|
||||
|
||||
NSLog(@"Haptic engine is not supported in this version of iOS");
|
||||
NSLog(@"Haptic engine is not supported");
|
||||
}
|
||||
|
||||
void iOS::start_haptic_engine() {
|
||||
void AppleEmbedded::start_haptic_engine() {
|
||||
if (@available(iOS 13, *)) {
|
||||
if (supports_haptic_engine()) {
|
||||
CHHapticEngine *cur_haptic_engine = get_haptic_engine_instance();
|
||||
|
@ -136,10 +136,10 @@ void iOS::start_haptic_engine() {
|
|||
}
|
||||
}
|
||||
|
||||
NSLog(@"Haptic engine is not supported in this version of iOS");
|
||||
NSLog(@"Haptic engine is not supported");
|
||||
}
|
||||
|
||||
void iOS::stop_haptic_engine() {
|
||||
void AppleEmbedded::stop_haptic_engine() {
|
||||
if (@available(iOS 13, *)) {
|
||||
if (supports_haptic_engine()) {
|
||||
CHHapticEngine *cur_haptic_engine = get_haptic_engine_instance();
|
||||
|
@ -155,10 +155,10 @@ void iOS::stop_haptic_engine() {
|
|||
}
|
||||
}
|
||||
|
||||
NSLog(@"Haptic engine is not supported in this version of iOS");
|
||||
NSLog(@"Haptic engine is not supported");
|
||||
}
|
||||
|
||||
void iOS::alert(const char *p_alert, const char *p_title) {
|
||||
void AppleEmbedded::alert(const char *p_alert, const char *p_title) {
|
||||
NSString *title = [NSString stringWithUTF8String:p_title];
|
||||
NSString *message = [NSString stringWithUTF8String:p_alert];
|
||||
|
||||
|
@ -170,10 +170,10 @@ void iOS::alert(const char *p_alert, const char *p_title) {
|
|||
|
||||
[alert addAction:button];
|
||||
|
||||
[AppDelegate.viewController presentViewController:alert animated:YES completion:nil];
|
||||
[GDTAppDelegateService.viewController presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
String iOS::get_model() const {
|
||||
String AppleEmbedded::get_model() const {
|
||||
// [[UIDevice currentDevice] model] only returns "iPad" or "iPhone".
|
||||
size_t size;
|
||||
sysctlbyname("hw.machine", nullptr, &size, nullptr, 0);
|
||||
|
@ -188,7 +188,7 @@ String iOS::get_model() const {
|
|||
return String::utf8(str != nullptr ? str : "");
|
||||
}
|
||||
|
||||
String iOS::get_rate_url(int p_app_id) const {
|
||||
String AppleEmbedded::get_rate_url(int p_app_id) const {
|
||||
String app_url_path = "itms-apps://itunes.apple.com/app/idAPP_ID";
|
||||
|
||||
String ret = app_url_path.replace("APP_ID", String::num_int64(p_app_id));
|
||||
|
@ -197,4 +197,4 @@ String iOS::get_rate_url(int p_app_id) const {
|
|||
return ret;
|
||||
}
|
||||
|
||||
iOS::iOS() {}
|
||||
AppleEmbedded::AppleEmbedded() {}
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* main.m */
|
||||
/* display_layer_apple_embedded.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -28,26 +28,15 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#import "godot_app_delegate.h"
|
||||
#pragma once
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#include <stdio.h>
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
int gargc;
|
||||
char **gargv;
|
||||
@protocol GDTDisplayLayer <NSObject>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
#if defined(VULKAN_ENABLED)
|
||||
//MoltenVK - enable full component swizzling support
|
||||
setenv("MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE", "1", 1);
|
||||
#endif
|
||||
- (void)startRenderDisplayLayer;
|
||||
- (void)stopRenderDisplayLayer;
|
||||
- (void)initializeDisplayLayer;
|
||||
- (void)layoutDisplayLayer;
|
||||
|
||||
gargc = argc;
|
||||
gargv = argv;
|
||||
|
||||
@autoreleasepool {
|
||||
NSString *className = NSStringFromClass([GodotApplicationDelegate class]);
|
||||
UIApplicationMain(argc, argv, nil, className);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@end
|
233
drivers/apple_embedded/display_server_apple_embedded.h
Normal file
233
drivers/apple_embedded/display_server_apple_embedded.h
Normal file
|
@ -0,0 +1,233 @@
|
|||
/**************************************************************************/
|
||||
/* display_server_apple_embedded.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/input/input.h"
|
||||
#include "servers/display_server.h"
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
|
||||
#include "servers/rendering/rendering_device.h"
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
#import "rendering_context_driver_vulkan_apple_embedded.h"
|
||||
|
||||
#include "drivers/vulkan/godot_vulkan.h"
|
||||
#endif // VULKAN_ENABLED
|
||||
|
||||
#if defined(METAL_ENABLED)
|
||||
#import "drivers/metal/rendering_context_driver_metal.h"
|
||||
#endif // METAL_ENABLED
|
||||
#endif // RD_ENABLED
|
||||
|
||||
#if defined(GLES3_ENABLED)
|
||||
#include "drivers/gles3/rasterizer_gles3.h"
|
||||
#endif // GLES3_ENABLED
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
class DisplayServerAppleEmbedded : public DisplayServer {
|
||||
GDSOFTCLASS(DisplayServerAppleEmbedded, DisplayServer);
|
||||
|
||||
_THREAD_SAFE_CLASS_
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
RenderingContextDriver *rendering_context = nullptr;
|
||||
RenderingDevice *rendering_device = nullptr;
|
||||
#endif
|
||||
NativeMenu *native_menu = nullptr;
|
||||
|
||||
id tts = nullptr;
|
||||
|
||||
DisplayServer::ScreenOrientation screen_orientation;
|
||||
|
||||
ObjectID window_attached_instance_id;
|
||||
|
||||
Callable window_event_callback;
|
||||
Callable window_resize_callback;
|
||||
Callable input_event_callback;
|
||||
Callable input_text_callback;
|
||||
|
||||
Callable system_theme_changed;
|
||||
|
||||
int virtual_keyboard_height = 0;
|
||||
|
||||
void perform_event(const Ref<InputEvent> &p_event);
|
||||
|
||||
void initialize_tts() const;
|
||||
|
||||
protected:
|
||||
DisplayServerAppleEmbedded(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error);
|
||||
~DisplayServerAppleEmbedded();
|
||||
|
||||
public:
|
||||
String rendering_driver;
|
||||
|
||||
static DisplayServerAppleEmbedded *get_singleton();
|
||||
|
||||
static Vector<String> get_rendering_drivers_func();
|
||||
|
||||
// MARK: - Events
|
||||
|
||||
virtual void process_events() override;
|
||||
|
||||
virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
|
||||
static void _dispatch_input_events(const Ref<InputEvent> &p_event);
|
||||
void send_input_event(const Ref<InputEvent> &p_event) const;
|
||||
void send_input_text(const String &p_text) const;
|
||||
void send_window_event(DisplayServer::WindowEvent p_event) const;
|
||||
void _window_callback(const Callable &p_callable, const Variant &p_arg) const;
|
||||
|
||||
void emit_system_theme_changed();
|
||||
|
||||
// MARK: - Input
|
||||
|
||||
// MARK: Touches and Apple Pencil
|
||||
|
||||
void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click);
|
||||
void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, float p_pressure, Vector2 p_tilt);
|
||||
void touches_canceled(int p_idx);
|
||||
|
||||
// MARK: Keyboard
|
||||
|
||||
void key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, NSInteger p_modifier, bool p_pressed, KeyLocation p_location);
|
||||
bool is_keyboard_active() const;
|
||||
|
||||
// MARK: Motion
|
||||
|
||||
void update_gravity(const Vector3 &p_gravity);
|
||||
void update_accelerometer(const Vector3 &p_accelerometer);
|
||||
void update_magnetometer(const Vector3 &p_magnetometer);
|
||||
void update_gyroscope(const Vector3 &p_gyroscope);
|
||||
|
||||
// MARK: -
|
||||
|
||||
virtual bool has_feature(Feature p_feature) const override;
|
||||
|
||||
virtual bool tts_is_speaking() const override;
|
||||
virtual bool tts_is_paused() const override;
|
||||
virtual TypedArray<Dictionary> tts_get_voices() const override;
|
||||
|
||||
virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override;
|
||||
virtual void tts_pause() override;
|
||||
virtual void tts_resume() override;
|
||||
virtual void tts_stop() override;
|
||||
|
||||
virtual bool is_dark_mode_supported() const override;
|
||||
virtual bool is_dark_mode() const override;
|
||||
virtual void set_system_theme_change_callback(const Callable &p_callable) override;
|
||||
|
||||
virtual Rect2i get_display_safe_area() const override;
|
||||
|
||||
virtual int get_screen_count() const override;
|
||||
virtual int get_primary_screen() const override;
|
||||
virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
|
||||
virtual Vector<DisplayServer::WindowID> get_window_list() const override;
|
||||
|
||||
virtual WindowID get_window_at_screen_position(const Point2i &p_position) const override;
|
||||
|
||||
virtual int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
|
||||
virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
|
||||
virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
virtual Point2i window_get_position_with_decorations(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
|
||||
virtual void window_set_transient(WindowID p_window, WindowID p_parent) override;
|
||||
|
||||
virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
virtual Size2i window_get_size_with_decorations(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual float screen_get_max_scale() const override;
|
||||
|
||||
virtual void screen_set_orientation(DisplayServer::ScreenOrientation p_orientation, int p_screen) override;
|
||||
virtual DisplayServer::ScreenOrientation screen_get_orientation(int p_screen) const override;
|
||||
|
||||
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual bool can_any_window_draw() const override;
|
||||
|
||||
virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override;
|
||||
|
||||
virtual bool is_touchscreen_available() const override;
|
||||
|
||||
virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_length, int p_cursor_start, int p_cursor_end) override;
|
||||
virtual void virtual_keyboard_hide() override;
|
||||
|
||||
void virtual_keyboard_set_height(int height);
|
||||
virtual int virtual_keyboard_get_height() const override;
|
||||
virtual bool has_hardware_keyboard() const override;
|
||||
|
||||
virtual void clipboard_set(const String &p_text) override;
|
||||
virtual String clipboard_get() const override;
|
||||
|
||||
virtual void screen_set_keep_on(bool p_enable) override;
|
||||
virtual bool screen_is_kept_on() const override;
|
||||
|
||||
void resize_window(CGSize size);
|
||||
virtual void swap_buffers() override {}
|
||||
};
|
791
drivers/apple_embedded/display_server_apple_embedded.mm
Normal file
791
drivers/apple_embedded/display_server_apple_embedded.mm
Normal file
|
@ -0,0 +1,791 @@
|
|||
/**************************************************************************/
|
||||
/* display_server_apple_embedded.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "display_server_apple_embedded.h"
|
||||
|
||||
#import "app_delegate_service.h"
|
||||
#import "apple_embedded.h"
|
||||
#import "godot_view_apple_embedded.h"
|
||||
#import "key_mapping_apple_embedded.h"
|
||||
#import "keyboard_input_view.h"
|
||||
#import "os_apple_embedded.h"
|
||||
#import "tts_apple_embedded.h"
|
||||
#import "view_controller.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/file_access_pack.h"
|
||||
|
||||
#import <GameController/GameController.h>
|
||||
|
||||
static const float kDisplayServerIOSAcceleration = 1.f;
|
||||
|
||||
DisplayServerAppleEmbedded *DisplayServerAppleEmbedded::get_singleton() {
|
||||
return (DisplayServerAppleEmbedded *)DisplayServer::get_singleton();
|
||||
}
|
||||
|
||||
DisplayServerAppleEmbedded::DisplayServerAppleEmbedded(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) {
|
||||
KeyMappingAppleEmbedded::initialize();
|
||||
|
||||
rendering_driver = p_rendering_driver;
|
||||
|
||||
// Init TTS
|
||||
bool tts_enabled = GLOBAL_GET("audio/general/text_to_speech");
|
||||
if (tts_enabled) {
|
||||
initialize_tts();
|
||||
}
|
||||
native_menu = memnew(NativeMenu);
|
||||
|
||||
bool has_made_render_compositor_current = false;
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
rendering_context = nullptr;
|
||||
rendering_device = nullptr;
|
||||
|
||||
CALayer *layer = nullptr;
|
||||
|
||||
union {
|
||||
#ifdef VULKAN_ENABLED
|
||||
RenderingContextDriverVulkanAppleEmbedded::WindowPlatformData vulkan;
|
||||
#endif
|
||||
#ifdef METAL_ENABLED
|
||||
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wunguarded-availability")
|
||||
// Eliminate "RenderingContextDriverMetal is only available on iOS 14.0 or newer".
|
||||
RenderingContextDriverMetal::WindowPlatformData metal;
|
||||
GODOT_CLANG_WARNING_POP
|
||||
#endif
|
||||
} wpd;
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
if (rendering_driver == "vulkan") {
|
||||
layer = [GDTAppDelegateService.viewController.godotView initializeRenderingForDriver:@"vulkan"];
|
||||
if (!layer) {
|
||||
ERR_FAIL_MSG("Failed to create iOS Vulkan rendering layer.");
|
||||
}
|
||||
wpd.vulkan.layer_ptr = (CAMetalLayer *const *)&layer;
|
||||
rendering_context = memnew(RenderingContextDriverVulkanAppleEmbedded);
|
||||
}
|
||||
#endif
|
||||
#ifdef METAL_ENABLED
|
||||
if (rendering_driver == "metal") {
|
||||
if (@available(iOS 14.0, *)) {
|
||||
layer = [GDTAppDelegateService.viewController.godotView initializeRenderingForDriver:@"metal"];
|
||||
wpd.metal.layer = (CAMetalLayer *)layer;
|
||||
rendering_context = memnew(RenderingContextDriverMetal);
|
||||
} else {
|
||||
OS::get_singleton()->alert("Metal is only supported on iOS 14.0 and later.");
|
||||
r_error = ERR_UNAVAILABLE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (rendering_context) {
|
||||
if (rendering_context->initialize() != OK) {
|
||||
memdelete(rendering_context);
|
||||
rendering_context = nullptr;
|
||||
#if defined(GLES3_ENABLED)
|
||||
bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3");
|
||||
if (fallback_to_opengl3 && rendering_driver != "opengl3") {
|
||||
WARN_PRINT("Your device seem not to support MoltenVK or Metal, switching to OpenGL 3.");
|
||||
rendering_driver = "opengl3";
|
||||
OS::get_singleton()->set_current_rendering_method("gl_compatibility");
|
||||
OS::get_singleton()->set_current_rendering_driver_name(rendering_driver);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ERR_PRINT(vformat("Failed to initialize %s context", rendering_driver));
|
||||
r_error = ERR_UNAVAILABLE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rendering_context) {
|
||||
if (rendering_context->window_create(MAIN_WINDOW_ID, &wpd) != OK) {
|
||||
ERR_PRINT(vformat("Failed to create %s window.", rendering_driver));
|
||||
memdelete(rendering_context);
|
||||
rendering_context = nullptr;
|
||||
r_error = ERR_UNAVAILABLE;
|
||||
return;
|
||||
}
|
||||
|
||||
Size2i size = Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_max_scale();
|
||||
rendering_context->window_set_size(MAIN_WINDOW_ID, size.width, size.height);
|
||||
rendering_context->window_set_vsync_mode(MAIN_WINDOW_ID, p_vsync_mode);
|
||||
|
||||
rendering_device = memnew(RenderingDevice);
|
||||
if (rendering_device->initialize(rendering_context, MAIN_WINDOW_ID) != OK) {
|
||||
rendering_device = nullptr;
|
||||
memdelete(rendering_context);
|
||||
rendering_context = nullptr;
|
||||
r_error = ERR_UNAVAILABLE;
|
||||
return;
|
||||
}
|
||||
rendering_device->screen_create(MAIN_WINDOW_ID);
|
||||
|
||||
RendererCompositorRD::make_current();
|
||||
has_made_render_compositor_current = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(GLES3_ENABLED)
|
||||
if (rendering_driver == "opengl3") {
|
||||
CALayer *layer = [GDTAppDelegateService.viewController.godotView initializeRenderingForDriver:@"opengl3"];
|
||||
|
||||
if (!layer) {
|
||||
ERR_FAIL_MSG("Failed to create iOS OpenGLES rendering layer.");
|
||||
}
|
||||
|
||||
RasterizerGLES3::make_current(false);
|
||||
has_made_render_compositor_current = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
ERR_FAIL_COND_MSG(!has_made_render_compositor_current, vformat("Failed to make RendererCompositor current for rendering driver %s", rendering_driver));
|
||||
|
||||
bool keep_screen_on = bool(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
|
||||
screen_set_keep_on(keep_screen_on);
|
||||
|
||||
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
|
||||
|
||||
r_error = OK;
|
||||
}
|
||||
|
||||
DisplayServerAppleEmbedded::~DisplayServerAppleEmbedded() {
|
||||
if (native_menu) {
|
||||
memdelete(native_menu);
|
||||
native_menu = nullptr;
|
||||
}
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
if (rendering_device) {
|
||||
rendering_device->screen_free(MAIN_WINDOW_ID);
|
||||
memdelete(rendering_device);
|
||||
rendering_device = nullptr;
|
||||
}
|
||||
|
||||
if (rendering_context) {
|
||||
rendering_context->window_destroy(MAIN_WINDOW_ID);
|
||||
memdelete(rendering_context);
|
||||
rendering_context = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Vector<String> DisplayServerAppleEmbedded::get_rendering_drivers_func() {
|
||||
Vector<String> drivers;
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
drivers.push_back("vulkan");
|
||||
#endif
|
||||
#if defined(METAL_ENABLED)
|
||||
if (@available(ios 14.0, *)) {
|
||||
drivers.push_back("metal");
|
||||
}
|
||||
#endif
|
||||
#if defined(GLES3_ENABLED)
|
||||
drivers.push_back("opengl3");
|
||||
#endif
|
||||
|
||||
return drivers;
|
||||
}
|
||||
|
||||
// MARK: Events
|
||||
|
||||
void DisplayServerAppleEmbedded::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
|
||||
window_resize_callback = p_callable;
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) {
|
||||
window_event_callback = p_callable;
|
||||
}
|
||||
void DisplayServerAppleEmbedded::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) {
|
||||
input_event_callback = p_callable;
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) {
|
||||
input_text_callback = p_callable;
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::process_events() {
|
||||
Input::get_singleton()->flush_buffered_events();
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::_dispatch_input_events(const Ref<InputEvent> &p_event) {
|
||||
DisplayServerAppleEmbedded::get_singleton()->send_input_event(p_event);
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::send_input_event(const Ref<InputEvent> &p_event) const {
|
||||
_window_callback(input_event_callback, p_event);
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::send_input_text(const String &p_text) const {
|
||||
_window_callback(input_text_callback, p_text);
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::send_window_event(DisplayServer::WindowEvent p_event) const {
|
||||
_window_callback(window_event_callback, int(p_event));
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::_window_callback(const Callable &p_callable, const Variant &p_arg) const {
|
||||
if (p_callable.is_valid()) {
|
||||
p_callable.call(p_arg);
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Input
|
||||
|
||||
// MARK: Touches
|
||||
|
||||
void DisplayServerAppleEmbedded::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click) {
|
||||
Ref<InputEventScreenTouch> ev;
|
||||
ev.instantiate();
|
||||
|
||||
ev->set_index(p_idx);
|
||||
ev->set_pressed(p_pressed);
|
||||
ev->set_position(Vector2(p_x, p_y));
|
||||
ev->set_double_tap(p_double_click);
|
||||
perform_event(ev);
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, float p_pressure, Vector2 p_tilt) {
|
||||
Ref<InputEventScreenDrag> ev;
|
||||
ev.instantiate();
|
||||
ev->set_index(p_idx);
|
||||
ev->set_pressure(p_pressure);
|
||||
ev->set_tilt(p_tilt);
|
||||
ev->set_position(Vector2(p_x, p_y));
|
||||
ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y));
|
||||
ev->set_relative_screen_position(ev->get_relative());
|
||||
perform_event(ev);
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::perform_event(const Ref<InputEvent> &p_event) {
|
||||
Input::get_singleton()->parse_input_event(p_event);
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::touches_canceled(int p_idx) {
|
||||
touch_press(p_idx, -1, -1, false, false);
|
||||
}
|
||||
|
||||
// MARK: Keyboard
|
||||
|
||||
void DisplayServerAppleEmbedded::key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, NSInteger p_modifier, bool p_pressed, KeyLocation p_location) {
|
||||
Ref<InputEventKey> ev;
|
||||
ev.instantiate();
|
||||
ev->set_echo(false);
|
||||
ev->set_pressed(p_pressed);
|
||||
ev->set_keycode(fix_keycode(p_char, p_key));
|
||||
if (@available(iOS 13.4, *)) {
|
||||
if (p_key != Key::SHIFT) {
|
||||
ev->set_shift_pressed(p_modifier & UIKeyModifierShift);
|
||||
}
|
||||
if (p_key != Key::CTRL) {
|
||||
ev->set_ctrl_pressed(p_modifier & UIKeyModifierControl);
|
||||
}
|
||||
if (p_key != Key::ALT) {
|
||||
ev->set_alt_pressed(p_modifier & UIKeyModifierAlternate);
|
||||
}
|
||||
if (p_key != Key::META) {
|
||||
ev->set_meta_pressed(p_modifier & UIKeyModifierCommand);
|
||||
}
|
||||
}
|
||||
ev->set_key_label(p_unshifted);
|
||||
ev->set_physical_keycode(p_physical);
|
||||
ev->set_unicode(fix_unicode(p_char));
|
||||
ev->set_location(p_location);
|
||||
perform_event(ev);
|
||||
}
|
||||
|
||||
// MARK: Motion
|
||||
|
||||
void DisplayServerAppleEmbedded::update_gravity(const Vector3 &p_gravity) {
|
||||
Input::get_singleton()->set_gravity(p_gravity);
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::update_accelerometer(const Vector3 &p_accelerometer) {
|
||||
Input::get_singleton()->set_accelerometer(p_accelerometer / kDisplayServerIOSAcceleration);
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::update_magnetometer(const Vector3 &p_magnetometer) {
|
||||
Input::get_singleton()->set_magnetometer(p_magnetometer);
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::update_gyroscope(const Vector3 &p_gyroscope) {
|
||||
Input::get_singleton()->set_gyroscope(p_gyroscope);
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
bool DisplayServerAppleEmbedded::has_feature(Feature p_feature) const {
|
||||
switch (p_feature) {
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
case FEATURE_GLOBAL_MENU: {
|
||||
return (native_menu && native_menu->has_feature(NativeMenu::FEATURE_GLOBAL_MENU));
|
||||
} break;
|
||||
#endif
|
||||
// case FEATURE_CURSOR_SHAPE:
|
||||
// case FEATURE_CUSTOM_CURSOR_SHAPE:
|
||||
// case FEATURE_HIDPI:
|
||||
// case FEATURE_ICON:
|
||||
// case FEATURE_IME:
|
||||
// case FEATURE_MOUSE:
|
||||
// case FEATURE_MOUSE_WARP:
|
||||
// case FEATURE_NATIVE_DIALOG:
|
||||
// case FEATURE_NATIVE_DIALOG_INPUT:
|
||||
// case FEATURE_NATIVE_DIALOG_FILE:
|
||||
// case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
|
||||
// case FEATURE_NATIVE_DIALOG_FILE_MIME:
|
||||
// case FEATURE_NATIVE_ICON:
|
||||
// case FEATURE_WINDOW_TRANSPARENCY:
|
||||
case FEATURE_CLIPBOARD:
|
||||
case FEATURE_KEEP_SCREEN_ON:
|
||||
case FEATURE_ORIENTATION:
|
||||
case FEATURE_TOUCHSCREEN:
|
||||
case FEATURE_VIRTUAL_KEYBOARD:
|
||||
case FEATURE_TEXT_TO_SPEECH:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::initialize_tts() const {
|
||||
const_cast<DisplayServerAppleEmbedded *>(this)->tts = [[GDTTTS alloc] init];
|
||||
}
|
||||
|
||||
bool DisplayServerAppleEmbedded::tts_is_speaking() const {
|
||||
if (unlikely(!tts)) {
|
||||
initialize_tts();
|
||||
}
|
||||
ERR_FAIL_NULL_V(tts, false);
|
||||
return [tts isSpeaking];
|
||||
}
|
||||
|
||||
bool DisplayServerAppleEmbedded::tts_is_paused() const {
|
||||
if (unlikely(!tts)) {
|
||||
initialize_tts();
|
||||
}
|
||||
ERR_FAIL_NULL_V(tts, false);
|
||||
return [tts isPaused];
|
||||
}
|
||||
|
||||
TypedArray<Dictionary> DisplayServerAppleEmbedded::tts_get_voices() const {
|
||||
if (unlikely(!tts)) {
|
||||
initialize_tts();
|
||||
}
|
||||
ERR_FAIL_NULL_V(tts, TypedArray<Dictionary>());
|
||||
return [tts getVoices];
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
|
||||
if (unlikely(!tts)) {
|
||||
initialize_tts();
|
||||
}
|
||||
ERR_FAIL_NULL(tts);
|
||||
[tts speak:p_text voice:p_voice volume:p_volume pitch:p_pitch rate:p_rate utterance_id:p_utterance_id interrupt:p_interrupt];
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::tts_pause() {
|
||||
if (unlikely(!tts)) {
|
||||
initialize_tts();
|
||||
}
|
||||
ERR_FAIL_NULL(tts);
|
||||
[tts pauseSpeaking];
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::tts_resume() {
|
||||
if (unlikely(!tts)) {
|
||||
initialize_tts();
|
||||
}
|
||||
ERR_FAIL_NULL(tts);
|
||||
[tts resumeSpeaking];
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::tts_stop() {
|
||||
if (unlikely(!tts)) {
|
||||
initialize_tts();
|
||||
}
|
||||
ERR_FAIL_NULL(tts);
|
||||
[tts stopSpeaking];
|
||||
}
|
||||
|
||||
bool DisplayServerAppleEmbedded::is_dark_mode_supported() const {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DisplayServerAppleEmbedded::is_dark_mode() const {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
return [UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::set_system_theme_change_callback(const Callable &p_callable) {
|
||||
system_theme_changed = p_callable;
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::emit_system_theme_changed() {
|
||||
if (system_theme_changed.is_valid()) {
|
||||
Variant ret;
|
||||
Callable::CallError ce;
|
||||
system_theme_changed.callp(nullptr, 0, ret, ce);
|
||||
if (ce.error != Callable::CallError::CALL_OK) {
|
||||
ERR_PRINT(vformat("Failed to execute system theme changed callback: %s.", Variant::get_callable_error_text(system_theme_changed, nullptr, 0, ce)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rect2i DisplayServerAppleEmbedded::get_display_safe_area() const {
|
||||
UIEdgeInsets insets = UIEdgeInsetsZero;
|
||||
UIView *view = GDTAppDelegateService.viewController.godotView;
|
||||
if ([view respondsToSelector:@selector(safeAreaInsets)]) {
|
||||
insets = [view safeAreaInsets];
|
||||
}
|
||||
float scale = screen_get_scale();
|
||||
Size2i insets_position = Size2i(insets.left, insets.top) * scale;
|
||||
Size2i insets_size = Size2i(insets.left + insets.right, insets.top + insets.bottom) * scale;
|
||||
return Rect2i(screen_get_position() + insets_position, screen_get_size() - insets_size);
|
||||
}
|
||||
|
||||
int DisplayServerAppleEmbedded::get_screen_count() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DisplayServerAppleEmbedded::get_primary_screen() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Point2i DisplayServerAppleEmbedded::screen_get_position(int p_screen) const {
|
||||
return Size2i();
|
||||
}
|
||||
|
||||
Size2i DisplayServerAppleEmbedded::screen_get_size(int p_screen) const {
|
||||
CALayer *layer = GDTAppDelegateService.viewController.godotView.renderingLayer;
|
||||
|
||||
if (!layer) {
|
||||
return Size2i();
|
||||
}
|
||||
|
||||
return Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_scale(p_screen);
|
||||
}
|
||||
|
||||
Rect2i DisplayServerAppleEmbedded::screen_get_usable_rect(int p_screen) const {
|
||||
return Rect2i(screen_get_position(p_screen), screen_get_size(p_screen));
|
||||
}
|
||||
|
||||
Vector<DisplayServer::WindowID> DisplayServerAppleEmbedded::get_window_list() const {
|
||||
Vector<DisplayServer::WindowID> list;
|
||||
list.push_back(MAIN_WINDOW_ID);
|
||||
return list;
|
||||
}
|
||||
|
||||
DisplayServer::WindowID DisplayServerAppleEmbedded::get_window_at_screen_position(const Point2i &p_position) const {
|
||||
return MAIN_WINDOW_ID;
|
||||
}
|
||||
|
||||
int64_t DisplayServerAppleEmbedded::window_get_native_handle(HandleType p_handle_type, WindowID p_window) const {
|
||||
ERR_FAIL_COND_V(p_window != MAIN_WINDOW_ID, 0);
|
||||
switch (p_handle_type) {
|
||||
case DISPLAY_HANDLE: {
|
||||
return 0; // Not supported.
|
||||
}
|
||||
case WINDOW_HANDLE: {
|
||||
return (int64_t)GDTAppDelegateService.viewController;
|
||||
}
|
||||
case WINDOW_VIEW: {
|
||||
return (int64_t)GDTAppDelegateService.viewController.godotView;
|
||||
}
|
||||
default: {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::window_attach_instance_id(ObjectID p_instance, WindowID p_window) {
|
||||
window_attached_instance_id = p_instance;
|
||||
}
|
||||
|
||||
ObjectID DisplayServerAppleEmbedded::window_get_attached_instance_id(WindowID p_window) const {
|
||||
return window_attached_instance_id;
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::window_set_title(const String &p_title, WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
int DisplayServerAppleEmbedded::window_get_current_screen(WindowID p_window) const {
|
||||
return SCREEN_OF_MAIN_WINDOW;
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::window_set_current_screen(int p_screen, WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
Point2i DisplayServerAppleEmbedded::window_get_position(WindowID p_window) const {
|
||||
return Point2i();
|
||||
}
|
||||
|
||||
Point2i DisplayServerAppleEmbedded::window_get_position_with_decorations(WindowID p_window) const {
|
||||
return Point2i();
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::window_set_position(const Point2i &p_position, WindowID p_window) {
|
||||
// Probably not supported for single window iOS app
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::window_set_transient(WindowID p_window, WindowID p_parent) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::window_set_max_size(const Size2i p_size, WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
Size2i DisplayServerAppleEmbedded::window_get_max_size(WindowID p_window) const {
|
||||
return Size2i();
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::window_set_min_size(const Size2i p_size, WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
Size2i DisplayServerAppleEmbedded::window_get_min_size(WindowID p_window) const {
|
||||
return Size2i();
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::window_set_size(const Size2i p_size, WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
Size2i DisplayServerAppleEmbedded::window_get_size(WindowID p_window) const {
|
||||
id<UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];
|
||||
CGRect windowBounds = appDelegate.window.bounds;
|
||||
return Size2i(windowBounds.size.width, windowBounds.size.height) * screen_get_max_scale();
|
||||
}
|
||||
|
||||
Size2i DisplayServerAppleEmbedded::window_get_size_with_decorations(WindowID p_window) const {
|
||||
return window_get_size(p_window);
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::window_set_mode(WindowMode p_mode, WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
DisplayServer::WindowMode DisplayServerAppleEmbedded::window_get_mode(WindowID p_window) const {
|
||||
return WindowMode::WINDOW_MODE_FULLSCREEN;
|
||||
}
|
||||
|
||||
bool DisplayServerAppleEmbedded::window_is_maximize_allowed(WindowID p_window) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
bool DisplayServerAppleEmbedded::window_get_flag(WindowFlags p_flag, WindowID p_window) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::window_request_attention(WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::window_move_to_foreground(WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
bool DisplayServerAppleEmbedded::window_is_focused(WindowID p_window) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
float DisplayServerAppleEmbedded::screen_get_max_scale() const {
|
||||
return screen_get_scale(SCREEN_OF_MAIN_WINDOW);
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::screen_set_orientation(DisplayServer::ScreenOrientation p_orientation, int p_screen) {
|
||||
screen_orientation = p_orientation;
|
||||
if (@available(iOS 16.0, *)) {
|
||||
[GDTAppDelegateService.viewController setNeedsUpdateOfSupportedInterfaceOrientations];
|
||||
} else {
|
||||
[UIViewController attemptRotationToDeviceOrientation];
|
||||
}
|
||||
}
|
||||
|
||||
DisplayServer::ScreenOrientation DisplayServerAppleEmbedded::screen_get_orientation(int p_screen) const {
|
||||
return screen_orientation;
|
||||
}
|
||||
|
||||
bool DisplayServerAppleEmbedded::window_can_draw(WindowID p_window) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DisplayServerAppleEmbedded::can_any_window_draw() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DisplayServerAppleEmbedded::is_touchscreen_available() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int _convert_utf32_offset_to_utf16(const String &p_existing_text, int p_pos) {
|
||||
int limit = p_pos;
|
||||
for (int i = 0; i < MIN(p_existing_text.length(), p_pos); i++) {
|
||||
if (p_existing_text[i] > 0xffff) {
|
||||
limit++;
|
||||
}
|
||||
}
|
||||
return limit;
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_length, int p_cursor_start, int p_cursor_end) {
|
||||
NSString *existingString = [[NSString alloc] initWithUTF8String:p_existing_text.utf8().get_data()];
|
||||
|
||||
GDTAppDelegateService.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault;
|
||||
GDTAppDelegateService.viewController.keyboardView.textContentType = nil;
|
||||
switch (p_type) {
|
||||
case KEYBOARD_TYPE_DEFAULT: {
|
||||
GDTAppDelegateService.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault;
|
||||
} break;
|
||||
case KEYBOARD_TYPE_MULTILINE: {
|
||||
GDTAppDelegateService.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault;
|
||||
} break;
|
||||
case KEYBOARD_TYPE_NUMBER: {
|
||||
GDTAppDelegateService.viewController.keyboardView.keyboardType = UIKeyboardTypeNumberPad;
|
||||
} break;
|
||||
case KEYBOARD_TYPE_NUMBER_DECIMAL: {
|
||||
GDTAppDelegateService.viewController.keyboardView.keyboardType = UIKeyboardTypeDecimalPad;
|
||||
} break;
|
||||
case KEYBOARD_TYPE_PHONE: {
|
||||
GDTAppDelegateService.viewController.keyboardView.keyboardType = UIKeyboardTypePhonePad;
|
||||
GDTAppDelegateService.viewController.keyboardView.textContentType = UITextContentTypeTelephoneNumber;
|
||||
} break;
|
||||
case KEYBOARD_TYPE_EMAIL_ADDRESS: {
|
||||
GDTAppDelegateService.viewController.keyboardView.keyboardType = UIKeyboardTypeEmailAddress;
|
||||
GDTAppDelegateService.viewController.keyboardView.textContentType = UITextContentTypeEmailAddress;
|
||||
} break;
|
||||
case KEYBOARD_TYPE_PASSWORD: {
|
||||
GDTAppDelegateService.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault;
|
||||
GDTAppDelegateService.viewController.keyboardView.textContentType = UITextContentTypePassword;
|
||||
} break;
|
||||
case KEYBOARD_TYPE_URL: {
|
||||
GDTAppDelegateService.viewController.keyboardView.keyboardType = UIKeyboardTypeWebSearch;
|
||||
GDTAppDelegateService.viewController.keyboardView.textContentType = UITextContentTypeURL;
|
||||
} break;
|
||||
}
|
||||
|
||||
[GDTAppDelegateService.viewController.keyboardView
|
||||
becomeFirstResponderWithString:existingString
|
||||
cursorStart:_convert_utf32_offset_to_utf16(p_existing_text, p_cursor_start)
|
||||
cursorEnd:_convert_utf32_offset_to_utf16(p_existing_text, p_cursor_end)];
|
||||
}
|
||||
|
||||
bool DisplayServerAppleEmbedded::is_keyboard_active() const {
|
||||
return [GDTAppDelegateService.viewController.keyboardView isFirstResponder];
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::virtual_keyboard_hide() {
|
||||
[GDTAppDelegateService.viewController.keyboardView resignFirstResponder];
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::virtual_keyboard_set_height(int height) {
|
||||
virtual_keyboard_height = height * screen_get_max_scale();
|
||||
}
|
||||
|
||||
int DisplayServerAppleEmbedded::virtual_keyboard_get_height() const {
|
||||
return virtual_keyboard_height;
|
||||
}
|
||||
|
||||
bool DisplayServerAppleEmbedded::has_hardware_keyboard() const {
|
||||
if (@available(iOS 14.0, *)) {
|
||||
return [GCKeyboard coalescedKeyboard];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::clipboard_set(const String &p_text) {
|
||||
[UIPasteboard generalPasteboard].string = [NSString stringWithUTF8String:p_text.utf8().get_data()];
|
||||
}
|
||||
|
||||
String DisplayServerAppleEmbedded::clipboard_get() const {
|
||||
NSString *text = [UIPasteboard generalPasteboard].string;
|
||||
|
||||
return String::utf8([text UTF8String]);
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::screen_set_keep_on(bool p_enable) {
|
||||
[UIApplication sharedApplication].idleTimerDisabled = p_enable;
|
||||
}
|
||||
|
||||
bool DisplayServerAppleEmbedded::screen_is_kept_on() const {
|
||||
return [UIApplication sharedApplication].idleTimerDisabled;
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::resize_window(CGSize viewSize) {
|
||||
Size2i size = Size2i(viewSize.width, viewSize.height) * screen_get_max_scale();
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
if (rendering_context) {
|
||||
rendering_context->window_set_size(MAIN_WINDOW_ID, size.x, size.y);
|
||||
}
|
||||
#endif
|
||||
|
||||
Variant resize_rect = Rect2i(Point2i(), size);
|
||||
_window_callback(window_resize_callback, resize_rect);
|
||||
}
|
||||
|
||||
void DisplayServerAppleEmbedded::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
|
||||
_THREAD_SAFE_METHOD_
|
||||
#if defined(RD_ENABLED)
|
||||
if (rendering_context) {
|
||||
rendering_context->window_set_vsync_mode(p_window, p_vsync_mode);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
DisplayServer::VSyncMode DisplayServerAppleEmbedded::window_get_vsync_mode(WindowID p_window) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
#if defined(RD_ENABLED)
|
||||
if (rendering_context) {
|
||||
return rendering_context->window_get_vsync_mode(p_window);
|
||||
}
|
||||
#endif
|
||||
return DisplayServer::VSYNC_ENABLED;
|
||||
}
|
|
@ -32,12 +32,12 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
typedef NSObject<UIApplicationDelegate> ApplicationDelegateService;
|
||||
typedef NSObject<UIApplicationDelegate> GDTAppDelegateServiceProtocol;
|
||||
|
||||
@interface GodotApplicationDelegate : NSObject <UIApplicationDelegate>
|
||||
@interface GDTApplicationDelegate : NSObject <UIApplicationDelegate>
|
||||
|
||||
@property(class, readonly, strong) NSArray<ApplicationDelegateService *> *services;
|
||||
@property(class, readonly, strong) NSArray<GDTAppDelegateServiceProtocol *> *services;
|
||||
|
||||
+ (void)addService:(ApplicationDelegateService *)service;
|
||||
+ (void)addService:(GDTAppDelegateServiceProtocol *)service;
|
||||
|
||||
@end
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* godot_app_delegate.m */
|
||||
/* godot_app_delegate.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -30,26 +30,22 @@
|
|||
|
||||
#import "godot_app_delegate.h"
|
||||
|
||||
#import "app_delegate.h"
|
||||
#import "app_delegate_service.h"
|
||||
|
||||
@interface GodotApplicationDelegate ()
|
||||
@implementation GDTApplicationDelegate
|
||||
|
||||
@end
|
||||
static NSMutableArray<GDTAppDelegateServiceProtocol *> *services = nil;
|
||||
|
||||
@implementation GodotApplicationDelegate
|
||||
|
||||
static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
||||
|
||||
+ (NSArray<ApplicationDelegateService *> *)services {
|
||||
+ (NSArray<GDTAppDelegateServiceProtocol *> *)services {
|
||||
return services;
|
||||
}
|
||||
|
||||
+ (void)load {
|
||||
services = [NSMutableArray new];
|
||||
[services addObject:[AppDelegate new]];
|
||||
[services addObject:[GDTAppDelegateService new]];
|
||||
}
|
||||
|
||||
+ (void)addService:(ApplicationDelegateService *)service {
|
||||
+ (void)addService:(GDTAppDelegateServiceProtocol *)service {
|
||||
if (!services || !service) {
|
||||
return;
|
||||
}
|
||||
|
@ -63,7 +59,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
- (UIWindow *)window {
|
||||
UIWindow *result = nil;
|
||||
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -83,7 +79,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey, id> *)launchOptions {
|
||||
BOOL result = NO;
|
||||
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -99,7 +95,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey, id> *)launchOptions {
|
||||
BOOL result = NO;
|
||||
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -125,7 +121,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
// MARK: Life-Cycle
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -135,7 +131,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
}
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication *)application {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -145,7 +141,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
}
|
||||
|
||||
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -155,7 +151,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
}
|
||||
|
||||
- (void)applicationWillEnterForeground:(UIApplication *)application {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -165,7 +161,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
}
|
||||
|
||||
- (void)applicationWillTerminate:(UIApplication *)application {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -177,7 +173,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
// MARK: Environment Changes
|
||||
|
||||
- (void)applicationProtectedDataDidBecomeAvailable:(UIApplication *)application {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -187,7 +183,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
}
|
||||
|
||||
- (void)applicationProtectedDataWillBecomeUnavailable:(UIApplication *)application {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -197,7 +193,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
}
|
||||
|
||||
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -207,7 +203,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
}
|
||||
|
||||
- (void)applicationSignificantTimeChange:(UIApplication *)application {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -221,7 +217,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
- (BOOL)application:(UIApplication *)application shouldSaveSecureApplicationState:(NSCoder *)coder API_AVAILABLE(ios(13.2)) {
|
||||
BOOL result = NO;
|
||||
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -237,7 +233,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
- (BOOL)application:(UIApplication *)application shouldRestoreSecureApplicationState:(NSCoder *)coder API_AVAILABLE(ios(13.2)) {
|
||||
BOOL result = NO;
|
||||
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -251,7 +247,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
}
|
||||
|
||||
- (UIViewController *)application:(UIApplication *)application viewControllerWithRestorationIdentifierPath:(NSArray<NSString *> *)identifierComponents coder:(NSCoder *)coder {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -267,7 +263,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
}
|
||||
|
||||
- (void)application:(UIApplication *)application willEncodeRestorableStateWithCoder:(NSCoder *)coder {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -277,7 +273,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
}
|
||||
|
||||
- (void)application:(UIApplication *)application didDecodeRestorableStateWithCoder:(NSCoder *)coder {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -289,7 +285,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
// MARK: Download Data in Background
|
||||
|
||||
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -309,7 +305,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
- (BOOL)application:(UIApplication *)application willContinueUserActivityWithType:(NSString *)userActivityType {
|
||||
BOOL result = NO;
|
||||
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -325,7 +321,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *restorableObjects))restorationHandler {
|
||||
BOOL result = NO;
|
||||
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -339,7 +335,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
}
|
||||
|
||||
- (void)application:(UIApplication *)application didUpdateUserActivity:(NSUserActivity *)userActivity {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -349,7 +345,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
}
|
||||
|
||||
- (void)application:(UIApplication *)application didFailToContinueUserActivityWithType:(NSString *)userActivityType error:(NSError *)error {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -359,7 +355,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
}
|
||||
|
||||
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL succeeded))completionHandler {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -371,7 +367,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
// MARK: WatchKit
|
||||
|
||||
- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *replyInfo))reply {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -383,7 +379,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
// MARK: HealthKit
|
||||
|
||||
- (void)applicationShouldRequestHealthAuthorization:(UIApplication *)application {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -395,7 +391,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
// MARK: Opening an URL
|
||||
|
||||
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -413,7 +409,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
- (BOOL)application:(UIApplication *)application shouldAllowExtensionPointIdentifier:(UIApplicationExtensionPointIdentifier)extensionPointIdentifier {
|
||||
BOOL result = NO;
|
||||
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -429,7 +425,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
// MARK: SiriKit
|
||||
|
||||
- (id)application:(UIApplication *)application handlerForIntent:(INIntent *)intent API_AVAILABLE(ios(14.0)) {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -447,7 +443,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
|
|||
// MARK: CloudKit
|
||||
|
||||
- (void)application:(UIApplication *)application userDidAcceptCloudKitShareWithMetadata:(CKShareMetadata *)cloudKitShareMetadata {
|
||||
for (ApplicationDelegateService *service in services) {
|
||||
for (GDTAppDelegateServiceProtocol *service in services) {
|
||||
if (![service respondsToSelector:_cmd]) {
|
||||
continue;
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* godot_view.h */
|
||||
/* godot_view_apple_embedded.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -34,31 +34,39 @@
|
|||
|
||||
class String;
|
||||
|
||||
@class GodotView;
|
||||
@protocol DisplayLayer;
|
||||
@protocol GodotViewRendererProtocol;
|
||||
@class GDTView;
|
||||
@protocol GDTDisplayLayer;
|
||||
@protocol GDTViewRendererProtocol;
|
||||
|
||||
@protocol GodotViewDelegate
|
||||
@protocol GDTViewDelegate
|
||||
|
||||
- (BOOL)godotViewFinishedSetup:(GodotView *)view;
|
||||
- (BOOL)godotViewFinishedSetup:(GDTView *)view;
|
||||
|
||||
@end
|
||||
|
||||
@interface GodotView : UIView
|
||||
@interface GDTView : UIView
|
||||
|
||||
@property(assign, nonatomic) id<GodotViewRendererProtocol> renderer;
|
||||
@property(assign, nonatomic) id<GodotViewDelegate> delegate;
|
||||
@property(assign, nonatomic) id<GDTViewRendererProtocol> renderer;
|
||||
@property(assign, nonatomic) id<GDTViewDelegate> delegate;
|
||||
|
||||
@property(assign, readonly, nonatomic) BOOL isActive;
|
||||
|
||||
@property(assign, nonatomic) BOOL useCADisplayLink;
|
||||
@property(strong, readonly, nonatomic) CALayer<DisplayLayer> *renderingLayer;
|
||||
@property(strong, readonly, nonatomic) CALayer<GDTDisplayLayer> *renderingLayer;
|
||||
@property(assign, readonly, nonatomic) BOOL canRender;
|
||||
|
||||
@property(assign, nonatomic) NSTimeInterval renderingInterval;
|
||||
|
||||
- (CALayer<DisplayLayer> *)initializeRenderingForDriver:(NSString *)driverName;
|
||||
// Can be extended by subclasses
|
||||
- (void)godot_commonInit;
|
||||
|
||||
// Implemented in subclasses
|
||||
- (CALayer<GDTDisplayLayer> *)initializeRenderingForDriver:(NSString *)driverName;
|
||||
|
||||
- (void)stopRendering;
|
||||
- (void)startRendering;
|
||||
|
||||
@end
|
||||
|
||||
// Implemented in subclasses
|
||||
extern GDTView *GDTViewCreate();
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* godot_view.mm */
|
||||
/* godot_view_apple_embedded.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -28,10 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#import "godot_view.h"
|
||||
#import "godot_view_apple_embedded.h"
|
||||
|
||||
#import "display_layer.h"
|
||||
#import "display_server_ios.h"
|
||||
#import "display_layer_apple_embedded.h"
|
||||
#import "display_server_apple_embedded.h"
|
||||
#import "godot_view_renderer.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
|
@ -43,7 +43,7 @@
|
|||
static const int max_touches = 32;
|
||||
static const float earth_gravity = 9.80665;
|
||||
|
||||
@interface GodotView () {
|
||||
@interface GDTView () {
|
||||
UITouch *godot_touches[max_touches];
|
||||
}
|
||||
|
||||
|
@ -56,48 +56,17 @@ static const float earth_gravity = 9.80665;
|
|||
// Only used if CADisplayLink is not
|
||||
@property(strong, nonatomic) NSTimer *animationTimer;
|
||||
|
||||
@property(strong, nonatomic) CALayer<DisplayLayer> *renderingLayer;
|
||||
@property(strong, nonatomic) CALayer<GDTDisplayLayer> *renderingLayer;
|
||||
|
||||
@property(strong, nonatomic) CMMotionManager *motionManager;
|
||||
|
||||
@end
|
||||
|
||||
@implementation GodotView
|
||||
@implementation GDTView
|
||||
|
||||
- (CALayer<DisplayLayer> *)initializeRenderingForDriver:(NSString *)driverName {
|
||||
if (self.renderingLayer) {
|
||||
return self.renderingLayer;
|
||||
}
|
||||
|
||||
CALayer<DisplayLayer> *layer;
|
||||
|
||||
if ([driverName isEqualToString:@"vulkan"] || [driverName isEqualToString:@"metal"]) {
|
||||
#if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR
|
||||
if (@available(iOS 13, *)) {
|
||||
layer = [GodotMetalLayer layer];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
#else
|
||||
layer = [GodotMetalLayer layer];
|
||||
#endif
|
||||
} else if ([driverName isEqualToString:@"opengl3"]) {
|
||||
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wdeprecated-declarations") // OpenGL is deprecated in iOS 12.0.
|
||||
layer = [GodotOpenGLLayer layer];
|
||||
GODOT_CLANG_WARNING_POP
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
|
||||
layer.frame = self.bounds;
|
||||
layer.contentsScale = self.contentScaleFactor;
|
||||
|
||||
[self.layer addSublayer:layer];
|
||||
self.renderingLayer = layer;
|
||||
|
||||
[layer initializeDisplayLayer];
|
||||
|
||||
return self.renderingLayer;
|
||||
// Implemented in subclasses
|
||||
- (CALayer<GDTDisplayLayer> *)initializeRenderingForDriver:(NSString *)driverName {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder {
|
||||
|
@ -150,6 +119,10 @@ static const float earth_gravity = 9.80665;
|
|||
- (void)godot_commonInit {
|
||||
self.contentScaleFactor = [UIScreen mainScreen].scale;
|
||||
|
||||
if (@available(iOS 17.0, *)) {
|
||||
[self registerForTraitChanges:@[ [UITraitUserInterfaceStyle class] ] withTarget:self action:@selector(traitCollectionDidChangeWithView:previousTraitCollection:)];
|
||||
}
|
||||
|
||||
[self initTouches];
|
||||
|
||||
self.multipleTouchEnabled = YES;
|
||||
|
@ -167,7 +140,7 @@ static const float earth_gravity = 9.80665;
|
|||
}
|
||||
|
||||
- (void)system_theme_changed {
|
||||
DisplayServerIOS *ds = (DisplayServerIOS *)DisplayServer::get_singleton();
|
||||
DisplayServerAppleEmbedded *ds = (DisplayServerAppleEmbedded *)DisplayServer::get_singleton();
|
||||
if (ds) {
|
||||
ds->emit_system_theme_changed();
|
||||
}
|
||||
|
@ -176,7 +149,13 @@ static const float earth_gravity = 9.80665;
|
|||
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
[super traitCollectionDidChange:previousTraitCollection];
|
||||
[self traitCollectionDidChangeWithView:self
|
||||
previousTraitCollection:previousTraitCollection];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)traitCollectionDidChangeWithView:(UIView *)view previousTraitCollection:(UITraitCollection *)previousTraitCollection {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
if ([UITraitCollection currentTraitCollection].userInterfaceStyle != previousTraitCollection.userInterfaceStyle) {
|
||||
[self system_theme_changed];
|
||||
}
|
||||
|
@ -293,8 +272,8 @@ static const float earth_gravity = 9.80665;
|
|||
self.renderingLayer.frame = self.bounds;
|
||||
[self.renderingLayer layoutDisplayLayer];
|
||||
|
||||
if (DisplayServerIOS::get_singleton()) {
|
||||
DisplayServerIOS::get_singleton()->resize_window(self.bounds.size);
|
||||
if (DisplayServerAppleEmbedded::get_singleton()) {
|
||||
DisplayServerAppleEmbedded::get_singleton()->resize_window(self.bounds.size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -357,7 +336,7 @@ static const float earth_gravity = 9.80665;
|
|||
int tid = [self getTouchIDForTouch:touch];
|
||||
ERR_FAIL_COND(tid == -1);
|
||||
CGPoint touchPoint = [touch locationInView:self];
|
||||
DisplayServerIOS::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1);
|
||||
DisplayServerAppleEmbedded::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -369,7 +348,7 @@ static const float earth_gravity = 9.80665;
|
|||
CGPoint prev_point = [touch previousLocationInView:self];
|
||||
CGFloat alt = [touch altitudeAngle];
|
||||
CGVector azim = [touch azimuthUnitVectorInView:self];
|
||||
DisplayServerIOS::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, [touch force] / [touch maximumPossibleForce], Vector2(azim.dx, azim.dy) * Math::cos(alt));
|
||||
DisplayServerAppleEmbedded::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, [touch force] / [touch maximumPossibleForce], Vector2(azim.dx, azim.dy) * Math::cos(alt));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,7 +358,7 @@ static const float earth_gravity = 9.80665;
|
|||
ERR_FAIL_COND(tid == -1);
|
||||
[self removeTouch:touch];
|
||||
CGPoint touchPoint = [touch locationInView:self];
|
||||
DisplayServerIOS::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false);
|
||||
DisplayServerAppleEmbedded::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -387,7 +366,7 @@ static const float earth_gravity = 9.80665;
|
|||
for (UITouch *touch in touches) {
|
||||
int tid = [self getTouchIDForTouch:touch];
|
||||
ERR_FAIL_COND(tid == -1);
|
||||
DisplayServerIOS::get_singleton()->touches_canceled(tid);
|
||||
DisplayServerAppleEmbedded::get_singleton()->touches_canceled(tid);
|
||||
}
|
||||
[self clearTouches];
|
||||
}
|
||||
|
@ -454,28 +433,28 @@ static const float earth_gravity = 9.80665;
|
|||
|
||||
switch (interfaceOrientation) {
|
||||
case UIInterfaceOrientationLandscapeLeft: {
|
||||
DisplayServerIOS::get_singleton()->update_gravity(Vector3(gravity.x, gravity.y, gravity.z).rotated(Vector3(0, 0, 1), -Math::PI * 0.5));
|
||||
DisplayServerIOS::get_singleton()->update_accelerometer(Vector3(acceleration.x + gravity.x, acceleration.y + gravity.y, acceleration.z + gravity.z).rotated(Vector3(0, 0, 1), -Math::PI * 0.5));
|
||||
DisplayServerIOS::get_singleton()->update_magnetometer(Vector3(magnetic.x, magnetic.y, magnetic.z).rotated(Vector3(0, 0, 1), -Math::PI * 0.5));
|
||||
DisplayServerIOS::get_singleton()->update_gyroscope(Vector3(rotation.x, rotation.y, rotation.z).rotated(Vector3(0, 0, 1), -Math::PI * 0.5));
|
||||
DisplayServerAppleEmbedded::get_singleton()->update_gravity(Vector3(gravity.x, gravity.y, gravity.z).rotated(Vector3(0, 0, 1), -Math::PI * 0.5));
|
||||
DisplayServerAppleEmbedded::get_singleton()->update_accelerometer(Vector3(acceleration.x + gravity.x, acceleration.y + gravity.y, acceleration.z + gravity.z).rotated(Vector3(0, 0, 1), -Math::PI * 0.5));
|
||||
DisplayServerAppleEmbedded::get_singleton()->update_magnetometer(Vector3(magnetic.x, magnetic.y, magnetic.z).rotated(Vector3(0, 0, 1), -Math::PI * 0.5));
|
||||
DisplayServerAppleEmbedded::get_singleton()->update_gyroscope(Vector3(rotation.x, rotation.y, rotation.z).rotated(Vector3(0, 0, 1), -Math::PI * 0.5));
|
||||
} break;
|
||||
case UIInterfaceOrientationLandscapeRight: {
|
||||
DisplayServerIOS::get_singleton()->update_gravity(Vector3(gravity.x, gravity.y, gravity.z).rotated(Vector3(0, 0, 1), Math::PI * 0.5));
|
||||
DisplayServerIOS::get_singleton()->update_accelerometer(Vector3(acceleration.x + gravity.x, acceleration.y + gravity.y, acceleration.z + gravity.z).rotated(Vector3(0, 0, 1), Math::PI * 0.5));
|
||||
DisplayServerIOS::get_singleton()->update_magnetometer(Vector3(magnetic.x, magnetic.y, magnetic.z).rotated(Vector3(0, 0, 1), Math::PI * 0.5));
|
||||
DisplayServerIOS::get_singleton()->update_gyroscope(Vector3(rotation.x, rotation.y, rotation.z).rotated(Vector3(0, 0, 1), Math::PI * 0.5));
|
||||
DisplayServerAppleEmbedded::get_singleton()->update_gravity(Vector3(gravity.x, gravity.y, gravity.z).rotated(Vector3(0, 0, 1), Math::PI * 0.5));
|
||||
DisplayServerAppleEmbedded::get_singleton()->update_accelerometer(Vector3(acceleration.x + gravity.x, acceleration.y + gravity.y, acceleration.z + gravity.z).rotated(Vector3(0, 0, 1), Math::PI * 0.5));
|
||||
DisplayServerAppleEmbedded::get_singleton()->update_magnetometer(Vector3(magnetic.x, magnetic.y, magnetic.z).rotated(Vector3(0, 0, 1), Math::PI * 0.5));
|
||||
DisplayServerAppleEmbedded::get_singleton()->update_gyroscope(Vector3(rotation.x, rotation.y, rotation.z).rotated(Vector3(0, 0, 1), Math::PI * 0.5));
|
||||
} break;
|
||||
case UIInterfaceOrientationPortraitUpsideDown: {
|
||||
DisplayServerIOS::get_singleton()->update_gravity(Vector3(gravity.x, gravity.y, gravity.z).rotated(Vector3(0, 0, 1), Math::PI));
|
||||
DisplayServerIOS::get_singleton()->update_accelerometer(Vector3(acceleration.x + gravity.x, acceleration.y + gravity.y, acceleration.z + gravity.z).rotated(Vector3(0, 0, 1), Math::PI));
|
||||
DisplayServerIOS::get_singleton()->update_magnetometer(Vector3(magnetic.x, magnetic.y, magnetic.z).rotated(Vector3(0, 0, 1), Math::PI));
|
||||
DisplayServerIOS::get_singleton()->update_gyroscope(Vector3(rotation.x, rotation.y, rotation.z).rotated(Vector3(0, 0, 1), Math::PI));
|
||||
DisplayServerAppleEmbedded::get_singleton()->update_gravity(Vector3(gravity.x, gravity.y, gravity.z).rotated(Vector3(0, 0, 1), Math::PI));
|
||||
DisplayServerAppleEmbedded::get_singleton()->update_accelerometer(Vector3(acceleration.x + gravity.x, acceleration.y + gravity.y, acceleration.z + gravity.z).rotated(Vector3(0, 0, 1), Math::PI));
|
||||
DisplayServerAppleEmbedded::get_singleton()->update_magnetometer(Vector3(magnetic.x, magnetic.y, magnetic.z).rotated(Vector3(0, 0, 1), Math::PI));
|
||||
DisplayServerAppleEmbedded::get_singleton()->update_gyroscope(Vector3(rotation.x, rotation.y, rotation.z).rotated(Vector3(0, 0, 1), Math::PI));
|
||||
} break;
|
||||
default: { // assume portrait
|
||||
DisplayServerIOS::get_singleton()->update_gravity(Vector3(gravity.x, gravity.y, gravity.z));
|
||||
DisplayServerIOS::get_singleton()->update_accelerometer(Vector3(acceleration.x + gravity.x, acceleration.y + gravity.y, acceleration.z + gravity.z));
|
||||
DisplayServerIOS::get_singleton()->update_magnetometer(Vector3(magnetic.x, magnetic.y, magnetic.z));
|
||||
DisplayServerIOS::get_singleton()->update_gyroscope(Vector3(rotation.x, rotation.y, rotation.z));
|
||||
DisplayServerAppleEmbedded::get_singleton()->update_gravity(Vector3(gravity.x, gravity.y, gravity.z));
|
||||
DisplayServerAppleEmbedded::get_singleton()->update_accelerometer(Vector3(acceleration.x + gravity.x, acceleration.y + gravity.y, acceleration.z + gravity.z));
|
||||
DisplayServerAppleEmbedded::get_singleton()->update_magnetometer(Vector3(magnetic.x, magnetic.y, magnetic.z));
|
||||
DisplayServerAppleEmbedded::get_singleton()->update_gyroscope(Vector3(rotation.x, rotation.y, rotation.z));
|
||||
} break;
|
||||
}
|
||||
}
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@protocol GodotViewRendererProtocol <NSObject>
|
||||
@protocol GDTViewRendererProtocol <NSObject>
|
||||
|
||||
@property(assign, readonly, nonatomic) BOOL hasFinishedSetup;
|
||||
|
||||
|
@ -41,6 +41,6 @@
|
|||
|
||||
@end
|
||||
|
||||
@interface GodotViewRenderer : NSObject <GodotViewRendererProtocol>
|
||||
@interface GDTViewRenderer : NSObject <GDTViewRendererProtocol>
|
||||
|
||||
@end
|
|
@ -30,8 +30,8 @@
|
|||
|
||||
#import "godot_view_renderer.h"
|
||||
|
||||
#import "display_server_ios.h"
|
||||
#import "os_ios.h"
|
||||
#import "display_server_apple_embedded.h"
|
||||
#import "os_apple_embedded.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/os/keyboard.h"
|
||||
|
@ -44,7 +44,7 @@
|
|||
#import <QuartzCore/QuartzCore.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface GodotViewRenderer ()
|
||||
@interface GDTViewRenderer ()
|
||||
|
||||
@property(assign, nonatomic) BOOL hasFinishedProjectDataSetup;
|
||||
@property(assign, nonatomic) BOOL hasStartedMain;
|
||||
|
@ -52,7 +52,7 @@
|
|||
|
||||
@end
|
||||
|
||||
@implementation GodotViewRenderer
|
||||
@implementation GDTViewRenderer
|
||||
|
||||
- (BOOL)setupView:(UIView *)view {
|
||||
if (self.hasFinishedSetup) {
|
||||
|
@ -70,7 +70,7 @@
|
|||
|
||||
if (!self.hasStartedMain) {
|
||||
self.hasStartedMain = YES;
|
||||
OS_IOS::get_singleton()->start();
|
||||
OS_AppleEmbedded::get_singleton()->start();
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
@ -109,11 +109,11 @@
|
|||
}
|
||||
|
||||
- (void)renderOnView:(UIView *)view {
|
||||
if (!OS_IOS::get_singleton()) {
|
||||
if (!OS_AppleEmbedded::get_singleton()) {
|
||||
return;
|
||||
}
|
||||
|
||||
OS_IOS::get_singleton()->iterate();
|
||||
OS_AppleEmbedded::get_singleton()->iterate();
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* key_mapping_ios.h */
|
||||
/* key_mapping_apple_embedded.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -34,8 +34,8 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
class KeyMappingIOS {
|
||||
KeyMappingIOS() {}
|
||||
class KeyMappingAppleEmbedded {
|
||||
KeyMappingAppleEmbedded() {}
|
||||
|
||||
public:
|
||||
static void initialize();
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* key_mapping_ios.mm */
|
||||
/* key_mapping_apple_embedded.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -28,7 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#import "key_mapping_ios.h"
|
||||
#import "key_mapping_apple_embedded.h"
|
||||
|
||||
#include "core/templates/hash_map.h"
|
||||
|
||||
|
@ -40,7 +40,7 @@ struct HashMapHasherKeys {
|
|||
HashMap<CFIndex, Key, HashMapHasherKeys> keyusage_map;
|
||||
HashMap<CFIndex, KeyLocation, HashMapHasherKeys> location_map;
|
||||
|
||||
void KeyMappingIOS::initialize() {
|
||||
void KeyMappingAppleEmbedded::initialize() {
|
||||
if (@available(iOS 13.4, *)) {
|
||||
keyusage_map[UIKeyboardHIDUsageKeyboardA] = Key::A;
|
||||
keyusage_map[UIKeyboardHIDUsageKeyboardB] = Key::B;
|
||||
|
@ -185,7 +185,7 @@ void KeyMappingIOS::initialize() {
|
|||
}
|
||||
}
|
||||
|
||||
Key KeyMappingIOS::remap_key(CFIndex p_keycode) {
|
||||
Key KeyMappingAppleEmbedded::remap_key(CFIndex p_keycode) {
|
||||
if (@available(iOS 13.4, *)) {
|
||||
const Key *key = keyusage_map.getptr(p_keycode);
|
||||
if (key) {
|
||||
|
@ -195,7 +195,7 @@ Key KeyMappingIOS::remap_key(CFIndex p_keycode) {
|
|||
return Key::NONE;
|
||||
}
|
||||
|
||||
KeyLocation KeyMappingIOS::key_location(CFIndex p_keycode) {
|
||||
KeyLocation KeyMappingAppleEmbedded::key_location(CFIndex p_keycode) {
|
||||
if (@available(iOS 13.4, *)) {
|
||||
const KeyLocation *location = location_map.getptr(p_keycode);
|
||||
if (location) {
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface GodotKeyboardInputView : UITextView
|
||||
@interface GDTKeyboardInputView : UITextView
|
||||
|
||||
- (BOOL)becomeFirstResponderWithString:(NSString *)existingString cursorStart:(NSInteger)start cursorEnd:(NSInteger)end;
|
||||
|
|
@ -30,19 +30,19 @@
|
|||
|
||||
#import "keyboard_input_view.h"
|
||||
|
||||
#import "display_server_ios.h"
|
||||
#import "os_ios.h"
|
||||
#import "display_server_apple_embedded.h"
|
||||
#import "os_apple_embedded.h"
|
||||
|
||||
#include "core/os/keyboard.h"
|
||||
|
||||
@interface GodotKeyboardInputView () <UITextViewDelegate>
|
||||
@interface GDTKeyboardInputView () <UITextViewDelegate>
|
||||
|
||||
@property(nonatomic, copy) NSString *previousText;
|
||||
@property(nonatomic, assign) NSRange previousSelectedRange;
|
||||
|
||||
@end
|
||||
|
||||
@implementation GodotKeyboardInputView
|
||||
@implementation GDTKeyboardInputView
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder {
|
||||
self = [super initWithCoder:coder];
|
||||
|
@ -116,8 +116,8 @@
|
|||
|
||||
- (void)deleteText:(NSInteger)charactersToDelete {
|
||||
for (int i = 0; i < charactersToDelete; i++) {
|
||||
DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, 0, Key::BACKSPACE, Key::NONE, 0, true, KeyLocation::UNSPECIFIED);
|
||||
DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, 0, Key::BACKSPACE, Key::NONE, 0, false, KeyLocation::UNSPECIFIED);
|
||||
DisplayServerAppleEmbedded::get_singleton()->key(Key::BACKSPACE, 0, Key::BACKSPACE, Key::NONE, 0, true, KeyLocation::UNSPECIFIED);
|
||||
DisplayServerAppleEmbedded::get_singleton()->key(Key::BACKSPACE, 0, Key::BACKSPACE, Key::NONE, 0, false, KeyLocation::UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,8 +136,8 @@
|
|||
key = Key::SPACE;
|
||||
}
|
||||
|
||||
DisplayServerIOS::get_singleton()->key(key, character, key, Key::NONE, 0, true, KeyLocation::UNSPECIFIED);
|
||||
DisplayServerIOS::get_singleton()->key(key, character, key, Key::NONE, 0, false, KeyLocation::UNSPECIFIED);
|
||||
DisplayServerAppleEmbedded::get_singleton()->key(key, character, key, Key::NONE, 0, true, KeyLocation::UNSPECIFIED);
|
||||
DisplayServerAppleEmbedded::get_singleton()->key(key, character, key, Key::NONE, 0, false, KeyLocation::UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
|
35
drivers/apple_embedded/main_utilities.h
Normal file
35
drivers/apple_embedded/main_utilities.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/**************************************************************************/
|
||||
/* main_utilities.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
void change_to_launch_dir(char **p_args);
|
||||
|
||||
int process_args(int p_argc, char **p_args, char **r_args);
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* godot_ios.mm */
|
||||
/* main_utilities.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -28,15 +28,29 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#import "os_ios.h"
|
||||
|
||||
#include "core/string/ustring.h"
|
||||
#include "main/main.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <cstdio>
|
||||
|
||||
static OS_IOS *os = nullptr;
|
||||
void change_to_launch_dir(char **p_args) {
|
||||
size_t len = strlen(p_args[0]);
|
||||
|
||||
while (len--) {
|
||||
if (p_args[0][len] == '/') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (len >= 0) {
|
||||
char path[512];
|
||||
memcpy(path, p_args[0], len > sizeof(path) ? sizeof(path) : len);
|
||||
path[len] = 0;
|
||||
chdir(path);
|
||||
}
|
||||
}
|
||||
|
||||
int add_path(int p_argc, char **p_args) {
|
||||
NSString *str = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"godot_path"];
|
||||
|
@ -70,50 +84,12 @@ int add_cmdline(int p_argc, char **p_args) {
|
|||
return p_argc;
|
||||
}
|
||||
|
||||
int ios_main(int argc, char **argv) {
|
||||
size_t len = strlen(argv[0]);
|
||||
|
||||
while (len--) {
|
||||
if (argv[0][len] == '/') {
|
||||
break;
|
||||
}
|
||||
int process_args(int p_argc, char **p_args, char **r_args) {
|
||||
for (int i = 0; i < p_argc; i++) {
|
||||
r_args[i] = p_args[i];
|
||||
}
|
||||
|
||||
if (len >= 0) {
|
||||
char path[512];
|
||||
memcpy(path, argv[0], len > sizeof(path) ? sizeof(path) : len);
|
||||
path[len] = 0;
|
||||
chdir(path);
|
||||
}
|
||||
|
||||
os = new OS_IOS();
|
||||
|
||||
// We must override main when testing is enabled
|
||||
TEST_MAIN_OVERRIDE
|
||||
|
||||
char *fargv[64];
|
||||
for (int i = 0; i < argc; i++) {
|
||||
fargv[i] = argv[i];
|
||||
}
|
||||
fargv[argc] = nullptr;
|
||||
argc = add_path(argc, fargv);
|
||||
argc = add_cmdline(argc, fargv);
|
||||
|
||||
Error err = Main::setup(fargv[0], argc - 1, &fargv[1], false);
|
||||
|
||||
if (err != OK) {
|
||||
if (err == ERR_HELP) { // Returned by --help and --version, so success.
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
os->initialize_modules();
|
||||
|
||||
return os->get_exit_code();
|
||||
}
|
||||
|
||||
void ios_finish() {
|
||||
Main::cleanup();
|
||||
delete os;
|
||||
r_args[p_argc] = nullptr;
|
||||
p_argc = add_path(p_argc, r_args);
|
||||
p_argc = add_cmdline(p_argc, r_args);
|
||||
return p_argc;
|
||||
}
|
137
drivers/apple_embedded/os_apple_embedded.h
Normal file
137
drivers/apple_embedded/os_apple_embedded.h
Normal file
|
@ -0,0 +1,137 @@
|
|||
/**************************************************************************/
|
||||
/* os_apple_embedded.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef APPLE_EMBEDDED_ENABLED
|
||||
|
||||
#import "apple_embedded.h"
|
||||
|
||||
#import "drivers/apple/joypad_apple.h"
|
||||
#import "drivers/coreaudio/audio_driver_coreaudio.h"
|
||||
#include "drivers/unix/os_unix.h"
|
||||
#include "servers/audio_server.h"
|
||||
#include "servers/rendering/renderer_compositor.h"
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
#include "servers/rendering/rendering_device.h"
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
#import "rendering_context_driver_vulkan_apple_embedded.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class OS_AppleEmbedded : public OS_Unix {
|
||||
private:
|
||||
static HashMap<String, void *> dynamic_symbol_lookup_table;
|
||||
friend void register_dynamic_symbol(char *name, void *address);
|
||||
|
||||
AudioDriverCoreAudio audio_driver;
|
||||
|
||||
AppleEmbedded *apple_embedded = nullptr;
|
||||
|
||||
JoypadApple *joypad_apple = nullptr;
|
||||
|
||||
MainLoop *main_loop = nullptr;
|
||||
|
||||
virtual void initialize_core() override;
|
||||
virtual void initialize() override;
|
||||
|
||||
virtual void initialize_joypads() override;
|
||||
|
||||
virtual void set_main_loop(MainLoop *p_main_loop) override;
|
||||
virtual MainLoop *get_main_loop() const override;
|
||||
|
||||
virtual void delete_main_loop() override;
|
||||
|
||||
virtual void finalize() override;
|
||||
|
||||
bool is_focused = false;
|
||||
|
||||
CGFloat _weight_to_ct(int p_weight) const;
|
||||
CGFloat _stretch_to_ct(int p_stretch) const;
|
||||
String _get_default_fontname(const String &p_font_name) const;
|
||||
|
||||
static _FORCE_INLINE_ String get_framework_executable(const String &p_path);
|
||||
|
||||
void deinitialize_modules();
|
||||
|
||||
public:
|
||||
static OS_AppleEmbedded *get_singleton();
|
||||
|
||||
OS_AppleEmbedded();
|
||||
~OS_AppleEmbedded();
|
||||
|
||||
void initialize_modules();
|
||||
|
||||
bool iterate();
|
||||
|
||||
void start();
|
||||
|
||||
virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
|
||||
|
||||
virtual Vector<String> get_system_fonts() const override;
|
||||
virtual Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override;
|
||||
virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override;
|
||||
|
||||
virtual Error open_dynamic_library(const String &p_path, void *&p_library_handle, GDExtensionData *p_data = nullptr) override;
|
||||
virtual Error close_dynamic_library(void *p_library_handle) override;
|
||||
virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String &p_name, void *&p_symbol_handle, bool p_optional = false) override;
|
||||
|
||||
virtual String get_distribution_name() const override;
|
||||
virtual String get_version() const override;
|
||||
virtual String get_model_name() const override;
|
||||
|
||||
virtual Error shell_open(const String &p_uri) override;
|
||||
|
||||
virtual String get_user_data_dir(const String &p_user_dir) const override;
|
||||
|
||||
virtual String get_cache_path() const override;
|
||||
virtual String get_temp_path() const override;
|
||||
|
||||
virtual String get_locale() const override;
|
||||
|
||||
virtual String get_unique_id() const override;
|
||||
virtual String get_processor_name() const override;
|
||||
|
||||
virtual void vibrate_handheld(int p_duration_ms = 500, float p_amplitude = -1.0) override;
|
||||
|
||||
virtual bool _check_internal_feature_support(const String &p_feature) override;
|
||||
|
||||
void on_focus_out();
|
||||
void on_focus_in();
|
||||
|
||||
void on_enter_background();
|
||||
void on_exit_background();
|
||||
|
||||
virtual Rect2 calculate_boot_screen_rect(const Size2 &p_window_size, const Size2 &p_imgrect_size) const override;
|
||||
};
|
||||
|
||||
#endif // APPLE_EMBEDDED_ENABLED
|
717
drivers/apple_embedded/os_apple_embedded.mm
Normal file
717
drivers/apple_embedded/os_apple_embedded.mm
Normal file
|
@ -0,0 +1,717 @@
|
|||
/**************************************************************************/
|
||||
/* os_apple_embedded.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "os_apple_embedded.h"
|
||||
|
||||
#ifdef APPLE_EMBEDDED_ENABLED
|
||||
|
||||
#import "app_delegate_service.h"
|
||||
#import "display_server_apple_embedded.h"
|
||||
#import "godot_view_apple_embedded.h"
|
||||
#import "terminal_logger_apple_embedded.h"
|
||||
#import "view_controller.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/dir_access.h"
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/io/file_access_pack.h"
|
||||
#include "drivers/unix/syslog_logger.h"
|
||||
#include "main/main.h"
|
||||
|
||||
#import <AudioToolbox/AudioServices.h>
|
||||
#import <CoreText/CoreText.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <dlfcn.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
#include "drivers/vulkan/godot_vulkan.h"
|
||||
#endif // VULKAN_ENABLED
|
||||
#endif
|
||||
|
||||
// Initialization order between compilation units is not guaranteed,
|
||||
// so we use this as a hack to ensure certain code is called before
|
||||
// everything else, but after all units are initialized.
|
||||
typedef void (*init_callback)();
|
||||
static init_callback *apple_init_callbacks = nullptr;
|
||||
static int apple_embedded_platform_init_callbacks_count = 0;
|
||||
static int apple_embedded_platform_init_callbacks_capacity = 0;
|
||||
HashMap<String, void *> OS_AppleEmbedded::dynamic_symbol_lookup_table;
|
||||
|
||||
void add_apple_embedded_platform_init_callback(init_callback cb) {
|
||||
if (apple_embedded_platform_init_callbacks_count == apple_embedded_platform_init_callbacks_capacity) {
|
||||
void *new_ptr = realloc(apple_init_callbacks, sizeof(cb) * (apple_embedded_platform_init_callbacks_capacity + 32));
|
||||
if (new_ptr) {
|
||||
apple_init_callbacks = (init_callback *)(new_ptr);
|
||||
apple_embedded_platform_init_callbacks_capacity += 32;
|
||||
} else {
|
||||
ERR_FAIL_MSG("Unable to allocate memory for extension callbacks.");
|
||||
}
|
||||
}
|
||||
apple_init_callbacks[apple_embedded_platform_init_callbacks_count++] = cb;
|
||||
}
|
||||
|
||||
void register_dynamic_symbol(char *name, void *address) {
|
||||
OS_AppleEmbedded::dynamic_symbol_lookup_table[String(name)] = address;
|
||||
}
|
||||
|
||||
Rect2 fit_keep_aspect_centered(const Vector2 &p_container, const Vector2 &p_rect) {
|
||||
real_t available_ratio = p_container.width / p_container.height;
|
||||
real_t fit_ratio = p_rect.width / p_rect.height;
|
||||
Rect2 result;
|
||||
if (fit_ratio < available_ratio) {
|
||||
// Fit height - we'll have horizontal gaps
|
||||
result.size.height = p_container.height;
|
||||
result.size.width = p_container.height * fit_ratio;
|
||||
result.position.y = 0;
|
||||
result.position.x = (p_container.width - result.size.width) * 0.5f;
|
||||
} else {
|
||||
// Fit width - we'll have vertical gaps
|
||||
result.size.width = p_container.width;
|
||||
result.size.height = p_container.width / fit_ratio;
|
||||
result.position.x = 0;
|
||||
result.position.y = (p_container.height - result.size.height) * 0.5f;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Rect2 fit_keep_aspect_covered(const Vector2 &p_container, const Vector2 &p_rect) {
|
||||
real_t available_ratio = p_container.width / p_container.height;
|
||||
real_t fit_ratio = p_rect.width / p_rect.height;
|
||||
Rect2 result;
|
||||
if (fit_ratio < available_ratio) {
|
||||
// Need to scale up to fit width, and crop height
|
||||
result.size.width = p_container.width;
|
||||
result.size.height = p_container.width / fit_ratio;
|
||||
result.position.x = 0;
|
||||
result.position.y = (p_container.height - result.size.height) * 0.5f;
|
||||
} else {
|
||||
// Need to scale up to fit height, and crop width
|
||||
result.size.width = p_container.height * fit_ratio;
|
||||
result.size.height = p_container.height;
|
||||
result.position.x = (p_container.width - result.size.width) * 0.5f;
|
||||
result.position.y = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
OS_AppleEmbedded *OS_AppleEmbedded::get_singleton() {
|
||||
return (OS_AppleEmbedded *)OS::get_singleton();
|
||||
}
|
||||
|
||||
OS_AppleEmbedded::OS_AppleEmbedded() {
|
||||
for (int i = 0; i < apple_embedded_platform_init_callbacks_count; ++i) {
|
||||
apple_init_callbacks[i]();
|
||||
}
|
||||
free(apple_init_callbacks);
|
||||
apple_init_callbacks = nullptr;
|
||||
apple_embedded_platform_init_callbacks_count = 0;
|
||||
apple_embedded_platform_init_callbacks_capacity = 0;
|
||||
|
||||
main_loop = nullptr;
|
||||
|
||||
Vector<Logger *> loggers;
|
||||
loggers.push_back(memnew(TerminalLoggerAppleEmbedded));
|
||||
_set_logger(memnew(CompositeLogger(loggers)));
|
||||
|
||||
AudioDriverManager::add_driver(&audio_driver);
|
||||
}
|
||||
|
||||
OS_AppleEmbedded::~OS_AppleEmbedded() {}
|
||||
|
||||
void OS_AppleEmbedded::alert(const String &p_alert, const String &p_title) {
|
||||
const CharString utf8_alert = p_alert.utf8();
|
||||
const CharString utf8_title = p_title.utf8();
|
||||
AppleEmbedded::alert(utf8_alert.get_data(), utf8_title.get_data());
|
||||
}
|
||||
|
||||
void OS_AppleEmbedded::initialize_core() {
|
||||
OS_Unix::initialize_core();
|
||||
}
|
||||
|
||||
void OS_AppleEmbedded::initialize() {
|
||||
initialize_core();
|
||||
}
|
||||
|
||||
void OS_AppleEmbedded::initialize_joypads() {
|
||||
joypad_apple = memnew(JoypadApple);
|
||||
}
|
||||
|
||||
void OS_AppleEmbedded::initialize_modules() {
|
||||
apple_embedded = memnew(AppleEmbedded);
|
||||
Engine::get_singleton()->add_singleton(Engine::Singleton("AppleEmbedded", apple_embedded));
|
||||
}
|
||||
|
||||
void OS_AppleEmbedded::deinitialize_modules() {
|
||||
if (joypad_apple) {
|
||||
memdelete(joypad_apple);
|
||||
}
|
||||
|
||||
if (apple_embedded) {
|
||||
memdelete(apple_embedded);
|
||||
}
|
||||
}
|
||||
|
||||
void OS_AppleEmbedded::set_main_loop(MainLoop *p_main_loop) {
|
||||
main_loop = p_main_loop;
|
||||
}
|
||||
|
||||
MainLoop *OS_AppleEmbedded::get_main_loop() const {
|
||||
return main_loop;
|
||||
}
|
||||
|
||||
void OS_AppleEmbedded::delete_main_loop() {
|
||||
if (main_loop) {
|
||||
main_loop->finalize();
|
||||
memdelete(main_loop);
|
||||
}
|
||||
|
||||
main_loop = nullptr;
|
||||
}
|
||||
|
||||
bool OS_AppleEmbedded::iterate() {
|
||||
if (!main_loop) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DisplayServer::get_singleton()) {
|
||||
DisplayServer::get_singleton()->process_events();
|
||||
}
|
||||
|
||||
joypad_apple->process_joypads();
|
||||
|
||||
return Main::iteration();
|
||||
}
|
||||
|
||||
void OS_AppleEmbedded::start() {
|
||||
if (Main::start() == EXIT_SUCCESS) {
|
||||
main_loop->initialize();
|
||||
}
|
||||
}
|
||||
|
||||
void OS_AppleEmbedded::finalize() {
|
||||
deinitialize_modules();
|
||||
|
||||
// Already gets called
|
||||
//delete_main_loop();
|
||||
}
|
||||
|
||||
// MARK: Dynamic Libraries
|
||||
|
||||
_FORCE_INLINE_ String OS_AppleEmbedded::get_framework_executable(const String &p_path) {
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
|
||||
// Read framework bundle to get executable name.
|
||||
NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())];
|
||||
NSBundle *bundle = [NSBundle bundleWithURL:url];
|
||||
if (bundle) {
|
||||
String exe_path = String::utf8([[bundle executablePath] UTF8String]);
|
||||
if (da->file_exists(exe_path)) {
|
||||
return exe_path;
|
||||
}
|
||||
}
|
||||
|
||||
// Try default executable name (invalid framework).
|
||||
if (da->dir_exists(p_path) && da->file_exists(p_path.path_join(p_path.get_file().get_basename()))) {
|
||||
return p_path.path_join(p_path.get_file().get_basename());
|
||||
}
|
||||
|
||||
// Not a framework, try loading as .dylib.
|
||||
return p_path;
|
||||
}
|
||||
|
||||
Error OS_AppleEmbedded::open_dynamic_library(const String &p_path, void *&p_library_handle, GDExtensionData *p_data) {
|
||||
if (p_path.length() == 0) {
|
||||
// Static xcframework.
|
||||
p_library_handle = RTLD_SELF;
|
||||
|
||||
if (p_data != nullptr && p_data->r_resolved_path != nullptr) {
|
||||
*p_data->r_resolved_path = p_path;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
String path = get_framework_executable(p_path);
|
||||
|
||||
if (!FileAccess::exists(path)) {
|
||||
// Load .dylib or framework from within the executable path.
|
||||
path = get_framework_executable(get_executable_path().get_base_dir().path_join(p_path.get_file()));
|
||||
}
|
||||
|
||||
if (!FileAccess::exists(path)) {
|
||||
// Load .dylib converted to framework from within the executable path.
|
||||
path = get_framework_executable(get_executable_path().get_base_dir().path_join(p_path.get_file().get_basename() + ".framework"));
|
||||
}
|
||||
|
||||
if (!FileAccess::exists(path)) {
|
||||
// Load .dylib or framework from a standard iOS location.
|
||||
path = get_framework_executable(get_executable_path().get_base_dir().path_join("Frameworks").path_join(p_path.get_file()));
|
||||
}
|
||||
|
||||
if (!FileAccess::exists(path)) {
|
||||
// Load .dylib converted to framework from a standard iOS location.
|
||||
path = get_framework_executable(get_executable_path().get_base_dir().path_join("Frameworks").path_join(p_path.get_file().get_basename() + ".framework"));
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V(!FileAccess::exists(path), ERR_FILE_NOT_FOUND);
|
||||
|
||||
p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
|
||||
ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, dlerror()));
|
||||
|
||||
if (p_data != nullptr && p_data->r_resolved_path != nullptr) {
|
||||
*p_data->r_resolved_path = path;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error OS_AppleEmbedded::close_dynamic_library(void *p_library_handle) {
|
||||
if (p_library_handle == RTLD_SELF) {
|
||||
return OK;
|
||||
}
|
||||
return OS_Unix::close_dynamic_library(p_library_handle);
|
||||
}
|
||||
|
||||
Error OS_AppleEmbedded::get_dynamic_library_symbol_handle(void *p_library_handle, const String &p_name, void *&p_symbol_handle, bool p_optional) {
|
||||
if (p_library_handle == RTLD_SELF) {
|
||||
void **ptr = OS_AppleEmbedded::dynamic_symbol_lookup_table.getptr(p_name);
|
||||
if (ptr) {
|
||||
p_symbol_handle = *ptr;
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
return OS_Unix::get_dynamic_library_symbol_handle(p_library_handle, p_name, p_symbol_handle, p_optional);
|
||||
}
|
||||
|
||||
String OS_AppleEmbedded::get_distribution_name() const {
|
||||
return get_name();
|
||||
}
|
||||
|
||||
String OS_AppleEmbedded::get_version() const {
|
||||
NSOperatingSystemVersion ver = [NSProcessInfo processInfo].operatingSystemVersion;
|
||||
return vformat("%d.%d.%d", (int64_t)ver.majorVersion, (int64_t)ver.minorVersion, (int64_t)ver.patchVersion);
|
||||
}
|
||||
|
||||
String OS_AppleEmbedded::get_model_name() const {
|
||||
String model = apple_embedded->get_model();
|
||||
if (model != "") {
|
||||
return model;
|
||||
}
|
||||
|
||||
return OS_Unix::get_model_name();
|
||||
}
|
||||
|
||||
Error OS_AppleEmbedded::shell_open(const String &p_uri) {
|
||||
NSString *urlPath = [[NSString alloc] initWithUTF8String:p_uri.utf8().get_data()];
|
||||
NSURL *url = [NSURL URLWithString:urlPath];
|
||||
|
||||
if (![[UIApplication sharedApplication] canOpenURL:url]) {
|
||||
return ERR_CANT_OPEN;
|
||||
}
|
||||
|
||||
print_verbose(vformat("Opening URL %s", p_uri));
|
||||
|
||||
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
String OS_AppleEmbedded::get_user_data_dir(const String &p_user_dir) const {
|
||||
static String ret;
|
||||
if (ret.is_empty()) {
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
if (paths && [paths count] >= 1) {
|
||||
ret.append_utf8([[paths firstObject] UTF8String]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
String OS_AppleEmbedded::get_cache_path() const {
|
||||
static String ret;
|
||||
if (ret.is_empty()) {
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||
if (paths && [paths count] >= 1) {
|
||||
ret.append_utf8([[paths firstObject] UTF8String]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
String OS_AppleEmbedded::get_temp_path() const {
|
||||
static String ret;
|
||||
if (ret.is_empty()) {
|
||||
NSURL *url = [NSURL fileURLWithPath:NSTemporaryDirectory()
|
||||
isDirectory:YES];
|
||||
if (url) {
|
||||
ret = String::utf8([url.path UTF8String]);
|
||||
ret = ret.trim_prefix("file://");
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
String OS_AppleEmbedded::get_locale() const {
|
||||
NSString *preferredLanguage = [NSLocale preferredLanguages].firstObject;
|
||||
|
||||
if (preferredLanguage) {
|
||||
return String::utf8([preferredLanguage UTF8String]).replace_char('-', '_');
|
||||
}
|
||||
|
||||
NSString *localeIdentifier = [[NSLocale currentLocale] localeIdentifier];
|
||||
return String::utf8([localeIdentifier UTF8String]).replace_char('-', '_');
|
||||
}
|
||||
|
||||
String OS_AppleEmbedded::get_unique_id() const {
|
||||
NSString *uuid = [UIDevice currentDevice].identifierForVendor.UUIDString;
|
||||
return String::utf8([uuid UTF8String]);
|
||||
}
|
||||
|
||||
String OS_AppleEmbedded::get_processor_name() const {
|
||||
char buffer[256];
|
||||
size_t buffer_len = 256;
|
||||
if (sysctlbyname("machdep.cpu.brand_string", &buffer, &buffer_len, nullptr, 0) == 0) {
|
||||
return String::utf8(buffer, buffer_len);
|
||||
}
|
||||
ERR_FAIL_V_MSG("", String("Couldn't get the CPU model name. Returning an empty string."));
|
||||
}
|
||||
|
||||
Vector<String> OS_AppleEmbedded::get_system_fonts() const {
|
||||
HashSet<String> font_names;
|
||||
CFArrayRef fonts = CTFontManagerCopyAvailableFontFamilyNames();
|
||||
if (fonts) {
|
||||
for (CFIndex i = 0; i < CFArrayGetCount(fonts); i++) {
|
||||
CFStringRef cf_name = (CFStringRef)CFArrayGetValueAtIndex(fonts, i);
|
||||
if (cf_name && (CFStringGetLength(cf_name) > 0) && (CFStringCompare(cf_name, CFSTR("LastResort"), kCFCompareCaseInsensitive) != kCFCompareEqualTo) && (CFStringGetCharacterAtIndex(cf_name, 0) != '.')) {
|
||||
NSString *ns_name = (__bridge NSString *)cf_name;
|
||||
font_names.insert(String::utf8([ns_name UTF8String]));
|
||||
}
|
||||
}
|
||||
CFRelease(fonts);
|
||||
}
|
||||
|
||||
Vector<String> ret;
|
||||
for (const String &E : font_names) {
|
||||
ret.push_back(E);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
String OS_AppleEmbedded::_get_default_fontname(const String &p_font_name) const {
|
||||
String font_name = p_font_name;
|
||||
if (font_name.to_lower() == "sans-serif") {
|
||||
font_name = "Helvetica";
|
||||
} else if (font_name.to_lower() == "serif") {
|
||||
font_name = "Times";
|
||||
} else if (font_name.to_lower() == "monospace") {
|
||||
font_name = "Courier";
|
||||
} else if (font_name.to_lower() == "fantasy") {
|
||||
font_name = "Papyrus";
|
||||
} else if (font_name.to_lower() == "cursive") {
|
||||
font_name = "Apple Chancery";
|
||||
};
|
||||
return font_name;
|
||||
}
|
||||
|
||||
CGFloat OS_AppleEmbedded::_weight_to_ct(int p_weight) const {
|
||||
if (p_weight < 150) {
|
||||
return -0.80;
|
||||
} else if (p_weight < 250) {
|
||||
return -0.60;
|
||||
} else if (p_weight < 350) {
|
||||
return -0.40;
|
||||
} else if (p_weight < 450) {
|
||||
return 0.0;
|
||||
} else if (p_weight < 550) {
|
||||
return 0.23;
|
||||
} else if (p_weight < 650) {
|
||||
return 0.30;
|
||||
} else if (p_weight < 750) {
|
||||
return 0.40;
|
||||
} else if (p_weight < 850) {
|
||||
return 0.56;
|
||||
} else if (p_weight < 925) {
|
||||
return 0.62;
|
||||
} else {
|
||||
return 1.00;
|
||||
}
|
||||
}
|
||||
|
||||
CGFloat OS_AppleEmbedded::_stretch_to_ct(int p_stretch) const {
|
||||
if (p_stretch < 56) {
|
||||
return -0.5;
|
||||
} else if (p_stretch < 69) {
|
||||
return -0.37;
|
||||
} else if (p_stretch < 81) {
|
||||
return -0.25;
|
||||
} else if (p_stretch < 93) {
|
||||
return -0.13;
|
||||
} else if (p_stretch < 106) {
|
||||
return 0.0;
|
||||
} else if (p_stretch < 137) {
|
||||
return 0.13;
|
||||
} else if (p_stretch < 144) {
|
||||
return 0.25;
|
||||
} else if (p_stretch < 162) {
|
||||
return 0.37;
|
||||
} else {
|
||||
return 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
Vector<String> OS_AppleEmbedded::get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale, const String &p_script, int p_weight, int p_stretch, bool p_italic) const {
|
||||
Vector<String> ret;
|
||||
String font_name = _get_default_fontname(p_font_name);
|
||||
|
||||
CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, font_name.utf8().get_data(), kCFStringEncodingUTF8);
|
||||
CTFontSymbolicTraits traits = 0;
|
||||
if (p_weight >= 700) {
|
||||
traits |= kCTFontBoldTrait;
|
||||
}
|
||||
if (p_italic) {
|
||||
traits |= kCTFontItalicTrait;
|
||||
}
|
||||
if (p_stretch < 100) {
|
||||
traits |= kCTFontCondensedTrait;
|
||||
} else if (p_stretch > 100) {
|
||||
traits |= kCTFontExpandedTrait;
|
||||
}
|
||||
|
||||
CFNumberRef sym_traits = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &traits);
|
||||
CFMutableDictionaryRef traits_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr);
|
||||
CFDictionaryAddValue(traits_dict, kCTFontSymbolicTrait, sym_traits);
|
||||
|
||||
CGFloat weight = _weight_to_ct(p_weight);
|
||||
CFNumberRef font_weight = CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &weight);
|
||||
CFDictionaryAddValue(traits_dict, kCTFontWeightTrait, font_weight);
|
||||
|
||||
CGFloat stretch = _stretch_to_ct(p_stretch);
|
||||
CFNumberRef font_stretch = CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &stretch);
|
||||
CFDictionaryAddValue(traits_dict, kCTFontWidthTrait, font_stretch);
|
||||
|
||||
CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr);
|
||||
CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, name);
|
||||
CFDictionaryAddValue(attributes, kCTFontTraitsAttribute, traits_dict);
|
||||
|
||||
CTFontDescriptorRef font = CTFontDescriptorCreateWithAttributes(attributes);
|
||||
if (font) {
|
||||
CTFontRef family = CTFontCreateWithFontDescriptor(font, 0, nullptr);
|
||||
if (family) {
|
||||
CFStringRef string = CFStringCreateWithCString(kCFAllocatorDefault, p_text.utf8().get_data(), kCFStringEncodingUTF8);
|
||||
CFRange range = CFRangeMake(0, CFStringGetLength(string));
|
||||
CTFontRef fallback_family = CTFontCreateForString(family, string, range);
|
||||
if (fallback_family) {
|
||||
CTFontDescriptorRef fallback_font = CTFontCopyFontDescriptor(fallback_family);
|
||||
if (fallback_font) {
|
||||
CFURLRef url = (CFURLRef)CTFontDescriptorCopyAttribute(fallback_font, kCTFontURLAttribute);
|
||||
if (url) {
|
||||
NSString *font_path = [NSString stringWithString:[(__bridge NSURL *)url path]];
|
||||
ret.push_back(String::utf8([font_path UTF8String]));
|
||||
CFRelease(url);
|
||||
}
|
||||
CFRelease(fallback_font);
|
||||
}
|
||||
CFRelease(fallback_family);
|
||||
}
|
||||
CFRelease(string);
|
||||
CFRelease(family);
|
||||
}
|
||||
CFRelease(font);
|
||||
}
|
||||
|
||||
CFRelease(attributes);
|
||||
CFRelease(traits_dict);
|
||||
CFRelease(sym_traits);
|
||||
CFRelease(font_stretch);
|
||||
CFRelease(font_weight);
|
||||
CFRelease(name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
String OS_AppleEmbedded::get_system_font_path(const String &p_font_name, int p_weight, int p_stretch, bool p_italic) const {
|
||||
String ret;
|
||||
String font_name = _get_default_fontname(p_font_name);
|
||||
|
||||
CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, font_name.utf8().get_data(), kCFStringEncodingUTF8);
|
||||
|
||||
CTFontSymbolicTraits traits = 0;
|
||||
if (p_weight >= 700) {
|
||||
traits |= kCTFontBoldTrait;
|
||||
}
|
||||
if (p_italic) {
|
||||
traits |= kCTFontItalicTrait;
|
||||
}
|
||||
if (p_stretch < 100) {
|
||||
traits |= kCTFontCondensedTrait;
|
||||
} else if (p_stretch > 100) {
|
||||
traits |= kCTFontExpandedTrait;
|
||||
}
|
||||
|
||||
CFNumberRef sym_traits = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &traits);
|
||||
CFMutableDictionaryRef traits_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr);
|
||||
CFDictionaryAddValue(traits_dict, kCTFontSymbolicTrait, sym_traits);
|
||||
|
||||
CGFloat weight = _weight_to_ct(p_weight);
|
||||
CFNumberRef font_weight = CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &weight);
|
||||
CFDictionaryAddValue(traits_dict, kCTFontWeightTrait, font_weight);
|
||||
|
||||
CGFloat stretch = _stretch_to_ct(p_stretch);
|
||||
CFNumberRef font_stretch = CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &stretch);
|
||||
CFDictionaryAddValue(traits_dict, kCTFontWidthTrait, font_stretch);
|
||||
|
||||
CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr);
|
||||
CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, name);
|
||||
CFDictionaryAddValue(attributes, kCTFontTraitsAttribute, traits_dict);
|
||||
|
||||
CTFontDescriptorRef font = CTFontDescriptorCreateWithAttributes(attributes);
|
||||
if (font) {
|
||||
CFURLRef url = (CFURLRef)CTFontDescriptorCopyAttribute(font, kCTFontURLAttribute);
|
||||
if (url) {
|
||||
NSString *font_path = [NSString stringWithString:[(__bridge NSURL *)url path]];
|
||||
ret = String::utf8([font_path UTF8String]);
|
||||
CFRelease(url);
|
||||
}
|
||||
CFRelease(font);
|
||||
}
|
||||
|
||||
CFRelease(attributes);
|
||||
CFRelease(traits_dict);
|
||||
CFRelease(sym_traits);
|
||||
CFRelease(font_stretch);
|
||||
CFRelease(font_weight);
|
||||
CFRelease(name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void OS_AppleEmbedded::vibrate_handheld(int p_duration_ms, float p_amplitude) {
|
||||
if (apple_embedded->supports_haptic_engine()) {
|
||||
if (p_amplitude > 0.0) {
|
||||
p_amplitude = CLAMP(p_amplitude, 0.0, 1.0);
|
||||
}
|
||||
|
||||
apple_embedded->vibrate_haptic_engine((float)p_duration_ms / 1000.f, p_amplitude);
|
||||
} else {
|
||||
// iOS <13 does not support duration for vibration
|
||||
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
|
||||
}
|
||||
}
|
||||
|
||||
bool OS_AppleEmbedded::_check_internal_feature_support(const String &p_feature) {
|
||||
if (p_feature == "system_fonts") {
|
||||
return true;
|
||||
}
|
||||
if (p_feature == "mobile") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void OS_AppleEmbedded::on_focus_out() {
|
||||
if (is_focused) {
|
||||
is_focused = false;
|
||||
|
||||
if (DisplayServerAppleEmbedded::get_singleton()) {
|
||||
DisplayServerAppleEmbedded::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
|
||||
}
|
||||
|
||||
if (OS::get_singleton()->get_main_loop()) {
|
||||
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
|
||||
}
|
||||
|
||||
[GDTAppDelegateService.viewController.godotView stopRendering];
|
||||
|
||||
audio_driver.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void OS_AppleEmbedded::on_focus_in() {
|
||||
if (!is_focused) {
|
||||
is_focused = true;
|
||||
|
||||
if (DisplayServerAppleEmbedded::get_singleton()) {
|
||||
DisplayServerAppleEmbedded::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_IN);
|
||||
}
|
||||
|
||||
if (OS::get_singleton()->get_main_loop()) {
|
||||
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN);
|
||||
}
|
||||
|
||||
[GDTAppDelegateService.viewController.godotView startRendering];
|
||||
|
||||
audio_driver.start();
|
||||
}
|
||||
}
|
||||
|
||||
void OS_AppleEmbedded::on_enter_background() {
|
||||
// Do not check for is_focused, because on_focus_out will always be fired first by applicationWillResignActive.
|
||||
|
||||
if (OS::get_singleton()->get_main_loop()) {
|
||||
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_PAUSED);
|
||||
}
|
||||
|
||||
on_focus_out();
|
||||
}
|
||||
|
||||
void OS_AppleEmbedded::on_exit_background() {
|
||||
if (!is_focused) {
|
||||
on_focus_in();
|
||||
|
||||
if (OS::get_singleton()->get_main_loop()) {
|
||||
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_RESUMED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rect2 OS_AppleEmbedded::calculate_boot_screen_rect(const Size2 &p_window_size, const Size2 &p_imgrect_size) const {
|
||||
String scalemodestr = GLOBAL_GET("ios/launch_screen_image_mode");
|
||||
|
||||
if (scalemodestr == "scaleAspectFit") {
|
||||
return fit_keep_aspect_centered(p_window_size, p_imgrect_size);
|
||||
} else if (scalemodestr == "scaleAspectFill") {
|
||||
return fit_keep_aspect_covered(p_window_size, p_imgrect_size);
|
||||
} else if (scalemodestr == "scaleToFill") {
|
||||
return Rect2(Point2(), p_window_size);
|
||||
} else if (scalemodestr == "center") {
|
||||
return OS_Unix::calculate_boot_screen_rect(p_window_size, p_imgrect_size);
|
||||
} else {
|
||||
WARN_PRINT(vformat("Boot screen scale mode mismatch between iOS and Godot: %s not supported", scalemodestr));
|
||||
return OS_Unix::calculate_boot_screen_rect(p_window_size, p_imgrect_size);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // APPLE_EMBEDDED_ENABLED
|
44
drivers/apple_embedded/platform_config.h
Normal file
44
drivers/apple_embedded/platform_config.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/**************************************************************************/
|
||||
/* platform_config.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <alloca.h>
|
||||
|
||||
#define PLATFORM_THREAD_OVERRIDE
|
||||
|
||||
#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")
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* rendering_context_driver_vulkan_ios.h */
|
||||
/* rendering_context_driver_vulkan_apple_embedded.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -36,7 +36,7 @@
|
|||
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
class RenderingContextDriverVulkanIOS : public RenderingContextDriverVulkan {
|
||||
class RenderingContextDriverVulkanAppleEmbedded : public RenderingContextDriverVulkan {
|
||||
private:
|
||||
virtual const char *_get_platform_surface_extension() const override final;
|
||||
|
||||
|
@ -48,8 +48,8 @@ public:
|
|||
CAMetalLayer *const *layer_ptr;
|
||||
};
|
||||
|
||||
RenderingContextDriverVulkanIOS();
|
||||
~RenderingContextDriverVulkanIOS();
|
||||
RenderingContextDriverVulkanAppleEmbedded();
|
||||
~RenderingContextDriverVulkanAppleEmbedded();
|
||||
};
|
||||
|
||||
#endif // VULKAN_ENABLED
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* rendering_context_driver_vulkan_ios.mm */
|
||||
/* rendering_context_driver_vulkan_apple_embedded.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -28,7 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#import "rendering_context_driver_vulkan_ios.h"
|
||||
#import "rendering_context_driver_vulkan_apple_embedded.h"
|
||||
|
||||
#ifdef VULKAN_ENABLED
|
||||
|
||||
|
@ -38,11 +38,11 @@
|
|||
#include <vulkan/vulkan_metal.h>
|
||||
#endif
|
||||
|
||||
const char *RenderingContextDriverVulkanIOS::_get_platform_surface_extension() const {
|
||||
const char *RenderingContextDriverVulkanAppleEmbedded::_get_platform_surface_extension() const {
|
||||
return VK_EXT_METAL_SURFACE_EXTENSION_NAME;
|
||||
}
|
||||
|
||||
RenderingContextDriver::SurfaceID RenderingContextDriverVulkanIOS::surface_create(const void *p_platform_data) {
|
||||
RenderingContextDriver::SurfaceID RenderingContextDriverVulkanAppleEmbedded::surface_create(const void *p_platform_data) {
|
||||
const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data);
|
||||
|
||||
VkMetalSurfaceCreateInfoEXT create_info = {};
|
||||
|
@ -58,11 +58,11 @@ RenderingContextDriver::SurfaceID RenderingContextDriverVulkanIOS::surface_creat
|
|||
return SurfaceID(surface);
|
||||
}
|
||||
|
||||
RenderingContextDriverVulkanIOS::RenderingContextDriverVulkanIOS() {
|
||||
RenderingContextDriverVulkanAppleEmbedded::RenderingContextDriverVulkanAppleEmbedded() {
|
||||
// Does nothing.
|
||||
}
|
||||
|
||||
RenderingContextDriverVulkanIOS::~RenderingContextDriverVulkanIOS() {
|
||||
RenderingContextDriverVulkanAppleEmbedded::~RenderingContextDriverVulkanAppleEmbedded() {
|
||||
// Does nothing.
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* ios_terminal_logger.h */
|
||||
/* terminal_logger_apple_embedded.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -30,13 +30,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifdef IOS_ENABLED
|
||||
#ifdef APPLE_EMBEDDED_ENABLED
|
||||
|
||||
#include "core/io/logger.h"
|
||||
|
||||
class IOSTerminalLogger : public StdLogger {
|
||||
class TerminalLoggerAppleEmbedded : public StdLogger {
|
||||
public:
|
||||
virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, ErrorType p_type = ERR_ERROR, const Vector<Ref<ScriptBacktrace>> &p_script_backtraces = {}) override;
|
||||
};
|
||||
|
||||
#endif // IOS_ENABLED
|
||||
#endif // APPLE_EMBEDDED_ENABLED
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* ios_terminal_logger.mm */
|
||||
/* terminal_logger_apple_embedded.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -28,13 +28,13 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#import "ios_terminal_logger.h"
|
||||
#import "terminal_logger_apple_embedded.h"
|
||||
|
||||
#ifdef IOS_ENABLED
|
||||
#ifdef APPLE_EMBEDDED_ENABLED
|
||||
|
||||
#import <os/log.h>
|
||||
|
||||
void IOSTerminalLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type, const Vector<Ref<ScriptBacktrace>> &p_script_backtraces) {
|
||||
void TerminalLoggerAppleEmbedded::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type, const Vector<Ref<ScriptBacktrace>> &p_script_backtraces) {
|
||||
if (!should_log(true)) {
|
||||
return;
|
||||
}
|
||||
|
@ -77,4 +77,4 @@ void IOSTerminalLogger::log_error(const char *p_function, const char *p_file, in
|
|||
}
|
||||
}
|
||||
|
||||
#endif // IOS_ENABLED
|
||||
#endif // APPLE_EMBEDDED_ENABLED
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* tts_ios.h */
|
||||
/* tts_apple_embedded.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -42,7 +42,7 @@
|
|||
#import <AVFoundation/AVFoundation.h>
|
||||
#endif
|
||||
|
||||
@interface TTS_IOS : NSObject <AVSpeechSynthesizerDelegate> {
|
||||
@interface GDTTTS : NSObject <AVSpeechSynthesizerDelegate> {
|
||||
bool speaking;
|
||||
HashMap<id, int> ids;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* tts_ios.mm */
|
||||
/* tts_apple_embedded.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -28,9 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#import "tts_ios.h"
|
||||
#import "tts_apple_embedded.h"
|
||||
|
||||
@implementation TTS_IOS
|
||||
@implementation GDTTTS
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
|
@ -32,13 +32,12 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class GodotView;
|
||||
@class GodotNativeVideoView;
|
||||
@class GodotKeyboardInputView;
|
||||
@class GDTView;
|
||||
@class GDTKeyboardInputView;
|
||||
|
||||
@interface ViewController : UIViewController
|
||||
@interface GDTViewController : UIViewController
|
||||
|
||||
@property(nonatomic, readonly, strong) GodotView *godotView;
|
||||
@property(nonatomic, readonly, strong) GodotKeyboardInputView *keyboardView;
|
||||
@property(nonatomic, readonly, strong) GDTView *godotView;
|
||||
@property(nonatomic, readonly, strong) GDTKeyboardInputView *keyboardView;
|
||||
|
||||
@end
|
|
@ -30,44 +30,44 @@
|
|||
|
||||
#import "view_controller.h"
|
||||
|
||||
#import "display_server_ios.h"
|
||||
#import "godot_view.h"
|
||||
#import "display_server_apple_embedded.h"
|
||||
#import "godot_view_apple_embedded.h"
|
||||
#import "godot_view_renderer.h"
|
||||
#import "key_mapping_ios.h"
|
||||
#import "key_mapping_apple_embedded.h"
|
||||
#import "keyboard_input_view.h"
|
||||
#import "os_ios.h"
|
||||
#import "os_apple_embedded.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <GameController/GameController.h>
|
||||
|
||||
@interface ViewController () <GodotViewDelegate>
|
||||
@interface GDTViewController () <GDTViewDelegate>
|
||||
|
||||
@property(strong, nonatomic) GodotViewRenderer *renderer;
|
||||
@property(strong, nonatomic) GodotKeyboardInputView *keyboardView;
|
||||
@property(strong, nonatomic) GDTViewRenderer *renderer;
|
||||
@property(strong, nonatomic) GDTKeyboardInputView *keyboardView;
|
||||
|
||||
@property(strong, nonatomic) UIView *godotLoadingOverlay;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ViewController
|
||||
@implementation GDTViewController
|
||||
|
||||
- (GodotView *)godotView {
|
||||
return (GodotView *)self.view;
|
||||
- (GDTView *)godotView {
|
||||
return (GDTView *)self.view;
|
||||
}
|
||||
|
||||
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
|
||||
[super pressesBegan:presses withEvent:event];
|
||||
|
||||
if (!DisplayServerIOS::get_singleton() || DisplayServerIOS::get_singleton()->is_keyboard_active()) {
|
||||
if (!DisplayServerAppleEmbedded::get_singleton() || DisplayServerAppleEmbedded::get_singleton()->is_keyboard_active()) {
|
||||
return;
|
||||
}
|
||||
if (@available(iOS 13.4, *)) {
|
||||
for (UIPress *press in presses) {
|
||||
String u32lbl = String::utf8([press.key.charactersIgnoringModifiers UTF8String]);
|
||||
String u32text = String::utf8([press.key.characters UTF8String]);
|
||||
Key key = KeyMappingIOS::remap_key(press.key.keyCode);
|
||||
Key key = KeyMappingAppleEmbedded::remap_key(press.key.keyCode);
|
||||
|
||||
if (press.key.keyCode == 0 && u32text.is_empty() && u32lbl.is_empty()) {
|
||||
continue;
|
||||
|
@ -78,15 +78,15 @@
|
|||
us = u32lbl[0];
|
||||
}
|
||||
|
||||
KeyLocation location = KeyMappingIOS::key_location(press.key.keyCode);
|
||||
KeyLocation location = KeyMappingAppleEmbedded::key_location(press.key.keyCode);
|
||||
|
||||
if (!u32text.is_empty() && !u32text.begins_with("UIKey")) {
|
||||
for (int i = 0; i < u32text.length(); i++) {
|
||||
const char32_t c = u32text[i];
|
||||
DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), c, fix_key_label(us, key), key, press.key.modifierFlags, true, location);
|
||||
DisplayServerAppleEmbedded::get_singleton()->key(fix_keycode(us, key), c, fix_key_label(us, key), key, press.key.modifierFlags, true, location);
|
||||
}
|
||||
} else {
|
||||
DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), 0, fix_key_label(us, key), key, press.key.modifierFlags, true, location);
|
||||
DisplayServerAppleEmbedded::get_singleton()->key(fix_keycode(us, key), 0, fix_key_label(us, key), key, press.key.modifierFlags, true, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,13 +95,13 @@
|
|||
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
|
||||
[super pressesEnded:presses withEvent:event];
|
||||
|
||||
if (!DisplayServerIOS::get_singleton() || DisplayServerIOS::get_singleton()->is_keyboard_active()) {
|
||||
if (!DisplayServerAppleEmbedded::get_singleton() || DisplayServerAppleEmbedded::get_singleton()->is_keyboard_active()) {
|
||||
return;
|
||||
}
|
||||
if (@available(iOS 13.4, *)) {
|
||||
for (UIPress *press in presses) {
|
||||
String u32lbl = String::utf8([press.key.charactersIgnoringModifiers UTF8String]);
|
||||
Key key = KeyMappingIOS::remap_key(press.key.keyCode);
|
||||
Key key = KeyMappingAppleEmbedded::remap_key(press.key.keyCode);
|
||||
|
||||
if (press.key.keyCode == 0 && u32lbl.is_empty()) {
|
||||
continue;
|
||||
|
@ -112,16 +112,16 @@
|
|||
us = u32lbl[0];
|
||||
}
|
||||
|
||||
KeyLocation location = KeyMappingIOS::key_location(press.key.keyCode);
|
||||
KeyLocation location = KeyMappingAppleEmbedded::key_location(press.key.keyCode);
|
||||
|
||||
DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), 0, fix_key_label(us, key), key, press.key.modifierFlags, false, location);
|
||||
DisplayServerAppleEmbedded::get_singleton()->key(fix_keycode(us, key), 0, fix_key_label(us, key), key, press.key.modifierFlags, false, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loadView {
|
||||
GodotView *view = [[GodotView alloc] init];
|
||||
GodotViewRenderer *renderer = [[GodotViewRenderer alloc] init];
|
||||
GDTView *view = GDTViewCreate();
|
||||
GDTViewRenderer *renderer = [[GDTViewRenderer alloc] init];
|
||||
|
||||
self.renderer = renderer;
|
||||
self.view = view;
|
||||
|
@ -170,7 +170,7 @@
|
|||
|
||||
- (void)observeKeyboard {
|
||||
print_verbose("Setting up keyboard input view.");
|
||||
self.keyboardView = [GodotKeyboardInputView new];
|
||||
self.keyboardView = [GDTKeyboardInputView new];
|
||||
[self.view addSubview:self.keyboardView];
|
||||
|
||||
print_verbose("Adding observer for keyboard show/hide.");
|
||||
|
@ -204,7 +204,7 @@
|
|||
[self.view addSubview:self.godotLoadingOverlay];
|
||||
}
|
||||
|
||||
- (BOOL)godotViewFinishedSetup:(GodotView *)view {
|
||||
- (BOOL)godotViewFinishedSetup:(GDTView *)view {
|
||||
[self.godotLoadingOverlay removeFromSuperview];
|
||||
self.godotLoadingOverlay = nil;
|
||||
|
||||
|
@ -235,11 +235,11 @@
|
|||
}
|
||||
|
||||
- (BOOL)shouldAutorotate {
|
||||
if (!DisplayServerIOS::get_singleton()) {
|
||||
if (!DisplayServerAppleEmbedded::get_singleton()) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
switch (DisplayServerIOS::get_singleton()->screen_get_orientation(DisplayServer::SCREEN_OF_MAIN_WINDOW)) {
|
||||
switch (DisplayServerAppleEmbedded::get_singleton()->screen_get_orientation(DisplayServer::SCREEN_OF_MAIN_WINDOW)) {
|
||||
case DisplayServer::SCREEN_SENSOR:
|
||||
case DisplayServer::SCREEN_SENSOR_LANDSCAPE:
|
||||
case DisplayServer::SCREEN_SENSOR_PORTRAIT:
|
||||
|
@ -250,11 +250,11 @@
|
|||
}
|
||||
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
if (!DisplayServerIOS::get_singleton()) {
|
||||
if (!DisplayServerAppleEmbedded::get_singleton()) {
|
||||
return UIInterfaceOrientationMaskAll;
|
||||
}
|
||||
|
||||
switch (DisplayServerIOS::get_singleton()->screen_get_orientation(DisplayServer::SCREEN_OF_MAIN_WINDOW)) {
|
||||
switch (DisplayServerAppleEmbedded::get_singleton()->screen_get_orientation(DisplayServer::SCREEN_OF_MAIN_WINDOW)) {
|
||||
case DisplayServer::SCREEN_PORTRAIT:
|
||||
return UIInterfaceOrientationMaskPortrait;
|
||||
case DisplayServer::SCREEN_REVERSE_LANDSCAPE:
|
||||
|
@ -305,14 +305,14 @@
|
|||
CGRect rawFrame = [value CGRectValue];
|
||||
CGRect keyboardFrame = [self.view convertRect:rawFrame fromView:nil];
|
||||
|
||||
if (DisplayServerIOS::get_singleton()) {
|
||||
DisplayServerIOS::get_singleton()->virtual_keyboard_set_height(keyboardFrame.size.height);
|
||||
if (DisplayServerAppleEmbedded::get_singleton()) {
|
||||
DisplayServerAppleEmbedded::get_singleton()->virtual_keyboard_set_height(keyboardFrame.size.height);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)keyboardHidden:(NSNotification *)notification {
|
||||
if (DisplayServerIOS::get_singleton()) {
|
||||
DisplayServerIOS::get_singleton()->virtual_keyboard_set_height(0);
|
||||
if (DisplayServerAppleEmbedded::get_singleton()) {
|
||||
DisplayServerAppleEmbedded::get_singleton()->virtual_keyboard_set_height(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +34,6 @@
|
|||
|
||||
#include "core/string/print_string.h"
|
||||
|
||||
#import <CoreAudio/HostTime.h>
|
||||
#import <CoreServices/CoreServices.h>
|
||||
|
||||
Mutex MIDIDriverCoreMidi::mutex;
|
||||
|
|
|
@ -39,6 +39,9 @@ if "-std=gnu++17" in env_metal["CXXFLAGS"]:
|
|||
env_metal["CXXFLAGS"].remove("-std=gnu++17")
|
||||
env_metal.Append(CXXFLAGS=["-std=c++20"])
|
||||
|
||||
# Enable module support
|
||||
env_metal.Append(CCFLAGS=["-fmodules", "-fcxx-modules"])
|
||||
|
||||
# Driver source files
|
||||
|
||||
driver_obj = []
|
||||
|
|
|
@ -4184,8 +4184,8 @@ Error RenderingDeviceDriverMetal::initialize(uint32_t p_device_index, uint32_t p
|
|||
error_string += "- No support for image cube arrays.\n";
|
||||
}
|
||||
|
||||
#if defined(IOS_ENABLED)
|
||||
// iOS platform ports currently don't exit themselves when this method returns `ERR_CANT_CREATE`.
|
||||
#if defined(APPLE_EMBEDDED_ENABLED)
|
||||
// Apple Embedded platforms exports currently don't exit themselves when this method returns `ERR_CANT_CREATE`.
|
||||
OS::get_singleton()->alert(error_string + "\nClick OK to exit (black screen will be visible).");
|
||||
#else
|
||||
OS::get_singleton()->alert(error_string + "\nClick OK to exit.");
|
||||
|
|
2750
editor/export/editor_export_platform_apple_embedded.cpp
Normal file
2750
editor/export/editor_export_platform_apple_embedded.cpp
Normal file
File diff suppressed because it is too large
Load diff
316
editor/export/editor_export_platform_apple_embedded.h
Normal file
316
editor/export/editor_export_platform_apple_embedded.h
Normal file
|
@ -0,0 +1,316 @@
|
|||
/**************************************************************************/
|
||||
/* editor_export_platform_apple_embedded.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "plugin_config_apple_embedded.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/io/image_loader.h"
|
||||
#include "core/io/marshalls.h"
|
||||
#include "core/io/resource_saver.h"
|
||||
#include "core/io/zip_io.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "editor/editor_settings.h"
|
||||
#include "editor/export/editor_export_platform.h"
|
||||
#include "main/splash.gen.h"
|
||||
#include "scene/resources/image_texture.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
// Optional environment variables for defining confidential information. If any
|
||||
// of these is set, they will override the values set in the credentials file.
|
||||
const String ENV_APPLE_PLATFORM_PROFILE_UUID_DEBUG = "GODOT_APPLE_PLATFORM_PROVISIONING_PROFILE_UUID_DEBUG";
|
||||
const String ENV_APPLE_PLATFORM_PROFILE_UUID_RELEASE = "GODOT_APPLE_PLATFORM_PROVISIONING_PROFILE_UUID_RELEASE";
|
||||
const String ENV_APPLE_PLATFORM_PROFILE_SPECIFIER_DEBUG = "GODOT_APPLE_PLATFORM_PROFILE_SPECIFIER_DEBUG";
|
||||
const String ENV_APPLE_PLATFORM_PROFILE_SPECIFIER_RELEASE = "GODOT_APPLE_PLATFORM_PROFILE_SPECIFIER_RELEASE";
|
||||
|
||||
static const String storyboard_image_scale_mode[] = {
|
||||
"center",
|
||||
"scaleAspectFit",
|
||||
"scaleAspectFill",
|
||||
"scaleToFill",
|
||||
};
|
||||
|
||||
class EditorExportPlatformAppleEmbedded : public EditorExportPlatform {
|
||||
GDCLASS(EditorExportPlatformAppleEmbedded, EditorExportPlatform);
|
||||
|
||||
Ref<ImageTexture> logo;
|
||||
Ref<ImageTexture> run_icon;
|
||||
|
||||
// Plugins
|
||||
mutable SafeFlag plugins_changed;
|
||||
SafeFlag devices_changed;
|
||||
|
||||
struct Device {
|
||||
String id;
|
||||
String name;
|
||||
bool wifi = false;
|
||||
bool use_ios_deploy = false;
|
||||
};
|
||||
|
||||
Vector<Device> devices;
|
||||
Mutex device_lock;
|
||||
|
||||
Mutex plugins_lock;
|
||||
mutable Vector<PluginConfigAppleEmbedded> plugins;
|
||||
#ifdef MACOS_ENABLED
|
||||
Thread check_for_changes_thread;
|
||||
SafeFlag quit_request;
|
||||
SafeFlag has_runnable_preset;
|
||||
|
||||
static bool _check_xcode_install();
|
||||
static void _check_for_changes_poll_thread(void *ud);
|
||||
void _update_preset_status();
|
||||
#endif
|
||||
|
||||
typedef Error (*FileHandler)(String p_file, void *p_userdata);
|
||||
static Error _walk_dir_recursive(Ref<DirAccess> &p_da, FileHandler p_handler, void *p_userdata);
|
||||
static Error _codesign(String p_file, void *p_userdata);
|
||||
|
||||
struct AppleEmbeddedConfigData {
|
||||
String pkg_name;
|
||||
String binary_name;
|
||||
String plist_content;
|
||||
String architectures;
|
||||
String linker_flags;
|
||||
String cpp_code;
|
||||
String modules_buildfile;
|
||||
String modules_fileref;
|
||||
String modules_buildphase;
|
||||
String modules_buildgrp;
|
||||
Vector<String> capabilities;
|
||||
bool use_swift_runtime;
|
||||
};
|
||||
|
||||
struct ExportArchitecture {
|
||||
String name;
|
||||
bool is_default = false;
|
||||
|
||||
ExportArchitecture() {}
|
||||
|
||||
ExportArchitecture(String p_name, bool p_is_default) {
|
||||
name = p_name;
|
||||
is_default = p_is_default;
|
||||
}
|
||||
};
|
||||
|
||||
struct AppleEmbeddedExportAsset {
|
||||
String exported_path;
|
||||
bool is_framework = false; // framework is anything linked to the binary, otherwise it's a resource
|
||||
bool should_embed = false;
|
||||
};
|
||||
|
||||
String _get_additional_plist_content();
|
||||
String _get_linker_flags();
|
||||
String _get_cpp_code();
|
||||
void _fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const AppleEmbeddedConfigData &p_config, bool p_debug);
|
||||
|
||||
Vector<ExportArchitecture> _get_supported_architectures() const;
|
||||
Vector<String> _get_preset_architectures(const Ref<EditorExportPreset> &p_preset) const;
|
||||
|
||||
void _check_xcframework_content(const String &p_path, int &r_total_libs, int &r_static_libs, int &r_dylibs, int &r_frameworks) const;
|
||||
Error _convert_to_framework(const String &p_source, const String &p_destination, const String &p_id) const;
|
||||
|
||||
void _add_assets_to_project(const String &p_out_dir, const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<AppleEmbeddedExportAsset> &p_additional_assets);
|
||||
Error _export_additional_assets(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<AppleEmbeddedExportAsset> &r_exported_assets);
|
||||
Error _copy_asset(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector<AppleEmbeddedExportAsset> &r_exported_assets);
|
||||
Error _export_additional_assets(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<AppleEmbeddedExportAsset> &r_exported_assets);
|
||||
Error _export_apple_embedded_plugins(const Ref<EditorExportPreset> &p_preset, AppleEmbeddedConfigData &p_config_data, const String &dest_dir, Vector<AppleEmbeddedExportAsset> &r_exported_assets, bool p_debug);
|
||||
|
||||
Error _export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags, bool p_oneclick);
|
||||
|
||||
bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const;
|
||||
|
||||
protected:
|
||||
struct IconInfo {
|
||||
const char *preset_key;
|
||||
const char *idiom;
|
||||
const char *export_name;
|
||||
const char *actual_size_side;
|
||||
const char *scale;
|
||||
const char *unscaled_size;
|
||||
bool force_opaque;
|
||||
};
|
||||
|
||||
void _blend_and_rotate(Ref<Image> &p_dst, Ref<Image> &p_src, bool p_rot);
|
||||
|
||||
virtual Error _export_loading_screen_file(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) { return OK; }
|
||||
virtual Error _export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir) { return OK; }
|
||||
|
||||
virtual String get_platform_name() const = 0;
|
||||
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
|
||||
virtual void get_export_options(List<ExportOption> *r_options) const override;
|
||||
virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const override;
|
||||
virtual String get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const override;
|
||||
|
||||
virtual Vector<IconInfo> get_icon_infos() const = 0;
|
||||
|
||||
void _notification(int p_what);
|
||||
|
||||
virtual void get_platform_features(List<String> *r_features) const override {
|
||||
r_features->push_back("mobile");
|
||||
r_features->push_back("apple_embedded");
|
||||
}
|
||||
|
||||
public:
|
||||
virtual Ref<Texture2D> get_logo() const override { return logo; }
|
||||
virtual Ref<Texture2D> get_run_icon() const override { return run_icon; }
|
||||
|
||||
virtual int get_options_count() const override;
|
||||
virtual String get_options_tooltip() const override;
|
||||
virtual Ref<ImageTexture> get_option_icon(int p_index) const override;
|
||||
virtual String get_option_label(int p_index) const override;
|
||||
virtual String get_option_tooltip(int p_index) const override;
|
||||
virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, BitField<EditorExportPlatform::DebugFlags> p_debug_flags) override;
|
||||
|
||||
virtual bool poll_export() override {
|
||||
bool dc = devices_changed.is_set();
|
||||
if (dc) {
|
||||
// don't clear unless we're reporting true, to avoid race
|
||||
devices_changed.clear();
|
||||
}
|
||||
return dc;
|
||||
}
|
||||
|
||||
virtual bool should_update_export_options() override {
|
||||
bool export_options_changed = plugins_changed.is_set();
|
||||
if (export_options_changed) {
|
||||
// don't clear unless we're reporting true, to avoid race
|
||||
plugins_changed.clear();
|
||||
}
|
||||
return export_options_changed;
|
||||
}
|
||||
|
||||
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override {
|
||||
List<String> list;
|
||||
if (p_preset.is_valid()) {
|
||||
bool project_only = p_preset->get("application/export_project_only");
|
||||
if (project_only) {
|
||||
list.push_back("xcodeproj");
|
||||
} else {
|
||||
list.push_back("ipa");
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags = 0) override;
|
||||
|
||||
virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const override;
|
||||
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
|
||||
|
||||
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) override {
|
||||
}
|
||||
|
||||
EditorExportPlatformAppleEmbedded(const char *p_platform_logo_svg, const char *p_run_icon_svg);
|
||||
~EditorExportPlatformAppleEmbedded();
|
||||
|
||||
/// List the gdip files in the directory specified by the p_path parameter.
|
||||
static Vector<String> list_plugin_config_files(const String &p_path, bool p_check_directories) {
|
||||
Vector<String> dir_files;
|
||||
Ref<DirAccess> da = DirAccess::open(p_path);
|
||||
if (da.is_valid()) {
|
||||
da->list_dir_begin();
|
||||
while (true) {
|
||||
String file = da->get_next();
|
||||
if (file.is_empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (file == "." || file == "..") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (da->current_is_hidden()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (da->current_is_dir()) {
|
||||
if (p_check_directories) {
|
||||
Vector<String> directory_files = list_plugin_config_files(p_path.path_join(file), false);
|
||||
for (int i = 0; i < directory_files.size(); ++i) {
|
||||
dir_files.push_back(file.path_join(directory_files[i]));
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (file.ends_with(PluginConfigAppleEmbedded::PLUGIN_CONFIG_EXT)) {
|
||||
dir_files.push_back(file);
|
||||
}
|
||||
}
|
||||
da->list_dir_end();
|
||||
}
|
||||
|
||||
return dir_files;
|
||||
}
|
||||
|
||||
static Vector<PluginConfigAppleEmbedded> get_plugins(const String &p_platform_name) {
|
||||
Vector<PluginConfigAppleEmbedded> loaded_plugins;
|
||||
|
||||
String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().path_join(p_platform_name + "/plugins");
|
||||
|
||||
if (DirAccess::exists(plugins_dir)) {
|
||||
Vector<String> plugins_filenames = list_plugin_config_files(plugins_dir, true);
|
||||
|
||||
if (!plugins_filenames.is_empty()) {
|
||||
Ref<ConfigFile> config_file;
|
||||
for (int i = 0; i < plugins_filenames.size(); i++) {
|
||||
PluginConfigAppleEmbedded config = PluginConfigAppleEmbedded::load_plugin_config(config_file, plugins_dir.path_join(plugins_filenames[i]));
|
||||
if (config.valid_config) {
|
||||
loaded_plugins.push_back(config);
|
||||
} else {
|
||||
print_error("Invalid plugin config file " + plugins_filenames[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loaded_plugins;
|
||||
}
|
||||
|
||||
static Vector<PluginConfigAppleEmbedded> get_enabled_plugins(const String &p_platform_name, const Ref<EditorExportPreset> &p_presets) {
|
||||
Vector<PluginConfigAppleEmbedded> enabled_plugins;
|
||||
Vector<PluginConfigAppleEmbedded> all_plugins = get_plugins(p_platform_name);
|
||||
for (int i = 0; i < all_plugins.size(); i++) {
|
||||
PluginConfigAppleEmbedded plugin = all_plugins[i];
|
||||
bool enabled = p_presets->get("plugins/" + plugin.name);
|
||||
if (enabled) {
|
||||
enabled_plugins.push_back(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
return enabled_plugins;
|
||||
}
|
||||
};
|
|
@ -67,55 +67,55 @@ void EditorExportPlugin::_add_shared_object(const SharedObject &p_shared_object)
|
|||
shared_objects.push_back(p_shared_object);
|
||||
}
|
||||
|
||||
void EditorExportPlugin::add_ios_framework(const String &p_path) {
|
||||
ios_frameworks.push_back(p_path);
|
||||
void EditorExportPlugin::add_apple_embedded_platform_framework(const String &p_path) {
|
||||
apple_embedded_platform_frameworks.push_back(p_path);
|
||||
}
|
||||
|
||||
void EditorExportPlugin::add_ios_embedded_framework(const String &p_path) {
|
||||
ios_embedded_frameworks.push_back(p_path);
|
||||
void EditorExportPlugin::add_apple_embedded_platform_embedded_framework(const String &p_path) {
|
||||
apple_embedded_platform_embedded_frameworks.push_back(p_path);
|
||||
}
|
||||
|
||||
Vector<String> EditorExportPlugin::get_ios_frameworks() const {
|
||||
return ios_frameworks;
|
||||
Vector<String> EditorExportPlugin::get_apple_embedded_platform_frameworks() const {
|
||||
return apple_embedded_platform_frameworks;
|
||||
}
|
||||
|
||||
Vector<String> EditorExportPlugin::get_ios_embedded_frameworks() const {
|
||||
return ios_embedded_frameworks;
|
||||
Vector<String> EditorExportPlugin::get_apple_embedded_platform_embedded_frameworks() const {
|
||||
return apple_embedded_platform_embedded_frameworks;
|
||||
}
|
||||
|
||||
void EditorExportPlugin::add_ios_plist_content(const String &p_plist_content) {
|
||||
ios_plist_content += p_plist_content + "\n";
|
||||
void EditorExportPlugin::add_apple_embedded_platform_plist_content(const String &p_plist_content) {
|
||||
apple_embedded_platform_plist_content += p_plist_content + "\n";
|
||||
}
|
||||
|
||||
String EditorExportPlugin::get_ios_plist_content() const {
|
||||
return ios_plist_content;
|
||||
String EditorExportPlugin::get_apple_embedded_platform_plist_content() const {
|
||||
return apple_embedded_platform_plist_content;
|
||||
}
|
||||
|
||||
void EditorExportPlugin::add_ios_linker_flags(const String &p_flags) {
|
||||
if (ios_linker_flags.length() > 0) {
|
||||
ios_linker_flags += ' ';
|
||||
void EditorExportPlugin::add_apple_embedded_platform_linker_flags(const String &p_flags) {
|
||||
if (apple_embedded_platform_linker_flags.length() > 0) {
|
||||
apple_embedded_platform_linker_flags += ' ';
|
||||
}
|
||||
ios_linker_flags += p_flags;
|
||||
apple_embedded_platform_linker_flags += p_flags;
|
||||
}
|
||||
|
||||
String EditorExportPlugin::get_ios_linker_flags() const {
|
||||
return ios_linker_flags;
|
||||
String EditorExportPlugin::get_apple_embedded_platform_linker_flags() const {
|
||||
return apple_embedded_platform_linker_flags;
|
||||
}
|
||||
|
||||
void EditorExportPlugin::add_ios_bundle_file(const String &p_path) {
|
||||
ios_bundle_files.push_back(p_path);
|
||||
void EditorExportPlugin::add_apple_embedded_platform_bundle_file(const String &p_path) {
|
||||
apple_embedded_platform_bundle_files.push_back(p_path);
|
||||
}
|
||||
|
||||
Vector<String> EditorExportPlugin::get_ios_bundle_files() const {
|
||||
return ios_bundle_files;
|
||||
Vector<String> EditorExportPlugin::get_apple_embedded_platform_bundle_files() const {
|
||||
return apple_embedded_platform_bundle_files;
|
||||
}
|
||||
|
||||
void EditorExportPlugin::add_ios_cpp_code(const String &p_code) {
|
||||
ios_cpp_code += p_code;
|
||||
void EditorExportPlugin::add_apple_embedded_platform_cpp_code(const String &p_code) {
|
||||
apple_embedded_platform_cpp_code += p_code;
|
||||
}
|
||||
|
||||
String EditorExportPlugin::get_ios_cpp_code() const {
|
||||
return ios_cpp_code;
|
||||
String EditorExportPlugin::get_apple_embedded_platform_cpp_code() const {
|
||||
return apple_embedded_platform_cpp_code;
|
||||
}
|
||||
|
||||
void EditorExportPlugin::add_macos_plugin_file(const String &p_path) {
|
||||
|
@ -126,12 +126,12 @@ const Vector<String> &EditorExportPlugin::get_macos_plugin_files() const {
|
|||
return macos_plugin_files;
|
||||
}
|
||||
|
||||
void EditorExportPlugin::add_ios_project_static_lib(const String &p_path) {
|
||||
ios_project_static_libs.push_back(p_path);
|
||||
void EditorExportPlugin::add_apple_embedded_platform_project_static_lib(const String &p_path) {
|
||||
apple_embedded_platform_project_static_libs.push_back(p_path);
|
||||
}
|
||||
|
||||
Vector<String> EditorExportPlugin::get_ios_project_static_libs() const {
|
||||
return ios_project_static_libs;
|
||||
Vector<String> EditorExportPlugin::get_apple_embedded_platform_project_static_libs() const {
|
||||
return apple_embedded_platform_project_static_libs;
|
||||
}
|
||||
|
||||
Variant EditorExportPlugin::get_option(const StringName &p_name) const {
|
||||
|
@ -328,14 +328,26 @@ void EditorExportPlugin::skip() {
|
|||
|
||||
void EditorExportPlugin::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("add_shared_object", "path", "tags", "target"), &EditorExportPlugin::add_shared_object);
|
||||
ClassDB::bind_method(D_METHOD("add_ios_project_static_lib", "path"), &EditorExportPlugin::add_ios_project_static_lib);
|
||||
ClassDB::bind_method(D_METHOD("add_file", "path", "file", "remap"), &EditorExportPlugin::add_file);
|
||||
ClassDB::bind_method(D_METHOD("add_ios_framework", "path"), &EditorExportPlugin::add_ios_framework);
|
||||
ClassDB::bind_method(D_METHOD("add_ios_embedded_framework", "path"), &EditorExportPlugin::add_ios_embedded_framework);
|
||||
ClassDB::bind_method(D_METHOD("add_ios_plist_content", "plist_content"), &EditorExportPlugin::add_ios_plist_content);
|
||||
ClassDB::bind_method(D_METHOD("add_ios_linker_flags", "flags"), &EditorExportPlugin::add_ios_linker_flags);
|
||||
ClassDB::bind_method(D_METHOD("add_ios_bundle_file", "path"), &EditorExportPlugin::add_ios_bundle_file);
|
||||
ClassDB::bind_method(D_METHOD("add_ios_cpp_code", "code"), &EditorExportPlugin::add_ios_cpp_code);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("add_apple_embedded_platform_project_static_lib", "path"), &EditorExportPlugin::add_apple_embedded_platform_project_static_lib);
|
||||
ClassDB::bind_method(D_METHOD("add_apple_embedded_platform_framework", "path"), &EditorExportPlugin::add_apple_embedded_platform_framework);
|
||||
ClassDB::bind_method(D_METHOD("add_apple_embedded_platform_embedded_framework", "path"), &EditorExportPlugin::add_apple_embedded_platform_embedded_framework);
|
||||
ClassDB::bind_method(D_METHOD("add_apple_embedded_platform_plist_content", "plist_content"), &EditorExportPlugin::add_apple_embedded_platform_plist_content);
|
||||
ClassDB::bind_method(D_METHOD("add_apple_embedded_platform_linker_flags", "flags"), &EditorExportPlugin::add_apple_embedded_platform_linker_flags);
|
||||
ClassDB::bind_method(D_METHOD("add_apple_embedded_platform_bundle_file", "path"), &EditorExportPlugin::add_apple_embedded_platform_bundle_file);
|
||||
ClassDB::bind_method(D_METHOD("add_apple_embedded_platform_cpp_code", "code"), &EditorExportPlugin::add_apple_embedded_platform_cpp_code);
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
ClassDB::bind_method(D_METHOD("add_ios_project_static_lib", "path"), &EditorExportPlugin::add_apple_embedded_platform_project_static_lib);
|
||||
ClassDB::bind_method(D_METHOD("add_ios_framework", "path"), &EditorExportPlugin::add_apple_embedded_platform_framework);
|
||||
ClassDB::bind_method(D_METHOD("add_ios_embedded_framework", "path"), &EditorExportPlugin::add_apple_embedded_platform_embedded_framework);
|
||||
ClassDB::bind_method(D_METHOD("add_ios_plist_content", "plist_content"), &EditorExportPlugin::add_apple_embedded_platform_plist_content);
|
||||
ClassDB::bind_method(D_METHOD("add_ios_linker_flags", "flags"), &EditorExportPlugin::add_apple_embedded_platform_linker_flags);
|
||||
ClassDB::bind_method(D_METHOD("add_ios_bundle_file", "path"), &EditorExportPlugin::add_apple_embedded_platform_bundle_file);
|
||||
ClassDB::bind_method(D_METHOD("add_ios_cpp_code", "code"), &EditorExportPlugin::add_apple_embedded_platform_cpp_code);
|
||||
#endif
|
||||
|
||||
ClassDB::bind_method(D_METHOD("add_macos_plugin_file", "path"), &EditorExportPlugin::add_macos_plugin_file);
|
||||
ClassDB::bind_method(D_METHOD("skip"), &EditorExportPlugin::skip);
|
||||
ClassDB::bind_method(D_METHOD("get_option", "name"), &EditorExportPlugin::get_option);
|
||||
|
|
|
@ -53,13 +53,13 @@ class EditorExportPlugin : public RefCounted {
|
|||
Vector<ExtraFile> extra_files;
|
||||
bool skipped = false;
|
||||
|
||||
Vector<String> ios_frameworks;
|
||||
Vector<String> ios_embedded_frameworks;
|
||||
Vector<String> ios_project_static_libs;
|
||||
String ios_plist_content;
|
||||
String ios_linker_flags;
|
||||
Vector<String> ios_bundle_files;
|
||||
String ios_cpp_code;
|
||||
Vector<String> apple_embedded_platform_frameworks;
|
||||
Vector<String> apple_embedded_platform_embedded_frameworks;
|
||||
Vector<String> apple_embedded_platform_project_static_libs;
|
||||
String apple_embedded_platform_plist_content;
|
||||
String apple_embedded_platform_linker_flags;
|
||||
Vector<String> apple_embedded_platform_bundle_files;
|
||||
String apple_embedded_platform_cpp_code;
|
||||
|
||||
Vector<String> macos_plugin_files;
|
||||
|
||||
|
@ -70,12 +70,12 @@ class EditorExportPlugin : public RefCounted {
|
|||
}
|
||||
|
||||
_FORCE_INLINE_ void _export_end_clear() {
|
||||
ios_frameworks.clear();
|
||||
ios_embedded_frameworks.clear();
|
||||
ios_bundle_files.clear();
|
||||
ios_plist_content = "";
|
||||
ios_linker_flags = "";
|
||||
ios_cpp_code = "";
|
||||
apple_embedded_platform_frameworks.clear();
|
||||
apple_embedded_platform_embedded_frameworks.clear();
|
||||
apple_embedded_platform_bundle_files.clear();
|
||||
apple_embedded_platform_plist_content = "";
|
||||
apple_embedded_platform_linker_flags = "";
|
||||
apple_embedded_platform_cpp_code = "";
|
||||
macos_plugin_files.clear();
|
||||
}
|
||||
|
||||
|
@ -95,13 +95,13 @@ protected:
|
|||
void add_shared_object(const String &p_path, const Vector<String> &tags, const String &p_target = String());
|
||||
void _add_shared_object(const SharedObject &p_shared_object);
|
||||
|
||||
void add_ios_framework(const String &p_path);
|
||||
void add_ios_embedded_framework(const String &p_path);
|
||||
void add_ios_project_static_lib(const String &p_path);
|
||||
void add_ios_plist_content(const String &p_plist_content);
|
||||
void add_ios_linker_flags(const String &p_flags);
|
||||
void add_ios_bundle_file(const String &p_path);
|
||||
void add_ios_cpp_code(const String &p_code);
|
||||
void add_apple_embedded_platform_framework(const String &p_path);
|
||||
void add_apple_embedded_platform_embedded_framework(const String &p_path);
|
||||
void add_apple_embedded_platform_project_static_lib(const String &p_path);
|
||||
void add_apple_embedded_platform_plist_content(const String &p_plist_content);
|
||||
void add_apple_embedded_platform_linker_flags(const String &p_flags);
|
||||
void add_apple_embedded_platform_bundle_file(const String &p_path);
|
||||
void add_apple_embedded_platform_cpp_code(const String &p_code);
|
||||
void add_macos_plugin_file(const String &p_path);
|
||||
|
||||
void skip();
|
||||
|
@ -177,13 +177,13 @@ public:
|
|||
virtual String get_android_manifest_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const;
|
||||
virtual PackedByteArray update_android_prebuilt_manifest(const Ref<EditorExportPlatform> &p_export_platform, const PackedByteArray &p_manifest_data) const;
|
||||
|
||||
Vector<String> get_ios_frameworks() const;
|
||||
Vector<String> get_ios_embedded_frameworks() const;
|
||||
Vector<String> get_ios_project_static_libs() const;
|
||||
String get_ios_plist_content() const;
|
||||
String get_ios_linker_flags() const;
|
||||
Vector<String> get_ios_bundle_files() const;
|
||||
String get_ios_cpp_code() const;
|
||||
Vector<String> get_apple_embedded_platform_frameworks() const;
|
||||
Vector<String> get_apple_embedded_platform_embedded_frameworks() const;
|
||||
Vector<String> get_apple_embedded_platform_project_static_libs() const;
|
||||
String get_apple_embedded_platform_plist_content() const;
|
||||
String get_apple_embedded_platform_linker_flags() const;
|
||||
Vector<String> get_apple_embedded_platform_bundle_files() const;
|
||||
String get_apple_embedded_platform_cpp_code() const;
|
||||
const Vector<String> &get_macos_plugin_files() const;
|
||||
Variant get_option(const StringName &p_name) const;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* godot_plugin_config.cpp */
|
||||
/* plugin_config_apple_embedded.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -28,13 +28,13 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "godot_plugin_config.h"
|
||||
#include "plugin_config_apple_embedded.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/dir_access.h"
|
||||
#include "core/io/file_access.h"
|
||||
|
||||
String PluginConfigIOS::resolve_local_dependency_path(String plugin_config_dir, String dependency_path) {
|
||||
String PluginConfigAppleEmbedded::resolve_local_dependency_path(String plugin_config_dir, String dependency_path) {
|
||||
String absolute_path;
|
||||
|
||||
if (dependency_path.is_empty()) {
|
||||
|
@ -51,7 +51,7 @@ String PluginConfigIOS::resolve_local_dependency_path(String plugin_config_dir,
|
|||
return absolute_path.replace(res_path, "res://");
|
||||
}
|
||||
|
||||
String PluginConfigIOS::resolve_system_dependency_path(String dependency_path) {
|
||||
String PluginConfigAppleEmbedded::resolve_system_dependency_path(String dependency_path) {
|
||||
String absolute_path;
|
||||
|
||||
if (dependency_path.is_empty()) {
|
||||
|
@ -67,7 +67,7 @@ String PluginConfigIOS::resolve_system_dependency_path(String dependency_path) {
|
|||
return system_path.path_join(dependency_path);
|
||||
}
|
||||
|
||||
Vector<String> PluginConfigIOS::resolve_local_dependencies(String plugin_config_dir, Vector<String> p_paths) {
|
||||
Vector<String> PluginConfigAppleEmbedded::resolve_local_dependencies(String plugin_config_dir, Vector<String> p_paths) {
|
||||
Vector<String> paths;
|
||||
|
||||
for (int i = 0; i < p_paths.size(); i++) {
|
||||
|
@ -83,7 +83,7 @@ Vector<String> PluginConfigIOS::resolve_local_dependencies(String plugin_config_
|
|||
return paths;
|
||||
}
|
||||
|
||||
Vector<String> PluginConfigIOS::resolve_system_dependencies(Vector<String> p_paths) {
|
||||
Vector<String> PluginConfigAppleEmbedded::resolve_system_dependencies(Vector<String> p_paths) {
|
||||
Vector<String> paths;
|
||||
|
||||
for (int i = 0; i < p_paths.size(); i++) {
|
||||
|
@ -99,7 +99,7 @@ Vector<String> PluginConfigIOS::resolve_system_dependencies(Vector<String> p_pat
|
|||
return paths;
|
||||
}
|
||||
|
||||
bool PluginConfigIOS::validate_plugin(PluginConfigIOS &plugin_config) {
|
||||
bool PluginConfigAppleEmbedded::validate_plugin(PluginConfigAppleEmbedded &plugin_config) {
|
||||
bool valid_name = !plugin_config.name.is_empty();
|
||||
bool valid_binary_name = !plugin_config.binary.is_empty();
|
||||
bool valid_initialize = !plugin_config.initialization_method.is_empty();
|
||||
|
@ -134,7 +134,7 @@ bool PluginConfigIOS::validate_plugin(PluginConfigIOS &plugin_config) {
|
|||
return plugin_config.valid_config;
|
||||
}
|
||||
|
||||
String PluginConfigIOS::get_plugin_main_binary(PluginConfigIOS &plugin_config, bool p_debug) {
|
||||
String PluginConfigAppleEmbedded::get_plugin_main_binary(PluginConfigAppleEmbedded &plugin_config, bool p_debug) {
|
||||
if (!plugin_config.supports_targets) {
|
||||
return plugin_config.binary;
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ String PluginConfigIOS::get_plugin_main_binary(PluginConfigIOS &plugin_config, b
|
|||
return plugin_binary_dir.path_join(plugin_file);
|
||||
}
|
||||
|
||||
uint64_t PluginConfigIOS::get_plugin_modification_time(const PluginConfigIOS &plugin_config, const String &config_path) {
|
||||
uint64_t PluginConfigAppleEmbedded::get_plugin_modification_time(const PluginConfigAppleEmbedded &plugin_config, const String &config_path) {
|
||||
uint64_t last_updated = FileAccess::get_modified_time(config_path);
|
||||
|
||||
if (!plugin_config.supports_targets) {
|
||||
|
@ -166,8 +166,8 @@ uint64_t PluginConfigIOS::get_plugin_modification_time(const PluginConfigIOS &pl
|
|||
return last_updated;
|
||||
}
|
||||
|
||||
PluginConfigIOS PluginConfigIOS::load_plugin_config(Ref<ConfigFile> config_file, const String &path) {
|
||||
PluginConfigIOS plugin_config = {};
|
||||
PluginConfigAppleEmbedded PluginConfigAppleEmbedded::load_plugin_config(Ref<ConfigFile> config_file, const String &path) {
|
||||
PluginConfigAppleEmbedded plugin_config = {};
|
||||
|
||||
if (config_file.is_null()) {
|
||||
return plugin_config;
|
||||
|
@ -183,19 +183,19 @@ PluginConfigIOS PluginConfigIOS::load_plugin_config(Ref<ConfigFile> config_file,
|
|||
|
||||
String config_base_dir = path.get_base_dir();
|
||||
|
||||
plugin_config.name = config_file->get_value(PluginConfigIOS::CONFIG_SECTION, PluginConfigIOS::CONFIG_NAME_KEY, String());
|
||||
plugin_config.use_swift_runtime = config_file->get_value(PluginConfigIOS::CONFIG_SECTION, PluginConfigIOS::CONFIG_USE_SWIFT_KEY, false);
|
||||
plugin_config.initialization_method = config_file->get_value(PluginConfigIOS::CONFIG_SECTION, PluginConfigIOS::CONFIG_INITIALIZE_KEY, String());
|
||||
plugin_config.deinitialization_method = config_file->get_value(PluginConfigIOS::CONFIG_SECTION, PluginConfigIOS::CONFIG_DEINITIALIZE_KEY, String());
|
||||
plugin_config.name = config_file->get_value(PluginConfigAppleEmbedded::CONFIG_SECTION, PluginConfigAppleEmbedded::CONFIG_NAME_KEY, String());
|
||||
plugin_config.use_swift_runtime = config_file->get_value(PluginConfigAppleEmbedded::CONFIG_SECTION, PluginConfigAppleEmbedded::CONFIG_USE_SWIFT_KEY, false);
|
||||
plugin_config.initialization_method = config_file->get_value(PluginConfigAppleEmbedded::CONFIG_SECTION, PluginConfigAppleEmbedded::CONFIG_INITIALIZE_KEY, String());
|
||||
plugin_config.deinitialization_method = config_file->get_value(PluginConfigAppleEmbedded::CONFIG_SECTION, PluginConfigAppleEmbedded::CONFIG_DEINITIALIZE_KEY, String());
|
||||
|
||||
String binary_path = config_file->get_value(PluginConfigIOS::CONFIG_SECTION, PluginConfigIOS::CONFIG_BINARY_KEY, String());
|
||||
String binary_path = config_file->get_value(PluginConfigAppleEmbedded::CONFIG_SECTION, PluginConfigAppleEmbedded::CONFIG_BINARY_KEY, String());
|
||||
plugin_config.binary = resolve_local_dependency_path(config_base_dir, binary_path);
|
||||
|
||||
if (config_file->has_section(PluginConfigIOS::DEPENDENCIES_SECTION)) {
|
||||
Vector<String> linked_dependencies = config_file->get_value(PluginConfigIOS::DEPENDENCIES_SECTION, PluginConfigIOS::DEPENDENCIES_LINKED_KEY, Vector<String>());
|
||||
Vector<String> embedded_dependencies = config_file->get_value(PluginConfigIOS::DEPENDENCIES_SECTION, PluginConfigIOS::DEPENDENCIES_EMBEDDED_KEY, Vector<String>());
|
||||
Vector<String> system_dependencies = config_file->get_value(PluginConfigIOS::DEPENDENCIES_SECTION, PluginConfigIOS::DEPENDENCIES_SYSTEM_KEY, Vector<String>());
|
||||
Vector<String> files = config_file->get_value(PluginConfigIOS::DEPENDENCIES_SECTION, PluginConfigIOS::DEPENDENCIES_FILES_KEY, Vector<String>());
|
||||
if (config_file->has_section(PluginConfigAppleEmbedded::DEPENDENCIES_SECTION)) {
|
||||
Vector<String> linked_dependencies = config_file->get_value(PluginConfigAppleEmbedded::DEPENDENCIES_SECTION, PluginConfigAppleEmbedded::DEPENDENCIES_LINKED_KEY, Vector<String>());
|
||||
Vector<String> embedded_dependencies = config_file->get_value(PluginConfigAppleEmbedded::DEPENDENCIES_SECTION, PluginConfigAppleEmbedded::DEPENDENCIES_EMBEDDED_KEY, Vector<String>());
|
||||
Vector<String> system_dependencies = config_file->get_value(PluginConfigAppleEmbedded::DEPENDENCIES_SECTION, PluginConfigAppleEmbedded::DEPENDENCIES_SYSTEM_KEY, Vector<String>());
|
||||
Vector<String> files = config_file->get_value(PluginConfigAppleEmbedded::DEPENDENCIES_SECTION, PluginConfigAppleEmbedded::DEPENDENCIES_FILES_KEY, Vector<String>());
|
||||
|
||||
plugin_config.linked_dependencies = resolve_local_dependencies(config_base_dir, linked_dependencies);
|
||||
plugin_config.embedded_dependencies = resolve_local_dependencies(config_base_dir, embedded_dependencies);
|
||||
|
@ -203,77 +203,77 @@ PluginConfigIOS PluginConfigIOS::load_plugin_config(Ref<ConfigFile> config_file,
|
|||
|
||||
plugin_config.files_to_copy = resolve_local_dependencies(config_base_dir, files);
|
||||
|
||||
plugin_config.capabilities = config_file->get_value(PluginConfigIOS::DEPENDENCIES_SECTION, PluginConfigIOS::DEPENDENCIES_CAPABILITIES_KEY, Vector<String>());
|
||||
plugin_config.capabilities = config_file->get_value(PluginConfigAppleEmbedded::DEPENDENCIES_SECTION, PluginConfigAppleEmbedded::DEPENDENCIES_CAPABILITIES_KEY, Vector<String>());
|
||||
|
||||
plugin_config.linker_flags = config_file->get_value(PluginConfigIOS::DEPENDENCIES_SECTION, PluginConfigIOS::DEPENDENCIES_LINKER_FLAGS, Vector<String>());
|
||||
plugin_config.linker_flags = config_file->get_value(PluginConfigAppleEmbedded::DEPENDENCIES_SECTION, PluginConfigAppleEmbedded::DEPENDENCIES_LINKER_FLAGS, Vector<String>());
|
||||
}
|
||||
|
||||
if (config_file->has_section(PluginConfigIOS::PLIST_SECTION)) {
|
||||
Vector<String> keys = config_file->get_section_keys(PluginConfigIOS::PLIST_SECTION);
|
||||
if (config_file->has_section(PluginConfigAppleEmbedded::PLIST_SECTION)) {
|
||||
Vector<String> keys = config_file->get_section_keys(PluginConfigAppleEmbedded::PLIST_SECTION);
|
||||
|
||||
for (const String &key : keys) {
|
||||
Vector<String> key_components = key.split(":");
|
||||
|
||||
String key_value = "";
|
||||
PluginConfigIOS::PlistItemType key_type = PluginConfigIOS::PlistItemType::UNKNOWN;
|
||||
PluginConfigAppleEmbedded::PlistItemType key_type = PluginConfigAppleEmbedded::PlistItemType::UNKNOWN;
|
||||
|
||||
if (key_components.size() == 1) {
|
||||
key_value = key_components[0];
|
||||
key_type = PluginConfigIOS::PlistItemType::STRING;
|
||||
key_type = PluginConfigAppleEmbedded::PlistItemType::STRING;
|
||||
} else if (key_components.size() == 2) {
|
||||
key_value = key_components[0];
|
||||
|
||||
if (key_components[1].to_lower() == "string") {
|
||||
key_type = PluginConfigIOS::PlistItemType::STRING;
|
||||
key_type = PluginConfigAppleEmbedded::PlistItemType::STRING;
|
||||
} else if (key_components[1].to_lower() == "integer") {
|
||||
key_type = PluginConfigIOS::PlistItemType::INTEGER;
|
||||
key_type = PluginConfigAppleEmbedded::PlistItemType::INTEGER;
|
||||
} else if (key_components[1].to_lower() == "boolean") {
|
||||
key_type = PluginConfigIOS::PlistItemType::BOOLEAN;
|
||||
key_type = PluginConfigAppleEmbedded::PlistItemType::BOOLEAN;
|
||||
} else if (key_components[1].to_lower() == "raw") {
|
||||
key_type = PluginConfigIOS::PlistItemType::RAW;
|
||||
key_type = PluginConfigAppleEmbedded::PlistItemType::RAW;
|
||||
} else if (key_components[1].to_lower() == "string_input") {
|
||||
key_type = PluginConfigIOS::PlistItemType::STRING_INPUT;
|
||||
key_type = PluginConfigAppleEmbedded::PlistItemType::STRING_INPUT;
|
||||
}
|
||||
}
|
||||
|
||||
if (key_value.is_empty() || key_type == PluginConfigIOS::PlistItemType::UNKNOWN) {
|
||||
if (key_value.is_empty() || key_type == PluginConfigAppleEmbedded::PlistItemType::UNKNOWN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String value;
|
||||
|
||||
switch (key_type) {
|
||||
case PluginConfigIOS::PlistItemType::STRING: {
|
||||
String raw_value = config_file->get_value(PluginConfigIOS::PLIST_SECTION, key, String());
|
||||
case PluginConfigAppleEmbedded::PlistItemType::STRING: {
|
||||
String raw_value = config_file->get_value(PluginConfigAppleEmbedded::PLIST_SECTION, key, String());
|
||||
value = "<string>" + raw_value + "</string>";
|
||||
} break;
|
||||
case PluginConfigIOS::PlistItemType::INTEGER: {
|
||||
int raw_value = config_file->get_value(PluginConfigIOS::PLIST_SECTION, key, 0);
|
||||
case PluginConfigAppleEmbedded::PlistItemType::INTEGER: {
|
||||
int raw_value = config_file->get_value(PluginConfigAppleEmbedded::PLIST_SECTION, key, 0);
|
||||
Dictionary value_dictionary;
|
||||
String value_format = "<integer>$value</integer>";
|
||||
value_dictionary["value"] = raw_value;
|
||||
value = value_format.format(value_dictionary, "$_");
|
||||
} break;
|
||||
case PluginConfigIOS::PlistItemType::BOOLEAN:
|
||||
if (config_file->get_value(PluginConfigIOS::PLIST_SECTION, key, false)) {
|
||||
case PluginConfigAppleEmbedded::PlistItemType::BOOLEAN:
|
||||
if (config_file->get_value(PluginConfigAppleEmbedded::PLIST_SECTION, key, false)) {
|
||||
value = "<true/>";
|
||||
} else {
|
||||
value = "<false/>";
|
||||
}
|
||||
break;
|
||||
case PluginConfigIOS::PlistItemType::RAW: {
|
||||
String raw_value = config_file->get_value(PluginConfigIOS::PLIST_SECTION, key, String());
|
||||
case PluginConfigAppleEmbedded::PlistItemType::RAW: {
|
||||
String raw_value = config_file->get_value(PluginConfigAppleEmbedded::PLIST_SECTION, key, String());
|
||||
value = raw_value;
|
||||
} break;
|
||||
case PluginConfigIOS::PlistItemType::STRING_INPUT: {
|
||||
String raw_value = config_file->get_value(PluginConfigIOS::PLIST_SECTION, key, String());
|
||||
case PluginConfigAppleEmbedded::PlistItemType::STRING_INPUT: {
|
||||
String raw_value = config_file->get_value(PluginConfigAppleEmbedded::PLIST_SECTION, key, String());
|
||||
value = raw_value;
|
||||
} break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
plugin_config.plist[key_value] = PluginConfigIOS::PlistItem{ key_type, value };
|
||||
plugin_config.plist[key_value] = PluginConfigAppleEmbedded::PlistItem{ key_type, value };
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* godot_plugin_config.h */
|
||||
/* plugin_config_apple_embedded.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -50,7 +50,7 @@ The `plist` section are optional.
|
|||
- **key**: key and value that would be added in Info.plist file.
|
||||
*/
|
||||
|
||||
struct PluginConfigIOS {
|
||||
struct PluginConfigAppleEmbedded {
|
||||
inline static const char *PLUGIN_CONFIG_EXT = ".gdip";
|
||||
|
||||
inline static const char *CONFIG_SECTION = "config";
|
||||
|
@ -121,11 +121,11 @@ struct PluginConfigIOS {
|
|||
|
||||
static Vector<String> resolve_system_dependencies(Vector<String> p_paths);
|
||||
|
||||
static bool validate_plugin(PluginConfigIOS &plugin_config);
|
||||
static bool validate_plugin(PluginConfigAppleEmbedded &plugin_config);
|
||||
|
||||
static String get_plugin_main_binary(PluginConfigIOS &plugin_config, bool p_debug);
|
||||
static String get_plugin_main_binary(PluginConfigAppleEmbedded &plugin_config, bool p_debug);
|
||||
|
||||
static uint64_t get_plugin_modification_time(const PluginConfigIOS &plugin_config, const String &config_path);
|
||||
static uint64_t get_plugin_modification_time(const PluginConfigAppleEmbedded &plugin_config, const String &config_path);
|
||||
|
||||
static PluginConfigIOS load_plugin_config(Ref<ConfigFile> config_file, const String &path);
|
||||
static PluginConfigAppleEmbedded load_plugin_config(Ref<ConfigFile> config_file, const String &path);
|
||||
};
|
|
@ -115,9 +115,9 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p
|
|||
libs_added.insert(library_path);
|
||||
add_shared_object(library_path, tags);
|
||||
|
||||
if (p_features.has("ios") && (library_path.ends_with(".a") || library_path.ends_with(".xcframework"))) {
|
||||
if (p_features.has("apple_embedded") && (library_path.ends_with(".a") || library_path.ends_with(".xcframework"))) {
|
||||
String additional_code = "extern void register_dynamic_symbol(char *name, void *address);\n"
|
||||
"extern void add_ios_init_callback(void (*cb)());\n"
|
||||
"extern void add_apple_embedded_platform_init_callback(void (*cb)());\n"
|
||||
"\n"
|
||||
"extern \"C\" void $ENTRY();\n"
|
||||
"void $ENTRY_init() {\n"
|
||||
|
@ -125,15 +125,15 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p
|
|||
"}\n"
|
||||
"struct $ENTRY_struct {\n"
|
||||
" $ENTRY_struct() {\n"
|
||||
" add_ios_init_callback($ENTRY_init);\n"
|
||||
" add_apple_embedded_platform_init_callback($ENTRY_init);\n"
|
||||
" }\n"
|
||||
"};\n"
|
||||
"$ENTRY_struct $ENTRY_struct_instance;\n\n";
|
||||
additional_code = additional_code.replace("$ENTRY", entry_symbol);
|
||||
add_ios_cpp_code(additional_code);
|
||||
add_apple_embedded_platform_cpp_code(additional_code);
|
||||
|
||||
String linker_flags = "-Wl,-U,_" + entry_symbol;
|
||||
add_ios_linker_flags(linker_flags);
|
||||
add_apple_embedded_platform_linker_flags(linker_flags);
|
||||
}
|
||||
|
||||
// Update found library info.
|
||||
|
|
|
@ -195,7 +195,7 @@ LightmapGIEditorPlugin::LightmapGIEditorPlugin() {
|
|||
#else
|
||||
// Disable lightmap baking if the module is disabled at compile-time.
|
||||
bake->set_disabled(true);
|
||||
#if defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
|
||||
#if defined(ANDROID_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
|
||||
bake->set_tooltip_text(vformat(TTR("Lightmaps cannot be baked on %s."), OS::get_singleton()->get_name()));
|
||||
#else
|
||||
bake->set_tooltip_text(TTR("Lightmaps cannot be baked, as the `lightmapper_rd` module was disabled at compile-time."));
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "editor/editor_undo_redo_manager.h"
|
||||
#include "editor/editor_vcs_interface.h"
|
||||
#include "editor/export/editor_export_platform.h"
|
||||
#include "editor/export/editor_export_platform_apple_embedded.h"
|
||||
#include "editor/export/editor_export_platform_extension.h"
|
||||
#include "editor/export/editor_export_platform_pc.h"
|
||||
#include "editor/export/editor_export_plugin.h"
|
||||
|
@ -163,6 +164,7 @@ void register_editor_types() {
|
|||
GDREGISTER_CLASS(EditorExportPlugin);
|
||||
GDREGISTER_ABSTRACT_CLASS(EditorExportPlatform);
|
||||
GDREGISTER_ABSTRACT_CLASS(EditorExportPlatformPC);
|
||||
GDREGISTER_ABSTRACT_CLASS(EditorExportPlatformAppleEmbedded);
|
||||
GDREGISTER_CLASS(EditorExportPlatformExtension);
|
||||
GDREGISTER_ABSTRACT_CLASS(EditorExportPreset);
|
||||
|
||||
|
|
|
@ -3797,7 +3797,7 @@ static MainTimerSync main_timer_sync;
|
|||
int Main::start() {
|
||||
OS::get_singleton()->benchmark_begin_measure("Startup", "Main::Start");
|
||||
|
||||
ERR_FAIL_COND_V(!_start_success, false);
|
||||
ERR_FAIL_COND_V(!_start_success, EXIT_FAILURE);
|
||||
|
||||
bool has_icon = false;
|
||||
String positional_arg;
|
||||
|
|
18
methods.py
18
methods.py
|
@ -609,17 +609,33 @@ def Run(env, function):
|
|||
return Action(function, "$GENCOMSTR")
|
||||
|
||||
|
||||
def detect_darwin_toolchain_path(env):
|
||||
var_name = "APPLE_TOOLCHAIN_PATH"
|
||||
if not env[var_name]:
|
||||
try:
|
||||
xcode_path = subprocess.check_output(["xcode-select", "-p"]).strip().decode("utf-8")
|
||||
if xcode_path:
|
||||
env[var_name] = xcode_path + "/Toolchains/XcodeDefault.xctoolchain"
|
||||
except (subprocess.CalledProcessError, OSError):
|
||||
print_error("Failed to find SDK path while running 'xcode-select -p'.")
|
||||
raise
|
||||
|
||||
|
||||
def detect_darwin_sdk_path(platform, env):
|
||||
sdk_name = ""
|
||||
|
||||
if platform == "macos":
|
||||
sdk_name = "macosx"
|
||||
var_name = "MACOS_SDK_PATH"
|
||||
|
||||
elif platform == "ios":
|
||||
sdk_name = "iphoneos"
|
||||
var_name = "IOS_SDK_PATH"
|
||||
|
||||
elif platform == "iossimulator":
|
||||
sdk_name = "iphonesimulator"
|
||||
var_name = "IOS_SDK_PATH"
|
||||
|
||||
else:
|
||||
raise Exception("Invalid platform argument passed to detect_darwin_sdk_path")
|
||||
|
||||
|
@ -629,7 +645,7 @@ def detect_darwin_sdk_path(platform, env):
|
|||
if sdk_path:
|
||||
env[var_name] = sdk_path
|
||||
except (subprocess.CalledProcessError, OSError):
|
||||
print_error("Failed to find SDK path while running xcrun --sdk {} --show-sdk-path.".format(sdk_name))
|
||||
print_error("Failed to find SDK path while running 'xcrun --sdk {} --show-sdk-path'.".format(sdk_name))
|
||||
raise
|
||||
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
054F8BE62D38852F00B81423 /* MetalFX.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 054F8BE52D38852F00B81423 /* MetalFX.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||
1F1575721F582BE20003B888 /* dylibs in Resources */ = {isa = PBXBuildFile; fileRef = 1F1575711F582BE20003B888 /* dylibs */; };
|
||||
DEADBEEF2F582BE20003B888 /* $binary.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = DEADBEEF1F582BE20003B888 /* $binary.xcframework */; };
|
||||
$modules_buildfile
|
||||
|
@ -43,7 +42,6 @@
|
|||
1FF4C1881F584E6300A41E41 /* $binary.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "$binary.entitlements"; sourceTree = "<group>"; };
|
||||
1FF8DBB01FBA9DE1009DE660 /* dummy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = dummy.cpp; sourceTree = "<group>"; };
|
||||
9039D3BD24C093AC0020482C /* MoltenVK.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = MoltenVK; path = MoltenVK.xcframework; sourceTree = "<group>"; };
|
||||
054F8BE52D38852F00B81423 /* MetalFX.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalFX.framework; path = System/Library/Frameworks/MetalFX.framework; sourceTree = SDKROOT; };
|
||||
D07CD44D1C5D589C00B7FB28 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
D0BCFE3418AEBDA2004A7AAE /* $binary.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "$binary.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D0BCFE4318AEBDA2004A7AAE /* $binary-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "$binary-Info.plist"; sourceTree = "<group>"; };
|
||||
|
@ -62,7 +60,6 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9039D3BE24C093AC0020482C /* MoltenVK.xcframework in Frameworks */,
|
||||
054F8BE62D38852F00B81423 /* MetalFX.framework in Frameworks */,
|
||||
DEADBEEF2F582BE20003B888 /* $binary.xcframework */,
|
||||
$modules_buildphase
|
||||
$additional_pbx_frameworks_build
|
||||
|
@ -97,7 +94,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
9039D3BD24C093AC0020482C /* MoltenVK.xcframework */,
|
||||
054F8BE52D38852F00B81423 /* MetalFX.framework */,
|
||||
DEADBEEF1F582BE20003B888 /* $binary.xcframework */,
|
||||
$modules_buildgrp
|
||||
$additional_pbx_frameworks_refs
|
||||
|
|
|
@ -406,7 +406,7 @@ namespace GodotTools.Export
|
|||
{
|
||||
if (platform == OS.Platforms.iOS && path.EndsWith(".dat", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
AddIosBundleFile(path);
|
||||
AddAppleEmbeddedPlatformBundleFile(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -453,7 +453,7 @@ namespace GodotTools.Export
|
|||
throw new InvalidOperationException("Failed to generate xcframework.");
|
||||
}
|
||||
|
||||
AddIosEmbeddedFramework(xcFrameworkPath);
|
||||
AddAppleEmbeddedPlatformEmbeddedFramework(xcFrameworkPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ namespace {
|
|||
String get_hostfxr_file_name() {
|
||||
#if defined(WINDOWS_ENABLED)
|
||||
return "hostfxr.dll";
|
||||
#elif defined(MACOS_ENABLED) || defined(IOS_ENABLED)
|
||||
#elif defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
|
||||
return "libhostfxr.dylib";
|
||||
#else
|
||||
return "libhostfxr.so";
|
||||
|
|
|
@ -450,7 +450,7 @@ godot_plugins_initialize_fn try_load_native_aot_library(void *&r_aot_dll_handle)
|
|||
|
||||
#if defined(WINDOWS_ENABLED)
|
||||
String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().path_join(assembly_name + ".dll");
|
||||
#elif defined(MACOS_ENABLED) || defined(IOS_ENABLED)
|
||||
#elif defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
|
||||
String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().path_join(assembly_name + ".dylib");
|
||||
#elif defined(ANDROID_ENABLED)
|
||||
String native_aot_so_path = "lib" + assembly_name + ".so";
|
||||
|
@ -599,7 +599,7 @@ void GDMono::initialize() {
|
|||
|
||||
godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
|
||||
|
||||
#if !defined(IOS_ENABLED)
|
||||
#if !defined(APPLE_EMBEDDED_ENABLED)
|
||||
// Check that the .NET assemblies directory exists before trying to use it.
|
||||
if (!DirAccess::exists(GodotSharpDirs::get_api_assemblies_dir())) {
|
||||
OS::get_singleton()->alert(vformat(RTR("Unable to find the .NET assemblies directory.\nMake sure the '%s' directory exists and contains the .NET assemblies."), GodotSharpDirs::get_api_assemblies_dir()), RTR(".NET assemblies not found"));
|
||||
|
@ -639,7 +639,7 @@ void GDMono::initialize() {
|
|||
|
||||
void *godot_dll_handle = nullptr;
|
||||
|
||||
#if defined(UNIX_ENABLED) && !defined(MACOS_ENABLED) && !defined(IOS_ENABLED)
|
||||
#if defined(UNIX_ENABLED) && !defined(MACOS_ENABLED) && !defined(APPLE_EMBEDDED_ENABLED)
|
||||
// Managed code can access it on its own on other platforms
|
||||
godot_dll_handle = dlopen(nullptr, RTLD_NOW);
|
||||
#endif
|
||||
|
|
|
@ -713,7 +713,7 @@ Vector<PluginConfigAndroid> EditorExportPlatformAndroid::get_plugins() {
|
|||
Vector<String> plugins_filenames = list_gdap_files(plugins_dir);
|
||||
|
||||
if (!plugins_filenames.is_empty()) {
|
||||
Ref<ConfigFile> config_file = memnew(ConfigFile);
|
||||
Ref<ConfigFile> config_file;
|
||||
for (int i = 0; i < plugins_filenames.size(); i++) {
|
||||
PluginConfigAndroid config = PluginConfigAndroid::load_plugin_config(config_file, plugins_dir.path_join(plugins_filenames[i]));
|
||||
if (config.valid_config) {
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
This folder contains the C++, Objective-C and Objective-C++ code for the iOS
|
||||
platform port.
|
||||
|
||||
This platform derives from the Apple embedded abstract platform ([`drivers/apple_embedded`](/drivers/apple_embedded)).
|
||||
|
||||
This platform uses shared Apple code ([`drivers/apple`](/drivers/apple)).
|
||||
|
||||
See also [`misc/dist/ios_xcode`](/misc/dist/ios_xcode) folder for the Xcode
|
||||
project template used for packaging the iOS export templates.
|
||||
|
||||
|
|
|
@ -1,28 +1,19 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
import platform_ios_builders
|
||||
from platform_ios_builders import generate_bundle
|
||||
|
||||
from platform_methods import combine_libs_apple_embedded
|
||||
|
||||
Import("env")
|
||||
|
||||
ios_lib = [
|
||||
"godot_ios.mm",
|
||||
"os_ios.mm",
|
||||
"main.m",
|
||||
"app_delegate.mm",
|
||||
"view_controller.mm",
|
||||
"ios.mm",
|
||||
"rendering_context_driver_vulkan_ios.mm",
|
||||
"device_metrics.mm",
|
||||
"display_layer_ios.mm",
|
||||
"display_server_ios.mm",
|
||||
"godot_view.mm",
|
||||
"tts_ios.mm",
|
||||
"display_layer.mm",
|
||||
"godot_app_delegate.m",
|
||||
"godot_view_renderer.mm",
|
||||
"device_metrics.m",
|
||||
"keyboard_input_view.mm",
|
||||
"key_mapping_ios.mm",
|
||||
"ios_terminal_logger.mm",
|
||||
"godot_view_ios.mm",
|
||||
"main_ios.mm",
|
||||
"os_ios.mm",
|
||||
]
|
||||
|
||||
env_ios = env.Clone()
|
||||
|
@ -31,12 +22,9 @@ ios_lib = env_ios.add_library("ios", ios_lib)
|
|||
# (iOS) Enable module support
|
||||
env_ios.Append(CCFLAGS=["-fmodules", "-fcxx-modules"])
|
||||
|
||||
|
||||
combine_command = env_ios.CommandNoCache(
|
||||
"#bin/libgodot" + env_ios["LIBSUFFIX"], [ios_lib] + env_ios["LIBS"], env.Run(platform_ios_builders.combine_libs)
|
||||
"#bin/libgodot" + env_ios["LIBSUFFIX"], [ios_lib] + env_ios["LIBS"], env.Run(combine_libs_apple_embedded)
|
||||
)
|
||||
|
||||
if env["generate_bundle"]:
|
||||
env.AlwaysBuild(
|
||||
env.CommandNoCache("generate_bundle", combine_command, env.Run(platform_ios_builders.generate_bundle))
|
||||
)
|
||||
env.AlwaysBuild(env.CommandNoCache("generate_bundle", combine_command, env.Run(generate_bundle)))
|
||||
|
|
|
@ -33,11 +33,11 @@
|
|||
#if defined(IOS_ENABLED)
|
||||
|
||||
void register_ios_api() {
|
||||
godot_ios_plugins_initialize();
|
||||
godot_apple_embedded_plugins_initialize();
|
||||
}
|
||||
|
||||
void unregister_ios_api() {
|
||||
godot_ios_plugins_deinitialize();
|
||||
godot_apple_embedded_plugins_deinitialize();
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
#pragma once
|
||||
|
||||
#if defined(IOS_ENABLED)
|
||||
extern void godot_ios_plugins_initialize();
|
||||
extern void godot_ios_plugins_deinitialize();
|
||||
extern void godot_apple_embedded_plugins_initialize();
|
||||
extern void godot_apple_embedded_plugins_deinitialize();
|
||||
#endif
|
||||
|
||||
void register_ios_api();
|
||||
|
|
|
@ -2,7 +2,7 @@ import os
|
|||
import sys
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from methods import detect_darwin_sdk_path, print_error, print_warning
|
||||
from methods import detect_darwin_sdk_path, detect_darwin_toolchain_path, print_error, print_warning
|
||||
from platform_methods import validate_arch
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
@ -25,14 +25,11 @@ def get_opts():
|
|||
|
||||
return [
|
||||
("vulkan_sdk_path", "Path to the Vulkan SDK", ""),
|
||||
(
|
||||
"IOS_TOOLCHAIN_PATH",
|
||||
"Path to iOS toolchain",
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain",
|
||||
),
|
||||
# APPLE_TOOLCHAIN_PATH Example: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain
|
||||
(("APPLE_TOOLCHAIN_PATH", "IOS_TOOLCHAIN_PATH"), "Path to the Apple toolchain", ""),
|
||||
("IOS_SDK_PATH", "Path to the iOS SDK", ""),
|
||||
BoolVariable("ios_simulator", "Build for iOS Simulator", False),
|
||||
("ios_triple", "Triple for ios toolchain", ""),
|
||||
(("apple_target_triple", "ios_triple"), "Triple for the corresponding target Apple platform toolchain", ""),
|
||||
BoolVariable(("simulator", "ios_simulator"), "Build for Simulator", False),
|
||||
BoolVariable("generate_bundle", "Generate an APP bundle after building iOS/macOS binaries", False),
|
||||
]
|
||||
|
||||
|
@ -62,6 +59,7 @@ def configure(env: "SConsEnvironment"):
|
|||
# Validate arch.
|
||||
supported_arches = ["x86_64", "arm64"]
|
||||
validate_arch(env["arch"], get_name(), supported_arches)
|
||||
detect_darwin_toolchain_path(env)
|
||||
|
||||
## LTO
|
||||
|
||||
|
@ -82,9 +80,9 @@ def configure(env: "SConsEnvironment"):
|
|||
if "OSXCROSS_IOS" in os.environ:
|
||||
env["osxcross"] = True
|
||||
|
||||
env["ENV"]["PATH"] = env["IOS_TOOLCHAIN_PATH"] + "/Developer/usr/bin/:" + env["ENV"]["PATH"]
|
||||
env["ENV"]["PATH"] = env["APPLE_TOOLCHAIN_PATH"] + "/Developer/usr/bin/:" + env["ENV"]["PATH"]
|
||||
|
||||
compiler_path = "$IOS_TOOLCHAIN_PATH/usr/bin/${ios_triple}"
|
||||
compiler_path = "$APPLE_TOOLCHAIN_PATH/usr/bin/${apple_target_triple}"
|
||||
|
||||
ccache_path = os.environ.get("CCACHE")
|
||||
if ccache_path is None:
|
||||
|
@ -102,7 +100,7 @@ def configure(env: "SConsEnvironment"):
|
|||
|
||||
## Compile flags
|
||||
|
||||
if env["ios_simulator"]:
|
||||
if env["simulator"]:
|
||||
detect_darwin_sdk_path("iossimulator", env)
|
||||
env.Append(ASFLAGS=["-mios-simulator-version-min=12.0"])
|
||||
env.Append(CCFLAGS=["-mios-simulator-version-min=12.0"])
|
||||
|
@ -114,8 +112,8 @@ def configure(env: "SConsEnvironment"):
|
|||
env.Append(CCFLAGS=["-miphoneos-version-min=12.0"])
|
||||
|
||||
if env["arch"] == "x86_64":
|
||||
if not env["ios_simulator"]:
|
||||
print_error("Building for iOS with 'arch=x86_64' requires 'ios_simulator=yes'.")
|
||||
if not env["simulator"]:
|
||||
print_error("Building for iOS with 'arch=x86_64' requires 'simulator=yes'.")
|
||||
sys.exit(255)
|
||||
|
||||
env["ENV"]["MACOSX_DEPLOYMENT_TARGET"] = "10.9"
|
||||
|
@ -149,10 +147,10 @@ def configure(env: "SConsEnvironment"):
|
|||
)
|
||||
|
||||
env.Prepend(CPPPATH=["#platform/ios"])
|
||||
env.Append(CPPDEFINES=["IOS_ENABLED", "UNIX_ENABLED", "COREAUDIO_ENABLED"])
|
||||
env.Append(CPPDEFINES=["IOS_ENABLED", "APPLE_EMBEDDED_ENABLED", "UNIX_ENABLED", "COREAUDIO_ENABLED"])
|
||||
|
||||
if env["metal"] and env["ios_simulator"]:
|
||||
print_warning("iOS simulator does not support the Metal rendering driver")
|
||||
if env["metal"] and env["simulator"]:
|
||||
print_warning("iOS Simulator does not support the Metal rendering driver")
|
||||
env["metal"] = False
|
||||
|
||||
if env["metal"]:
|
||||
|
@ -166,8 +164,8 @@ def configure(env: "SConsEnvironment"):
|
|||
)
|
||||
env.Prepend(CPPEXTPATH=["#thirdparty/spirv-cross"])
|
||||
|
||||
if env["vulkan"] and env["ios_simulator"]:
|
||||
print_warning("iOS simulator does not support the Vulkan rendering driver")
|
||||
if env["vulkan"] and env["simulator"]:
|
||||
print_warning("iOS Simulator does not support the Vulkan rendering driver")
|
||||
env["vulkan"] = False
|
||||
|
||||
if env["vulkan"]:
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface GodotDeviceMetrics : NSObject
|
||||
@interface GDTDeviceMetrics : NSObject
|
||||
|
||||
@property(nonatomic, class, readonly, strong) NSDictionary<NSArray *, NSNumber *> *dpiList;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* device_metrics.m */
|
||||
/* device_metrics.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -30,7 +30,7 @@
|
|||
|
||||
#import "device_metrics.h"
|
||||
|
||||
@implementation GodotDeviceMetrics
|
||||
@implementation GDTDeviceMetrics
|
||||
|
||||
+ (NSDictionary *)dpiList {
|
||||
return @{
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* display_layer.h */
|
||||
/* display_layer_ios.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -30,32 +30,25 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "drivers/apple_embedded/display_layer_apple_embedded.h"
|
||||
|
||||
#import <OpenGLES/EAGLDrawable.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
@protocol DisplayLayer <NSObject>
|
||||
|
||||
- (void)startRenderDisplayLayer;
|
||||
- (void)stopRenderDisplayLayer;
|
||||
- (void)initializeDisplayLayer;
|
||||
- (void)layoutDisplayLayer;
|
||||
|
||||
@end
|
||||
|
||||
// An ugly workaround for iOS simulator
|
||||
#if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR
|
||||
#if defined(__IPHONE_13_0)
|
||||
API_AVAILABLE(ios(13.0))
|
||||
@interface GodotMetalLayer : CAMetalLayer <DisplayLayer>
|
||||
@interface GDTMetalLayer : CAMetalLayer <GDTDisplayLayer>
|
||||
#else
|
||||
@interface GodotMetalLayer : CALayer <DisplayLayer>
|
||||
@interface GDTMetalLayer : CALayer <GDTDisplayLayer>
|
||||
#endif
|
||||
#else
|
||||
@interface GodotMetalLayer : CAMetalLayer <DisplayLayer>
|
||||
@interface GDTMetalLayer : CAMetalLayer <GDTDisplayLayer>
|
||||
#endif
|
||||
@end
|
||||
|
||||
API_DEPRECATED("OpenGLES is deprecated", ios(2.0, 12.0))
|
||||
@interface GodotOpenGLLayer : CAEAGLLayer <DisplayLayer>
|
||||
@interface GDTOpenGLLayer : CAEAGLLayer <GDTDisplayLayer>
|
||||
|
||||
@end
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* display_layer.mm */
|
||||
/* display_layer_ios.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -28,7 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#import "display_layer.h"
|
||||
#import "display_layer_ios.h"
|
||||
|
||||
#import "display_server_ios.h"
|
||||
#import "os_ios.h"
|
||||
|
@ -46,7 +46,7 @@
|
|||
#import <QuartzCore/QuartzCore.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@implementation GodotMetalLayer
|
||||
@implementation GDTMetalLayer
|
||||
|
||||
- (void)initializeDisplayLayer {
|
||||
#if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR
|
||||
|
@ -69,7 +69,7 @@
|
|||
|
||||
@end
|
||||
|
||||
@implementation GodotOpenGLLayer {
|
||||
@implementation GDTOpenGLLayer {
|
||||
// The pixel dimensions of the backbuffer
|
||||
GLint backingWidth;
|
||||
GLint backingHeight;
|
|
@ -30,209 +30,25 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "core/input/input.h"
|
||||
#include "servers/display_server.h"
|
||||
#include "drivers/apple_embedded/display_server_apple_embedded.h"
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
|
||||
#include "servers/rendering/rendering_device.h"
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
#import "rendering_context_driver_vulkan_ios.h"
|
||||
|
||||
#include "drivers/vulkan/godot_vulkan.h"
|
||||
#endif // VULKAN_ENABLED
|
||||
|
||||
#if defined(METAL_ENABLED)
|
||||
#import "drivers/metal/rendering_context_driver_metal.h"
|
||||
#endif // METAL_ENABLED
|
||||
#endif // RD_ENABLED
|
||||
|
||||
#if defined(GLES3_ENABLED)
|
||||
#include "drivers/gles3/rasterizer_gles3.h"
|
||||
#endif // GLES3_ENABLED
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
class DisplayServerIOS : public DisplayServer {
|
||||
GDSOFTCLASS(DisplayServerIOS, DisplayServer);
|
||||
class DisplayServerIOS : public DisplayServerAppleEmbedded {
|
||||
GDSOFTCLASS(DisplayServerIOS, DisplayServerAppleEmbedded);
|
||||
|
||||
_THREAD_SAFE_CLASS_
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
RenderingContextDriver *rendering_context = nullptr;
|
||||
RenderingDevice *rendering_device = nullptr;
|
||||
#endif
|
||||
NativeMenu *native_menu = nullptr;
|
||||
|
||||
id tts = nullptr;
|
||||
|
||||
DisplayServer::ScreenOrientation screen_orientation;
|
||||
|
||||
ObjectID window_attached_instance_id;
|
||||
|
||||
Callable window_event_callback;
|
||||
Callable window_resize_callback;
|
||||
Callable input_event_callback;
|
||||
Callable input_text_callback;
|
||||
|
||||
Callable system_theme_changed;
|
||||
|
||||
int virtual_keyboard_height = 0;
|
||||
|
||||
void perform_event(const Ref<InputEvent> &p_event);
|
||||
|
||||
void initialize_tts() const;
|
||||
|
||||
DisplayServerIOS(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error);
|
||||
~DisplayServerIOS();
|
||||
|
||||
public:
|
||||
String rendering_driver;
|
||||
|
||||
static DisplayServerIOS *get_singleton();
|
||||
|
||||
static void register_ios_driver();
|
||||
static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error);
|
||||
static Vector<String> get_rendering_drivers_func();
|
||||
|
||||
// MARK: - Events
|
||||
|
||||
virtual void process_events() override;
|
||||
|
||||
virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
|
||||
static void _dispatch_input_events(const Ref<InputEvent> &p_event);
|
||||
void send_input_event(const Ref<InputEvent> &p_event) const;
|
||||
void send_input_text(const String &p_text) const;
|
||||
void send_window_event(DisplayServer::WindowEvent p_event) const;
|
||||
void _window_callback(const Callable &p_callable, const Variant &p_arg) const;
|
||||
|
||||
void emit_system_theme_changed();
|
||||
|
||||
// MARK: - Input
|
||||
|
||||
// MARK: Touches and Apple Pencil
|
||||
|
||||
void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click);
|
||||
void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, float p_pressure, Vector2 p_tilt);
|
||||
void touches_canceled(int p_idx);
|
||||
|
||||
// MARK: Keyboard
|
||||
|
||||
void key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, NSInteger p_modifier, bool p_pressed, KeyLocation p_location);
|
||||
bool is_keyboard_active() const;
|
||||
|
||||
// MARK: Motion
|
||||
|
||||
void update_gravity(const Vector3 &p_gravity);
|
||||
void update_accelerometer(const Vector3 &p_accelerometer);
|
||||
void update_magnetometer(const Vector3 &p_magnetometer);
|
||||
void update_gyroscope(const Vector3 &p_gyroscope);
|
||||
|
||||
// MARK: -
|
||||
|
||||
virtual bool has_feature(Feature p_feature) const override;
|
||||
virtual String get_name() const override;
|
||||
|
||||
virtual bool tts_is_speaking() const override;
|
||||
virtual bool tts_is_paused() const override;
|
||||
virtual TypedArray<Dictionary> tts_get_voices() const override;
|
||||
|
||||
virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override;
|
||||
virtual void tts_pause() override;
|
||||
virtual void tts_resume() override;
|
||||
virtual void tts_stop() override;
|
||||
|
||||
virtual bool is_dark_mode_supported() const override;
|
||||
virtual bool is_dark_mode() const override;
|
||||
virtual void set_system_theme_change_callback(const Callable &p_callable) override;
|
||||
|
||||
virtual Rect2i get_display_safe_area() const override;
|
||||
|
||||
virtual int get_screen_count() const override;
|
||||
virtual int get_primary_screen() const override;
|
||||
virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
|
||||
|
||||
virtual Vector<DisplayServer::WindowID> get_window_list() const override;
|
||||
|
||||
virtual WindowID get_window_at_screen_position(const Point2i &p_position) const override;
|
||||
|
||||
virtual int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
|
||||
virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
|
||||
virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
virtual Point2i window_get_position_with_decorations(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
|
||||
virtual void window_set_transient(WindowID p_window, WindowID p_parent) override;
|
||||
|
||||
virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
virtual Size2i window_get_size_with_decorations(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual float screen_get_max_scale() const override;
|
||||
|
||||
virtual void screen_set_orientation(DisplayServer::ScreenOrientation p_orientation, int p_screen) override;
|
||||
virtual DisplayServer::ScreenOrientation screen_get_orientation(int p_screen) const override;
|
||||
|
||||
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual bool can_any_window_draw() const override;
|
||||
|
||||
virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override;
|
||||
|
||||
virtual bool is_touchscreen_available() const override;
|
||||
|
||||
virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_length, int p_cursor_start, int p_cursor_end) override;
|
||||
virtual void virtual_keyboard_hide() override;
|
||||
|
||||
void virtual_keyboard_set_height(int height);
|
||||
virtual int virtual_keyboard_get_height() const override;
|
||||
virtual bool has_hardware_keyboard() const override;
|
||||
|
||||
virtual void clipboard_set(const String &p_text) override;
|
||||
virtual String clipboard_get() const override;
|
||||
|
||||
virtual void screen_set_keep_on(bool p_enable) override;
|
||||
virtual bool screen_is_kept_on() const override;
|
||||
|
||||
void resize_window(CGSize size);
|
||||
virtual void swap_buffers() override {}
|
||||
};
|
||||
|
|
|
@ -30,492 +30,33 @@
|
|||
|
||||
#import "display_server_ios.h"
|
||||
|
||||
#import "app_delegate.h"
|
||||
#import "device_metrics.h"
|
||||
#import "godot_view.h"
|
||||
#import "ios.h"
|
||||
#import "key_mapping_ios.h"
|
||||
#import "keyboard_input_view.h"
|
||||
#import "os_ios.h"
|
||||
#import "tts_ios.h"
|
||||
#import "view_controller.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/file_access_pack.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <sys/utsname.h>
|
||||
|
||||
#import <GameController/GameController.h>
|
||||
|
||||
static const float kDisplayServerIOSAcceleration = 1.f;
|
||||
|
||||
DisplayServerIOS *DisplayServerIOS::get_singleton() {
|
||||
return (DisplayServerIOS *)DisplayServer::get_singleton();
|
||||
return (DisplayServerIOS *)DisplayServerAppleEmbedded::get_singleton();
|
||||
}
|
||||
|
||||
DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) {
|
||||
KeyMappingIOS::initialize();
|
||||
|
||||
rendering_driver = p_rendering_driver;
|
||||
|
||||
// Init TTS
|
||||
bool tts_enabled = GLOBAL_GET("audio/general/text_to_speech");
|
||||
if (tts_enabled) {
|
||||
initialize_tts();
|
||||
}
|
||||
native_menu = memnew(NativeMenu);
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
rendering_context = nullptr;
|
||||
rendering_device = nullptr;
|
||||
|
||||
CALayer *layer = nullptr;
|
||||
|
||||
union {
|
||||
#ifdef VULKAN_ENABLED
|
||||
RenderingContextDriverVulkanIOS::WindowPlatformData vulkan;
|
||||
#endif
|
||||
#ifdef METAL_ENABLED
|
||||
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wunguarded-availability")
|
||||
// Eliminate "RenderingContextDriverMetal is only available on iOS 14.0 or newer".
|
||||
RenderingContextDriverMetal::WindowPlatformData metal;
|
||||
GODOT_CLANG_WARNING_POP
|
||||
#endif
|
||||
} wpd;
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
if (rendering_driver == "vulkan") {
|
||||
layer = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"vulkan"];
|
||||
if (!layer) {
|
||||
ERR_FAIL_MSG("Failed to create iOS Vulkan rendering layer.");
|
||||
}
|
||||
wpd.vulkan.layer_ptr = (CAMetalLayer *const *)&layer;
|
||||
rendering_context = memnew(RenderingContextDriverVulkanIOS);
|
||||
}
|
||||
#endif
|
||||
#ifdef METAL_ENABLED
|
||||
if (rendering_driver == "metal") {
|
||||
if (@available(iOS 14.0, *)) {
|
||||
layer = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"metal"];
|
||||
wpd.metal.layer = (CAMetalLayer *)layer;
|
||||
rendering_context = memnew(RenderingContextDriverMetal);
|
||||
} else {
|
||||
OS::get_singleton()->alert("Metal is only supported on iOS 14.0 and later.");
|
||||
r_error = ERR_UNAVAILABLE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (rendering_context) {
|
||||
if (rendering_context->initialize() != OK) {
|
||||
memdelete(rendering_context);
|
||||
rendering_context = nullptr;
|
||||
#if defined(GLES3_ENABLED)
|
||||
bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3");
|
||||
if (fallback_to_opengl3 && rendering_driver != "opengl3") {
|
||||
WARN_PRINT("Your device seem not to support MoltenVK or Metal, switching to OpenGL 3.");
|
||||
rendering_driver = "opengl3";
|
||||
OS::get_singleton()->set_current_rendering_method("gl_compatibility");
|
||||
OS::get_singleton()->set_current_rendering_driver_name(rendering_driver);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ERR_PRINT(vformat("Failed to initialize %s context", rendering_driver));
|
||||
r_error = ERR_UNAVAILABLE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rendering_context) {
|
||||
if (rendering_context->window_create(MAIN_WINDOW_ID, &wpd) != OK) {
|
||||
ERR_PRINT(vformat("Failed to create %s window.", rendering_driver));
|
||||
memdelete(rendering_context);
|
||||
rendering_context = nullptr;
|
||||
r_error = ERR_UNAVAILABLE;
|
||||
return;
|
||||
}
|
||||
|
||||
Size2i size = Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_max_scale();
|
||||
rendering_context->window_set_size(MAIN_WINDOW_ID, size.width, size.height);
|
||||
rendering_context->window_set_vsync_mode(MAIN_WINDOW_ID, p_vsync_mode);
|
||||
|
||||
rendering_device = memnew(RenderingDevice);
|
||||
if (rendering_device->initialize(rendering_context, MAIN_WINDOW_ID) != OK) {
|
||||
rendering_device = nullptr;
|
||||
memdelete(rendering_context);
|
||||
rendering_context = nullptr;
|
||||
r_error = ERR_UNAVAILABLE;
|
||||
return;
|
||||
}
|
||||
rendering_device->screen_create(MAIN_WINDOW_ID);
|
||||
|
||||
RendererCompositorRD::make_current();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(GLES3_ENABLED)
|
||||
if (rendering_driver == "opengl3") {
|
||||
CALayer *layer = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"opengl3"];
|
||||
|
||||
if (!layer) {
|
||||
ERR_FAIL_MSG("Failed to create iOS OpenGLES rendering layer.");
|
||||
}
|
||||
|
||||
RasterizerGLES3::make_current(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool keep_screen_on = bool(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
|
||||
screen_set_keep_on(keep_screen_on);
|
||||
|
||||
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
|
||||
|
||||
r_error = OK;
|
||||
DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) :
|
||||
DisplayServerAppleEmbedded(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, p_parent_window, r_error) {
|
||||
}
|
||||
|
||||
DisplayServerIOS::~DisplayServerIOS() {
|
||||
if (native_menu) {
|
||||
memdelete(native_menu);
|
||||
native_menu = nullptr;
|
||||
}
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
if (rendering_device) {
|
||||
rendering_device->screen_free(MAIN_WINDOW_ID);
|
||||
memdelete(rendering_device);
|
||||
rendering_device = nullptr;
|
||||
}
|
||||
|
||||
if (rendering_context) {
|
||||
rendering_context->window_destroy(MAIN_WINDOW_ID);
|
||||
memdelete(rendering_context);
|
||||
rendering_context = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
DisplayServer *DisplayServerIOS::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) {
|
||||
return memnew(DisplayServerIOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, p_parent_window, r_error));
|
||||
}
|
||||
|
||||
Vector<String> DisplayServerIOS::get_rendering_drivers_func() {
|
||||
Vector<String> drivers;
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
drivers.push_back("vulkan");
|
||||
#endif
|
||||
#if defined(METAL_ENABLED)
|
||||
if (@available(ios 14.0, *)) {
|
||||
drivers.push_back("metal");
|
||||
}
|
||||
#endif
|
||||
#if defined(GLES3_ENABLED)
|
||||
drivers.push_back("opengl3");
|
||||
#endif
|
||||
|
||||
return drivers;
|
||||
}
|
||||
|
||||
void DisplayServerIOS::register_ios_driver() {
|
||||
register_create_function("iOS", create_func, get_rendering_drivers_func);
|
||||
}
|
||||
|
||||
// MARK: Events
|
||||
|
||||
void DisplayServerIOS::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
|
||||
window_resize_callback = p_callable;
|
||||
}
|
||||
|
||||
void DisplayServerIOS::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) {
|
||||
window_event_callback = p_callable;
|
||||
}
|
||||
void DisplayServerIOS::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) {
|
||||
input_event_callback = p_callable;
|
||||
}
|
||||
|
||||
void DisplayServerIOS::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) {
|
||||
input_text_callback = p_callable;
|
||||
}
|
||||
|
||||
void DisplayServerIOS::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
void DisplayServerIOS::process_events() {
|
||||
Input::get_singleton()->flush_buffered_events();
|
||||
}
|
||||
|
||||
void DisplayServerIOS::_dispatch_input_events(const Ref<InputEvent> &p_event) {
|
||||
DisplayServerIOS::get_singleton()->send_input_event(p_event);
|
||||
}
|
||||
|
||||
void DisplayServerIOS::send_input_event(const Ref<InputEvent> &p_event) const {
|
||||
_window_callback(input_event_callback, p_event);
|
||||
}
|
||||
|
||||
void DisplayServerIOS::send_input_text(const String &p_text) const {
|
||||
_window_callback(input_text_callback, p_text);
|
||||
}
|
||||
|
||||
void DisplayServerIOS::send_window_event(DisplayServer::WindowEvent p_event) const {
|
||||
_window_callback(window_event_callback, int(p_event));
|
||||
}
|
||||
|
||||
void DisplayServerIOS::_window_callback(const Callable &p_callable, const Variant &p_arg) const {
|
||||
if (p_callable.is_valid()) {
|
||||
p_callable.call(p_arg);
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Input
|
||||
|
||||
// MARK: Touches
|
||||
|
||||
void DisplayServerIOS::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click) {
|
||||
Ref<InputEventScreenTouch> ev;
|
||||
ev.instantiate();
|
||||
|
||||
ev->set_index(p_idx);
|
||||
ev->set_pressed(p_pressed);
|
||||
ev->set_position(Vector2(p_x, p_y));
|
||||
ev->set_double_tap(p_double_click);
|
||||
perform_event(ev);
|
||||
}
|
||||
|
||||
void DisplayServerIOS::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, float p_pressure, Vector2 p_tilt) {
|
||||
Ref<InputEventScreenDrag> ev;
|
||||
ev.instantiate();
|
||||
ev->set_index(p_idx);
|
||||
ev->set_pressure(p_pressure);
|
||||
ev->set_tilt(p_tilt);
|
||||
ev->set_position(Vector2(p_x, p_y));
|
||||
ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y));
|
||||
ev->set_relative_screen_position(ev->get_relative());
|
||||
perform_event(ev);
|
||||
}
|
||||
|
||||
void DisplayServerIOS::perform_event(const Ref<InputEvent> &p_event) {
|
||||
Input::get_singleton()->parse_input_event(p_event);
|
||||
}
|
||||
|
||||
void DisplayServerIOS::touches_canceled(int p_idx) {
|
||||
touch_press(p_idx, -1, -1, false, false);
|
||||
}
|
||||
|
||||
// MARK: Keyboard
|
||||
|
||||
void DisplayServerIOS::key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, NSInteger p_modifier, bool p_pressed, KeyLocation p_location) {
|
||||
Ref<InputEventKey> ev;
|
||||
ev.instantiate();
|
||||
ev->set_echo(false);
|
||||
ev->set_pressed(p_pressed);
|
||||
ev->set_keycode(fix_keycode(p_char, p_key));
|
||||
if (@available(iOS 13.4, *)) {
|
||||
if (p_key != Key::SHIFT) {
|
||||
ev->set_shift_pressed(p_modifier & UIKeyModifierShift);
|
||||
}
|
||||
if (p_key != Key::CTRL) {
|
||||
ev->set_ctrl_pressed(p_modifier & UIKeyModifierControl);
|
||||
}
|
||||
if (p_key != Key::ALT) {
|
||||
ev->set_alt_pressed(p_modifier & UIKeyModifierAlternate);
|
||||
}
|
||||
if (p_key != Key::META) {
|
||||
ev->set_meta_pressed(p_modifier & UIKeyModifierCommand);
|
||||
}
|
||||
}
|
||||
ev->set_key_label(p_unshifted);
|
||||
ev->set_physical_keycode(p_physical);
|
||||
ev->set_unicode(fix_unicode(p_char));
|
||||
ev->set_location(p_location);
|
||||
perform_event(ev);
|
||||
}
|
||||
|
||||
// MARK: Motion
|
||||
|
||||
void DisplayServerIOS::update_gravity(const Vector3 &p_gravity) {
|
||||
Input::get_singleton()->set_gravity(p_gravity);
|
||||
}
|
||||
|
||||
void DisplayServerIOS::update_accelerometer(const Vector3 &p_accelerometer) {
|
||||
Input::get_singleton()->set_accelerometer(p_accelerometer / kDisplayServerIOSAcceleration);
|
||||
}
|
||||
|
||||
void DisplayServerIOS::update_magnetometer(const Vector3 &p_magnetometer) {
|
||||
Input::get_singleton()->set_magnetometer(p_magnetometer);
|
||||
}
|
||||
|
||||
void DisplayServerIOS::update_gyroscope(const Vector3 &p_gyroscope) {
|
||||
Input::get_singleton()->set_gyroscope(p_gyroscope);
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
bool DisplayServerIOS::has_feature(Feature p_feature) const {
|
||||
switch (p_feature) {
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
case FEATURE_GLOBAL_MENU: {
|
||||
return (native_menu && native_menu->has_feature(NativeMenu::FEATURE_GLOBAL_MENU));
|
||||
} break;
|
||||
#endif
|
||||
// case FEATURE_CURSOR_SHAPE:
|
||||
// case FEATURE_CUSTOM_CURSOR_SHAPE:
|
||||
// case FEATURE_HIDPI:
|
||||
// case FEATURE_ICON:
|
||||
// case FEATURE_IME:
|
||||
// case FEATURE_MOUSE:
|
||||
// case FEATURE_MOUSE_WARP:
|
||||
// case FEATURE_NATIVE_DIALOG:
|
||||
// case FEATURE_NATIVE_DIALOG_INPUT:
|
||||
// case FEATURE_NATIVE_DIALOG_FILE:
|
||||
// case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
|
||||
// case FEATURE_NATIVE_DIALOG_FILE_MIME:
|
||||
// case FEATURE_NATIVE_ICON:
|
||||
// case FEATURE_WINDOW_TRANSPARENCY:
|
||||
case FEATURE_CLIPBOARD:
|
||||
case FEATURE_KEEP_SCREEN_ON:
|
||||
case FEATURE_ORIENTATION:
|
||||
case FEATURE_TOUCHSCREEN:
|
||||
case FEATURE_VIRTUAL_KEYBOARD:
|
||||
case FEATURE_TEXT_TO_SPEECH:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String DisplayServerIOS::get_name() const {
|
||||
return "iOS";
|
||||
}
|
||||
void DisplayServerIOS::initialize_tts() const {
|
||||
const_cast<DisplayServerIOS *>(this)->tts = [[TTS_IOS alloc] init];
|
||||
}
|
||||
|
||||
bool DisplayServerIOS::tts_is_speaking() const {
|
||||
if (unlikely(!tts)) {
|
||||
initialize_tts();
|
||||
}
|
||||
ERR_FAIL_NULL_V(tts, false);
|
||||
return [tts isSpeaking];
|
||||
}
|
||||
|
||||
bool DisplayServerIOS::tts_is_paused() const {
|
||||
if (unlikely(!tts)) {
|
||||
initialize_tts();
|
||||
}
|
||||
ERR_FAIL_NULL_V(tts, false);
|
||||
return [tts isPaused];
|
||||
}
|
||||
|
||||
TypedArray<Dictionary> DisplayServerIOS::tts_get_voices() const {
|
||||
if (unlikely(!tts)) {
|
||||
initialize_tts();
|
||||
}
|
||||
ERR_FAIL_NULL_V(tts, TypedArray<Dictionary>());
|
||||
return [tts getVoices];
|
||||
}
|
||||
|
||||
void DisplayServerIOS::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
|
||||
if (unlikely(!tts)) {
|
||||
initialize_tts();
|
||||
}
|
||||
ERR_FAIL_NULL(tts);
|
||||
[tts speak:p_text voice:p_voice volume:p_volume pitch:p_pitch rate:p_rate utterance_id:p_utterance_id interrupt:p_interrupt];
|
||||
}
|
||||
|
||||
void DisplayServerIOS::tts_pause() {
|
||||
if (unlikely(!tts)) {
|
||||
initialize_tts();
|
||||
}
|
||||
ERR_FAIL_NULL(tts);
|
||||
[tts pauseSpeaking];
|
||||
}
|
||||
|
||||
void DisplayServerIOS::tts_resume() {
|
||||
if (unlikely(!tts)) {
|
||||
initialize_tts();
|
||||
}
|
||||
ERR_FAIL_NULL(tts);
|
||||
[tts resumeSpeaking];
|
||||
}
|
||||
|
||||
void DisplayServerIOS::tts_stop() {
|
||||
if (unlikely(!tts)) {
|
||||
initialize_tts();
|
||||
}
|
||||
ERR_FAIL_NULL(tts);
|
||||
[tts stopSpeaking];
|
||||
}
|
||||
|
||||
bool DisplayServerIOS::is_dark_mode_supported() const {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DisplayServerIOS::is_dark_mode() const {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
return [UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayServerIOS::set_system_theme_change_callback(const Callable &p_callable) {
|
||||
system_theme_changed = p_callable;
|
||||
}
|
||||
|
||||
void DisplayServerIOS::emit_system_theme_changed() {
|
||||
if (system_theme_changed.is_valid()) {
|
||||
Variant ret;
|
||||
Callable::CallError ce;
|
||||
system_theme_changed.callp(nullptr, 0, ret, ce);
|
||||
if (ce.error != Callable::CallError::CALL_OK) {
|
||||
ERR_PRINT(vformat("Failed to execute system theme changed callback: %s.", Variant::get_callable_error_text(system_theme_changed, nullptr, 0, ce)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rect2i DisplayServerIOS::get_display_safe_area() const {
|
||||
UIEdgeInsets insets = UIEdgeInsetsZero;
|
||||
UIView *view = AppDelegate.viewController.godotView;
|
||||
if ([view respondsToSelector:@selector(safeAreaInsets)]) {
|
||||
insets = [view safeAreaInsets];
|
||||
}
|
||||
float scale = screen_get_scale();
|
||||
Size2i insets_position = Size2i(insets.left, insets.top) * scale;
|
||||
Size2i insets_size = Size2i(insets.left + insets.right, insets.top + insets.bottom) * scale;
|
||||
return Rect2i(screen_get_position() + insets_position, screen_get_size() - insets_size);
|
||||
}
|
||||
|
||||
int DisplayServerIOS::get_screen_count() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DisplayServerIOS::get_primary_screen() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Point2i DisplayServerIOS::screen_get_position(int p_screen) const {
|
||||
return Size2i();
|
||||
}
|
||||
|
||||
Size2i DisplayServerIOS::screen_get_size(int p_screen) const {
|
||||
CALayer *layer = AppDelegate.viewController.godotView.renderingLayer;
|
||||
|
||||
if (!layer) {
|
||||
return Size2i();
|
||||
}
|
||||
|
||||
return Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_scale(p_screen);
|
||||
}
|
||||
|
||||
Rect2i DisplayServerIOS::screen_get_usable_rect(int p_screen) const {
|
||||
return Rect2i(screen_get_position(p_screen), screen_get_size(p_screen));
|
||||
}
|
||||
|
||||
int DisplayServerIOS::screen_get_dpi(int p_screen) const {
|
||||
struct utsname systemInfo;
|
||||
|
@ -523,7 +64,7 @@ int DisplayServerIOS::screen_get_dpi(int p_screen) const {
|
|||
|
||||
NSString *string = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
|
||||
|
||||
NSDictionary *iOSModelToDPI = [GodotDeviceMetrics dpiList];
|
||||
NSDictionary *iOSModelToDPI = [GDTDeviceMetrics dpiList];
|
||||
|
||||
for (NSArray *keyArray in iOSModelToDPI) {
|
||||
if ([keyArray containsObject:string]) {
|
||||
|
@ -565,283 +106,3 @@ float DisplayServerIOS::screen_get_refresh_rate(int p_screen) const {
|
|||
float DisplayServerIOS::screen_get_scale(int p_screen) const {
|
||||
return [UIScreen mainScreen].scale;
|
||||
}
|
||||
|
||||
Vector<DisplayServer::WindowID> DisplayServerIOS::get_window_list() const {
|
||||
Vector<DisplayServer::WindowID> list;
|
||||
list.push_back(MAIN_WINDOW_ID);
|
||||
return list;
|
||||
}
|
||||
|
||||
DisplayServer::WindowID DisplayServerIOS::get_window_at_screen_position(const Point2i &p_position) const {
|
||||
return MAIN_WINDOW_ID;
|
||||
}
|
||||
|
||||
int64_t DisplayServerIOS::window_get_native_handle(HandleType p_handle_type, WindowID p_window) const {
|
||||
ERR_FAIL_COND_V(p_window != MAIN_WINDOW_ID, 0);
|
||||
switch (p_handle_type) {
|
||||
case DISPLAY_HANDLE: {
|
||||
return 0; // Not supported.
|
||||
}
|
||||
case WINDOW_HANDLE: {
|
||||
return (int64_t)AppDelegate.viewController;
|
||||
}
|
||||
case WINDOW_VIEW: {
|
||||
return (int64_t)AppDelegate.viewController.godotView;
|
||||
}
|
||||
default: {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayServerIOS::window_attach_instance_id(ObjectID p_instance, WindowID p_window) {
|
||||
window_attached_instance_id = p_instance;
|
||||
}
|
||||
|
||||
ObjectID DisplayServerIOS::window_get_attached_instance_id(WindowID p_window) const {
|
||||
return window_attached_instance_id;
|
||||
}
|
||||
|
||||
void DisplayServerIOS::window_set_title(const String &p_title, WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
int DisplayServerIOS::window_get_current_screen(WindowID p_window) const {
|
||||
return SCREEN_OF_MAIN_WINDOW;
|
||||
}
|
||||
|
||||
void DisplayServerIOS::window_set_current_screen(int p_screen, WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
Point2i DisplayServerIOS::window_get_position(WindowID p_window) const {
|
||||
return Point2i();
|
||||
}
|
||||
|
||||
Point2i DisplayServerIOS::window_get_position_with_decorations(WindowID p_window) const {
|
||||
return Point2i();
|
||||
}
|
||||
|
||||
void DisplayServerIOS::window_set_position(const Point2i &p_position, WindowID p_window) {
|
||||
// Probably not supported for single window iOS app
|
||||
}
|
||||
|
||||
void DisplayServerIOS::window_set_transient(WindowID p_window, WindowID p_parent) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
void DisplayServerIOS::window_set_max_size(const Size2i p_size, WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
Size2i DisplayServerIOS::window_get_max_size(WindowID p_window) const {
|
||||
return Size2i();
|
||||
}
|
||||
|
||||
void DisplayServerIOS::window_set_min_size(const Size2i p_size, WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
Size2i DisplayServerIOS::window_get_min_size(WindowID p_window) const {
|
||||
return Size2i();
|
||||
}
|
||||
|
||||
void DisplayServerIOS::window_set_size(const Size2i p_size, WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
Size2i DisplayServerIOS::window_get_size(WindowID p_window) const {
|
||||
CGRect screenBounds = [UIScreen mainScreen].bounds;
|
||||
return Size2i(screenBounds.size.width, screenBounds.size.height) * screen_get_max_scale();
|
||||
}
|
||||
|
||||
Size2i DisplayServerIOS::window_get_size_with_decorations(WindowID p_window) const {
|
||||
return window_get_size(p_window);
|
||||
}
|
||||
|
||||
void DisplayServerIOS::window_set_mode(WindowMode p_mode, WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
DisplayServer::WindowMode DisplayServerIOS::window_get_mode(WindowID p_window) const {
|
||||
return WindowMode::WINDOW_MODE_FULLSCREEN;
|
||||
}
|
||||
|
||||
bool DisplayServerIOS::window_is_maximize_allowed(WindowID p_window) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void DisplayServerIOS::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
bool DisplayServerIOS::window_get_flag(WindowFlags p_flag, WindowID p_window) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void DisplayServerIOS::window_request_attention(WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
void DisplayServerIOS::window_move_to_foreground(WindowID p_window) {
|
||||
// Probably not supported for iOS
|
||||
}
|
||||
|
||||
bool DisplayServerIOS::window_is_focused(WindowID p_window) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
float DisplayServerIOS::screen_get_max_scale() const {
|
||||
return screen_get_scale(SCREEN_OF_MAIN_WINDOW);
|
||||
}
|
||||
|
||||
void DisplayServerIOS::screen_set_orientation(DisplayServer::ScreenOrientation p_orientation, int p_screen) {
|
||||
screen_orientation = p_orientation;
|
||||
if (@available(iOS 16.0, *)) {
|
||||
[AppDelegate.viewController setNeedsUpdateOfSupportedInterfaceOrientations];
|
||||
} else {
|
||||
[UIViewController attemptRotationToDeviceOrientation];
|
||||
}
|
||||
}
|
||||
|
||||
DisplayServer::ScreenOrientation DisplayServerIOS::screen_get_orientation(int p_screen) const {
|
||||
return screen_orientation;
|
||||
}
|
||||
|
||||
bool DisplayServerIOS::window_can_draw(WindowID p_window) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DisplayServerIOS::can_any_window_draw() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DisplayServerIOS::is_touchscreen_available() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int _convert_utf32_offset_to_utf16(const String &p_existing_text, int p_pos) {
|
||||
int limit = p_pos;
|
||||
for (int i = 0; i < MIN(p_existing_text.length(), p_pos); i++) {
|
||||
if (p_existing_text[i] > 0xffff) {
|
||||
limit++;
|
||||
}
|
||||
}
|
||||
return limit;
|
||||
}
|
||||
|
||||
void DisplayServerIOS::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_length, int p_cursor_start, int p_cursor_end) {
|
||||
NSString *existingString = [[NSString alloc] initWithUTF8String:p_existing_text.utf8().get_data()];
|
||||
|
||||
AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault;
|
||||
AppDelegate.viewController.keyboardView.textContentType = nil;
|
||||
switch (p_type) {
|
||||
case KEYBOARD_TYPE_DEFAULT: {
|
||||
AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault;
|
||||
} break;
|
||||
case KEYBOARD_TYPE_MULTILINE: {
|
||||
AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault;
|
||||
} break;
|
||||
case KEYBOARD_TYPE_NUMBER: {
|
||||
AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeNumberPad;
|
||||
} break;
|
||||
case KEYBOARD_TYPE_NUMBER_DECIMAL: {
|
||||
AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeDecimalPad;
|
||||
} break;
|
||||
case KEYBOARD_TYPE_PHONE: {
|
||||
AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypePhonePad;
|
||||
AppDelegate.viewController.keyboardView.textContentType = UITextContentTypeTelephoneNumber;
|
||||
} break;
|
||||
case KEYBOARD_TYPE_EMAIL_ADDRESS: {
|
||||
AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeEmailAddress;
|
||||
AppDelegate.viewController.keyboardView.textContentType = UITextContentTypeEmailAddress;
|
||||
} break;
|
||||
case KEYBOARD_TYPE_PASSWORD: {
|
||||
AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault;
|
||||
AppDelegate.viewController.keyboardView.textContentType = UITextContentTypePassword;
|
||||
} break;
|
||||
case KEYBOARD_TYPE_URL: {
|
||||
AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeWebSearch;
|
||||
AppDelegate.viewController.keyboardView.textContentType = UITextContentTypeURL;
|
||||
} break;
|
||||
}
|
||||
|
||||
[AppDelegate.viewController.keyboardView
|
||||
becomeFirstResponderWithString:existingString
|
||||
cursorStart:_convert_utf32_offset_to_utf16(p_existing_text, p_cursor_start)
|
||||
cursorEnd:_convert_utf32_offset_to_utf16(p_existing_text, p_cursor_end)];
|
||||
}
|
||||
|
||||
bool DisplayServerIOS::is_keyboard_active() const {
|
||||
return [AppDelegate.viewController.keyboardView isFirstResponder];
|
||||
}
|
||||
|
||||
void DisplayServerIOS::virtual_keyboard_hide() {
|
||||
[AppDelegate.viewController.keyboardView resignFirstResponder];
|
||||
}
|
||||
|
||||
void DisplayServerIOS::virtual_keyboard_set_height(int height) {
|
||||
virtual_keyboard_height = height * screen_get_max_scale();
|
||||
}
|
||||
|
||||
int DisplayServerIOS::virtual_keyboard_get_height() const {
|
||||
return virtual_keyboard_height;
|
||||
}
|
||||
|
||||
bool DisplayServerIOS::has_hardware_keyboard() const {
|
||||
if (@available(iOS 14.0, *)) {
|
||||
return [GCKeyboard coalescedKeyboard];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayServerIOS::clipboard_set(const String &p_text) {
|
||||
[UIPasteboard generalPasteboard].string = [NSString stringWithUTF8String:p_text.utf8().get_data()];
|
||||
}
|
||||
|
||||
String DisplayServerIOS::clipboard_get() const {
|
||||
NSString *text = [UIPasteboard generalPasteboard].string;
|
||||
|
||||
return String::utf8([text UTF8String]);
|
||||
}
|
||||
|
||||
void DisplayServerIOS::screen_set_keep_on(bool p_enable) {
|
||||
[UIApplication sharedApplication].idleTimerDisabled = p_enable;
|
||||
}
|
||||
|
||||
bool DisplayServerIOS::screen_is_kept_on() const {
|
||||
return [UIApplication sharedApplication].idleTimerDisabled;
|
||||
}
|
||||
|
||||
void DisplayServerIOS::resize_window(CGSize viewSize) {
|
||||
Size2i size = Size2i(viewSize.width, viewSize.height) * screen_get_max_scale();
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
if (rendering_context) {
|
||||
rendering_context->window_set_size(MAIN_WINDOW_ID, size.x, size.y);
|
||||
}
|
||||
#endif
|
||||
|
||||
Variant resize_rect = Rect2i(Point2i(), size);
|
||||
_window_callback(window_resize_callback, resize_rect);
|
||||
}
|
||||
|
||||
void DisplayServerIOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
|
||||
_THREAD_SAFE_METHOD_
|
||||
#if defined(RD_ENABLED)
|
||||
if (rendering_context) {
|
||||
rendering_context->window_set_vsync_mode(p_window, p_vsync_mode);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
DisplayServer::VSyncMode DisplayServerIOS::window_get_vsync_mode(WindowID p_window) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
#if defined(RD_ENABLED)
|
||||
if (rendering_context) {
|
||||
return rendering_context->window_get_vsync_mode(p_window);
|
||||
}
|
||||
#endif
|
||||
return DisplayServer::VSYNC_ENABLED;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="EditorExportPlatformIOS" inherits="EditorExportPlatform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||
<class name="EditorExportPlatformIOS" inherits="EditorExportPlatformAppleEmbedded" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||
<brief_description>
|
||||
Exporter for iOS.
|
||||
</brief_description>
|
||||
|
@ -24,10 +24,10 @@
|
|||
Unique application identifier in a reverse-DNS format, can only contain alphanumeric characters ([code]A-Z[/code], [code]a-z[/code], and [code]0-9[/code]), hyphens ([code]-[/code]), and periods ([code].[/code]).
|
||||
</member>
|
||||
<member name="application/code_sign_identity_debug" type="String" setter="" getter="">
|
||||
The "Full Name", "Common Name" or SHA-1 hash of the signing identity used for debug export.
|
||||
The "Full Name", "Common Name", or SHA-1 hash of the signing identity used for debug export.
|
||||
</member>
|
||||
<member name="application/code_sign_identity_release" type="String" setter="" getter="">
|
||||
The "Full Name", "Common Name" or SHA-1 hash of the signing identity used for release export.
|
||||
The "Full Name", "Common Name", or SHA-1 hash of the signing identity used for release export.
|
||||
</member>
|
||||
<member name="application/delete_old_export_files_unconditionally" type="bool" setter="" getter="">
|
||||
If [code]true[/code], existing "project name" and "project name.xcodeproj" in the export destination directory will be unconditionally deleted during export.
|
||||
|
@ -48,20 +48,20 @@
|
|||
Minimum version of iOS required for this application to run in the [code]major.minor.patch[/code] or [code]major.minor[/code] format, can only contain numeric characters ([code]0-9[/code]) and periods ([code].[/code]).
|
||||
</member>
|
||||
<member name="application/provisioning_profile_specifier_debug" type="String" setter="" getter="">
|
||||
Name of the provisioning profile. Sets XCode PROVISIONING_PROFILE_SPECIFIER for debug. [url=https://developer.apple.com/documentation/xcode/build-settings-reference#Provisioning-Profile]Used for manual provisioning[/url].
|
||||
Can be overridden with the environment variable [code]GODOT_IOS_PROFILE_SPECIFIER_DEBUG[/code].
|
||||
Name of the provisioning profile. Sets Xcode PROVISIONING_PROFILE_SPECIFIER for debug. [url=https://developer.apple.com/documentation/xcode/build-settings-reference#Provisioning-Profile]Used for manual provisioning[/url].
|
||||
Can be overridden with the environment variable [code]GODOT_APPLE_PLATFORM_PROFILE_SPECIFIER_DEBUG[/code].
|
||||
</member>
|
||||
<member name="application/provisioning_profile_specifier_release" type="String" setter="" getter="">
|
||||
Name of the provisioning profile. Sets XCode PROVISIONING_PROFILE_SPECIFIER for release. [url=https://developer.apple.com/documentation/xcode/build-settings-reference#Provisioning-Profile]Used for manual provisioning[/url].
|
||||
Can be overridden with the environment variable [code]GODOT_IOS_PROFILE_SPECIFIER_RELEASE[/code].
|
||||
Name of the provisioning profile. Sets Xcode PROVISIONING_PROFILE_SPECIFIER for release. [url=https://developer.apple.com/documentation/xcode/build-settings-reference#Provisioning-Profile]Used for manual provisioning[/url].
|
||||
Can be overridden with the environment variable [code]GODOT_APPLE_PLATFORM_PROFILE_SPECIFIER_RELEASE[/code].
|
||||
</member>
|
||||
<member name="application/provisioning_profile_uuid_debug" type="String" setter="" getter="">
|
||||
UUID of the provisioning profile. If left empty, Xcode will download or create a provisioning profile automatically. See [url=https://developer.apple.com/help/account/manage-profiles/edit-download-or-delete-profiles]Edit, download, or delete provisioning profiles[/url].
|
||||
Can be overridden with the environment variable [code]GODOT_IOS_PROVISIONING_PROFILE_UUID_DEBUG[/code].
|
||||
Can be overridden with the environment variable [code]GODOT_APPLE_PLATFORM_PROVISIONING_PROFILE_UUID_DEBUG[/code].
|
||||
</member>
|
||||
<member name="application/provisioning_profile_uuid_release" type="String" setter="" getter="">
|
||||
UUID of the provisioning profile. If left empty, Xcode will download or create a provisioning profile automatically. See [url=https://developer.apple.com/help/account/manage-profiles/edit-download-or-delete-profiles]Edit, download, or delete provisioning profiles[/url].
|
||||
Can be overridden with the environment variable [code]GODOT_IOS_PROVISIONING_PROFILE_UUID_RELEASE[/code].
|
||||
Can be overridden with the environment variable [code]GODOT_APPLE_PLATFORM_PROVISIONING_PROFILE_UUID_RELEASE[/code].
|
||||
</member>
|
||||
<member name="application/short_version" type="String" setter="" getter="">
|
||||
Application version visible to the user, can only contain numeric characters ([code]0-9[/code]) and periods ([code].[/code]). Falls back to [member ProjectSettings.application/config/version] if left empty.
|
||||
|
@ -86,7 +86,7 @@
|
|||
</member>
|
||||
<member name="capabilities/performance_a12" type="bool" setter="" getter="">
|
||||
Requires the graphics performance and features of the A12 Bionic and later chips (devices supporting all Vulkan renderer features).
|
||||
Enabling this option limits supported devices to: iPhone XS, iPhone XR, iPad Mini (5th gen.), iPad Air (3rd gen.), iPad (8th gen) and newer.
|
||||
Enabling this option limits supported devices to: iPhone XS, iPhone XR, iPad Mini (5th gen.), iPad Air (3rd gen.), iPad (8th gen), and newer.
|
||||
</member>
|
||||
<member name="capabilities/performance_gaming_tier" type="bool" setter="" getter="">
|
||||
Requires the graphics performance and features of the A17 Pro and later chips.
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -30,268 +30,31 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "godot_plugin_config.h"
|
||||
#include "editor/export/editor_export_platform_apple_embedded.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/io/image_loader.h"
|
||||
#include "core/io/marshalls.h"
|
||||
#include "core/io/resource_saver.h"
|
||||
#include "core/io/zip_io.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "editor/editor_settings.h"
|
||||
#include "editor/export/editor_export_platform.h"
|
||||
#include "main/splash.gen.h"
|
||||
#include "scene/resources/image_texture.h"
|
||||
class EditorExportPlatformIOS : public EditorExportPlatformAppleEmbedded {
|
||||
GDCLASS(EditorExportPlatformIOS, EditorExportPlatformAppleEmbedded);
|
||||
|
||||
#include <sys/stat.h>
|
||||
virtual String get_platform_name() const override { return "ios"; }
|
||||
|
||||
// Optional environment variables for defining confidential information. If any
|
||||
// of these is set, they will override the values set in the credentials file.
|
||||
const String ENV_IOS_PROFILE_UUID_DEBUG = "GODOT_IOS_PROVISIONING_PROFILE_UUID_DEBUG";
|
||||
const String ENV_IOS_PROFILE_UUID_RELEASE = "GODOT_IOS_PROVISIONING_PROFILE_UUID_RELEASE";
|
||||
const String ENV_IOS_PROFILE_SPECIFIER_DEBUG = "GODOT_IOS_PROFILE_SPECIFIER_DEBUG";
|
||||
const String ENV_IOS_PROFILE_SPECIFIER_RELEASE = "GODOT_IOS_PROFILE_SPECIFIER_RELEASE";
|
||||
virtual Vector<IconInfo> get_icon_infos() const override;
|
||||
|
||||
class EditorExportPlatformIOS : public EditorExportPlatform {
|
||||
GDCLASS(EditorExportPlatformIOS, EditorExportPlatform);
|
||||
|
||||
Ref<ImageTexture> logo;
|
||||
Ref<ImageTexture> run_icon;
|
||||
|
||||
// Plugins
|
||||
mutable SafeFlag plugins_changed;
|
||||
SafeFlag devices_changed;
|
||||
|
||||
struct Device {
|
||||
String id;
|
||||
String name;
|
||||
bool wifi = false;
|
||||
bool use_ios_deploy = false;
|
||||
};
|
||||
|
||||
Vector<Device> devices;
|
||||
Mutex device_lock;
|
||||
|
||||
Mutex plugins_lock;
|
||||
mutable Vector<PluginConfigIOS> plugins;
|
||||
#ifdef MACOS_ENABLED
|
||||
Thread check_for_changes_thread;
|
||||
SafeFlag quit_request;
|
||||
SafeFlag has_runnable_preset;
|
||||
|
||||
static bool _check_xcode_install();
|
||||
static void _check_for_changes_poll_thread(void *ud);
|
||||
void _update_preset_status();
|
||||
#endif
|
||||
|
||||
typedef Error (*FileHandler)(String p_file, void *p_userdata);
|
||||
static Error _walk_dir_recursive(Ref<DirAccess> &p_da, FileHandler p_handler, void *p_userdata);
|
||||
static Error _codesign(String p_file, void *p_userdata);
|
||||
void _blend_and_rotate(Ref<Image> &p_dst, Ref<Image> &p_src, bool p_rot);
|
||||
|
||||
struct IOSConfigData {
|
||||
String pkg_name;
|
||||
String binary_name;
|
||||
String plist_content;
|
||||
String architectures;
|
||||
String linker_flags;
|
||||
String cpp_code;
|
||||
String modules_buildfile;
|
||||
String modules_fileref;
|
||||
String modules_buildphase;
|
||||
String modules_buildgrp;
|
||||
Vector<String> capabilities;
|
||||
bool use_swift_runtime;
|
||||
};
|
||||
struct ExportArchitecture {
|
||||
String name;
|
||||
bool is_default = false;
|
||||
|
||||
ExportArchitecture() {}
|
||||
|
||||
ExportArchitecture(String p_name, bool p_is_default) {
|
||||
name = p_name;
|
||||
is_default = p_is_default;
|
||||
}
|
||||
};
|
||||
|
||||
struct IOSExportAsset {
|
||||
String exported_path;
|
||||
bool is_framework = false; // framework is anything linked to the binary, otherwise it's a resource
|
||||
bool should_embed = false;
|
||||
};
|
||||
|
||||
String _get_additional_plist_content();
|
||||
String _get_linker_flags();
|
||||
String _get_cpp_code();
|
||||
void _fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug);
|
||||
Error _export_loading_screen_file(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir);
|
||||
Error _export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir);
|
||||
|
||||
Vector<ExportArchitecture> _get_supported_architectures() const;
|
||||
Vector<String> _get_preset_architectures(const Ref<EditorExportPreset> &p_preset) const;
|
||||
|
||||
void _check_xcframework_content(const String &p_path, int &r_total_libs, int &r_static_libs, int &r_dylibs, int &r_frameworks) const;
|
||||
Error _convert_to_framework(const String &p_source, const String &p_destination, const String &p_id) const;
|
||||
|
||||
void _add_assets_to_project(const String &p_out_dir, const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets);
|
||||
Error _export_additional_assets(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets);
|
||||
Error _copy_asset(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets);
|
||||
Error _export_additional_assets(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets);
|
||||
Error _export_ios_plugins(const Ref<EditorExportPreset> &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector<IOSExportAsset> &r_exported_assets, bool p_debug);
|
||||
|
||||
Error _export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags, bool p_oneclick);
|
||||
|
||||
bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const;
|
||||
|
||||
protected:
|
||||
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
|
||||
virtual void get_export_options(List<ExportOption> *r_options) const override;
|
||||
virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const override;
|
||||
virtual String get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const override;
|
||||
virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const override;
|
||||
|
||||
void _notification(int p_what);
|
||||
virtual Error _export_loading_screen_file(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) override;
|
||||
virtual Error _export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir) override;
|
||||
virtual HashMap<String, Variant> get_custom_project_settings(const Ref<EditorExportPreset> &p_preset) const override;
|
||||
|
||||
public:
|
||||
virtual String get_name() const override { return "iOS"; }
|
||||
virtual String get_os_name() const override { return "iOS"; }
|
||||
virtual Ref<Texture2D> get_logo() const override { return logo; }
|
||||
virtual Ref<Texture2D> get_run_icon() const override { return run_icon; }
|
||||
|
||||
virtual int get_options_count() const override;
|
||||
virtual String get_options_tooltip() const override;
|
||||
virtual Ref<ImageTexture> get_option_icon(int p_index) const override;
|
||||
virtual String get_option_label(int p_index) const override;
|
||||
virtual String get_option_tooltip(int p_index) const override;
|
||||
virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, BitField<EditorExportPlatform::DebugFlags> p_debug_flags) override;
|
||||
|
||||
virtual bool poll_export() override {
|
||||
bool dc = devices_changed.is_set();
|
||||
if (dc) {
|
||||
// don't clear unless we're reporting true, to avoid race
|
||||
devices_changed.clear();
|
||||
}
|
||||
return dc;
|
||||
}
|
||||
|
||||
virtual bool should_update_export_options() override {
|
||||
bool export_options_changed = plugins_changed.is_set();
|
||||
if (export_options_changed) {
|
||||
// don't clear unless we're reporting true, to avoid race
|
||||
plugins_changed.clear();
|
||||
}
|
||||
return export_options_changed;
|
||||
}
|
||||
|
||||
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override {
|
||||
List<String> list;
|
||||
if (p_preset.is_valid()) {
|
||||
bool project_only = p_preset->get("application/export_project_only");
|
||||
if (project_only) {
|
||||
list.push_back("xcodeproj");
|
||||
} else {
|
||||
list.push_back("ipa");
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
virtual HashMap<String, Variant> get_custom_project_settings(const Ref<EditorExportPreset> &p_preset) const override;
|
||||
|
||||
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags = 0) override;
|
||||
|
||||
virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const override;
|
||||
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
|
||||
|
||||
virtual void get_platform_features(List<String> *r_features) const override {
|
||||
r_features->push_back("mobile");
|
||||
EditorExportPlatformAppleEmbedded::get_platform_features(r_features);
|
||||
r_features->push_back("ios");
|
||||
}
|
||||
|
||||
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) override {
|
||||
}
|
||||
|
||||
EditorExportPlatformIOS();
|
||||
~EditorExportPlatformIOS();
|
||||
|
||||
/// List the gdip files in the directory specified by the p_path parameter.
|
||||
static Vector<String> list_plugin_config_files(const String &p_path, bool p_check_directories) {
|
||||
Vector<String> dir_files;
|
||||
Ref<DirAccess> da = DirAccess::open(p_path);
|
||||
if (da.is_valid()) {
|
||||
da->list_dir_begin();
|
||||
while (true) {
|
||||
String file = da->get_next();
|
||||
if (file.is_empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (file == "." || file == "..") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (da->current_is_hidden()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (da->current_is_dir()) {
|
||||
if (p_check_directories) {
|
||||
Vector<String> directory_files = list_plugin_config_files(p_path.path_join(file), false);
|
||||
for (int i = 0; i < directory_files.size(); ++i) {
|
||||
dir_files.push_back(file.path_join(directory_files[i]));
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (file.ends_with(PluginConfigIOS::PLUGIN_CONFIG_EXT)) {
|
||||
dir_files.push_back(file);
|
||||
}
|
||||
}
|
||||
da->list_dir_end();
|
||||
}
|
||||
|
||||
return dir_files;
|
||||
}
|
||||
|
||||
static Vector<PluginConfigIOS> get_plugins() {
|
||||
Vector<PluginConfigIOS> loaded_plugins;
|
||||
|
||||
String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().path_join("ios/plugins");
|
||||
|
||||
if (DirAccess::exists(plugins_dir)) {
|
||||
Vector<String> plugins_filenames = list_plugin_config_files(plugins_dir, true);
|
||||
|
||||
if (!plugins_filenames.is_empty()) {
|
||||
Ref<ConfigFile> config_file = memnew(ConfigFile);
|
||||
for (int i = 0; i < plugins_filenames.size(); i++) {
|
||||
PluginConfigIOS config = PluginConfigIOS::load_plugin_config(config_file, plugins_dir.path_join(plugins_filenames[i]));
|
||||
if (config.valid_config) {
|
||||
loaded_plugins.push_back(config);
|
||||
} else {
|
||||
print_error("Invalid plugin config file " + plugins_filenames[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loaded_plugins;
|
||||
}
|
||||
|
||||
static Vector<PluginConfigIOS> get_enabled_plugins(const Ref<EditorExportPreset> &p_presets) {
|
||||
Vector<PluginConfigIOS> enabled_plugins;
|
||||
Vector<PluginConfigIOS> all_plugins = get_plugins();
|
||||
for (int i = 0; i < all_plugins.size(); i++) {
|
||||
PluginConfigIOS plugin = all_plugins[i];
|
||||
bool enabled = p_presets->get("plugins/" + plugin.name);
|
||||
if (enabled) {
|
||||
enabled_plugins.push_back(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
return enabled_plugins;
|
||||
}
|
||||
};
|
||||
|
|
37
platform/ios/godot_view_ios.h
Normal file
37
platform/ios/godot_view_ios.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/**************************************************************************/
|
||||
/* godot_view_ios.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "drivers/apple_embedded/godot_view_apple_embedded.h"
|
||||
|
||||
@interface GDTViewIOS : GDTView
|
||||
|
||||
@end
|
87
platform/ios/godot_view_ios.mm
Normal file
87
platform/ios/godot_view_ios.mm
Normal file
|
@ -0,0 +1,87 @@
|
|||
/**************************************************************************/
|
||||
/* godot_view_ios.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "godot_view_ios.h"
|
||||
|
||||
#import "display_layer_ios.h"
|
||||
|
||||
#include "core/error/error_macros.h"
|
||||
|
||||
@interface GDTViewIOS ()
|
||||
|
||||
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wobjc-property-synthesis")
|
||||
@property(strong, nonatomic) CALayer<GDTDisplayLayer> *renderingLayer;
|
||||
GODOT_CLANG_WARNING_POP
|
||||
|
||||
@end
|
||||
|
||||
@implementation GDTViewIOS
|
||||
|
||||
- (CALayer<GDTDisplayLayer> *)initializeRenderingForDriver:(NSString *)driverName {
|
||||
if (self.renderingLayer) {
|
||||
return self.renderingLayer;
|
||||
}
|
||||
|
||||
CALayer<GDTDisplayLayer> *layer;
|
||||
|
||||
if ([driverName isEqualToString:@"vulkan"] || [driverName isEqualToString:@"metal"]) {
|
||||
#if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR
|
||||
if (@available(iOS 13, *)) {
|
||||
layer = [GDTMetalLayer layer];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
#else
|
||||
layer = [GDTMetalLayer layer];
|
||||
#endif
|
||||
} else if ([driverName isEqualToString:@"opengl3"]) {
|
||||
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wdeprecated-declarations") // OpenGL is deprecated in iOS 12.0.
|
||||
layer = [GDTOpenGLLayer layer];
|
||||
GODOT_CLANG_WARNING_POP
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
|
||||
layer.frame = self.bounds;
|
||||
layer.contentsScale = self.contentScaleFactor;
|
||||
|
||||
[self.layer addSublayer:layer];
|
||||
self.renderingLayer = layer;
|
||||
|
||||
[layer initializeDisplayLayer];
|
||||
|
||||
return self.renderingLayer;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
GDTView *GDTViewCreate() {
|
||||
return [GDTViewIOS new];
|
||||
}
|
|
@ -30,30 +30,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
#include "drivers/apple_embedded/apple_embedded.h"
|
||||
|
||||
#import <CoreHaptics/CoreHaptics.h>
|
||||
|
||||
class iOS : public Object {
|
||||
GDCLASS(iOS, Object);
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
private:
|
||||
CHHapticEngine *haptic_engine API_AVAILABLE(ios(13)) = nullptr;
|
||||
|
||||
CHHapticEngine *get_haptic_engine_instance() API_AVAILABLE(ios(13));
|
||||
void start_haptic_engine();
|
||||
void stop_haptic_engine();
|
||||
|
||||
public:
|
||||
static void alert(const char *p_alert, const char *p_title);
|
||||
|
||||
bool supports_haptic_engine();
|
||||
void vibrate_haptic_engine(float p_duration_seconds, float p_amplitude);
|
||||
|
||||
String get_model() const;
|
||||
String get_rate_url(int p_app_id) const;
|
||||
|
||||
iOS();
|
||||
class iOS : public AppleEmbedded {
|
||||
GDCLASS(iOS, AppleEmbedded);
|
||||
};
|
||||
|
|
89
platform/ios/main_ios.mm
Normal file
89
platform/ios/main_ios.mm
Normal file
|
@ -0,0 +1,89 @@
|
|||
/**************************************************************************/
|
||||
/* main_ios.mm */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "os_ios.h"
|
||||
|
||||
#import "drivers/apple_embedded/godot_app_delegate.h"
|
||||
#import "drivers/apple_embedded/main_utilities.h"
|
||||
#include "main/main.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#include <cstdio>
|
||||
|
||||
int gargc;
|
||||
char **gargv;
|
||||
|
||||
static OS_IOS *os = nullptr;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
#if defined(VULKAN_ENABLED)
|
||||
//MoltenVK - enable full component swizzling support
|
||||
setenv("MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE", "1", 1);
|
||||
#endif
|
||||
|
||||
gargc = argc;
|
||||
gargv = argv;
|
||||
|
||||
@autoreleasepool {
|
||||
NSString *className = NSStringFromClass([GDTApplicationDelegate class]);
|
||||
UIApplicationMain(argc, argv, nil, className);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int apple_embedded_main(int argc, char **argv) {
|
||||
change_to_launch_dir(argv);
|
||||
|
||||
os = new OS_IOS();
|
||||
|
||||
// We must override main when testing is enabled
|
||||
TEST_MAIN_OVERRIDE
|
||||
|
||||
char *fargv[64];
|
||||
argc = process_args(argc, argv, fargv);
|
||||
|
||||
Error err = Main::setup(fargv[0], argc - 1, &fargv[1], false);
|
||||
|
||||
if (err != OK) {
|
||||
if (err == ERR_HELP) { // Returned by --help and --version, so success.
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
os->initialize_modules();
|
||||
|
||||
return os->get_exit_code();
|
||||
}
|
||||
|
||||
void apple_embedded_finish() {
|
||||
Main::cleanup();
|
||||
delete os;
|
||||
}
|
|
@ -32,107 +32,16 @@
|
|||
|
||||
#ifdef IOS_ENABLED
|
||||
|
||||
#import "ios.h"
|
||||
|
||||
#import "drivers/apple/joypad_apple.h"
|
||||
#import "drivers/coreaudio/audio_driver_coreaudio.h"
|
||||
#include "drivers/unix/os_unix.h"
|
||||
#include "servers/audio_server.h"
|
||||
#include "servers/rendering/renderer_compositor.h"
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
#include "servers/rendering/rendering_device.h"
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
#import "rendering_context_driver_vulkan_ios.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class OS_IOS : public OS_Unix {
|
||||
private:
|
||||
static HashMap<String, void *> dynamic_symbol_lookup_table;
|
||||
friend void register_dynamic_symbol(char *name, void *address);
|
||||
|
||||
AudioDriverCoreAudio audio_driver;
|
||||
|
||||
iOS *ios = nullptr;
|
||||
|
||||
JoypadApple *joypad_apple = nullptr;
|
||||
|
||||
MainLoop *main_loop = nullptr;
|
||||
|
||||
virtual void initialize_core() override;
|
||||
virtual void initialize() override;
|
||||
|
||||
virtual void initialize_joypads() override;
|
||||
|
||||
virtual void set_main_loop(MainLoop *p_main_loop) override;
|
||||
virtual MainLoop *get_main_loop() const override;
|
||||
|
||||
virtual void delete_main_loop() override;
|
||||
|
||||
virtual void finalize() override;
|
||||
|
||||
bool is_focused = false;
|
||||
|
||||
CGFloat _weight_to_ct(int p_weight) const;
|
||||
CGFloat _stretch_to_ct(int p_stretch) const;
|
||||
String _get_default_fontname(const String &p_font_name) const;
|
||||
|
||||
static _FORCE_INLINE_ String get_framework_executable(const String &p_path);
|
||||
|
||||
void deinitialize_modules();
|
||||
#import "drivers/apple_embedded/os_apple_embedded.h"
|
||||
|
||||
class OS_IOS : public OS_AppleEmbedded {
|
||||
public:
|
||||
static OS_IOS *get_singleton();
|
||||
|
||||
OS_IOS();
|
||||
~OS_IOS();
|
||||
|
||||
void initialize_modules();
|
||||
|
||||
bool iterate();
|
||||
|
||||
void start();
|
||||
|
||||
virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
|
||||
|
||||
virtual Vector<String> get_system_fonts() const override;
|
||||
virtual Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override;
|
||||
virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override;
|
||||
|
||||
virtual Error open_dynamic_library(const String &p_path, void *&p_library_handle, GDExtensionData *p_data = nullptr) override;
|
||||
virtual Error close_dynamic_library(void *p_library_handle) override;
|
||||
virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String &p_name, void *&p_symbol_handle, bool p_optional = false) override;
|
||||
|
||||
virtual String get_name() const override;
|
||||
virtual String get_distribution_name() const override;
|
||||
virtual String get_version() const override;
|
||||
virtual String get_model_name() const override;
|
||||
|
||||
virtual Error shell_open(const String &p_uri) override;
|
||||
|
||||
virtual String get_user_data_dir(const String &p_user_dir) const override;
|
||||
|
||||
virtual String get_cache_path() const override;
|
||||
virtual String get_temp_path() const override;
|
||||
|
||||
virtual String get_locale() const override;
|
||||
|
||||
virtual String get_unique_id() const override;
|
||||
virtual String get_processor_name() const override;
|
||||
|
||||
virtual void vibrate_handheld(int p_duration_ms = 500, float p_amplitude = -1.0) override;
|
||||
|
||||
virtual bool _check_internal_feature_support(const String &p_feature) override;
|
||||
|
||||
void on_focus_out();
|
||||
void on_focus_in();
|
||||
|
||||
void on_enter_background();
|
||||
void on_exit_background();
|
||||
|
||||
virtual Rect2 calculate_boot_screen_rect(const Size2 &p_window_size, const Size2 &p_imgrect_size) const override;
|
||||
};
|
||||
|
||||
#endif // IOS_ENABLED
|
||||
|
|
|
@ -30,694 +30,23 @@
|
|||
|
||||
#import "os_ios.h"
|
||||
|
||||
#import "display_server_ios.h"
|
||||
|
||||
#ifdef IOS_ENABLED
|
||||
|
||||
#import "app_delegate.h"
|
||||
#import "display_server_ios.h"
|
||||
#import "godot_view.h"
|
||||
#import "ios_terminal_logger.h"
|
||||
#import "view_controller.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/dir_access.h"
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/io/file_access_pack.h"
|
||||
#include "drivers/unix/syslog_logger.h"
|
||||
#include "main/main.h"
|
||||
|
||||
#import <AudioToolbox/AudioServices.h>
|
||||
#import <CoreText/CoreText.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <dlfcn.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#if defined(RD_ENABLED)
|
||||
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
#include "drivers/vulkan/godot_vulkan.h"
|
||||
#endif // VULKAN_ENABLED
|
||||
#endif
|
||||
|
||||
// Initialization order between compilation units is not guaranteed,
|
||||
// so we use this as a hack to ensure certain code is called before
|
||||
// everything else, but after all units are initialized.
|
||||
typedef void (*init_callback)();
|
||||
static init_callback *ios_init_callbacks = nullptr;
|
||||
static int ios_init_callbacks_count = 0;
|
||||
static int ios_init_callbacks_capacity = 0;
|
||||
HashMap<String, void *> OS_IOS::dynamic_symbol_lookup_table;
|
||||
|
||||
void add_ios_init_callback(init_callback cb) {
|
||||
if (ios_init_callbacks_count == ios_init_callbacks_capacity) {
|
||||
void *new_ptr = realloc(ios_init_callbacks, sizeof(cb) * (ios_init_callbacks_capacity + 32));
|
||||
if (new_ptr) {
|
||||
ios_init_callbacks = (init_callback *)(new_ptr);
|
||||
ios_init_callbacks_capacity += 32;
|
||||
} else {
|
||||
ERR_FAIL_MSG("Unable to allocate memory for extension callbacks.");
|
||||
}
|
||||
}
|
||||
ios_init_callbacks[ios_init_callbacks_count++] = cb;
|
||||
}
|
||||
|
||||
void register_dynamic_symbol(char *name, void *address) {
|
||||
OS_IOS::dynamic_symbol_lookup_table[String(name)] = address;
|
||||
}
|
||||
|
||||
Rect2 fit_keep_aspect_centered(const Vector2 &p_container, const Vector2 &p_rect) {
|
||||
real_t available_ratio = p_container.width / p_container.height;
|
||||
real_t fit_ratio = p_rect.width / p_rect.height;
|
||||
Rect2 result;
|
||||
if (fit_ratio < available_ratio) {
|
||||
// Fit height - we'll have horizontal gaps
|
||||
result.size.height = p_container.height;
|
||||
result.size.width = p_container.height * fit_ratio;
|
||||
result.position.y = 0;
|
||||
result.position.x = (p_container.width - result.size.width) * 0.5f;
|
||||
} else {
|
||||
// Fit width - we'll have vertical gaps
|
||||
result.size.width = p_container.width;
|
||||
result.size.height = p_container.width / fit_ratio;
|
||||
result.position.x = 0;
|
||||
result.position.y = (p_container.height - result.size.height) * 0.5f;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Rect2 fit_keep_aspect_covered(const Vector2 &p_container, const Vector2 &p_rect) {
|
||||
real_t available_ratio = p_container.width / p_container.height;
|
||||
real_t fit_ratio = p_rect.width / p_rect.height;
|
||||
Rect2 result;
|
||||
if (fit_ratio < available_ratio) {
|
||||
// Need to scale up to fit width, and crop height
|
||||
result.size.width = p_container.width;
|
||||
result.size.height = p_container.width / fit_ratio;
|
||||
result.position.x = 0;
|
||||
result.position.y = (p_container.height - result.size.height) * 0.5f;
|
||||
} else {
|
||||
// Need to scale up to fit height, and crop width
|
||||
result.size.width = p_container.height * fit_ratio;
|
||||
result.size.height = p_container.height;
|
||||
result.position.x = (p_container.width - result.size.width) * 0.5f;
|
||||
result.position.y = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
OS_IOS *OS_IOS::get_singleton() {
|
||||
return (OS_IOS *)OS::get_singleton();
|
||||
return (OS_IOS *)OS_AppleEmbedded::get_singleton();
|
||||
}
|
||||
|
||||
OS_IOS::OS_IOS() {
|
||||
for (int i = 0; i < ios_init_callbacks_count; ++i) {
|
||||
ios_init_callbacks[i]();
|
||||
}
|
||||
free(ios_init_callbacks);
|
||||
ios_init_callbacks = nullptr;
|
||||
ios_init_callbacks_count = 0;
|
||||
ios_init_callbacks_capacity = 0;
|
||||
|
||||
main_loop = nullptr;
|
||||
|
||||
Vector<Logger *> loggers;
|
||||
loggers.push_back(memnew(IOSTerminalLogger));
|
||||
_set_logger(memnew(CompositeLogger(loggers)));
|
||||
|
||||
AudioDriverManager::add_driver(&audio_driver);
|
||||
|
||||
OS_IOS::OS_IOS() :
|
||||
OS_AppleEmbedded() {
|
||||
DisplayServerIOS::register_ios_driver();
|
||||
}
|
||||
|
||||
OS_IOS::~OS_IOS() {}
|
||||
|
||||
void OS_IOS::alert(const String &p_alert, const String &p_title) {
|
||||
const CharString utf8_alert = p_alert.utf8();
|
||||
const CharString utf8_title = p_title.utf8();
|
||||
iOS::alert(utf8_alert.get_data(), utf8_title.get_data());
|
||||
}
|
||||
|
||||
void OS_IOS::initialize_core() {
|
||||
OS_Unix::initialize_core();
|
||||
}
|
||||
|
||||
void OS_IOS::initialize() {
|
||||
initialize_core();
|
||||
}
|
||||
|
||||
void OS_IOS::initialize_joypads() {
|
||||
joypad_apple = memnew(JoypadApple);
|
||||
}
|
||||
|
||||
void OS_IOS::initialize_modules() {
|
||||
ios = memnew(iOS);
|
||||
Engine::get_singleton()->add_singleton(Engine::Singleton("iOS", ios));
|
||||
}
|
||||
|
||||
void OS_IOS::deinitialize_modules() {
|
||||
if (joypad_apple) {
|
||||
memdelete(joypad_apple);
|
||||
}
|
||||
|
||||
if (ios) {
|
||||
memdelete(ios);
|
||||
}
|
||||
}
|
||||
|
||||
void OS_IOS::set_main_loop(MainLoop *p_main_loop) {
|
||||
main_loop = p_main_loop;
|
||||
}
|
||||
|
||||
MainLoop *OS_IOS::get_main_loop() const {
|
||||
return main_loop;
|
||||
}
|
||||
|
||||
void OS_IOS::delete_main_loop() {
|
||||
if (main_loop) {
|
||||
main_loop->finalize();
|
||||
memdelete(main_loop);
|
||||
}
|
||||
|
||||
main_loop = nullptr;
|
||||
}
|
||||
|
||||
bool OS_IOS::iterate() {
|
||||
if (!main_loop) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DisplayServer::get_singleton()) {
|
||||
DisplayServer::get_singleton()->process_events();
|
||||
}
|
||||
|
||||
joypad_apple->process_joypads();
|
||||
|
||||
return Main::iteration();
|
||||
}
|
||||
|
||||
void OS_IOS::start() {
|
||||
if (Main::start() == EXIT_SUCCESS) {
|
||||
main_loop->initialize();
|
||||
}
|
||||
}
|
||||
|
||||
void OS_IOS::finalize() {
|
||||
deinitialize_modules();
|
||||
|
||||
// Already gets called
|
||||
//delete_main_loop();
|
||||
}
|
||||
|
||||
// MARK: Dynamic Libraries
|
||||
|
||||
_FORCE_INLINE_ String OS_IOS::get_framework_executable(const String &p_path) {
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
|
||||
// Read framework bundle to get executable name.
|
||||
NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())];
|
||||
NSBundle *bundle = [NSBundle bundleWithURL:url];
|
||||
if (bundle) {
|
||||
String exe_path = String::utf8([[bundle executablePath] UTF8String]);
|
||||
if (da->file_exists(exe_path)) {
|
||||
return exe_path;
|
||||
}
|
||||
}
|
||||
|
||||
// Try default executable name (invalid framework).
|
||||
if (da->dir_exists(p_path) && da->file_exists(p_path.path_join(p_path.get_file().get_basename()))) {
|
||||
return p_path.path_join(p_path.get_file().get_basename());
|
||||
}
|
||||
|
||||
// Not a framework, try loading as .dylib.
|
||||
return p_path;
|
||||
}
|
||||
|
||||
Error OS_IOS::open_dynamic_library(const String &p_path, void *&p_library_handle, GDExtensionData *p_data) {
|
||||
if (p_path.length() == 0) {
|
||||
// Static xcframework.
|
||||
p_library_handle = RTLD_SELF;
|
||||
|
||||
if (p_data != nullptr && p_data->r_resolved_path != nullptr) {
|
||||
*p_data->r_resolved_path = p_path;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
String path = get_framework_executable(p_path);
|
||||
|
||||
if (!FileAccess::exists(path)) {
|
||||
// Load .dylib or framework from within the executable path.
|
||||
path = get_framework_executable(get_executable_path().get_base_dir().path_join(p_path.get_file()));
|
||||
}
|
||||
|
||||
if (!FileAccess::exists(path)) {
|
||||
// Load .dylib converted to framework from within the executable path.
|
||||
path = get_framework_executable(get_executable_path().get_base_dir().path_join(p_path.get_file().get_basename() + ".framework"));
|
||||
}
|
||||
|
||||
if (!FileAccess::exists(path)) {
|
||||
// Load .dylib or framework from a standard iOS location.
|
||||
path = get_framework_executable(get_executable_path().get_base_dir().path_join("Frameworks").path_join(p_path.get_file()));
|
||||
}
|
||||
|
||||
if (!FileAccess::exists(path)) {
|
||||
// Load .dylib converted to framework from a standard iOS location.
|
||||
path = get_framework_executable(get_executable_path().get_base_dir().path_join("Frameworks").path_join(p_path.get_file().get_basename() + ".framework"));
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V(!FileAccess::exists(path), ERR_FILE_NOT_FOUND);
|
||||
|
||||
p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
|
||||
ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, dlerror()));
|
||||
|
||||
if (p_data != nullptr && p_data->r_resolved_path != nullptr) {
|
||||
*p_data->r_resolved_path = path;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error OS_IOS::close_dynamic_library(void *p_library_handle) {
|
||||
if (p_library_handle == RTLD_SELF) {
|
||||
return OK;
|
||||
}
|
||||
return OS_Unix::close_dynamic_library(p_library_handle);
|
||||
}
|
||||
|
||||
Error OS_IOS::get_dynamic_library_symbol_handle(void *p_library_handle, const String &p_name, void *&p_symbol_handle, bool p_optional) {
|
||||
if (p_library_handle == RTLD_SELF) {
|
||||
void **ptr = OS_IOS::dynamic_symbol_lookup_table.getptr(p_name);
|
||||
if (ptr) {
|
||||
p_symbol_handle = *ptr;
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
return OS_Unix::get_dynamic_library_symbol_handle(p_library_handle, p_name, p_symbol_handle, p_optional);
|
||||
}
|
||||
|
||||
String OS_IOS::get_name() const {
|
||||
return "iOS";
|
||||
}
|
||||
|
||||
String OS_IOS::get_distribution_name() const {
|
||||
return get_name();
|
||||
}
|
||||
|
||||
String OS_IOS::get_version() const {
|
||||
NSOperatingSystemVersion ver = [NSProcessInfo processInfo].operatingSystemVersion;
|
||||
return vformat("%d.%d.%d", (int64_t)ver.majorVersion, (int64_t)ver.minorVersion, (int64_t)ver.patchVersion);
|
||||
}
|
||||
|
||||
String OS_IOS::get_model_name() const {
|
||||
String model = ios->get_model();
|
||||
if (model != "") {
|
||||
return model;
|
||||
}
|
||||
|
||||
return OS_Unix::get_model_name();
|
||||
}
|
||||
|
||||
Error OS_IOS::shell_open(const String &p_uri) {
|
||||
NSString *urlPath = [[NSString alloc] initWithUTF8String:p_uri.utf8().get_data()];
|
||||
NSURL *url = [NSURL URLWithString:urlPath];
|
||||
|
||||
if (![[UIApplication sharedApplication] canOpenURL:url]) {
|
||||
return ERR_CANT_OPEN;
|
||||
}
|
||||
|
||||
print_verbose(vformat("Opening URL %s", p_uri));
|
||||
|
||||
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
String OS_IOS::get_user_data_dir(const String &p_user_dir) const {
|
||||
static String ret;
|
||||
if (ret.is_empty()) {
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
if (paths && [paths count] >= 1) {
|
||||
ret.append_utf8([[paths firstObject] UTF8String]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
String OS_IOS::get_cache_path() const {
|
||||
static String ret;
|
||||
if (ret.is_empty()) {
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||
if (paths && [paths count] >= 1) {
|
||||
ret.append_utf8([[paths firstObject] UTF8String]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
String OS_IOS::get_temp_path() const {
|
||||
static String ret;
|
||||
if (ret.is_empty()) {
|
||||
NSURL *url = [NSURL fileURLWithPath:NSTemporaryDirectory()
|
||||
isDirectory:YES];
|
||||
if (url) {
|
||||
ret = String::utf8([url.path UTF8String]);
|
||||
ret = ret.trim_prefix("file://");
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
String OS_IOS::get_locale() const {
|
||||
NSString *preferredLanguage = [NSLocale preferredLanguages].firstObject;
|
||||
|
||||
if (preferredLanguage) {
|
||||
return String::utf8([preferredLanguage UTF8String]).replace_char('-', '_');
|
||||
}
|
||||
|
||||
NSString *localeIdentifier = [[NSLocale currentLocale] localeIdentifier];
|
||||
return String::utf8([localeIdentifier UTF8String]).replace_char('-', '_');
|
||||
}
|
||||
|
||||
String OS_IOS::get_unique_id() const {
|
||||
NSString *uuid = [UIDevice currentDevice].identifierForVendor.UUIDString;
|
||||
return String::utf8([uuid UTF8String]);
|
||||
}
|
||||
|
||||
String OS_IOS::get_processor_name() const {
|
||||
char buffer[256];
|
||||
size_t buffer_len = 256;
|
||||
if (sysctlbyname("machdep.cpu.brand_string", &buffer, &buffer_len, nullptr, 0) == 0) {
|
||||
return String::utf8(buffer, buffer_len);
|
||||
}
|
||||
ERR_FAIL_V_MSG("", String("Couldn't get the CPU model name. Returning an empty string."));
|
||||
}
|
||||
|
||||
Vector<String> OS_IOS::get_system_fonts() const {
|
||||
HashSet<String> font_names;
|
||||
CFArrayRef fonts = CTFontManagerCopyAvailableFontFamilyNames();
|
||||
if (fonts) {
|
||||
for (CFIndex i = 0; i < CFArrayGetCount(fonts); i++) {
|
||||
CFStringRef cf_name = (CFStringRef)CFArrayGetValueAtIndex(fonts, i);
|
||||
if (cf_name && (CFStringGetLength(cf_name) > 0) && (CFStringCompare(cf_name, CFSTR("LastResort"), kCFCompareCaseInsensitive) != kCFCompareEqualTo) && (CFStringGetCharacterAtIndex(cf_name, 0) != '.')) {
|
||||
NSString *ns_name = (__bridge NSString *)cf_name;
|
||||
font_names.insert(String::utf8([ns_name UTF8String]));
|
||||
}
|
||||
}
|
||||
CFRelease(fonts);
|
||||
}
|
||||
|
||||
Vector<String> ret;
|
||||
for (const String &E : font_names) {
|
||||
ret.push_back(E);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
String OS_IOS::_get_default_fontname(const String &p_font_name) const {
|
||||
String font_name = p_font_name;
|
||||
if (font_name.to_lower() == "sans-serif") {
|
||||
font_name = "Helvetica";
|
||||
} else if (font_name.to_lower() == "serif") {
|
||||
font_name = "Times";
|
||||
} else if (font_name.to_lower() == "monospace") {
|
||||
font_name = "Courier";
|
||||
} else if (font_name.to_lower() == "fantasy") {
|
||||
font_name = "Papyrus";
|
||||
} else if (font_name.to_lower() == "cursive") {
|
||||
font_name = "Apple Chancery";
|
||||
};
|
||||
return font_name;
|
||||
}
|
||||
|
||||
CGFloat OS_IOS::_weight_to_ct(int p_weight) const {
|
||||
if (p_weight < 150) {
|
||||
return -0.80;
|
||||
} else if (p_weight < 250) {
|
||||
return -0.60;
|
||||
} else if (p_weight < 350) {
|
||||
return -0.40;
|
||||
} else if (p_weight < 450) {
|
||||
return 0.0;
|
||||
} else if (p_weight < 550) {
|
||||
return 0.23;
|
||||
} else if (p_weight < 650) {
|
||||
return 0.30;
|
||||
} else if (p_weight < 750) {
|
||||
return 0.40;
|
||||
} else if (p_weight < 850) {
|
||||
return 0.56;
|
||||
} else if (p_weight < 925) {
|
||||
return 0.62;
|
||||
} else {
|
||||
return 1.00;
|
||||
}
|
||||
}
|
||||
|
||||
CGFloat OS_IOS::_stretch_to_ct(int p_stretch) const {
|
||||
if (p_stretch < 56) {
|
||||
return -0.5;
|
||||
} else if (p_stretch < 69) {
|
||||
return -0.37;
|
||||
} else if (p_stretch < 81) {
|
||||
return -0.25;
|
||||
} else if (p_stretch < 93) {
|
||||
return -0.13;
|
||||
} else if (p_stretch < 106) {
|
||||
return 0.0;
|
||||
} else if (p_stretch < 137) {
|
||||
return 0.13;
|
||||
} else if (p_stretch < 144) {
|
||||
return 0.25;
|
||||
} else if (p_stretch < 162) {
|
||||
return 0.37;
|
||||
} else {
|
||||
return 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
Vector<String> OS_IOS::get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale, const String &p_script, int p_weight, int p_stretch, bool p_italic) const {
|
||||
Vector<String> ret;
|
||||
String font_name = _get_default_fontname(p_font_name);
|
||||
|
||||
CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, font_name.utf8().get_data(), kCFStringEncodingUTF8);
|
||||
CTFontSymbolicTraits traits = 0;
|
||||
if (p_weight >= 700) {
|
||||
traits |= kCTFontBoldTrait;
|
||||
}
|
||||
if (p_italic) {
|
||||
traits |= kCTFontItalicTrait;
|
||||
}
|
||||
if (p_stretch < 100) {
|
||||
traits |= kCTFontCondensedTrait;
|
||||
} else if (p_stretch > 100) {
|
||||
traits |= kCTFontExpandedTrait;
|
||||
}
|
||||
|
||||
CFNumberRef sym_traits = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &traits);
|
||||
CFMutableDictionaryRef traits_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr);
|
||||
CFDictionaryAddValue(traits_dict, kCTFontSymbolicTrait, sym_traits);
|
||||
|
||||
CGFloat weight = _weight_to_ct(p_weight);
|
||||
CFNumberRef font_weight = CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &weight);
|
||||
CFDictionaryAddValue(traits_dict, kCTFontWeightTrait, font_weight);
|
||||
|
||||
CGFloat stretch = _stretch_to_ct(p_stretch);
|
||||
CFNumberRef font_stretch = CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &stretch);
|
||||
CFDictionaryAddValue(traits_dict, kCTFontWidthTrait, font_stretch);
|
||||
|
||||
CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr);
|
||||
CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, name);
|
||||
CFDictionaryAddValue(attributes, kCTFontTraitsAttribute, traits_dict);
|
||||
|
||||
CTFontDescriptorRef font = CTFontDescriptorCreateWithAttributes(attributes);
|
||||
if (font) {
|
||||
CTFontRef family = CTFontCreateWithFontDescriptor(font, 0, nullptr);
|
||||
if (family) {
|
||||
CFStringRef string = CFStringCreateWithCString(kCFAllocatorDefault, p_text.utf8().get_data(), kCFStringEncodingUTF8);
|
||||
CFRange range = CFRangeMake(0, CFStringGetLength(string));
|
||||
CTFontRef fallback_family = CTFontCreateForString(family, string, range);
|
||||
if (fallback_family) {
|
||||
CTFontDescriptorRef fallback_font = CTFontCopyFontDescriptor(fallback_family);
|
||||
if (fallback_font) {
|
||||
CFURLRef url = (CFURLRef)CTFontDescriptorCopyAttribute(fallback_font, kCTFontURLAttribute);
|
||||
if (url) {
|
||||
NSString *font_path = [NSString stringWithString:[(__bridge NSURL *)url path]];
|
||||
ret.push_back(String::utf8([font_path UTF8String]));
|
||||
CFRelease(url);
|
||||
}
|
||||
CFRelease(fallback_font);
|
||||
}
|
||||
CFRelease(fallback_family);
|
||||
}
|
||||
CFRelease(string);
|
||||
CFRelease(family);
|
||||
}
|
||||
CFRelease(font);
|
||||
}
|
||||
|
||||
CFRelease(attributes);
|
||||
CFRelease(traits_dict);
|
||||
CFRelease(sym_traits);
|
||||
CFRelease(font_stretch);
|
||||
CFRelease(font_weight);
|
||||
CFRelease(name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
String OS_IOS::get_system_font_path(const String &p_font_name, int p_weight, int p_stretch, bool p_italic) const {
|
||||
String ret;
|
||||
String font_name = _get_default_fontname(p_font_name);
|
||||
|
||||
CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, font_name.utf8().get_data(), kCFStringEncodingUTF8);
|
||||
|
||||
CTFontSymbolicTraits traits = 0;
|
||||
if (p_weight >= 700) {
|
||||
traits |= kCTFontBoldTrait;
|
||||
}
|
||||
if (p_italic) {
|
||||
traits |= kCTFontItalicTrait;
|
||||
}
|
||||
if (p_stretch < 100) {
|
||||
traits |= kCTFontCondensedTrait;
|
||||
} else if (p_stretch > 100) {
|
||||
traits |= kCTFontExpandedTrait;
|
||||
}
|
||||
|
||||
CFNumberRef sym_traits = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &traits);
|
||||
CFMutableDictionaryRef traits_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr);
|
||||
CFDictionaryAddValue(traits_dict, kCTFontSymbolicTrait, sym_traits);
|
||||
|
||||
CGFloat weight = _weight_to_ct(p_weight);
|
||||
CFNumberRef font_weight = CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &weight);
|
||||
CFDictionaryAddValue(traits_dict, kCTFontWeightTrait, font_weight);
|
||||
|
||||
CGFloat stretch = _stretch_to_ct(p_stretch);
|
||||
CFNumberRef font_stretch = CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &stretch);
|
||||
CFDictionaryAddValue(traits_dict, kCTFontWidthTrait, font_stretch);
|
||||
|
||||
CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr);
|
||||
CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, name);
|
||||
CFDictionaryAddValue(attributes, kCTFontTraitsAttribute, traits_dict);
|
||||
|
||||
CTFontDescriptorRef font = CTFontDescriptorCreateWithAttributes(attributes);
|
||||
if (font) {
|
||||
CFURLRef url = (CFURLRef)CTFontDescriptorCopyAttribute(font, kCTFontURLAttribute);
|
||||
if (url) {
|
||||
NSString *font_path = [NSString stringWithString:[(__bridge NSURL *)url path]];
|
||||
ret = String::utf8([font_path UTF8String]);
|
||||
CFRelease(url);
|
||||
}
|
||||
CFRelease(font);
|
||||
}
|
||||
|
||||
CFRelease(attributes);
|
||||
CFRelease(traits_dict);
|
||||
CFRelease(sym_traits);
|
||||
CFRelease(font_stretch);
|
||||
CFRelease(font_weight);
|
||||
CFRelease(name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void OS_IOS::vibrate_handheld(int p_duration_ms, float p_amplitude) {
|
||||
if (ios->supports_haptic_engine()) {
|
||||
if (p_amplitude > 0.0) {
|
||||
p_amplitude = CLAMP(p_amplitude, 0.0, 1.0);
|
||||
}
|
||||
|
||||
ios->vibrate_haptic_engine((float)p_duration_ms / 1000.f, p_amplitude);
|
||||
} else {
|
||||
// iOS <13 does not support duration for vibration
|
||||
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
|
||||
}
|
||||
}
|
||||
|
||||
bool OS_IOS::_check_internal_feature_support(const String &p_feature) {
|
||||
if (p_feature == "system_fonts") {
|
||||
return true;
|
||||
}
|
||||
if (p_feature == "mobile") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void OS_IOS::on_focus_out() {
|
||||
if (is_focused) {
|
||||
is_focused = false;
|
||||
|
||||
if (DisplayServerIOS::get_singleton()) {
|
||||
DisplayServerIOS::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
|
||||
}
|
||||
|
||||
if (OS::get_singleton()->get_main_loop()) {
|
||||
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
|
||||
}
|
||||
|
||||
[AppDelegate.viewController.godotView stopRendering];
|
||||
|
||||
audio_driver.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void OS_IOS::on_focus_in() {
|
||||
if (!is_focused) {
|
||||
is_focused = true;
|
||||
|
||||
if (DisplayServerIOS::get_singleton()) {
|
||||
DisplayServerIOS::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_IN);
|
||||
}
|
||||
|
||||
if (OS::get_singleton()->get_main_loop()) {
|
||||
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN);
|
||||
}
|
||||
|
||||
[AppDelegate.viewController.godotView startRendering];
|
||||
|
||||
audio_driver.start();
|
||||
}
|
||||
}
|
||||
|
||||
void OS_IOS::on_enter_background() {
|
||||
// Do not check for is_focused, because on_focus_out will always be fired first by applicationWillResignActive.
|
||||
|
||||
if (OS::get_singleton()->get_main_loop()) {
|
||||
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_PAUSED);
|
||||
}
|
||||
|
||||
on_focus_out();
|
||||
}
|
||||
|
||||
void OS_IOS::on_exit_background() {
|
||||
if (!is_focused) {
|
||||
on_focus_in();
|
||||
|
||||
if (OS::get_singleton()->get_main_loop()) {
|
||||
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_RESUMED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rect2 OS_IOS::calculate_boot_screen_rect(const Size2 &p_window_size, const Size2 &p_imgrect_size) const {
|
||||
String scalemodestr = GLOBAL_GET("ios/launch_screen_image_mode");
|
||||
|
||||
if (scalemodestr == "scaleAspectFit") {
|
||||
return fit_keep_aspect_centered(p_window_size, p_imgrect_size);
|
||||
} else if (scalemodestr == "scaleAspectFill") {
|
||||
return fit_keep_aspect_covered(p_window_size, p_imgrect_size);
|
||||
} else if (scalemodestr == "scaleToFill") {
|
||||
return Rect2(Point2(), p_window_size);
|
||||
} else if (scalemodestr == "center") {
|
||||
return OS_Unix::calculate_boot_screen_rect(p_window_size, p_imgrect_size);
|
||||
} else {
|
||||
WARN_PRINT(vformat("Boot screen scale mode mismatch between iOS and Godot: %s not supported", scalemodestr));
|
||||
return OS_Unix::calculate_boot_screen_rect(p_window_size, p_imgrect_size);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // IOS_ENABLED
|
||||
|
|
|
@ -30,15 +30,4 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <alloca.h>
|
||||
|
||||
#define PLATFORM_THREAD_OVERRIDE
|
||||
|
||||
#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")
|
||||
#import "drivers/apple_embedded/platform_config.h"
|
||||
|
|
|
@ -1,67 +1,7 @@
|
|||
"""Functions used to generate source files during build time"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from platform_methods import detect_mvk, lipo
|
||||
|
||||
|
||||
def combine_libs(target, source, env):
|
||||
lib_path = target[0].srcnode().abspath
|
||||
if "osxcross" in env:
|
||||
libtool = "$IOS_TOOLCHAIN_PATH/usr/bin/${ios_triple}libtool"
|
||||
else:
|
||||
libtool = "$IOS_TOOLCHAIN_PATH/usr/bin/libtool"
|
||||
env.Execute(
|
||||
libtool + ' -static -o "' + lib_path + '" ' + " ".join([('"' + lib.srcnode().abspath + '"') for lib in source])
|
||||
)
|
||||
from platform_methods import generate_bundle_apple_embedded
|
||||
|
||||
|
||||
def generate_bundle(target, source, env):
|
||||
bin_dir = env.Dir("#bin").abspath
|
||||
|
||||
# Template bundle.
|
||||
app_prefix = "godot." + env["platform"]
|
||||
rel_prefix = "libgodot." + env["platform"] + "." + "template_release"
|
||||
dbg_prefix = "libgodot." + env["platform"] + "." + "template_debug"
|
||||
if env.dev_build:
|
||||
app_prefix += ".dev"
|
||||
rel_prefix += ".dev"
|
||||
dbg_prefix += ".dev"
|
||||
if env["precision"] == "double":
|
||||
app_prefix += ".double"
|
||||
rel_prefix += ".double"
|
||||
dbg_prefix += ".double"
|
||||
|
||||
# Lipo template libraries.
|
||||
rel_target_bin = lipo(bin_dir + "/" + rel_prefix, env.extra_suffix + ".a")
|
||||
dbg_target_bin = lipo(bin_dir + "/" + dbg_prefix, env.extra_suffix + ".a")
|
||||
rel_target_bin_sim = lipo(bin_dir + "/" + rel_prefix, ".simulator" + env.extra_suffix + ".a")
|
||||
dbg_target_bin_sim = lipo(bin_dir + "/" + dbg_prefix, ".simulator" + env.extra_suffix + ".a")
|
||||
|
||||
# Assemble Xcode project bundle.
|
||||
app_dir = env.Dir("#bin/ios_xcode").abspath
|
||||
templ = env.Dir("#misc/dist/ios_xcode").abspath
|
||||
if os.path.exists(app_dir):
|
||||
shutil.rmtree(app_dir)
|
||||
shutil.copytree(templ, app_dir)
|
||||
if rel_target_bin != "":
|
||||
shutil.copy(rel_target_bin, app_dir + "/libgodot.ios.release.xcframework/ios-arm64/libgodot.a")
|
||||
if dbg_target_bin != "":
|
||||
shutil.copy(dbg_target_bin, app_dir + "/libgodot.ios.debug.xcframework/ios-arm64/libgodot.a")
|
||||
if rel_target_bin_sim != "":
|
||||
shutil.copy(
|
||||
rel_target_bin_sim, app_dir + "/libgodot.ios.release.xcframework/ios-arm64_x86_64-simulator/libgodot.a"
|
||||
)
|
||||
if dbg_target_bin_sim != "":
|
||||
shutil.copy(
|
||||
dbg_target_bin_sim, app_dir + "/libgodot.ios.debug.xcframework/ios-arm64_x86_64-simulator/libgodot.a"
|
||||
)
|
||||
mvk_path = detect_mvk(env, "ios-arm64")
|
||||
if mvk_path != "":
|
||||
shutil.copytree(mvk_path, app_dir + "/MoltenVK.xcframework")
|
||||
|
||||
# ZIP Xcode project bundle.
|
||||
zip_dir = env.Dir("#bin/" + (app_prefix + env.extra_suffix).replace(".", "_")).abspath
|
||||
shutil.make_archive(zip_dir, "zip", root_dir=app_dir)
|
||||
shutil.rmtree(app_dir)
|
||||
generate_bundle_apple_embedded("ios", "ios-arm64", "ios-arm64_x86_64-simulator", True, target, source, env)
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
This folder contains the C++, Objective-C and Objective-C++ code for the macOS
|
||||
platform port.
|
||||
|
||||
This platform uses shared Apple code ([`drivers/apple`](/drivers/apple)).
|
||||
|
||||
See also [`misc/dist/macos`](/misc/dist/macos) folder for additional files used
|
||||
by this platform. [`misc/dist/macos_tools.app`](/misc/dist/macos_tools.app) is
|
||||
an `.app` bundle template used for packaging the macOS editor, while
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
@ -160,3 +161,79 @@ def detect_mvk(env, osname):
|
|||
return mvk_path
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
def combine_libs_apple_embedded(target, source, env):
|
||||
lib_path = target[0].srcnode().abspath
|
||||
if "osxcross" in env:
|
||||
libtool = "$APPLE_TOOLCHAIN_PATH/usr/bin/${apple_target_triple}libtool"
|
||||
else:
|
||||
libtool = "$APPLE_TOOLCHAIN_PATH/usr/bin/libtool"
|
||||
env.Execute(
|
||||
libtool + ' -static -o "' + lib_path + '" ' + " ".join([('"' + lib.srcnode().abspath + '"') for lib in source])
|
||||
)
|
||||
|
||||
|
||||
def generate_bundle_apple_embedded(platform, framework_dir, framework_dir_sim, use_mkv, target, source, env):
|
||||
bin_dir = env.Dir("#bin").abspath
|
||||
|
||||
# Template bundle.
|
||||
app_prefix = "godot." + platform
|
||||
rel_prefix = "libgodot." + platform + "." + "template_release"
|
||||
dbg_prefix = "libgodot." + platform + "." + "template_debug"
|
||||
if env.dev_build:
|
||||
app_prefix += ".dev"
|
||||
rel_prefix += ".dev"
|
||||
dbg_prefix += ".dev"
|
||||
if env["precision"] == "double":
|
||||
app_prefix += ".double"
|
||||
rel_prefix += ".double"
|
||||
dbg_prefix += ".double"
|
||||
|
||||
# Lipo template libraries.
|
||||
#
|
||||
# env.extra_suffix contains ".simulator" when building for simulator,
|
||||
# but it's undesired when calling lipo()
|
||||
extra_suffix = env.extra_suffix.replace(".simulator", "")
|
||||
rel_target_bin = lipo(bin_dir + "/" + rel_prefix, extra_suffix + ".a")
|
||||
dbg_target_bin = lipo(bin_dir + "/" + dbg_prefix, extra_suffix + ".a")
|
||||
rel_target_bin_sim = lipo(bin_dir + "/" + rel_prefix, ".simulator" + extra_suffix + ".a")
|
||||
dbg_target_bin_sim = lipo(bin_dir + "/" + dbg_prefix, ".simulator" + extra_suffix + ".a")
|
||||
# Assemble Xcode project bundle.
|
||||
app_dir = env.Dir("#bin/" + platform + "_xcode").abspath
|
||||
templ = env.Dir("#misc/dist/" + platform + "_xcode").abspath
|
||||
if os.path.exists(app_dir):
|
||||
shutil.rmtree(app_dir)
|
||||
shutil.copytree(templ, app_dir)
|
||||
if rel_target_bin != "":
|
||||
print(f' Copying "{platform}" release framework')
|
||||
shutil.copy(
|
||||
rel_target_bin, app_dir + "/libgodot." + platform + ".release.xcframework/" + framework_dir + "/libgodot.a"
|
||||
)
|
||||
if dbg_target_bin != "":
|
||||
print(f' Copying "{platform}" debug framework')
|
||||
shutil.copy(
|
||||
dbg_target_bin, app_dir + "/libgodot." + platform + ".debug.xcframework/" + framework_dir + "/libgodot.a"
|
||||
)
|
||||
if rel_target_bin_sim != "":
|
||||
print(f' Copying "{platform}" (simulator) release framework')
|
||||
shutil.copy(
|
||||
rel_target_bin_sim,
|
||||
app_dir + "/libgodot." + platform + ".release.xcframework/" + framework_dir_sim + "/libgodot.a",
|
||||
)
|
||||
if dbg_target_bin_sim != "":
|
||||
print(f' Copying "{platform}" (simulator) debug framework')
|
||||
shutil.copy(
|
||||
dbg_target_bin_sim,
|
||||
app_dir + "/libgodot." + platform + ".debug.xcframework/" + framework_dir_sim + "/libgodot.a",
|
||||
)
|
||||
|
||||
if use_mkv:
|
||||
mvk_path = detect_mvk(env, "ios-arm64")
|
||||
if mvk_path != "":
|
||||
shutil.copytree(mvk_path, app_dir + "/MoltenVK.xcframework")
|
||||
|
||||
# ZIP Xcode project bundle.
|
||||
zip_dir = env.Dir("#bin/" + (app_prefix + extra_suffix).replace(".", "_")).abspath
|
||||
shutil.make_archive(zip_dir, "zip", root_dir=app_dir)
|
||||
shutil.rmtree(app_dir)
|
||||
|
|
|
@ -1791,7 +1791,7 @@ PackedStringArray LightmapGI::get_configuration_warnings() const {
|
|||
warnings.push_back(RTR("The lightmap has no baked shadowmask textures. Please rebake with the Shadowmask Mode set to anything other than None."));
|
||||
}
|
||||
|
||||
#elif defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
|
||||
#elif defined(ANDROID_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
|
||||
warnings.push_back(vformat(RTR("Lightmaps cannot be baked on %s. Rendering existing baked lightmaps will still work."), OS::get_singleton()->get_name()));
|
||||
#else
|
||||
warnings.push_back(RTR("Lightmaps cannot be baked, as the `lightmapper_rd` module was disabled at compile-time. Rendering existing baked lightmaps will still work."));
|
||||
|
|
|
@ -435,7 +435,7 @@ void Fog::VolumetricFog::init(const Vector3i &fog_size, RID p_sky_shader) {
|
|||
fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
|
||||
RD::get_singleton()->set_resource_name(fog_map, "Fog map");
|
||||
|
||||
#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
|
||||
#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
|
||||
Vector<uint8_t> dm;
|
||||
dm.resize_zeroed(fog_size.x * fog_size.y * fog_size.z * 4);
|
||||
|
||||
|
@ -574,7 +574,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
|
|||
|
||||
{
|
||||
RD::Uniform u;
|
||||
#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
|
||||
#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
|
||||
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
|
||||
#else
|
||||
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
|
||||
|
@ -594,7 +594,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
|
|||
|
||||
{
|
||||
RD::Uniform u;
|
||||
#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
|
||||
#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
|
||||
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
|
||||
#else
|
||||
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
|
||||
|
@ -606,7 +606,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
|
|||
|
||||
{
|
||||
RD::Uniform u;
|
||||
#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
|
||||
#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
|
||||
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
|
||||
#else
|
||||
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
|
||||
|
@ -913,7 +913,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
|
|||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
|
||||
#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
|
||||
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
|
||||
#else
|
||||
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
|
||||
|
@ -924,7 +924,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
|
|||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
|
||||
#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
|
||||
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
|
||||
#else
|
||||
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
|
||||
|
@ -936,7 +936,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
|
|||
|
||||
{
|
||||
RD::Uniform u;
|
||||
#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
|
||||
#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
|
||||
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
|
||||
#else
|
||||
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
|
||||
|
|
|
@ -227,7 +227,7 @@ void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, c
|
|||
for (const KeyValue<StringName, CharString> &E : p_version->code_sections) {
|
||||
builder.append(String("#define ") + String(E.key) + "_CODE_USED\n");
|
||||
}
|
||||
#if (defined(MACOS_ENABLED) || defined(IOS_ENABLED))
|
||||
#if (defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED))
|
||||
if (RD::get_singleton()->get_device_capabilities().device_family == RDD::DEVICE_VULKAN) {
|
||||
builder.append("#define MOLTENVK_USED\n");
|
||||
}
|
||||
|
|
|
@ -265,7 +265,7 @@ bool Utilities::has_os_feature(const String &p_feature) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
#if !defined(ANDROID_ENABLED) && !defined(IOS_ENABLED)
|
||||
#if !defined(ANDROID_ENABLED) && !defined(APPLE_EMBEDDED_ENABLED)
|
||||
// Some Android devices report support for S3TC but we don't expect that and don't export the textures.
|
||||
// This could be fixed but so few devices support it that it doesn't seem useful (and makes bigger APKs).
|
||||
// For good measure we do the same hack for iOS, just in case.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue