summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/bind/core_bind.cpp21
-rw-r--r--core/os/os.cpp4
-rw-r--r--core/os/os.h2
-rw-r--r--doc/classes/Directory.xml4
-rw-r--r--doc/classes/HTTPRequest.xml10
-rw-r--r--doc/classes/PackedScene.xml7
-rw-r--r--doc/classes/Resource.xml3
-rw-r--r--doc/classes/Timer.xml1
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.cpp6
-rw-r--r--drivers/png/image_loader_png.cpp5
-rw-r--r--drivers/png/png_driver_common.cpp7
-rw-r--r--drivers/png/png_driver_common.h2
-rw-r--r--editor/project_manager.cpp8
-rw-r--r--main/main.cpp1
-rw-r--r--misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj8
-rw-r--r--misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/Contents.json22
-rw-r--r--misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@2x.pngbin0 -> 21443 bytes
-rw-r--r--misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@3x.pngbin0 -> 21443 bytes
-rw-r--r--misc/dist/ios_xcode/godot_ios/Launch Screen.storyboard41
-rw-r--r--misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist1
-rw-r--r--modules/bullet/bullet_physics_server.cpp7
-rw-r--r--modules/bullet/space_bullet.cpp5
-rw-r--r--platform/iphone/export/export.cpp179
-rw-r--r--platform/osx/display_server_osx.mm4
-rw-r--r--scene/main/window.cpp7
25 files changed, 323 insertions, 32 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index 6df8dd380a..94da74cbda 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -1673,8 +1673,15 @@ int _Directory::get_current_drive() {
}
Error _Directory::change_dir(String p_dir) {
- ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
- return d->change_dir(p_dir);
+ ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory is not configured properly.");
+ Error err = d->change_dir(p_dir);
+
+ if (err != OK) {
+ return err;
+ }
+ dir_open = true;
+
+ return OK;
}
String _Directory::get_current_dir() {
@@ -1705,8 +1712,7 @@ Error _Directory::make_dir_recursive(String p_dir) {
}
bool _Directory::file_exists(String p_file) {
- ERR_FAIL_COND_V_MSG(!is_open(), false, "Directory must be opened before use.");
-
+ ERR_FAIL_COND_V_MSG(!d, false, "Directory is not configured properly.");
if (!p_file.is_rel_path()) {
return FileAccess::exists(p_file);
}
@@ -1715,16 +1721,15 @@ bool _Directory::file_exists(String p_file) {
}
bool _Directory::dir_exists(String p_dir) {
- ERR_FAIL_COND_V_MSG(!is_open(), false, "Directory must be opened before use.");
+ ERR_FAIL_COND_V_MSG(!d, false, "Directory is not configured properly.");
if (!p_dir.is_rel_path()) {
DirAccess *d = DirAccess::create_for_path(p_dir);
bool exists = d->dir_exists(p_dir);
memdelete(d);
return exists;
-
- } else {
- return d->dir_exists(p_dir);
}
+
+ return d->dir_exists(p_dir);
}
int _Directory::get_space_left() {
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 231069fcfb..dc8bd5ee69 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -163,6 +163,10 @@ bool OS::is_stdout_verbose() const {
return _verbose_stdout;
}
+bool OS::is_stdout_debug_enabled() const {
+ return _debug_stdout;
+}
+
void OS::dump_memory_to_file(const char *p_file) {
//Memory::dump_static_mem_to_file(p_file);
}
diff --git a/core/os/os.h b/core/os/os.h
index f21c0d4df7..48dae99188 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -50,6 +50,7 @@ class OS {
bool low_processor_usage_mode = false;
int low_processor_usage_mode_sleep_usec = 10000;
bool _verbose_stdout = false;
+ bool _debug_stdout = false;
String _local_clipboard;
uint64_t _msec_splash;
bool _no_window = false;
@@ -222,6 +223,7 @@ public:
virtual bool is_userfs_persistent() const { return true; }
bool is_stdout_verbose() const;
+ bool is_stdout_debug_enabled() const;
virtual void disable_crash_handler() {}
virtual bool is_disable_crash_handler() const { return false; }
diff --git a/doc/classes/Directory.xml b/doc/classes/Directory.xml
index ed4257a809..a86dbfedde 100644
--- a/doc/classes/Directory.xml
+++ b/doc/classes/Directory.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Directory type. It is used to manage directories and their content (not restricted to the project folder).
- When creating a new [Directory], its default opened directory will be [code]res://[/code]. This may change in the future, so it is advised to always use [method open] to initialize your [Directory] where you want to operate, with explicit error checking.
+ When creating a new [Directory], it must be explicitly opened using [method open] before most methods can be used. However, [method file_exists] and [method dir_exists] can be used without opening a directory. If so, they use a path relative to [code]res://[/code].
Here is an example on how to iterate through the files of a directory:
[codeblock]
func dir_contents(path):
@@ -63,6 +63,7 @@
</argument>
<description>
Returns whether the target directory exists. The argument can be relative to the current directory, or an absolute path.
+ If the [Directory] is not open, the path is relative to [code]res://[/code].
</description>
</method>
<method name="file_exists">
@@ -72,6 +73,7 @@
</argument>
<description>
Returns whether the target file exists. The argument can be relative to the current directory, or an absolute path.
+ If the [Directory] is not open, the path is relative to [code]res://[/code].
</description>
</method>
<method name="get_current_dir">
diff --git a/doc/classes/HTTPRequest.xml b/doc/classes/HTTPRequest.xml
index 53ca1fc6a9..0b0d71fccf 100644
--- a/doc/classes/HTTPRequest.xml
+++ b/doc/classes/HTTPRequest.xml
@@ -14,11 +14,19 @@
add_child(http_request)
http_request.connect("request_completed", self, "_http_request_completed")
- # Perform the HTTP request. The URL below returns some JSON as of writing.
+ # Perform a GET request. The URL below returns JSON as of writing.
var error = http_request.request("https://httpbin.org/get")
if error != OK:
push_error("An error occurred in the HTTP request.")
+ # Perform a POST request. The URL below returns JSON as of writing.
+ # Note: Don't make simultaneous requests using a single HTTPRequest node.
+ # The snippet below is provided for reference only.
+ var body = {"name": "Godette"}
+ var error = http_request.request("https://httpbin.org/post", [], true, HTTPClient.METHOD_POST, body)
+ if error != OK:
+ push_error("An error occurred in the HTTP request.")
+
# Called when the HTTP request is completed.
func _http_request_completed(result, response_code, headers, body):
diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml
index 2d70dea012..bb56330248 100644
--- a/doc/classes/PackedScene.xml
+++ b/doc/classes/PackedScene.xml
@@ -7,6 +7,13 @@
A simplified interface to a scene file. Provides access to operations and checks that can be performed on the scene resource itself.
Can be used to save a node to a file. When saving, the node as well as all the node it owns get saved (see [code]owner[/code] property on [Node]).
[b]Note:[/b] The node doesn't need to own itself.
+ [b]Example of loading a saved scene:[/b]
+ [codeblock]
+ # Use `load()` instead of `preload()` if the path isn't known at compile-time.
+ var scene = preload("res://scene.tscn").instance()
+ # Add the node as a child of the node the script is attached to.
+ add_child(scene)
+ [/codeblock]
[b]Example of saving a node with different owners:[/b] The following example creates 3 objects: [code]Node2D[/code] ([code]node[/code]), [code]RigidBody2D[/code] ([code]rigid[/code]) and [code]CollisionObject2D[/code] ([code]collision[/code]). [code]collision[/code] is a child of [code]rigid[/code] which is a child of [code]node[/code]. Only [code]rigid[/code] is owned by [code]node[/code] and [code]pack[/code] will therefore only save those two nodes, but not [code]collision[/code].
[codeblock]
# Create the objects.
diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml
index 5bc34772c8..0aa40dffb3 100644
--- a/doc/classes/Resource.xml
+++ b/doc/classes/Resource.xml
@@ -23,7 +23,8 @@
<argument index="0" name="subresources" type="bool" default="false">
</argument>
<description>
- Duplicates the resource, returning a new resource. By default, sub-resources are shared between resource copies for efficiency, this can be changed by passing [code]true[/code] to the [code]subresources[/code] argument.
+ Duplicates the resource, returning a new resource. By default, sub-resources are shared between resource copies for efficiency. This can be changed by passing [code]true[/code] to the [code]subresources[/code] argument which will copy the subresources.
+ [b]Note:[/b] If [code]subresources[/code] is [code]true[/code], this method will only perform a shallow copy. Nested resources within subresources will not be duplicated and will still be shared.
</description>
</method>
<method name="get_local_scene" qualifiers="const">
diff --git a/doc/classes/Timer.xml b/doc/classes/Timer.xml
index c1e5987a06..5d684755fa 100644
--- a/doc/classes/Timer.xml
+++ b/doc/classes/Timer.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
Counts down a specified interval and emits a signal on reaching 0. Can be set to repeat or "one-shot" mode.
+ [b]Note:[/b] To create an one-shot timer without instantiating a node, use [method SceneTree.create_timer].
</description>
<tutorials>
</tutorials>
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
index 6eef04b87f..4dd66c06e6 100644
--- a/drivers/gles2/rasterizer_storage_gles2.cpp
+++ b/drivers/gles2/rasterizer_storage_gles2.cpp
@@ -2566,9 +2566,7 @@ Vector<uint8_t> RasterizerStorageGLES2::mesh_surface_get_array(RID p_mesh, int p
ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Vector<uint8_t>());
Surface *surface = mesh->surfaces[p_surface];
-#ifndef TOOLS_ENABLED
- ERR_PRINT("OpenGL ES 2.0 does not allow retrieving mesh array data");
-#endif
+
return surface->data;
}
@@ -2612,7 +2610,7 @@ Vector<Vector<uint8_t>> RasterizerStorageGLES2::mesh_surface_get_blend_shapes(RI
ERR_FAIL_COND_V(!mesh, Vector<Vector<uint8_t>>());
ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Vector<Vector<uint8_t>>());
#ifndef TOOLS_ENABLED
- ERR_PRINT("OpenGL ES 2.0 does not allow retrieving mesh array data");
+ ERR_PRINT("OpenGL ES 2.0 does not allow retrieving blend shape data");
#endif
return mesh->surfaces[p_surface]->blend_shape_data;
diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp
index 8af58a7ed7..79924b849c 100644
--- a/drivers/png/image_loader_png.cpp
+++ b/drivers/png/image_loader_png.cpp
@@ -50,7 +50,7 @@ Error ImageLoaderPNG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
f->close();
}
const uint8_t *reader = file_buffer.ptr();
- return PNGDriverCommon::png_to_image(reader, buffer_size, p_image);
+ return PNGDriverCommon::png_to_image(reader, buffer_size, p_force_linear, p_image);
}
void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const {
@@ -61,7 +61,8 @@ Ref<Image> ImageLoaderPNG::load_mem_png(const uint8_t *p_png, int p_size) {
Ref<Image> img;
img.instance();
- Error err = PNGDriverCommon::png_to_image(p_png, p_size, img);
+ // the value of p_force_linear does not matter since it only applies to 16 bit
+ Error err = PNGDriverCommon::png_to_image(p_png, p_size, false, img);
ERR_FAIL_COND_V(err, Ref<Image>());
return img;
diff --git a/drivers/png/png_driver_common.cpp b/drivers/png/png_driver_common.cpp
index 77d5e68826..d3e187c501 100644
--- a/drivers/png/png_driver_common.cpp
+++ b/drivers/png/png_driver_common.cpp
@@ -58,7 +58,7 @@ static bool check_error(const png_image &image) {
return false;
}
-Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image) {
+Error png_to_image(const uint8_t *p_source, size_t p_size, bool p_force_linear, Ref<Image> p_image) {
png_image png_img;
zeromem(&png_img, sizeof(png_img));
png_img.version = PNG_IMAGE_VERSION;
@@ -99,6 +99,11 @@ Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image) {
return ERR_UNAVAILABLE;
}
+ if (!p_force_linear) {
+ // assume 16 bit pngs without sRGB or gAMA chunks are in sRGB format
+ png_img.flags |= PNG_IMAGE_FLAG_16BIT_sRGB;
+ }
+
const png_uint_32 stride = PNG_IMAGE_ROW_STRIDE(png_img);
Vector<uint8_t> buffer;
Error err = buffer.resize(PNG_IMAGE_BUFFER_SIZE(png_img, stride));
diff --git a/drivers/png/png_driver_common.h b/drivers/png/png_driver_common.h
index 12129f034e..2099ddc536 100644
--- a/drivers/png/png_driver_common.h
+++ b/drivers/png/png_driver_common.h
@@ -36,7 +36,7 @@
namespace PNGDriverCommon {
// Attempt to load png from buffer (p_source, p_size) into p_image
-Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image);
+Error png_to_image(const uint8_t *p_source, size_t p_size, bool p_force_linear, Ref<Image> p_image);
// Append p_image, as a png, to p_buffer.
// Contents of p_buffer is unspecified if error returned.
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 5184793760..1880fd5112 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -2004,6 +2004,14 @@ void ProjectManager::_open_selected_projects() {
args.push_back("--editor");
+ if (OS::get_singleton()->is_stdout_debug_enabled()) {
+ args.push_back("--debug");
+ }
+
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ args.push_back("--verbose");
+ }
+
if (OS::get_singleton()->is_disable_crash_handler()) {
args.push_back("--disable-crash-handler");
}
diff --git a/main/main.cpp b/main/main.cpp
index 4ea11cfaeb..7492d3d6c9 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -836,6 +836,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
} else if (I->get() == "-d" || I->get() == "--debug") {
debug_uri = "local://";
+ OS::get_singleton()->_debug_stdout = true;
#if defined(DEBUG_ENABLED) && !defined(SERVER_ENABLED)
} else if (I->get() == "--debug-collisions") {
debug_collisions = true;
diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
index 8c92ae2a7c..54dda2563d 100644
--- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
+++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
@@ -14,6 +14,7 @@
D07CD44E1C5D589C00B7FB28 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D07CD44D1C5D589C00B7FB28 /* Images.xcassets */; };
D0BCFE4618AEBDA2004A7AAE /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D0BCFE4418AEBDA2004A7AAE /* InfoPlist.strings */; };
D0BCFE7818AEBFEB004A7AAE /* $binary.pck in Resources */ = {isa = PBXBuildFile; fileRef = D0BCFE7718AEBFEB004A7AAE /* $binary.pck */; };
+ $pbx_launch_screen_build_reference
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -41,6 +42,7 @@
D0BCFE4318AEBDA2004A7AAE /* $binary-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "$binary-Info.plist"; sourceTree = "<group>"; };
D0BCFE4518AEBDA2004A7AAE /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
D0BCFE7718AEBFEB004A7AAE /* $binary.pck */ = {isa = PBXFileReference; lastKnownFileType = file; path = "$binary.pck"; sourceTree = "<group>"; };
+ $pbx_launch_screen_file_reference
/* End PBXFileReference section */
$additional_pbx_files
@@ -92,6 +94,7 @@
D0BCFE4118AEBDA2004A7AAE /* $binary */ = {
isa = PBXGroup;
children = (
+ $pbx_launch_screen_copy_files
1FF4C1881F584E6300A41E41 /* $binary.entitlements */,
D07CD44D1C5D589C00B7FB28 /* Images.xcassets */,
D0BCFE4218AEBDA2004A7AAE /* Supporting Files */,
@@ -247,6 +250,7 @@
files = (
D07CD44E1C5D589C00B7FB28 /* Images.xcassets in Resources */,
D0BCFE7818AEBFEB004A7AAE /* $binary.pck in Resources */,
+ $pbx_launch_screen_build_phase
D0BCFE4618AEBDA2004A7AAE /* InfoPlist.strings in Resources */,
$additional_pbx_resources_build
);
@@ -367,7 +371,7 @@
buildSettings = {
ARCHS = "$godot_archs";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ $pbx_launch_image_usage_setting
CODE_SIGN_ENTITLEMENTS = "$binary/$binary.entitlements";
CODE_SIGN_IDENTITY = "$code_sign_identity_debug";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "$code_sign_identity_debug";
@@ -397,7 +401,7 @@
buildSettings = {
ARCHS = "$godot_archs";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ $pbx_launch_image_usage_setting
CODE_SIGN_ENTITLEMENTS = "$binary/$binary.entitlements";
CODE_SIGN_IDENTITY = "$code_sign_identity_release";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "$code_sign_identity_release";
diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/Contents.json b/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/Contents.json
new file mode 100644
index 0000000000..1e63e78eda
--- /dev/null
+++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/Contents.json
@@ -0,0 +1,22 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "splash@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "splash@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@2x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@2x.png
new file mode 100644
index 0000000000..766b0b66ef
--- /dev/null
+++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@2x.png
Binary files differ
diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@3x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@3x.png
new file mode 100644
index 0000000000..766b0b66ef
--- /dev/null
+++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@3x.png
Binary files differ
diff --git a/misc/dist/ios_xcode/godot_ios/Launch Screen.storyboard b/misc/dist/ios_xcode/godot_ios/Launch Screen.storyboard
new file mode 100644
index 0000000000..3a7752a669
--- /dev/null
+++ b/misc/dist/ios_xcode/godot_ios/Launch Screen.storyboard
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
+ <device id="retina6_1" orientation="portrait" appearance="light"/>
+ <dependencies>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <scenes>
+ <!--View Controller-->
+ <scene sceneID="EHf-IW-A2E">
+ <objects>
+ <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+ <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+ <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="$launch_screen_image_mode" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="SplashImage" translatesAutoresizingMaskIntoConstraints="NO" id="tjZ-vn-Lsv">
+ <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
+ </imageView>
+ </subviews>
+ <color key="backgroundColor" $launch_screen_background_color colorSpace="custom" customColorSpace="sRGB"/>
+ <constraints>
+ <constraint firstItem="tjZ-vn-Lsv" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="Ak7-I4-yrQ"/>
+ <constraint firstAttribute="trailing" secondItem="tjZ-vn-Lsv" secondAttribute="trailing" id="Fon-JO-5cz"/>
+ <constraint firstItem="tjZ-vn-Lsv" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="bkx-rj-PKc"/>
+ <constraint firstAttribute="bottom" secondItem="tjZ-vn-Lsv" secondAttribute="bottom" id="yjq-MJ-tym"/>
+ </constraints>
+ <viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
+ </view>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="52.173913043478265" y="375"/>
+ </scene>
+ </scenes>
+ <resources>
+ <image name="SplashImage" width="266.66665649414062" height="200"/>
+ </resources>
+</document>
diff --git a/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist b/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist
index e0cad2e7d1..e9d22f6b4d 100644
--- a/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist
+++ b/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist
@@ -57,5 +57,6 @@
$interface_orientations
</array>
$additional_plist_content
+ $plist_launch_screen_name
</dict>
</plist>
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index bb1678a994..8f64c11867 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -1557,6 +1557,13 @@ void BulletPhysicsServer3D::sync() {
}
void BulletPhysicsServer3D::flush_queries() {
+ if (!active) {
+ return;
+ }
+
+ for (int i = 0; i < active_spaces_count; ++i) {
+ active_spaces[i]->flush_queries();
+ }
}
void BulletPhysicsServer3D::finish() {
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index 8204d7ed20..70e137b16d 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -579,10 +579,6 @@ void SpaceBullet::remove_all_collision_objects() {
}
}
-void onBulletPreTickCallback(btDynamicsWorld *p_dynamicsWorld, btScalar timeStep) {
- static_cast<SpaceBullet *>(p_dynamicsWorld->getWorldUserInfo())->flush_queries();
-}
-
void onBulletTickCallback(btDynamicsWorld *p_dynamicsWorld, btScalar timeStep) {
const btCollisionObjectArray &colObjArray = p_dynamicsWorld->getCollisionObjectArray();
@@ -650,7 +646,6 @@ void SpaceBullet::create_empty_world(bool p_create_soft_world) {
dynamicsWorld->setWorldUserInfo(this);
- dynamicsWorld->setInternalTickCallback(onBulletPreTickCallback, this, true);
dynamicsWorld->setInternalTickCallback(onBulletTickCallback, this, false);
dynamicsWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(ghostPairCallback); // Setup ghost check
dynamicsWorld->getPairCache()->setOverlapFilterCallback(godotFilterCallback);
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
index 289bbdb7f4..038f6e1038 100644
--- a/platform/iphone/export/export.cpp
+++ b/platform/iphone/export/export.cpp
@@ -92,7 +92,8 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
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_screens(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir);
+ Error _export_loading_screen_images(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir);
+ 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();
@@ -255,6 +256,13 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight on devices with retina display
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_launch_screen_storyboard"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "storyboard/image_scale_mode", PROPERTY_HINT_ENUM, "Same as Logo,Center,Scale To Fit,Scale To Fill,Scale"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_custom_bg_color"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "storyboard/custom_bg_color"), Color()));
+
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "launch_screens/generate_missing"), false));
for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) {
@@ -274,6 +282,12 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
"ad-hoc",
"enterprise"
};
+ static const String storyboard_image_scale_mode[] = {
+ "center",
+ "scaleAspectFit",
+ "scaleAspectFill",
+ "scaleToFill"
+ };
String str;
String strnew;
str.parse_utf8((const char *)pfile.ptr(), pfile.size());
@@ -390,6 +404,60 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
} else if (lines[i].find("$photolibrary_usage_description") != -1) {
String description = p_preset->get("privacy/photolibrary_usage_description");
strnew += lines[i].replace("$photolibrary_usage_description", description) + "\n";
+ } else if (lines[i].find("$plist_launch_screen_name") != -1) {
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
+ String value = is_on ? "<key>UILaunchStoryboardName</key>\n<string>Launch Screen</string>" : "";
+ strnew += lines[i].replace("$plist_launch_screen_name", value) + "\n";
+ } else if (lines[i].find("$pbx_launch_screen_file_reference") != -1) {
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
+ String value = is_on ? "90DD2D9D24B36E8000717FE1 = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = \"Launch Screen.storyboard\"; sourceTree = \"<group>\"; };" : "";
+ strnew += lines[i].replace("$pbx_launch_screen_file_reference", value) + "\n";
+ } else if (lines[i].find("$pbx_launch_screen_copy_files") != -1) {
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
+ String value = is_on ? "90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */," : "";
+ strnew += lines[i].replace("$pbx_launch_screen_copy_files", value) + "\n";
+ } else if (lines[i].find("$pbx_launch_screen_build_phase") != -1) {
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
+ String value = is_on ? "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */," : "";
+ strnew += lines[i].replace("$pbx_launch_screen_build_phase", value) + "\n";
+ } else if (lines[i].find("$pbx_launch_screen_build_reference") != -1) {
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
+ String value = is_on ? "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */; };" : "";
+ strnew += lines[i].replace("$pbx_launch_screen_build_reference", value) + "\n";
+ } else if (lines[i].find("$pbx_launch_image_usage_setting") != -1) {
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
+ String value = is_on ? "" : "ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;";
+ strnew += lines[i].replace("$pbx_launch_image_usage_setting", value) + "\n";
+ } else if (lines[i].find("$launch_screen_image_mode") != -1) {
+ int image_scale_mode = p_preset->get("storyboard/image_scale_mode");
+ String value;
+
+ switch (image_scale_mode) {
+ case 0: {
+ String logo_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
+ bool is_on = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize");
+ // If custom logo is not specified, Godot does not scale default one, so we should do the same.
+ value = (is_on && logo_path.length() > 0) ? "scaleAspectFit" : "center";
+ } break;
+ default: {
+ value = storyboard_image_scale_mode[image_scale_mode - 1];
+ }
+ }
+
+ strnew += lines[i].replace("$launch_screen_image_mode", value) + "\n";
+ } else if (lines[i].find("$launch_screen_background_color") != -1) {
+ bool use_custom = p_preset->get("storyboard/use_custom_bg_color");
+ Color color = use_custom ? p_preset->get("storyboard/custom_bg_color") : ProjectSettings::get_singleton()->get("application/boot_splash/bg_color");
+ const String value_format = "red=\"$red\" green=\"$green\" blue=\"$blue\" alpha=\"$alpha\"";
+
+ Dictionary value_dictionary;
+ value_dictionary["red"] = color.r;
+ value_dictionary["green"] = color.g;
+ value_dictionary["blue"] = color.b;
+ value_dictionary["alpha"] = color.a;
+ String value = value_format.format(value_dictionary, "$_");
+
+ strnew += lines[i].replace("$launch_screen_background_color", value) + "\n";
} else {
strnew += lines[i] + "\n";
}
@@ -591,7 +659,75 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr
return OK;
}
-Error EditorExportPlatformIOS::_export_loading_screens(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) {
+Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) {
+ const String custom_launch_image_2x = p_preset->get("storyboard/custom_image@2x");
+ const String custom_launch_image_3x = p_preset->get("storyboard/custom_image@3x");
+
+ if (custom_launch_image_2x.length() > 0 && custom_launch_image_3x.length() > 0) {
+ Ref<Image> image;
+ String image_path = p_dest_dir.plus_file("splash@2x.png");
+ image.instance();
+ Error err = image->load(custom_launch_image_2x);
+
+ if (err) {
+ image.unref();
+ return err;
+ }
+
+ if (image->save_png(image_path) != OK) {
+ return ERR_FILE_CANT_WRITE;
+ }
+
+ image.unref();
+ image_path = p_dest_dir.plus_file("splash@3x.png");
+ image.instance();
+ err = image->load(custom_launch_image_3x);
+
+ if (err) {
+ image.unref();
+ return err;
+ }
+
+ if (image->save_png(image_path) != OK) {
+ return ERR_FILE_CANT_WRITE;
+ }
+ } else {
+ Ref<Image> splash;
+
+ const String splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
+
+ if (!splash_path.empty()) {
+ splash.instance();
+ const Error err = splash->load(splash_path);
+ if (err) {
+ splash.unref();
+ }
+ }
+
+ if (splash.is_null()) {
+ splash = Ref<Image>(memnew(Image(boot_splash_png)));
+ }
+
+ // Using same image for both @2x and @3x
+ // because Godot's own boot logo uses single image for all resolutions.
+ // Also not using @1x image, because devices using this image variant
+ // are not supported by iOS 9, which is minimal target.
+ const String splash_png_path_2x = p_dest_dir.plus_file("splash@2x.png");
+ const String splash_png_path_3x = p_dest_dir.plus_file("splash@3x.png");
+
+ if (splash->save_png(splash_png_path_2x) != OK) {
+ return ERR_FILE_CANT_WRITE;
+ }
+
+ if (splash->save_png(splash_png_path_3x) != OK) {
+ return ERR_FILE_CANT_WRITE;
+ }
+ }
+
+ return OK;
+}
+
+Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) {
DirAccess *da = DirAccess::open(p_dest_dir);
ERR_FAIL_COND_V_MSG(!da, ERR_CANT_OPEN, "Cannot open directory '" + p_dest_dir + "'.");
@@ -1177,6 +1313,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
files_to_parse.insert("godot_ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata");
files_to_parse.insert("godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme");
files_to_parse.insert("godot_ios/godot_ios.entitlements");
+ files_to_parse.insert("godot_ios/Launch Screen.storyboard");
IOSConfigData config_data = {
pkg_name,
@@ -1352,7 +1489,43 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
return err;
}
- err = _export_loading_screens(p_preset, dest_dir + binary_name + "/Images.xcassets/LaunchImage.launchimage/");
+ bool use_storyboard = p_preset->get("storyboard/use_launch_screen_storyboard");
+
+ String launch_image_path = dest_dir + binary_name + "/Images.xcassets/LaunchImage.launchimage/";
+ String splash_image_path = dest_dir + binary_name + "/Images.xcassets/SplashImage.imageset/";
+
+ DirAccess *launch_screen_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+
+ if (!launch_screen_da) {
+ return ERR_CANT_CREATE;
+ }
+
+ if (use_storyboard) {
+ print_line("Using Launch Storyboard");
+
+ if (launch_screen_da->change_dir(launch_image_path) == OK) {
+ launch_screen_da->erase_contents_recursive();
+ launch_screen_da->remove(launch_image_path);
+ }
+
+ err = _export_loading_screen_file(p_preset, splash_image_path);
+ } else {
+ print_line("Using Launch Images");
+
+ const String launch_screen_path = dest_dir + binary_name + "/Launch Screen.storyboard";
+
+ launch_screen_da->remove(launch_screen_path);
+
+ if (launch_screen_da->change_dir(splash_image_path) == OK) {
+ launch_screen_da->erase_contents_recursive();
+ launch_screen_da->remove(splash_image_path);
+ }
+
+ err = _export_loading_screen_images(p_preset, launch_image_path);
+ }
+
+ memdelete(launch_screen_da);
+
if (err) {
return err;
}
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index b7b750a975..07ecd5d2c6 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -2465,7 +2465,7 @@ void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent
wd_window.transient_parent = INVALID_WINDOW_ID;
wd_parent.transient_children.erase(p_window);
- [wd_window.window_object setParentWindow:nil];
+ [wd_parent.window_object removeChildWindow:wd_window.window_object];
} else {
ERR_FAIL_COND(!windows.has(p_parent));
ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent");
@@ -2474,7 +2474,7 @@ void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent
wd_window.transient_parent = p_parent;
wd_parent.transient_children.insert(p_window);
- [wd_window.window_object setParentWindow:wd_parent.window_object];
+ [wd_parent.window_object addChildWindow:wd_window.window_object ordered:NSWindowAbove];
}
}
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index ae30972558..81f33d74fe 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -893,7 +893,12 @@ void Window::_window_input(const Ref<InputEvent> &p_ev) {
}
if (exclusive_child != nullptr) {
- exclusive_child->grab_focus();
+ Window *focus_target = exclusive_child;
+ while (focus_target->exclusive_child != nullptr) {
+ focus_target->grab_focus();
+ focus_target = focus_target->exclusive_child;
+ }
+ focus_target->grab_focus();
if (!is_embedding_subwindows()) { //not embedding, no need for event
return;