From 4d8234d50ec3b477e08ce72a03b26c6fb4249551 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pa=CC=84vels=20Nadtoc=CC=8Cajevs?=
<7645683+bruvzg@users.noreply.github.com>
Date: Wed, 28 Jan 2026 11:43:57 +0200
Subject: [PATCH] [iOS] Reintegrate camera module to the main repo.
---
doc/classes/CameraServer.xml | 2 +-
.../editor_export_platform_apple_embedded.cpp | 71 ++++++++--
.../editor_export_platform_apple_embedded.h | 2 +-
.../Info.plist | 40 ++++++
.../ios-arm64/empty | 1 +
.../ios-arm64_x86_64-simulator/empty | 1 +
.../Info.plist | 40 ++++++
.../ios-arm64/empty | 1 +
.../ios-arm64_x86_64-simulator/empty | 1 +
.../Info.plist | 39 +++++
.../xros-arm64-simulator/empty | 1 +
.../xros-arm64/empty | 1 +
.../Info.plist | 39 +++++
.../xros-arm64-simulator/empty | 1 +
.../xros-arm64/empty | 1 +
modules/camera/SCsub | 10 +-
.../camera/{camera_macos.h => camera_apple.h} | 8 +-
.../{camera_macos.mm => camera_apple.mm} | 133 +++++++++++++-----
modules/camera/config.py | 9 +-
modules/camera/register_types.cpp | 4 +-
platform/ios/SCsub | 3 +
.../doc_classes/EditorExportPlatformIOS.xml | 3 +
platform/visionos/SCsub | 3 +
.../EditorExportPlatformVisionOS.xml | 3 +
platform_methods.py | 109 ++++++++++----
25 files changed, 441 insertions(+), 85 deletions(-)
create mode 100644 misc/dist/apple_embedded_xcode/libgodot_camera.ios.debug.xcframework/Info.plist
create mode 100644 misc/dist/apple_embedded_xcode/libgodot_camera.ios.debug.xcframework/ios-arm64/empty
create mode 100644 misc/dist/apple_embedded_xcode/libgodot_camera.ios.debug.xcframework/ios-arm64_x86_64-simulator/empty
create mode 100644 misc/dist/apple_embedded_xcode/libgodot_camera.ios.release.xcframework/Info.plist
create mode 100644 misc/dist/apple_embedded_xcode/libgodot_camera.ios.release.xcframework/ios-arm64/empty
create mode 100644 misc/dist/apple_embedded_xcode/libgodot_camera.ios.release.xcframework/ios-arm64_x86_64-simulator/empty
create mode 100644 misc/dist/apple_embedded_xcode/libgodot_camera.visionos.debug.xcframework/Info.plist
create mode 100644 misc/dist/apple_embedded_xcode/libgodot_camera.visionos.debug.xcframework/xros-arm64-simulator/empty
create mode 100644 misc/dist/apple_embedded_xcode/libgodot_camera.visionos.debug.xcframework/xros-arm64/empty
create mode 100644 misc/dist/apple_embedded_xcode/libgodot_camera.visionos.release.xcframework/Info.plist
create mode 100644 misc/dist/apple_embedded_xcode/libgodot_camera.visionos.release.xcframework/xros-arm64-simulator/empty
create mode 100644 misc/dist/apple_embedded_xcode/libgodot_camera.visionos.release.xcframework/xros-arm64/empty
rename modules/camera/{camera_macos.h => camera_apple.h} (93%)
rename modules/camera/{camera_macos.mm => camera_apple.mm} (77%)
diff --git a/doc/classes/CameraServer.xml b/doc/classes/CameraServer.xml
index 3b16768a3b0..7de268c8571 100644
--- a/doc/classes/CameraServer.xml
+++ b/doc/classes/CameraServer.xml
@@ -6,7 +6,7 @@
The [CameraServer] keeps track of different cameras accessible in Godot. These are external cameras such as webcams or the cameras on your phone.
It is notably used to provide AR modules with a video feed from the camera.
- [b]Note:[/b] This class is currently only implemented on Linux, Android, macOS, and iOS. On other platforms no [CameraFeed]s will be available. To get a [CameraFeed] on iOS, the camera plugin from [url=https://github.com/godotengine/godot-ios-plugins]godot-ios-plugins[/url] is required.
+ [b]Note:[/b] This class is currently only implemented on Linux, Android, macOS, and iOS. On other platforms no [CameraFeed]s will be available. To get a [CameraFeed] on iOS, enable [member EditorExportPlatformIOS.modules/camera].
diff --git a/editor/export/editor_export_platform_apple_embedded.cpp b/editor/export/editor_export_platform_apple_embedded.cpp
index 2f9db30283e..458e22e9793 100644
--- a/editor/export/editor_export_platform_apple_embedded.cpp
+++ b/editor/export/editor_export_platform_apple_embedded.cpp
@@ -283,6 +283,8 @@ void EditorExportPlatformAppleEmbedded::get_export_options(List *r
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/export_project_only"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/delete_old_export_files_unconditionally"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "modules/camera"), false));
+
Vector found_plugins = get_plugins(get_platform_name());
for (int i = 0; i < found_plugins.size(); i++) {
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("plugins"), found_plugins[i].name)), false));
@@ -1422,7 +1424,7 @@ Vector EditorExportPlatformAppleEmbedded::_get_preset_architectures(cons
return enabled_archs;
}
-Error EditorExportPlatformAppleEmbedded::_export_apple_embedded_plugins(const Ref &p_preset, AppleEmbeddedConfigData &p_config_data, const String &dest_dir, Vector &r_exported_assets, bool p_debug) {
+Error EditorExportPlatformAppleEmbedded::_export_apple_embedded_plugins(const Ref &p_preset, AppleEmbeddedConfigData &p_config_data, const String &p_dest_dir, const Vector &p_module_libs, Vector &r_exported_assets, bool p_debug) {
String plugin_definition_cpp_code;
String plugin_initialization_cpp_code;
String plugin_deinitialization_cpp_code;
@@ -1449,7 +1451,7 @@ Error EditorExportPlatformAppleEmbedded::_export_apple_embedded_plugins(const Re
String plugin_binary_result_file = plugin.binary.get_file();
// We shouldn't embed .xcframework that contains static libraries.
// Static libraries are not embedded anyway.
- err = _copy_asset(p_preset, dest_dir, plugin_main_binary, &plugin_binary_result_file, true, false, r_exported_assets);
+ err = _copy_asset(p_preset, p_dest_dir, plugin_main_binary, &plugin_binary_result_file, true, false, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
// Adding dependencies.
@@ -1553,6 +1555,23 @@ Error EditorExportPlatformAppleEmbedded::_export_apple_embedded_plugins(const Re
plugin_deinitialization_cpp_code += "\t" + deinitialization_method;
}
+ for (const String &lib_name : p_module_libs) {
+ String definition_comment = "// Module: " + lib_name + "\n";
+ String initialization_method = "register_" + lib_name + "_external_module();\n";
+ String deinitialization_method = "unregister_" + lib_name + "_external_module();\n";
+
+ plugin_definition_cpp_code += definition_comment +
+ "extern void " + initialization_method +
+ "extern void " + deinitialization_method + "\n";
+
+ plugin_initialization_cpp_code += "\t" + initialization_method;
+ plugin_deinitialization_cpp_code += "\t" + deinitialization_method;
+
+ String binary_name = p_dest_dir.get_file().get_basename();
+ AppleEmbeddedExportAsset exported_asset = { binary_name + "_" + lib_name + ".xcframework", true, false };
+ r_exported_assets.push_back(exported_asset);
+ }
+
// Updating `Info.plist`
{
for (const KeyValue &E : plist_values) {
@@ -1570,15 +1589,15 @@ Error EditorExportPlatformAppleEmbedded::_export_apple_embedded_plugins(const Re
// Export files
{
// Export linked plugin dependency
- err = _export_additional_assets(p_preset, dest_dir, plugin_linked_dependencies, true, false, r_exported_assets);
+ err = _export_additional_assets(p_preset, p_dest_dir, plugin_linked_dependencies, true, false, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
// Export embedded plugin dependency
- err = _export_additional_assets(p_preset, dest_dir, plugin_embedded_dependencies, true, true, r_exported_assets);
+ err = _export_additional_assets(p_preset, p_dest_dir, plugin_embedded_dependencies, true, true, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
// Export plugin files
- err = _export_additional_assets(p_preset, dest_dir, plugin_files, false, false, r_exported_assets);
+ err = _export_additional_assets(p_preset, p_dest_dir, plugin_files, false, false, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
}
@@ -1765,6 +1784,10 @@ Error EditorExportPlatformAppleEmbedded::_export_project_helper(const Ref module_libs;
+ if (p_preset->get("modules/camera").operator bool()) {
+ module_libs.push_back("camera");
+ }
print_line("Static framework: " + library_to_use);
String pkg_name;
@@ -1774,7 +1797,7 @@ Error EditorExportPlatformAppleEmbedded::_export_project_helper(const Ref files_to_parse;
const String project_file = "godot_apple_embedded.xcodeproj/project.pbxproj";
@@ -1821,7 +1844,7 @@ Error EditorExportPlatformAppleEmbedded::_export_project_helper(const Refget("modules/camera").operator bool()) {
+ String description = p_preset->get("privacy/camera_usage_description");
+ if (description.is_empty()) {
+ valid = false;
+ err += TTR("Camera module enabled, but camera usage description is not set.") + "\n";
+ }
+ }
+
const String &additional_plist_content = p_preset->get("application/additional_plist_content");
if (!additional_plist_content.is_empty()) {
const String &plist = vformat("\n"
diff --git a/editor/export/editor_export_platform_apple_embedded.h b/editor/export/editor_export_platform_apple_embedded.h
index 3a346ef72bb..4536ce05d43 100644
--- a/editor/export/editor_export_platform_apple_embedded.h
+++ b/editor/export/editor_export_platform_apple_embedded.h
@@ -197,7 +197,7 @@ class EditorExportPlatformAppleEmbedded : public EditorExportPlatform {
Error _export_additional_assets(const Ref &p_preset, const String &p_out_dir, const Vector &p_assets, bool p_is_framework, bool p_should_embed, Vector &r_exported_assets);
Error _copy_asset(const Ref &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 &r_exported_assets);
Error _export_additional_assets(const Ref &p_preset, const String &p_out_dir, const Vector &p_libraries, Vector &r_exported_assets);
- Error _export_apple_embedded_plugins(const Ref &p_preset, AppleEmbeddedConfigData &p_config_data, const String &dest_dir, Vector &r_exported_assets, bool p_debug);
+ Error _export_apple_embedded_plugins(const Ref &p_preset, AppleEmbeddedConfigData &p_config_data, const String &p_dest_dir, const Vector &p_module_libs, Vector &r_exported_assets, bool p_debug);
Error _export_project_helper(const Ref &p_preset, bool p_debug, const String &p_path, BitField p_flags, bool p_oneclick);
diff --git a/misc/dist/apple_embedded_xcode/libgodot_camera.ios.debug.xcframework/Info.plist b/misc/dist/apple_embedded_xcode/libgodot_camera.ios.debug.xcframework/Info.plist
new file mode 100644
index 00000000000..5c352d09166
--- /dev/null
+++ b/misc/dist/apple_embedded_xcode/libgodot_camera.ios.debug.xcframework/Info.plist
@@ -0,0 +1,40 @@
+
+
+
+
+ AvailableLibraries
+
+
+ LibraryIdentifier
+ ios-arm64
+ LibraryPath
+ libgodot_camera.a
+ SupportedArchitectures
+
+ arm64
+
+ SupportedPlatform
+ ios
+
+
+ LibraryIdentifier
+ ios-arm64_x86_64-simulator
+ LibraryPath
+ libgodot_camera.a
+ SupportedArchitectures
+
+ arm64
+ x86_64
+
+ SupportedPlatform
+ ios
+ SupportedPlatformVariant
+ simulator
+
+
+ CFBundlePackageType
+ XFWK
+ XCFrameworkFormatVersion
+ 1.0
+
+
diff --git a/misc/dist/apple_embedded_xcode/libgodot_camera.ios.debug.xcframework/ios-arm64/empty b/misc/dist/apple_embedded_xcode/libgodot_camera.ios.debug.xcframework/ios-arm64/empty
new file mode 100644
index 00000000000..bd3e8943336
--- /dev/null
+++ b/misc/dist/apple_embedded_xcode/libgodot_camera.ios.debug.xcframework/ios-arm64/empty
@@ -0,0 +1 @@
+Dummy file to make dylibs folder exported
diff --git a/misc/dist/apple_embedded_xcode/libgodot_camera.ios.debug.xcframework/ios-arm64_x86_64-simulator/empty b/misc/dist/apple_embedded_xcode/libgodot_camera.ios.debug.xcframework/ios-arm64_x86_64-simulator/empty
new file mode 100644
index 00000000000..bd3e8943336
--- /dev/null
+++ b/misc/dist/apple_embedded_xcode/libgodot_camera.ios.debug.xcframework/ios-arm64_x86_64-simulator/empty
@@ -0,0 +1 @@
+Dummy file to make dylibs folder exported
diff --git a/misc/dist/apple_embedded_xcode/libgodot_camera.ios.release.xcframework/Info.plist b/misc/dist/apple_embedded_xcode/libgodot_camera.ios.release.xcframework/Info.plist
new file mode 100644
index 00000000000..5c352d09166
--- /dev/null
+++ b/misc/dist/apple_embedded_xcode/libgodot_camera.ios.release.xcframework/Info.plist
@@ -0,0 +1,40 @@
+
+
+
+
+ AvailableLibraries
+
+
+ LibraryIdentifier
+ ios-arm64
+ LibraryPath
+ libgodot_camera.a
+ SupportedArchitectures
+
+ arm64
+
+ SupportedPlatform
+ ios
+
+
+ LibraryIdentifier
+ ios-arm64_x86_64-simulator
+ LibraryPath
+ libgodot_camera.a
+ SupportedArchitectures
+
+ arm64
+ x86_64
+
+ SupportedPlatform
+ ios
+ SupportedPlatformVariant
+ simulator
+
+
+ CFBundlePackageType
+ XFWK
+ XCFrameworkFormatVersion
+ 1.0
+
+
diff --git a/misc/dist/apple_embedded_xcode/libgodot_camera.ios.release.xcframework/ios-arm64/empty b/misc/dist/apple_embedded_xcode/libgodot_camera.ios.release.xcframework/ios-arm64/empty
new file mode 100644
index 00000000000..bd3e8943336
--- /dev/null
+++ b/misc/dist/apple_embedded_xcode/libgodot_camera.ios.release.xcframework/ios-arm64/empty
@@ -0,0 +1 @@
+Dummy file to make dylibs folder exported
diff --git a/misc/dist/apple_embedded_xcode/libgodot_camera.ios.release.xcframework/ios-arm64_x86_64-simulator/empty b/misc/dist/apple_embedded_xcode/libgodot_camera.ios.release.xcframework/ios-arm64_x86_64-simulator/empty
new file mode 100644
index 00000000000..bd3e8943336
--- /dev/null
+++ b/misc/dist/apple_embedded_xcode/libgodot_camera.ios.release.xcframework/ios-arm64_x86_64-simulator/empty
@@ -0,0 +1 @@
+Dummy file to make dylibs folder exported
diff --git a/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.debug.xcframework/Info.plist b/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.debug.xcframework/Info.plist
new file mode 100644
index 00000000000..25f87359e67
--- /dev/null
+++ b/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.debug.xcframework/Info.plist
@@ -0,0 +1,39 @@
+
+
+
+
+ AvailableLibraries
+
+
+ LibraryIdentifier
+ xros-arm64
+ LibraryPath
+ libgodot_camera.a
+ SupportedArchitectures
+
+ arm64
+
+ SupportedPlatform
+ xros
+
+
+ LibraryIdentifier
+ xros-arm64-simulator
+ LibraryPath
+ libgodot_camera.a
+ SupportedArchitectures
+
+ arm64
+
+ SupportedPlatform
+ xros
+ SupportedPlatformVariant
+ simulator
+
+
+ CFBundlePackageType
+ XFWK
+ XCFrameworkFormatVersion
+ 1.0
+
+
diff --git a/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.debug.xcframework/xros-arm64-simulator/empty b/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.debug.xcframework/xros-arm64-simulator/empty
new file mode 100644
index 00000000000..bd3e8943336
--- /dev/null
+++ b/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.debug.xcframework/xros-arm64-simulator/empty
@@ -0,0 +1 @@
+Dummy file to make dylibs folder exported
diff --git a/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.debug.xcframework/xros-arm64/empty b/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.debug.xcframework/xros-arm64/empty
new file mode 100644
index 00000000000..bd3e8943336
--- /dev/null
+++ b/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.debug.xcframework/xros-arm64/empty
@@ -0,0 +1 @@
+Dummy file to make dylibs folder exported
diff --git a/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.release.xcframework/Info.plist b/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.release.xcframework/Info.plist
new file mode 100644
index 00000000000..25f87359e67
--- /dev/null
+++ b/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.release.xcframework/Info.plist
@@ -0,0 +1,39 @@
+
+
+
+
+ AvailableLibraries
+
+
+ LibraryIdentifier
+ xros-arm64
+ LibraryPath
+ libgodot_camera.a
+ SupportedArchitectures
+
+ arm64
+
+ SupportedPlatform
+ xros
+
+
+ LibraryIdentifier
+ xros-arm64-simulator
+ LibraryPath
+ libgodot_camera.a
+ SupportedArchitectures
+
+ arm64
+
+ SupportedPlatform
+ xros
+ SupportedPlatformVariant
+ simulator
+
+
+ CFBundlePackageType
+ XFWK
+ XCFrameworkFormatVersion
+ 1.0
+
+
diff --git a/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.release.xcframework/xros-arm64-simulator/empty b/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.release.xcframework/xros-arm64-simulator/empty
new file mode 100644
index 00000000000..bd3e8943336
--- /dev/null
+++ b/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.release.xcframework/xros-arm64-simulator/empty
@@ -0,0 +1 @@
+Dummy file to make dylibs folder exported
diff --git a/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.release.xcframework/xros-arm64/empty b/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.release.xcframework/xros-arm64/empty
new file mode 100644
index 00000000000..bd3e8943336
--- /dev/null
+++ b/misc/dist/apple_embedded_xcode/libgodot_camera.visionos.release.xcframework/xros-arm64/empty
@@ -0,0 +1 @@
+Dummy file to make dylibs folder exported
diff --git a/modules/camera/SCsub b/modules/camera/SCsub
index 750dc7c368c..22555f2921a 100644
--- a/modules/camera/SCsub
+++ b/modules/camera/SCsub
@@ -6,19 +6,25 @@ Import("env_modules")
env_camera = env_modules.Clone()
-if env["platform"] in ["windows", "macos", "linuxbsd", "android"]:
+if env["platform"] in ["windows", "macos", "linuxbsd", "android", "ios", "visionos"]:
env_camera.add_source_files(env.modules_sources, "register_types.cpp")
if env["platform"] == "windows":
env_camera.add_source_files(env.modules_sources, "camera_win.cpp")
elif env["platform"] == "macos":
- env_camera.add_source_files(env.modules_sources, "camera_macos.mm")
+ env_camera.add_source_files(env.modules_sources, "camera_apple.mm")
elif env["platform"] == "android":
env_camera.add_source_files(env.modules_sources, "camera_android.cpp")
env.Append(LIBS=["camera2ndk", "mediandk"])
+elif env["platform"] in ["ios", "visionos"]:
+ ext_module_source = ["camera_apple.mm"]
+ ext_camera_lib = env_camera.add_library("#bin/libgodot_camera", ext_module_source)
+ env.Append(LIBS_EXTERNAL=[ext_camera_lib])
+ env.Append(MODULES_EXTERNAL=["_camera"])
+
elif env["platform"] == "linuxbsd":
env_camera.add_source_files(env.modules_sources, "camera_linux.cpp")
env_camera.add_source_files(env.modules_sources, "camera_feed_linux.cpp")
diff --git a/modules/camera/camera_macos.h b/modules/camera/camera_apple.h
similarity index 93%
rename from modules/camera/camera_macos.h
rename to modules/camera/camera_apple.h
index 9713b66df0d..82b5e7dec53 100644
--- a/modules/camera/camera_macos.h
+++ b/modules/camera/camera_apple.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* camera_macos.h */
+/* camera_apple.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -35,11 +35,11 @@
#include "servers/camera/camera_server.h"
-class CameraMacOS : public CameraServer {
- GDSOFTCLASS(CameraMacOS, CameraServer);
+class CameraApple : public CameraServer {
+ GDSOFTCLASS(CameraApple, CameraServer);
public:
- CameraMacOS() = default;
+ CameraApple() = default;
void update_feeds();
void set_monitoring_feeds(bool p_monitoring_feeds) override;
diff --git a/modules/camera/camera_macos.mm b/modules/camera/camera_apple.mm
similarity index 77%
rename from modules/camera/camera_macos.mm
rename to modules/camera/camera_apple.mm
index 7e3b78e2daa..5943bbd686f 100644
--- a/modules/camera/camera_macos.mm
+++ b/modules/camera/camera_apple.mm
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* camera_macos.mm */
+/* camera_apple.mm */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -31,11 +31,14 @@
///@TODO this is a near duplicate of CameraIOS, we should find a way to combine those to minimize code duplication!!!!
// If you fix something here, make sure you fix it there as well!
-#import "camera_macos.h"
+#import "camera_apple.h"
#include "servers/camera/camera_feed.h"
#import
+#ifdef IOS_ENABLED
+#import
+#endif
//////////////////////////////////////////////////////////////////////////
// MyCaptureSession - This is a little helper class so we can capture our frames
@@ -63,23 +66,30 @@ - (id)initForFeed:(Ref)p_feed andDevice:(AVCaptureDevice *)p_device
width[1] = 0;
height[1] = 0;
-#ifdef APPLE_EMBEDDED_ENABLED
- [p_device lockForConfiguration:&error];
-
- [p_device setFocusMode:AVCaptureFocusModeLocked];
- [p_device setExposureMode:AVCaptureExposureModeLocked];
- [p_device setWhiteBalanceMode:AVCaptureWhiteBalanceModeLocked];
+#ifdef IOS_ENABLED
+ if ([p_device lockForConfiguration:&error]) {
+ if ([p_device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {
+ [p_device setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
+ }
+ if ([p_device isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) {
+ [p_device setExposureMode:AVCaptureExposureModeContinuousAutoExposure];
+ }
+ if ([p_device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance]) {
+ [p_device setWhiteBalanceMode:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance];
+ }
- [p_device unlockForConfiguration];
-#endif // APPLE_EMBEDDED_ENABLED
+ [p_device unlockForConfiguration];
+ }
+#endif // IOS_ENABLED
[self beginConfiguration];
-#ifdef APPLE_EMBEDDED_ENABLED
+#ifdef IOS_ENABLED
self.sessionPreset = AVCaptureSessionPreset1280x720;
-#endif // APPLE_EMBEDDED_ENABLED
+#endif // IOS_ENABLED
+
+ input = [[AVCaptureDeviceInput alloc] initWithDevice:p_device error:&error];
- input = [AVCaptureDeviceInput deviceInputWithDevice:p_device error:&error];
if (!input) {
print_line("Couldn't get input device for camera");
[self commitConfiguration];
@@ -219,6 +229,28 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM
// set our texture...
feed->set_ycbcr_images(img[0], img[1]);
+#ifdef IOS_ENABLED
+ UIInterfaceOrientation orientation = [UIApplication sharedApplication].delegate.window.windowScene.interfaceOrientation;
+
+ Transform2D display_transform;
+ switch (orientation) {
+ case UIInterfaceOrientationPortrait: {
+ display_transform = Transform2D(0.0, -1.0, -1.0, 0.0, 1.0, 1.0);
+ } break;
+ case UIInterfaceOrientationLandscapeRight: {
+ display_transform = Transform2D(1.0, 0.0, 0.0, -1.0, 0.0, 1.0);
+ } break;
+ case UIInterfaceOrientationLandscapeLeft: {
+ display_transform = Transform2D(-1.0, 0.0, 0.0, 1.0, 1.0, 0.0);
+ } break;
+ default: {
+ display_transform = Transform2D(0.0, 1.0, 1.0, 0.0, 0.0, 0.0);
+ } break;
+ }
+
+ feed->set_transform(display_transform);
+#endif // IOS_ENABLED
+
// and unlock
CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
}
@@ -226,10 +258,10 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM
@end
//////////////////////////////////////////////////////////////////////////
-// CameraFeedMacOS - Subclass for camera feeds in macOS
+// CameraFeedApple - Subclass for camera feeds in macOS
-class CameraFeedMacOS : public CameraFeed {
- GDSOFTCLASS(CameraFeedMacOS, CameraFeed);
+class CameraFeedApple : public CameraFeed {
+ GDSOFTCLASS(CameraFeedApple, CameraFeed);
private:
AVCaptureDevice *device;
@@ -238,8 +270,8 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM
public:
AVCaptureDevice *get_device() const;
- CameraFeedMacOS();
- ~CameraFeedMacOS();
+ CameraFeedApple();
+ ~CameraFeedApple();
void set_device(AVCaptureDevice *p_device);
@@ -247,22 +279,23 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM
void deactivate_feed() override;
};
-AVCaptureDevice *CameraFeedMacOS::get_device() const {
+AVCaptureDevice *CameraFeedApple::get_device() const {
return device;
}
-CameraFeedMacOS::CameraFeedMacOS() {
+CameraFeedApple::CameraFeedApple() {
device = nullptr;
capture_session = nullptr;
+ transform = Transform2D(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); /* should re-orientate this based on device orientation */
}
-CameraFeedMacOS::~CameraFeedMacOS() {
+CameraFeedApple::~CameraFeedApple() {
if (is_active()) {
deactivate_feed();
}
}
-void CameraFeedMacOS::set_device(AVCaptureDevice *p_device) {
+void CameraFeedApple::set_device(AVCaptureDevice *p_device) {
device = p_device;
// get some info
@@ -276,14 +309,14 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM
};
}
-bool CameraFeedMacOS::activate_feed() {
+bool CameraFeedApple::activate_feed() {
if (capture_session) {
// Already recording.
return true;
}
// Start camera capture, check permission.
- if (@available(macOS 10.14, *)) {
+ if (@available(macOS 10.14, iOS 14.0, visionOS 1.0, *)) {
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if (status == AVAuthorizationStatusAuthorized) {
capture_session = [[MyCaptureSession alloc] initForFeed:this andDevice:device];
@@ -311,7 +344,7 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM
}
}
-void CameraFeedMacOS::deactivate_feed() {
+void CameraFeedApple::deactivate_feed() {
// end camera capture if we have one
if (capture_session) {
[capture_session cleanup];
@@ -324,7 +357,7 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CM
// when devices are connected/disconnected
@interface MyDeviceNotifications : NSObject {
- CameraMacOS *camera_server;
+ CameraApple *camera_server;
}
@end
@@ -335,7 +368,7 @@ - (void)devices_changed:(NSNotification *)notification {
camera_server->update_feeds();
}
-- (id)initForServer:(CameraMacOS *)p_server {
+- (id)initForServer:(CameraApple *)p_server {
if (self = [super init]) {
camera_server = p_server;
@@ -356,13 +389,31 @@ - (void)dealloc {
MyDeviceNotifications *device_notifications = nil;
//////////////////////////////////////////////////////////////////////////
-// CameraMacOS - Subclass for our camera server on macOS
+// CameraApple - Subclass for our camera server on macOS
-void CameraMacOS::update_feeds() {
+void CameraApple::update_feeds() {
NSArray *devices = nullptr;
+#ifdef APPLE_EMBEDDED_ENABLED
+ {
+ NSMutableArray *deviceTypes = [NSMutableArray array];
+ if (@available(iOS 14.0, visionOS 2.1, *)) {
+ [deviceTypes addObject:AVCaptureDeviceTypeBuiltInWideAngleCamera];
+ }
+#ifdef IOS_ENABLED
+ [deviceTypes addObject:AVCaptureDeviceTypeBuiltInTelephotoCamera];
+ [deviceTypes addObject:AVCaptureDeviceTypeBuiltInDualCamera];
+ [deviceTypes addObject:AVCaptureDeviceTypeBuiltInTrueDepthCamera];
+ [deviceTypes addObject:AVCaptureDeviceTypeBuiltInUltraWideCamera];
+ [deviceTypes addObject:AVCaptureDeviceTypeBuiltInDualWideCamera];
+ [deviceTypes addObject:AVCaptureDeviceTypeBuiltInTripleCamera];
+#endif // IOS_ENABLED
+ AVCaptureDeviceDiscoverySession *session = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:deviceTypes mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified];
+ devices = session.devices;
+ }
+#else // APPLE_EMBEDDED_ENABLED
#if defined(__x86_64__)
if (@available(macOS 10.15, *)) {
-#endif
+#endif // __x86_64__
AVCaptureDeviceDiscoverySession *session;
if (@available(macOS 14.0, *)) {
session = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:[NSArray arrayWithObjects:AVCaptureDeviceTypeExternal, AVCaptureDeviceTypeBuiltInWideAngleCamera, AVCaptureDeviceTypeContinuityCamera, nil] mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified];
@@ -374,11 +425,12 @@ - (void)dealloc {
} else {
devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
}
-#endif
+#endif // __x86_64__
+#endif // APPLE_EMBEDDED_ENABLED
// Deactivate feeds that are gone before removing them.
for (int i = feeds.size() - 1; i >= 0; i--) {
- Ref feed = (Ref)feeds[i];
+ Ref feed = (Ref)feeds[i];
if (feed.is_null()) {
continue;
}
@@ -394,7 +446,7 @@ - (void)dealloc {
for (AVCaptureDevice *device in devices) {
bool found = false;
for (int i = 0; i < feeds.size() && !found; i++) {
- Ref feed = (Ref)feeds[i];
+ Ref feed = (Ref)feeds[i];
if (feed.is_null()) {
continue;
}
@@ -404,7 +456,7 @@ - (void)dealloc {
};
if (!found) {
- Ref newfeed;
+ Ref newfeed;
newfeed.instantiate();
newfeed->set_device(device);
@@ -414,7 +466,7 @@ - (void)dealloc {
emit_signal(SNAME(CameraServer::feeds_updated_signal_name));
}
-void CameraMacOS::set_monitoring_feeds(bool p_monitoring_feeds) {
+void CameraApple::set_monitoring_feeds(bool p_monitoring_feeds) {
if (p_monitoring_feeds == monitoring_feeds) {
return;
}
@@ -431,3 +483,14 @@ - (void)dealloc {
device_notifications = nil;
}
}
+
+#ifdef APPLE_EMBEDDED_ENABLED
+
+void register_camera_external_module() {
+ CameraServer::make_default();
+}
+
+void unregister_camera_external_module() {
+}
+
+#endif // APPLE_EMBEDDED_ENABLED
diff --git a/modules/camera/config.py b/modules/camera/config.py
index d699d4e456c..7bcf7655927 100644
--- a/modules/camera/config.py
+++ b/modules/camera/config.py
@@ -3,7 +3,14 @@ def can_build(env, platform):
if sys.platform.startswith("freebsd") or sys.platform.startswith("openbsd"):
return False
- return platform == "macos" or platform == "windows" or platform == "linuxbsd" or platform == "android"
+ return (
+ platform == "macos"
+ or platform == "windows"
+ or platform == "linuxbsd"
+ or platform == "android"
+ or platform == "ios"
+ or platform == "visionos"
+ )
def configure(env):
diff --git a/modules/camera/register_types.cpp b/modules/camera/register_types.cpp
index c56ddfe862e..5f4969de17c 100644
--- a/modules/camera/register_types.cpp
+++ b/modules/camera/register_types.cpp
@@ -37,7 +37,7 @@
#include "camera_win.h"
#endif
#if defined(MACOS_ENABLED)
-#include "camera_macos.h"
+#include "camera_apple.h"
#endif
#if defined(ANDROID_ENABLED)
#include "camera_android.h"
@@ -55,7 +55,7 @@ void initialize_camera_module(ModuleInitializationLevel p_level) {
CameraServer::make_default();
#endif
#if defined(MACOS_ENABLED)
- CameraServer::make_default();
+ CameraServer::make_default();
#endif
#if defined(ANDROID_ENABLED)
CameraServer::make_default();
diff --git a/platform/ios/SCsub b/platform/ios/SCsub
index a313442e2ae..92f6c1714bb 100644
--- a/platform/ios/SCsub
+++ b/platform/ios/SCsub
@@ -22,6 +22,9 @@ ios_lib = env_ios.add_library("ios", ios_lib)
# (iOS) Enable module support
env_ios.Append(CCFLAGS=["-fmodules", "-fcxx-modules"])
+if "LIBS_EXTERNAL" in env_ios:
+ env_ios.Depends(ios_lib, env_ios["LIBS_EXTERNAL"])
+
combine_command = env_ios.CommandNoCache(
"#bin/libgodot" + env_ios["LIBSUFFIX"], [ios_lib] + env_ios["LIBS"], env.Run(combine_libs_apple_embedded)
)
diff --git a/platform/ios/doc_classes/EditorExportPlatformIOS.xml b/platform/ios/doc_classes/EditorExportPlatformIOS.xml
index c9723a52b24..d2be73aea3d 100644
--- a/platform/ios/doc_classes/EditorExportPlatformIOS.xml
+++ b/platform/ios/doc_classes/EditorExportPlatformIOS.xml
@@ -269,6 +269,9 @@
Spotlight icon file on iPad and iPhone (3x DPI), tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+
+ If [code]true[/code], [CameraServer] module is added to the exported project.
+
The reasons your app use active keyboard API. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api]Describing use of required reason API[/url].
diff --git a/platform/visionos/SCsub b/platform/visionos/SCsub
index d3da9bb04a4..8f64654d8bd 100644
--- a/platform/visionos/SCsub
+++ b/platform/visionos/SCsub
@@ -21,6 +21,9 @@ visionos_lib = env_visionos.add_library("visionos", visionos_lib)
# Enable module support
env_visionos.Append(CCFLAGS=["-fmodules", "-fcxx-modules"])
+if "LIBS_EXTERNAL" in env_visionos:
+ env_visionos.Depends(visionos_lib, env_visionos["LIBS_EXTERNAL"])
+
combine_command = env_visionos.Command(
"#bin/libgodot" + env_visionos["LIBSUFFIX"], [visionos_lib] + env_visionos["LIBS"], combine_libs_apple_embedded
)
diff --git a/platform/visionos/doc_classes/EditorExportPlatformVisionOS.xml b/platform/visionos/doc_classes/EditorExportPlatformVisionOS.xml
index 0297bed0576..b61c87cd18f 100644
--- a/platform/visionos/doc_classes/EditorExportPlatformVisionOS.xml
+++ b/platform/visionos/doc_classes/EditorExportPlatformVisionOS.xml
@@ -121,6 +121,9 @@
Base application icon used to generate other icons, tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+
+ If [code]true[/code], [CameraServer] module is added to the exported project.
+
The reasons your app use active keyboard API. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api]Describing use of required reason API[/url].
diff --git a/platform_methods.py b/platform_methods.py
index 2b5aaa61b8f..7a702c08b04 100644
--- a/platform_methods.py
+++ b/platform_methods.py
@@ -172,60 +172,115 @@ def combine_libs_apple_embedded(target, source, env):
)
-def generate_bundle_apple_embedded(platform, framework_dir, framework_dir_sim, use_mkv, target, source, env):
+def lipo_and_copy_apple_embedded(
+ platform, framework_dir, framework_dir_sim, rel_prefix, dbg_prefix, module_prefix, app_dir, 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")
+ rel_target_bin = lipo(bin_dir + "/libgodot" + module_prefix + "." + rel_prefix, extra_suffix + ".a")
+ dbg_target_bin = lipo(bin_dir + "/libgodot" + module_prefix + "." + dbg_prefix, extra_suffix + ".a")
+ rel_target_bin_sim = lipo(
+ bin_dir + "/libgodot" + module_prefix + "." + rel_prefix, ".simulator" + extra_suffix + ".a"
+ )
+ dbg_target_bin_sim = lipo(
+ bin_dir + "/libgodot" + module_prefix + "." + dbg_prefix, ".simulator" + extra_suffix + ".a"
+ )
# Assemble Xcode project bundle.
- app_dir = env.Dir("#bin/" + platform + "_xcode").abspath
- templ = env.Dir("#misc/dist/apple_embedded_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"
+ rel_target_bin,
+ app_dir
+ + "/libgodot"
+ + module_prefix
+ + "."
+ + platform
+ + ".release.xcframework/"
+ + framework_dir
+ + "/libgodot"
+ + module_prefix
+ + ".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"
+ dbg_target_bin,
+ app_dir
+ + "/libgodot"
+ + module_prefix
+ + "."
+ + platform
+ + ".debug.xcframework/"
+ + framework_dir
+ + "/libgodot"
+ + module_prefix
+ + ".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",
+ app_dir
+ + "/libgodot"
+ + module_prefix
+ + "."
+ + platform
+ + ".release.xcframework/"
+ + framework_dir_sim
+ + "/libgodot"
+ + module_prefix
+ + ".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",
+ app_dir
+ + "/libgodot"
+ + module_prefix
+ + "."
+ + platform
+ + ".debug.xcframework/"
+ + framework_dir_sim
+ + "/libgodot"
+ + module_prefix
+ + ".a",
)
+
+def generate_bundle_apple_embedded(platform, framework_dir, framework_dir_sim, use_mkv, target, source, env):
+ # Template bundle.
+ extra_suffix = env.extra_suffix.replace(".simulator", "")
+ app_prefix = "godot." + platform
+ rel_prefix = platform + "." + "template_release"
+ dbg_prefix = 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"
+
+ app_dir = env.Dir("#bin/" + platform + "_xcode").abspath
+ templ = env.Dir("#misc/dist/apple_embedded_xcode").abspath
+ if os.path.exists(app_dir):
+ shutil.rmtree(app_dir)
+ shutil.copytree(templ, app_dir)
+
+ lipo_and_copy_apple_embedded(platform, framework_dir, framework_dir_sim, rel_prefix, dbg_prefix, "", app_dir, env)
+ if "MODULES_EXTERNAL" in env:
+ for mod in env["MODULES_EXTERNAL"]:
+ lipo_and_copy_apple_embedded(
+ platform, framework_dir, framework_dir_sim, rel_prefix, dbg_prefix, mod, app_dir, env
+ )
+
# Remove other platform xcframeworks
for entry in os.listdir(app_dir):
if (entry.startswith("libgodot.") or entry.startswith("libgodot_")) and entry.endswith(".xcframework"):