summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/SCsub2
-rw-r--r--platform/android/android_keys_utils.h4
-rw-r--r--platform/android/api/java_class_wrapper.h4
-rw-r--r--platform/android/audio_driver_opensl.cpp2
-rw-r--r--platform/android/audio_driver_opensl.h12
-rw-r--r--platform/android/detect.py4
-rw-r--r--platform/android/dir_access_jandroid.cpp4
-rw-r--r--platform/android/display_server_android.cpp77
-rw-r--r--platform/android/display_server_android.h21
-rw-r--r--platform/android/export/export.cpp6
-rw-r--r--platform/android/file_access_android.cpp5
-rw-r--r--platform/android/file_access_android.h9
-rw-r--r--platform/android/file_access_jandroid.cpp197
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java5
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java5
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java5
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java13
-rw-r--r--platform/android/java_godot_lib_jni.cpp10
-rw-r--r--platform/android/java_godot_view_wrapper.cpp66
-rw-r--r--platform/android/java_godot_view_wrapper.h (renamed from platform/android/file_access_jandroid.h)63
-rw-r--r--platform/android/java_godot_wrapper.cpp10
-rw-r--r--platform/android/java_godot_wrapper.h4
-rw-r--r--platform/android/os_android.cpp11
-rw-r--r--platform/iphone/display_server_iphone.h2
-rw-r--r--platform/iphone/display_server_iphone.mm4
-rw-r--r--platform/iphone/export/export.cpp14
-rw-r--r--platform/iphone/os_iphone.h2
-rw-r--r--platform/iphone/os_iphone.mm2
-rw-r--r--platform/javascript/SCsub68
-rw-r--r--platform/javascript/audio_driver_javascript.cpp4
-rw-r--r--platform/javascript/detect.py78
-rw-r--r--platform/javascript/display_server_javascript.cpp4
-rw-r--r--platform/javascript/export/export.cpp125
-rw-r--r--platform/javascript/godot_audio.h4
-rw-r--r--platform/javascript/http_request.h2
-rw-r--r--platform/javascript/javascript_main.cpp2
-rw-r--r--platform/javascript/javascript_runtime.cpp35
-rw-r--r--platform/javascript/js/dynlink.pre.js1
-rw-r--r--platform/javascript/js/engine/engine.js13
-rw-r--r--platform/javascript/js/engine/utils.js2
-rw-r--r--platform/javascript/js/libs/library_godot_audio.js36
-rw-r--r--platform/javascript/js/libs/library_godot_display.js19
-rw-r--r--platform/javascript/js/libs/library_godot_editor_tools.js1
-rw-r--r--platform/javascript/js/libs/library_godot_eval.js1
-rw-r--r--platform/javascript/js/libs/library_godot_http_request.js15
-rw-r--r--platform/javascript/js/libs/library_godot_os.js11
-rw-r--r--platform/javascript/os_javascript.cpp26
-rw-r--r--platform/javascript/os_javascript.h1
-rw-r--r--platform/linuxbsd/detect.py20
-rw-r--r--platform/linuxbsd/detect_prime_x11.cpp2
-rw-r--r--platform/linuxbsd/display_server_x11.cpp356
-rw-r--r--platform/linuxbsd/display_server_x11.h40
-rw-r--r--platform/linuxbsd/joypad_linux.cpp9
-rw-r--r--platform/linuxbsd/joypad_linux.h13
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp146
-rw-r--r--platform/linuxbsd/os_linuxbsd.h2
-rw-r--r--platform/osx/display_server_osx.h14
-rw-r--r--platform/osx/display_server_osx.mm42
-rw-r--r--platform/osx/export/export.cpp37
-rw-r--r--platform/osx/joypad_osx.cpp8
-rw-r--r--platform/osx/joypad_osx.h18
-rw-r--r--platform/osx/os_osx.mm2
-rw-r--r--platform/server/detect.py32
-rw-r--r--platform/server/os_server.cpp12
-rw-r--r--platform/server/os_server.h16
-rw-r--r--platform/uwp/context_egl_uwp.cpp3
-rw-r--r--platform/uwp/export/export.cpp6
-rw-r--r--platform/uwp/joypad_uwp.h21
-rw-r--r--platform/uwp/os_uwp.cpp4
-rw-r--r--platform/uwp/os_uwp.h16
-rw-r--r--platform/windows/context_gl_windows.cpp1
-rw-r--r--platform/windows/crash_handler_windows.cpp2
-rw-r--r--platform/windows/detect.py19
-rw-r--r--platform/windows/display_server_windows.cpp42
-rw-r--r--platform/windows/display_server_windows.h4
-rw-r--r--platform/windows/joypad_windows.cpp2
-rw-r--r--platform/windows/joypad_windows.h20
-rw-r--r--platform/windows/os_windows.cpp16
-rw-r--r--platform/windows/os_windows.h2
79 files changed, 1238 insertions, 700 deletions
diff --git a/platform/android/SCsub b/platform/android/SCsub
index ec42bc42b5..d8013b0baf 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -6,7 +6,6 @@ android_files = [
"os_android.cpp",
"file_access_android.cpp",
"audio_driver_opensl.cpp",
- "file_access_jandroid.cpp",
"dir_access_jandroid.cpp",
"thread_jandroid.cpp",
"net_socket_android.cpp",
@@ -14,6 +13,7 @@ android_files = [
"java_godot_lib_jni.cpp",
"java_class_wrapper.cpp",
"java_godot_wrapper.cpp",
+ "java_godot_view_wrapper.cpp",
"java_godot_io_wrapper.cpp",
"jni_utils.cpp",
"android_keys_utils.cpp",
diff --git a/platform/android/android_keys_utils.h b/platform/android/android_keys_utils.h
index a10afa1df8..4a34e77324 100644
--- a/platform/android/android_keys_utils.h
+++ b/platform/android/android_keys_utils.h
@@ -35,8 +35,8 @@
#include <core/os/keyboard.h>
struct _WinTranslatePair {
- unsigned int keysym;
- unsigned int keycode;
+ unsigned int keysym = 0;
+ unsigned int keycode = 0;
};
static _WinTranslatePair _ak_to_keycode[] = {
diff --git a/platform/android/api/java_class_wrapper.h b/platform/android/api/java_class_wrapper.h
index 64da049407..63d71f5cf1 100644
--- a/platform/android/api/java_class_wrapper.h
+++ b/platform/android/api/java_class_wrapper.h
@@ -66,10 +66,10 @@ class JavaClass : public Reference {
Map<StringName, Variant> constant_map;
struct MethodInfo {
- bool _static;
+ bool _static = false;
Vector<uint32_t> param_types;
Vector<StringName> param_sigs;
- uint32_t return_type;
+ uint32_t return_type = 0;
jmethodID method;
};
diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp
index 740e9a3132..e96e80e967 100644
--- a/platform/android/audio_driver_opensl.cpp
+++ b/platform/android/audio_driver_opensl.cpp
@@ -339,6 +339,4 @@ void AudioDriverOpenSL::set_pause(bool p_pause) {
AudioDriverOpenSL::AudioDriverOpenSL() {
s_ad = this;
- pause = false;
- active = false;
}
diff --git a/platform/android/audio_driver_opensl.h b/platform/android/audio_driver_opensl.h
index b30711705b..999cbe4657 100644
--- a/platform/android/audio_driver_opensl.h
+++ b/platform/android/audio_driver_opensl.h
@@ -38,19 +38,19 @@
#include <SLES/OpenSLES_Android.h>
class AudioDriverOpenSL : public AudioDriver {
- bool active;
+ bool active = false;
Mutex mutex;
enum {
BUFFER_COUNT = 2
};
- bool pause;
+ bool pause = false;
- uint32_t buffer_size;
- int16_t *buffers[BUFFER_COUNT];
- int32_t *mixdown_buffer;
- int last_free;
+ uint32_t buffer_size = 0;
+ int16_t *buffers[BUFFER_COUNT] = {};
+ int32_t *mixdown_buffer = nullptr;
+ int last_free = 0;
Vector<int16_t> rec_buffer;
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 0accacb679..650606ff8b 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -215,7 +215,7 @@ def configure(env):
env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++abi/include"])
# Disable exceptions and rtti on non-tools (template) builds
- if env["tools"]:
+ if env["tools"] or env["builtin_icu"]:
env.Append(CXXFLAGS=["-frtti"])
else:
env.Append(CXXFLAGS=["-fno-rtti", "-fno-exceptions"])
@@ -334,6 +334,6 @@ def get_ndk_version(path):
key_value = list(map(lambda x: x.strip(), line.split("=")))
if key_value[0] == "Pkg.Revision":
return key_value[1]
- except:
+ except Exception:
print("Could not read source prop file '%s'" % prop_file_path)
return None
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
index ba75a4b10c..ac619973d2 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -30,7 +30,7 @@
#include "dir_access_jandroid.h"
#include "core/string/print_string.h"
-#include "file_access_jandroid.h"
+#include "file_access_android.h"
#include "string_android.h"
#include "thread_jandroid.h"
@@ -146,7 +146,7 @@ bool DirAccessJAndroid::file_exists(String p_file) {
else
sd = current_dir.plus_file(p_file);
- FileAccessJAndroid *f = memnew(FileAccessJAndroid);
+ FileAccessAndroid *f = memnew(FileAccessAndroid);
bool exists = f->file_exists(sd);
memdelete(f);
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index e82a12ece5..8711a4333c 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -41,7 +41,7 @@
#if defined(VULKAN_ENABLED)
#include "drivers/vulkan/rendering_device_vulkan.h"
#include "platform/android/vulkan/vulkan_context_android.h"
-#include "servers/rendering/rasterizer_rd/rasterizer_rd.h"
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#endif
DisplayServerAndroid *DisplayServerAndroid::get_singleton() {
@@ -447,7 +447,7 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
rendering_device_vulkan = memnew(RenderingDeviceVulkan);
rendering_device_vulkan->initialize(context_vulkan);
- RasterizerRD::make_current();
+ RendererCompositorRD::make_current();
}
#endif
@@ -498,9 +498,28 @@ void DisplayServerAndroid::_set_key_modifier_state(Ref<InputEventWithModifiers>
}
void DisplayServerAndroid::process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed) {
+ static char32_t prev_wc = 0;
+ char32_t unicode = p_unicode_char;
+ if ((p_unicode_char & 0xfffffc00) == 0xd800) {
+ if (prev_wc != 0) {
+ ERR_PRINT("invalid utf16 surrogate input");
+ }
+ prev_wc = unicode;
+ return; // Skip surrogate.
+ } else if ((unicode & 0xfffffc00) == 0xdc00) {
+ if (prev_wc == 0) {
+ ERR_PRINT("invalid utf16 surrogate input");
+ return; // Skip invalid surrogate.
+ }
+ unicode = (prev_wc << 10UL) + unicode - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
+ prev_wc = 0;
+ } else {
+ prev_wc = 0;
+ }
+
Ref<InputEventKey> ev;
ev.instance();
- int val = p_unicode_char;
+ int val = unicode;
int keycode = android_get_keysym(p_keycode);
int phy_keycode = android_get_keysym(p_scancode);
@@ -667,7 +686,7 @@ void DisplayServerAndroid::process_hover(int p_type, Point2 p_pos) {
}
}
-void DisplayServerAndroid::process_mouse_event(int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor, float event_horizontal_factor) {
+void DisplayServerAndroid::process_mouse_event(int input_device, int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor, float event_horizontal_factor) {
int event_buttons_mask = _android_button_mask_to_godot_button_mask(event_android_buttons_mask);
switch (event_action) {
case AMOTION_EVENT_ACTION_BUTTON_PRESS:
@@ -675,8 +694,13 @@ void DisplayServerAndroid::process_mouse_event(int event_action, int event_andro
Ref<InputEventMouseButton> ev;
ev.instance();
_set_key_modifier_state(ev);
- ev->set_position(event_pos);
- ev->set_global_position(event_pos);
+ if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) {
+ ev->set_position(event_pos);
+ ev->set_global_position(event_pos);
+ } else {
+ ev->set_position(hover_prev_pos);
+ ev->set_global_position(hover_prev_pos);
+ }
ev->set_pressed(event_action == AMOTION_EVENT_ACTION_BUTTON_PRESS);
int changed_button_mask = buttons_state ^ event_buttons_mask;
@@ -691,18 +715,29 @@ void DisplayServerAndroid::process_mouse_event(int event_action, int event_andro
Ref<InputEventMouseMotion> ev;
ev.instance();
_set_key_modifier_state(ev);
- ev->set_position(event_pos);
- ev->set_global_position(event_pos);
- ev->set_relative(event_pos - hover_prev_pos);
+ if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) {
+ ev->set_position(event_pos);
+ ev->set_global_position(event_pos);
+ ev->set_relative(event_pos - hover_prev_pos);
+ hover_prev_pos = event_pos;
+ } else {
+ ev->set_position(hover_prev_pos);
+ ev->set_global_position(hover_prev_pos);
+ ev->set_relative(event_pos);
+ }
ev->set_button_mask(event_buttons_mask);
Input::get_singleton()->accumulate_input_event(ev);
- hover_prev_pos = event_pos;
} break;
case AMOTION_EVENT_ACTION_SCROLL: {
Ref<InputEventMouseButton> ev;
ev.instance();
- ev->set_position(event_pos);
- ev->set_global_position(event_pos);
+ if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) {
+ ev->set_position(event_pos);
+ ev->set_global_position(event_pos);
+ } else {
+ ev->set_position(hover_prev_pos);
+ ev->set_global_position(hover_prev_pos);
+ }
ev->set_pressed(true);
buttons_state = event_buttons_mask;
if (event_vertical_factor > 0) {
@@ -790,6 +825,24 @@ void DisplayServerAndroid::process_gyroscope(const Vector3 &p_gyroscope) {
Input::get_singleton()->set_gyroscope(p_gyroscope);
}
+void DisplayServerAndroid::mouse_set_mode(MouseMode p_mode) {
+ if (mouse_mode == p_mode) {
+ return;
+ }
+
+ if (p_mode == MouseMode::MOUSE_MODE_CAPTURED) {
+ OS_Android::get_singleton()->get_godot_java()->get_godot_view()->request_pointer_capture();
+ } else {
+ OS_Android::get_singleton()->get_godot_java()->get_godot_view()->release_pointer_capture();
+ }
+
+ mouse_mode = p_mode;
+}
+
+DisplayServer::MouseMode DisplayServerAndroid::mouse_get_mode() const {
+ return mouse_mode;
+}
+
Point2i DisplayServerAndroid::mouse_get_position() const {
return hover_prev_pos;
}
diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h
index aa5a2c1185..f1f1a6a278 100644
--- a/platform/android/display_server_android.h
+++ b/platform/android/display_server_android.h
@@ -41,7 +41,7 @@ class RenderingDeviceVulkan;
class DisplayServerAndroid : public DisplayServer {
public:
struct TouchPos {
- int id;
+ int id = 0;
Point2 pos;
};
@@ -52,12 +52,12 @@ public:
};
struct JoypadEvent {
- int device;
- int type;
- int index;
- bool pressed;
- float value;
- int hat;
+ int device = 0;
+ int type = 0;
+ int index = 0;
+ bool pressed = false;
+ float value = 0;
+ int hat = 0;
};
private:
@@ -70,6 +70,8 @@ private:
int buttons_state;
+ MouseMode mouse_mode;
+
bool keep_screen_on;
Vector<TouchPos> touch;
@@ -172,12 +174,15 @@ public:
void process_gyroscope(const Vector3 &p_gyroscope);
void process_touch(int p_event, int p_pointer, const Vector<TouchPos> &p_points);
void process_hover(int p_type, Point2 p_pos);
- void process_mouse_event(int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor = 0, float event_horizontal_factor = 0);
+ void process_mouse_event(int input_device, int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor = 0, float event_horizontal_factor = 0);
void process_double_tap(int event_android_button_mask, Point2 p_pos);
void process_scroll(Point2 p_pos);
void process_joy_event(JoypadEvent p_event);
void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed);
+ void mouse_set_mode(MouseMode p_mode);
+ MouseMode mouse_get_mode() const;
+
static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
static Vector<String> get_rendering_drivers_func();
static void register_android_driver();
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index d24c96f87a..eed3b226c8 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -205,7 +205,7 @@ static const char *SPLASH_BG_COLOR_PATH = "res/drawable/splash_bg_color.png";
struct LauncherIcon {
const char *export_path;
- int dimensions;
+ int dimensions = 0;
};
static const int icon_densities_count = 6;
@@ -250,12 +250,12 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
String id;
String name;
String description;
- int api_level;
+ int api_level = 0;
};
struct APKExportData {
zipFile apk;
- EditorProgress *ep;
+ EditorProgress *ep = nullptr;
};
Vector<PluginConfig> plugins;
diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp
index 2446ca2829..0d933fb858 100644
--- a/platform/android/file_access_android.cpp
+++ b/platform/android/file_access_android.cpp
@@ -157,11 +157,6 @@ bool FileAccessAndroid::file_exists(const String &p_path) {
return true;
}
-FileAccessAndroid::FileAccessAndroid() {
- a = nullptr;
- eof = false;
-}
-
FileAccessAndroid::~FileAccessAndroid() {
close();
}
diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h
index a347c63ffb..7fc7d8c83d 100644
--- a/platform/android/file_access_android.h
+++ b/platform/android/file_access_android.h
@@ -39,10 +39,10 @@
class FileAccessAndroid : public FileAccess {
static FileAccess *create_android();
- mutable AAsset *a;
- mutable size_t len;
- mutable size_t pos;
- mutable bool eof;
+ mutable AAsset *a = nullptr;
+ mutable size_t len = 0;
+ mutable size_t pos = 0;
+ mutable bool eof = false;
public:
static AAssetManager *asset_manager;
@@ -74,7 +74,6 @@ public:
//static void make_default();
- FileAccessAndroid();
~FileAccessAndroid();
};
diff --git a/platform/android/file_access_jandroid.cpp b/platform/android/file_access_jandroid.cpp
deleted file mode 100644
index df8b57fd3a..0000000000
--- a/platform/android/file_access_jandroid.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/*************************************************************************/
-/* file_access_jandroid.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "file_access_jandroid.h"
-#include "core/os/os.h"
-#include "thread_jandroid.h"
-#include <unistd.h>
-
-jobject FileAccessJAndroid::io = nullptr;
-jclass FileAccessJAndroid::cls;
-jmethodID FileAccessJAndroid::_file_open = 0;
-jmethodID FileAccessJAndroid::_file_get_size = 0;
-jmethodID FileAccessJAndroid::_file_seek = 0;
-jmethodID FileAccessJAndroid::_file_read = 0;
-jmethodID FileAccessJAndroid::_file_tell = 0;
-jmethodID FileAccessJAndroid::_file_eof = 0;
-jmethodID FileAccessJAndroid::_file_close = 0;
-
-FileAccess *FileAccessJAndroid::create_jandroid() {
- return memnew(FileAccessJAndroid);
-}
-
-Error FileAccessJAndroid::_open(const String &p_path, int p_mode_flags) {
- if (is_open())
- close();
-
- String path = fix_path(p_path).simplify_path();
- if (path.begins_with("/"))
- path = path.substr(1, path.length());
- else if (path.begins_with("res://"))
- path = path.substr(6, path.length());
-
- JNIEnv *env = ThreadAndroid::get_env();
-
- jstring js = env->NewStringUTF(path.utf8().get_data());
- int res = env->CallIntMethod(io, _file_open, js, (p_mode_flags & WRITE) ? true : false);
- env->DeleteLocalRef(js);
-
- OS::get_singleton()->print("fopen: '%s' ret %i\n", path.utf8().get_data(), res);
-
- if (res <= 0)
- return ERR_FILE_CANT_OPEN;
- id = res;
-
- return OK;
-}
-
-void FileAccessJAndroid::close() {
- if (!is_open())
- return;
-
- JNIEnv *env = ThreadAndroid::get_env();
-
- env->CallVoidMethod(io, _file_close, id);
- id = 0;
-}
-
-bool FileAccessJAndroid::is_open() const {
- return id != 0;
-}
-
-void FileAccessJAndroid::seek(size_t p_position) {
- JNIEnv *env = ThreadAndroid::get_env();
-
- ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use.");
- env->CallVoidMethod(io, _file_seek, id, p_position);
-}
-
-void FileAccessJAndroid::seek_end(int64_t p_position) {
- ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use.");
-
- seek(get_len());
-}
-
-size_t FileAccessJAndroid::get_position() const {
- JNIEnv *env = ThreadAndroid::get_env();
- ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");
- return env->CallIntMethod(io, _file_tell, id);
-}
-
-size_t FileAccessJAndroid::get_len() const {
- JNIEnv *env = ThreadAndroid::get_env();
- ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");
- return env->CallIntMethod(io, _file_get_size, id);
-}
-
-bool FileAccessJAndroid::eof_reached() const {
- JNIEnv *env = ThreadAndroid::get_env();
- ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");
- return env->CallIntMethod(io, _file_eof, id);
-}
-
-uint8_t FileAccessJAndroid::get_8() const {
- ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");
- uint8_t byte;
- get_buffer(&byte, 1);
- return byte;
-}
-
-int FileAccessJAndroid::get_buffer(uint8_t *p_dst, int p_length) const {
- ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");
- if (p_length == 0)
- return 0;
- JNIEnv *env = ThreadAndroid::get_env();
-
- jbyteArray jca = (jbyteArray)env->CallObjectMethod(io, _file_read, id, p_length);
-
- int len = env->GetArrayLength(jca);
- env->GetByteArrayRegion(jca, 0, len, (jbyte *)p_dst);
- env->DeleteLocalRef((jobject)jca);
-
- return len;
-}
-
-Error FileAccessJAndroid::get_error() const {
- if (eof_reached())
- return ERR_FILE_EOF;
- return OK;
-}
-
-void FileAccessJAndroid::flush() {
-}
-
-void FileAccessJAndroid::store_8(uint8_t p_dest) {
-}
-
-bool FileAccessJAndroid::file_exists(const String &p_path) {
- JNIEnv *env = ThreadAndroid::get_env();
-
- String path = fix_path(p_path).simplify_path();
- if (path.begins_with("/"))
- path = path.substr(1, path.length());
- else if (path.begins_with("res://"))
- path = path.substr(6, path.length());
-
- jstring js = env->NewStringUTF(path.utf8().get_data());
- int res = env->CallIntMethod(io, _file_open, js, false);
- if (res <= 0) {
- env->DeleteLocalRef(js);
- return false;
- }
- env->CallVoidMethod(io, _file_close, res);
- env->DeleteLocalRef(js);
- return true;
-}
-
-void FileAccessJAndroid::setup(jobject p_io) {
- io = p_io;
- JNIEnv *env = ThreadAndroid::get_env();
-
- jclass c = env->GetObjectClass(io);
- cls = (jclass)env->NewGlobalRef(c);
-
- _file_open = env->GetMethodID(cls, "file_open", "(Ljava/lang/String;Z)I");
- _file_get_size = env->GetMethodID(cls, "file_get_size", "(I)I");
- _file_tell = env->GetMethodID(cls, "file_tell", "(I)I");
- _file_eof = env->GetMethodID(cls, "file_eof", "(I)Z");
- _file_seek = env->GetMethodID(cls, "file_seek", "(II)V");
- _file_read = env->GetMethodID(cls, "file_read", "(II)[B");
- _file_close = env->GetMethodID(cls, "file_close", "(I)V");
-}
-
-FileAccessJAndroid::FileAccessJAndroid() {
- id = 0;
-}
-
-FileAccessJAndroid::~FileAccessJAndroid() {
- if (is_open())
- close();
-}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index 3bbe35091c..ad1dc53bc0 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -988,4 +988,9 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
public void initInputDevices() {
mRenderView.initInputDevices();
}
+
+ @Keep
+ private GodotRenderView getRenderView() { // used by native side to get renderView
+ return mRenderView;
+ }
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
index d731e080c4..2cd67933ee 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
@@ -144,6 +144,11 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
return inputHandler.onGenericMotionEvent(event) || super.onGenericMotionEvent(event);
}
+ @Override
+ public boolean onCapturedPointerEvent(MotionEvent event) {
+ return inputHandler.onGenericMotionEvent(event);
+ }
+
private void init(XRMode xrMode, boolean translucent, int depth, int stencil) {
setPreserveEGLContextOnPause(true);
setFocusableInTouchMode(true);
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
index 6cd5ca7b4e..d5e0345a9c 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
@@ -120,6 +120,11 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
}
@Override
+ public boolean onCapturedPointerEvent(MotionEvent event) {
+ return mInputHandler.onGenericMotionEvent(event);
+ }
+
+ @Override
public void onResume() {
super.onResume();
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index f3e985f944..b052cd9d92 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
@@ -181,6 +181,7 @@ public class GodotInputHandler implements InputDeviceListener {
arr[i * 3 + 2] = event.getY(i);
}
final int action = event.getActionMasked();
+ final int pointer_idx = event.getPointerId(event.getActionIndex());
mRenderView.queueOnRenderThread(new Runnable() {
@Override
@@ -189,12 +190,9 @@ public class GodotInputHandler implements InputDeviceListener {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_MOVE: {
- GodotLib.touch(event.getSource(), action, 0, evcount, arr);
- } break;
+ case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_DOWN: {
- int pointer_idx = event.getPointerId(event.getActionIndex());
GodotLib.touch(event.getSource(), action, pointer_idx, evcount, arr);
} break;
}
@@ -247,7 +245,7 @@ public class GodotInputHandler implements InputDeviceListener {
}
});
return true;
- } else if ((event.getSource() & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
+ } else if (event.isFromSource(InputDevice.SOURCE_MOUSE) || event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return handleMouseEvent(event);
}
@@ -464,6 +462,11 @@ public class GodotInputHandler implements InputDeviceListener {
}
});
}
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_UP: {
+ // we can safely ignore these cases because they are always come beside ACTION_BUTTON_PRESS and ACTION_BUTTON_RELEASE
+ return true;
+ }
}
return false;
}
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 5dc773fae2..48b8171222 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -43,7 +43,6 @@
#include "dir_access_jandroid.h"
#include "display_server_android.h"
#include "file_access_android.h"
-#include "file_access_jandroid.h"
#include "jni_utils.h"
#include "main/main.h"
#include "net_socket_android.h"
@@ -89,14 +88,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
godot_io_java = new GodotIOJavaWrapper(env, godot_java->get_member_object("io", "Lorg/godotengine/godot/GodotIO;", env));
ThreadAndroid::make_default(jvm);
-#ifdef USE_JAVA_FILE_ACCESS
- FileAccessJAndroid::setup(godot_io_java->get_instance());
-#else
jobject amgr = env->NewGlobalRef(p_asset_manager);
FileAccessAndroid::asset_manager = AAssetManager_fromJava(env, amgr);
-#endif
DirAccessJAndroid::setup(godot_io_java->get_instance());
AudioDriverAndroid::setup(godot_io_java->get_instance());
@@ -251,9 +246,8 @@ void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev,
tp.id = (int)p[0];
points.push_back(tp);
}
-
- if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) {
- DisplayServerAndroid::get_singleton()->process_mouse_event(ev, buttons_mask, points[0].pos, vertical_factor, horizontal_factor);
+ if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE || (input_device & AINPUT_SOURCE_MOUSE_RELATIVE) == AINPUT_SOURCE_MOUSE_RELATIVE) {
+ DisplayServerAndroid::get_singleton()->process_mouse_event(input_device, ev, buttons_mask, points[0].pos, vertical_factor, horizontal_factor);
} else {
DisplayServerAndroid::get_singleton()->process_touch(ev, pointer, points);
}
diff --git a/platform/android/java_godot_view_wrapper.cpp b/platform/android/java_godot_view_wrapper.cpp
new file mode 100644
index 0000000000..6655dd9895
--- /dev/null
+++ b/platform/android/java_godot_view_wrapper.cpp
@@ -0,0 +1,66 @@
+/*************************************************************************/
+/* java_godot_view_wrapper.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "java_godot_view_wrapper.h"
+
+#include "thread_jandroid.h"
+
+GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) {
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ _godot_view = env->NewGlobalRef(godot_view);
+
+ _cls = (jclass)env->NewGlobalRef(env->GetObjectClass(godot_view));
+
+ if (android_get_device_api_level() >= __ANDROID_API_O__) {
+ _request_pointer_capture = env->GetMethodID(_cls, "requestPointerCapture", "()V");
+ _release_pointer_capture = env->GetMethodID(_cls, "releasePointerCapture", "()V");
+ }
+}
+
+void GodotJavaViewWrapper::request_pointer_capture() {
+ if (_request_pointer_capture != 0) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ env->CallVoidMethod(_godot_view, _request_pointer_capture);
+ }
+}
+
+void GodotJavaViewWrapper::release_pointer_capture() {
+ if (_request_pointer_capture != 0) {
+ JNIEnv *env = ThreadAndroid::get_env();
+ env->CallVoidMethod(_godot_view, _release_pointer_capture);
+ }
+}
+
+GodotJavaViewWrapper::~GodotJavaViewWrapper() {
+ JNIEnv *env = ThreadAndroid::get_env();
+ env->DeleteGlobalRef(_godot_view);
+ env->DeleteGlobalRef(_cls);
+}
diff --git a/platform/android/file_access_jandroid.h b/platform/android/java_godot_view_wrapper.h
index e252a4d3ac..4c8f6edad0 100644
--- a/platform/android/file_access_jandroid.h
+++ b/platform/android/java_godot_view_wrapper.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* file_access_jandroid.h */
+/* java_godot_view_wrapper.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,56 +28,29 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef FILE_ACCESS_JANDROID_H
-#define FILE_ACCESS_JANDROID_H
+#ifndef GODOT_JAVA_GODOT_VIEW_WRAPPER_H
+#define GODOT_JAVA_GODOT_VIEW_WRAPPER_H
-#include "core/os/file_access.h"
-#include "java_godot_lib_jni.h"
-class FileAccessJAndroid : public FileAccess {
- static jobject io;
- static jclass cls;
+#include <android/log.h>
+#include <jni.h>
- static jmethodID _file_open;
- static jmethodID _file_get_size;
- static jmethodID _file_seek;
- static jmethodID _file_tell;
- static jmethodID _file_eof;
- static jmethodID _file_read;
- static jmethodID _file_close;
+// Class that makes functions in java/src/org/godotengine/godot/GodotView.java callable from C++
+class GodotJavaViewWrapper {
+private:
+ jclass _cls;
- int id;
- static FileAccess *create_jandroid();
+ jobject _godot_view;
-public:
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual void close(); ///< close a file
- virtual bool is_open() const; ///< true when file is open
-
- virtual void seek(size_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual size_t get_position() const; ///< get position in the file
- virtual size_t get_len() const; ///< get size of the file
-
- virtual bool eof_reached() const; ///< reading passed EOF
-
- virtual uint8_t get_8() const; ///< get a byte
- virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+ jmethodID _request_pointer_capture = 0;
+ jmethodID _release_pointer_capture = 0;
- virtual Error get_error() const; ///< get last error
-
- virtual void flush();
- virtual void store_8(uint8_t p_dest); ///< store a byte
-
- virtual bool file_exists(const String &p_path); ///< return true if a file exists
-
- static void setup(jobject p_io);
+public:
+ GodotJavaViewWrapper(jobject godot_view);
- virtual uint64_t _get_modified_time(const String &p_file) { return 0; }
- virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
+ void request_pointer_capture();
+ void release_pointer_capture();
- FileAccessJAndroid();
- ~FileAccessJAndroid();
+ ~GodotJavaViewWrapper();
};
-#endif // FILE_ACCESS_JANDROID_H
+#endif //GODOT_JAVA_GODOT_VIEW_WRAPPER_H
diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp
index cff591d903..7919e47b5c 100644
--- a/platform/android/java_godot_wrapper.cpp
+++ b/platform/android/java_godot_wrapper.cpp
@@ -109,6 +109,16 @@ jobject GodotJavaWrapper::get_class_loader() {
}
}
+GodotJavaViewWrapper *GodotJavaWrapper::get_godot_view() {
+ if (_godot_view != nullptr) {
+ return _godot_view;
+ }
+ JNIEnv *env = ThreadAndroid::get_env();
+ jmethodID godot_view_getter = env->GetMethodID(godot_class, "getRenderView", "()Lorg/godotengine/godot/GodotRenderView;");
+ _godot_view = new GodotJavaViewWrapper(env->CallObjectMethod(godot_instance, godot_view_getter));
+ return _godot_view;
+}
+
void GodotJavaWrapper::on_video_init(JNIEnv *p_env) {
if (_on_video_init)
if (p_env == nullptr)
diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h
index e0c3809a64..c212e107cb 100644
--- a/platform/android/java_godot_wrapper.h
+++ b/platform/android/java_godot_wrapper.h
@@ -37,6 +37,7 @@
#include <android/log.h>
#include <jni.h>
+#include "java_godot_view_wrapper.h"
#include "string_android.h"
// Class that makes functions in java/src/org/godotengine/godot/Godot.java callable from C++
@@ -47,6 +48,8 @@ private:
jclass godot_class;
jclass activity_class;
+ GodotJavaViewWrapper *_godot_view = nullptr;
+
jmethodID _on_video_init = 0;
jmethodID _restart = 0;
jmethodID _finish = 0;
@@ -74,6 +77,7 @@ public:
jobject get_member_object(const char *p_name, const char *p_class, JNIEnv *p_env = nullptr);
jobject get_class_loader();
+ GodotJavaViewWrapper *get_godot_view();
void on_video_init(JNIEnv *p_env = nullptr);
void on_godot_main_loop_started(JNIEnv *p_env = nullptr);
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 00733f6dbb..b90fb3ce6e 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -31,15 +31,13 @@
#include "os_android.h"
#include "core/config/project_settings.h"
-#include "core/io/file_access_buffered_fa.h"
#include "drivers/unix/dir_access_unix.h"
#include "drivers/unix/file_access_unix.h"
-#include "file_access_android.h"
#include "main/main.h"
#include "platform/android/display_server_android.h"
#include "dir_access_jandroid.h"
-#include "file_access_jandroid.h"
+#include "file_access_android.h"
#include "net_socket_android.h"
#include <dlfcn.h>
@@ -62,16 +60,10 @@ void OS_Android::initialize_core() {
if (use_apk_expansion)
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES);
else {
-#ifdef USE_JAVA_FILE_ACCESS
- FileAccess::make_default<FileAccessBufferedFA<FileAccessJAndroid>>(FileAccess::ACCESS_RESOURCES);
-#else
- //FileAccess::make_default<FileAccessBufferedFA<FileAccessAndroid> >(FileAccess::ACCESS_RESOURCES);
FileAccess::make_default<FileAccessAndroid>(FileAccess::ACCESS_RESOURCES);
-#endif
}
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA);
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM);
- //FileAccessBufferedFA<FileAccessUnix>::make_default();
if (use_apk_expansion)
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_RESOURCES);
else
@@ -314,6 +306,7 @@ OS_Android::OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_god
#if defined(OPENGL_ENABLED)
gl_extensions = nullptr;
use_gl2 = false;
+ use_16bits_fbo = false;
#endif
#if defined(VULKAN_ENABLED)
diff --git a/platform/iphone/display_server_iphone.h b/platform/iphone/display_server_iphone.h
index 229b1e80db..2d77e9adff 100644
--- a/platform/iphone/display_server_iphone.h
+++ b/platform/iphone/display_server_iphone.h
@@ -36,7 +36,7 @@
#if defined(VULKAN_ENABLED)
#include "drivers/vulkan/rendering_device_vulkan.h"
-#include "servers/rendering/rasterizer_rd/rasterizer_rd.h"
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "vulkan_context_iphone.h"
diff --git a/platform/iphone/display_server_iphone.mm b/platform/iphone/display_server_iphone.mm
index d47d131719..e8abf1e3fa 100644
--- a/platform/iphone/display_server_iphone.mm
+++ b/platform/iphone/display_server_iphone.mm
@@ -73,7 +73,7 @@ DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, Displ
// return ERR_UNAVAILABLE;
}
- // rendering_server = memnew(RenderingServerRaster);
+ // rendering_server = memnew(RenderingServerDefault);
// // FIXME: Reimplement threaded rendering
// if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
// rendering_server = memnew(RenderingServerWrapMT(rendering_server,
@@ -118,7 +118,7 @@ DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, Displ
rendering_device_vulkan = memnew(RenderingDeviceVulkan);
rendering_device_vulkan->initialize(context_vulkan);
- RasterizerRD::make_current();
+ RendererCompositorRD::make_current();
}
#endif
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
index fff82c9467..3406c75c35 100644
--- a/platform/iphone/export/export.cpp
+++ b/platform/iphone/export/export.cpp
@@ -94,8 +94,8 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
struct IOSExportAsset {
String exported_path;
- bool is_framework; // framework is anything linked to the binary, otherwise it's a resource
- bool should_embed;
+ 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();
@@ -314,9 +314,9 @@ Vector<EditorExportPlatformIOS::ExportArchitecture> EditorExportPlatformIOS::_ge
struct LoadingScreenInfo {
const char *preset_key;
const char *export_name;
- int width;
- int height;
- bool rotate;
+ int width = 0;
+ int height = 0;
+ bool rotate = false;
};
static const LoadingScreenInfo loading_screen_infos[] = {
@@ -667,7 +667,7 @@ struct IconInfo {
const char *actual_size_side;
const char *scale;
const char *unscaled_size;
- bool is_required;
+ bool is_required = false;
};
static const IconInfo icon_infos[] = {
@@ -962,7 +962,7 @@ Error EditorExportPlatformIOS::_walk_dir_recursive(DirAccess *p_da, FileHandler
struct CodesignData {
const Ref<EditorExportPreset> &preset;
- bool debug;
+ bool debug = false;
CodesignData(const Ref<EditorExportPreset> &p_preset, bool p_debug) :
preset(p_preset),
diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h
index 04a0a478d5..e98f870ba9 100644
--- a/platform/iphone/os_iphone.h
+++ b/platform/iphone/os_iphone.h
@@ -38,7 +38,7 @@
#include "ios.h"
#include "joypad_iphone.h"
#include "servers/audio_server.h"
-#include "servers/rendering/rasterizer.h"
+#include "servers/rendering/renderer_compositor.h"
#if defined(VULKAN_ENABLED)
#include "drivers/vulkan/rendering_device_vulkan.h"
diff --git a/platform/iphone/os_iphone.mm b/platform/iphone/os_iphone.mm
index b87e6f37a0..dac61f2d9d 100644
--- a/platform/iphone/os_iphone.mm
+++ b/platform/iphone/os_iphone.mm
@@ -47,7 +47,7 @@
#import <dlfcn.h>
#if defined(VULKAN_ENABLED)
-#include "servers/rendering/rasterizer_rd/rasterizer_rd.h"
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#import <QuartzCore/CAMetalLayer.h>
#include <vulkan/vulkan_metal.h>
#endif
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index 627ae778b1..7a8005fe30 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -12,13 +12,8 @@ javascript_files = [
"api/javascript_tools_editor_plugin.cpp",
]
-build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
-if env["threads_enabled"]:
- build_targets.append("#bin/godot${PROGSUFFIX}.worker.js")
-
-build = env.add_program(build_targets, javascript_files)
-
-env.AddJSLibraries(
+sys_env = env.Clone()
+sys_env.AddJSLibraries(
[
"js/libs/library_godot_audio.js",
"js/libs/library_godot_display.js",
@@ -29,12 +24,48 @@ env.AddJSLibraries(
)
if env["tools"]:
- env.AddJSLibraries(["js/libs/library_godot_editor_tools.js"])
+ sys_env.AddJSLibraries(["js/libs/library_godot_editor_tools.js"])
if env["javascript_eval"]:
- env.AddJSLibraries(["js/libs/library_godot_eval.js"])
-for lib in env["JS_LIBS"]:
- env.Append(LINKFLAGS=["--js-library", lib])
-env.Depends(build, env["JS_LIBS"])
+ sys_env.AddJSLibraries(["js/libs/library_godot_eval.js"])
+for lib in sys_env["JS_LIBS"]:
+ sys_env.Append(LINKFLAGS=["--js-library", lib])
+
+build = []
+if env["gdnative_enabled"]:
+ build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
+ # Reset libraries. The main runtime will only link emscripten libraries, not godot ones.
+ sys_env["LIBS"] = []
+ # We use IDBFS. Since Emscripten 1.39.1 it needs to be linked explicitly.
+ sys_env.Append(LIBS=["idbfs.js"])
+ # JS prepended to the module code loading the side library.
+ sys_env.Append(LINKFLAGS=["--pre-js", sys_env.File("js/dynlink.pre.js")])
+ # Configure it as a main module (dynamic linking support).
+ sys_env.Append(CCFLAGS=["-s", "MAIN_MODULE=1"])
+ sys_env.Append(LINKFLAGS=["-s", "MAIN_MODULE=1"])
+ sys_env.Append(CCFLAGS=["-s", "EXPORT_ALL=1"])
+ sys_env.Append(LINKFLAGS=["-s", "EXPORT_ALL=1"])
+ # Force exporting the standard library (printf, malloc, etc.)
+ sys_env["ENV"]["EMCC_FORCE_STDLIBS"] = "libc,libc++,libc++abi"
+ # The main emscripten runtime, with exported standard libraries.
+ sys = sys_env.Program(build_targets, ["javascript_runtime.cpp"])
+ sys_env.Depends(sys, "js/dynlink.pre.js")
+
+ # The side library, containing all Godot code.
+ wasm_env = env.Clone()
+ wasm_env.Append(CPPDEFINES=["WASM_GDNATIVE"]) # So that OS knows it can run GDNative libraries.
+ wasm_env.Append(CCFLAGS=["-s", "SIDE_MODULE=2"])
+ wasm_env.Append(LINKFLAGS=["-s", "SIDE_MODULE=2"])
+ wasm = wasm_env.add_program("#bin/godot.side${PROGSUFFIX}.wasm", javascript_files)
+ build = [sys[0], sys[1], wasm[0]]
+else:
+ build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
+ if env["threads_enabled"]:
+ build_targets.append("#bin/godot${PROGSUFFIX}.worker.js")
+ # We use IDBFS. Since Emscripten 1.39.1 it needs to be linked explicitly.
+ sys_env.Append(LIBS=["idbfs.js"])
+ build = sys_env.Program(build_targets, javascript_files + ["javascript_runtime.cpp"])
+
+sys_env.Depends(build[0], sys_env["JS_LIBS"])
engine = [
"js/engine/preloader.js",
@@ -61,10 +92,19 @@ out_files = [
]
html_file = "#misc/dist/html/editor.html" if env["tools"] else "#misc/dist/html/full-size.html"
in_files = [js_wrapped, build[1], html_file, "#platform/javascript/js/libs/audio.worklet.js"]
-if env["threads_enabled"]:
- in_files.append(build[2])
+if env["gdnative_enabled"]:
+ in_files.append(build[2]) # Runtime
+ out_files.append(zip_dir.File(binary_name + ".side.wasm"))
+elif env["threads_enabled"]:
+ in_files.append(build[2]) # Worker
out_files.append(zip_dir.File(binary_name + ".worker.js"))
+if env["tools"]:
+ in_files.append("#misc/dist/html/logo.svg")
+ out_files.append(zip_dir.File("logo.svg"))
+ in_files.append("#icon.png")
+ out_files.append(zip_dir.File("favicon.png"))
+
zip_files = env.InstallAs(out_files, in_files)
env.Zip(
"#bin/godot",
diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp
index dd982bc3a8..78fbed6d0f 100644
--- a/platform/javascript/audio_driver_javascript.cpp
+++ b/platform/javascript/audio_driver_javascript.cpp
@@ -189,7 +189,9 @@ Error AudioDriverJavaScript::capture_start() {
lock();
input_buffer_init(buffer_length);
unlock();
- godot_audio_capture_start();
+ if (godot_audio_capture_start()) {
+ return FAILED;
+ }
return OK;
}
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 71189cf697..d53c774e77 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -1,6 +1,8 @@
import os
+import sys
from emscripten_helpers import run_closure_compiler, create_engine_file, add_js_libraries
+from methods import get_compiler_version
from SCons.Util import WhereIs
@@ -20,9 +22,17 @@ def get_opts():
from SCons.Variables import BoolVariable
return [
+ ("initial_memory", "Initial WASM memory (in MiB)", 16),
+ BoolVariable("use_assertions", "Use Emscripten runtime assertions", False),
+ BoolVariable("use_thinlto", "Use ThinLTO", False),
+ BoolVariable("use_ubsan", "Use Emscripten undefined behavior sanitizer (UBSAN)", False),
+ BoolVariable("use_asan", "Use Emscripten address sanitizer (ASAN)", False),
+ BoolVariable("use_lsan", "Use Emscripten leak sanitizer (LSAN)", False),
+ BoolVariable("use_safe_heap", "Use Emscripten SAFE_HEAP sanitizer", False),
# eval() can be a security concern, so it can be disabled.
BoolVariable("javascript_eval", "Enable JavaScript eval interface", True),
BoolVariable("threads_enabled", "Enable WebAssembly Threads support (limited browser support)", False),
+ BoolVariable("gdnative_enabled", "Enable WebAssembly GDNative support (produces bigger binaries)", False),
BoolVariable("use_closure_compiler", "Use closure compiler to minimize JavaScript code", False),
]
@@ -40,6 +50,9 @@ def get_flags():
def configure(env):
+ if not isinstance(env["initial_memory"], int):
+ print("Initial memory must be a valid integer")
+ sys.exit(255)
## Build type
@@ -62,15 +75,20 @@ def configure(env):
env.Append(CPPDEFINES=["DEBUG_ENABLED"])
env.Append(CCFLAGS=["-O1", "-g"])
env.Append(LINKFLAGS=["-O1", "-g"])
+ env["use_assertions"] = True
+
+ if env["use_assertions"]:
env.Append(LINKFLAGS=["-s", "ASSERTIONS=1"])
if env["tools"]:
if not env["threads_enabled"]:
- raise RuntimeError(
- "Threads must be enabled to build the editor. Please add the 'threads_enabled=yes' option"
- )
- # Tools need more memory. Initial stack memory in bytes. See `src/settings.js` in emscripten repository (will be renamed to INITIAL_MEMORY).
- env.Append(LINKFLAGS=["-s", "TOTAL_MEMORY=33554432"])
+ print("Threads must be enabled to build the editor. Please add the 'threads_enabled=yes' option")
+ sys.exit(255)
+ if env["initial_memory"] < 32:
+ print("Editor build requires at least 32MiB of initial memory. Forcing it.")
+ env["initial_memory"] = 32
+ elif env["builtin_icu"]:
+ env.Append(CCFLAGS=["-frtti"])
else:
# Disable exceptions and rtti on non-tools (template) builds
# These flags help keep the file size down.
@@ -78,15 +96,32 @@ def configure(env):
# Don't use dynamic_cast, necessary with no-rtti.
env.Append(CPPDEFINES=["NO_SAFE_CAST"])
+ env.Append(LINKFLAGS=["-s", "INITIAL_MEMORY=%sMB" % env["initial_memory"]])
+
## Copy env variables.
env["ENV"] = os.environ
# LTO
- if env["use_lto"]:
- env.Append(CCFLAGS=["-s", "WASM_OBJECT_FILES=0"])
- env.Append(LINKFLAGS=["-s", "WASM_OBJECT_FILES=0"])
- env.Append(CCFLAGS=["-flto"])
- env.Append(LINKFLAGS=["-flto"])
+ if env["use_thinlto"]:
+ env.Append(CCFLAGS=["-flto=thin"])
+ env.Append(LINKFLAGS=["-flto=thin"])
+ elif env["use_lto"]:
+ env.Append(CCFLAGS=["-flto=full"])
+ env.Append(LINKFLAGS=["-flto=full"])
+
+ # Sanitizers
+ if env["use_ubsan"]:
+ env.Append(CCFLAGS=["-fsanitize=undefined"])
+ env.Append(LINKFLAGS=["-fsanitize=undefined"])
+ if env["use_asan"]:
+ env.Append(CCFLAGS=["-fsanitize=address"])
+ env.Append(LINKFLAGS=["-fsanitize=address"])
+ if env["use_lsan"]:
+ env.Append(CCFLAGS=["-fsanitize=leak"])
+ env.Append(LINKFLAGS=["-fsanitize=leak"])
+ if env["use_safe_heap"]:
+ env.Append(CCFLAGS=["-s", "SAFE_HEAP=1"])
+ env.Append(LINKFLAGS=["-s", "SAFE_HEAP=1"])
# Closure compiler
if env["use_closure_compiler"]:
@@ -133,6 +168,10 @@ def configure(env):
if env["javascript_eval"]:
env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"])
+ if env["threads_enabled"] and env["gdnative_enabled"]:
+ print("Threads and GDNative support can't be both enabled due to WebAssembly limitations")
+ sys.exit(255)
+
# Thread support (via SharedArrayBuffer).
if env["threads_enabled"]:
env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"])
@@ -144,14 +183,19 @@ def configure(env):
else:
env.Append(CPPDEFINES=["NO_THREADS"])
+ if env["gdnative_enabled"]:
+ major, minor, patch = get_compiler_version(env)
+ if major < 2 or (major == 2 and minor == 0 and patch < 10):
+ print("GDNative support requires emscripten >= 2.0.10, detected: %s.%s.%s" % (major, minor, patch))
+ sys.exit(255)
+ env.Append(CCFLAGS=["-s", "RELOCATABLE=1"])
+ env.Append(LINKFLAGS=["-s", "RELOCATABLE=1"])
+ env.extra_suffix = ".gdnative" + env.extra_suffix
+
# Reduce code size by generating less support code (e.g. skip NodeJS support).
env.Append(LINKFLAGS=["-s", "ENVIRONMENT=web,worker"])
- # We use IDBFS in javascript_main.cpp. Since Emscripten 1.39.1 it needs to
- # be linked explicitly.
- env.Append(LIBS=["idbfs.js"])
-
- env.Append(LINKFLAGS=["-s", "BINARYEN=1"])
+ # Wrap the JavaScript support code around a closure named Godot.
env.Append(LINKFLAGS=["-s", "MODULARIZE=1", "-s", "EXPORT_NAME='Godot'"])
# Allow increasing memory buffer size during runtime. This is efficient
@@ -162,12 +206,14 @@ def configure(env):
# This setting just makes WebGL 2 APIs available, it does NOT disable WebGL 1.
env.Append(LINKFLAGS=["-s", "USE_WEBGL2=1"])
+ # Do not call main immediately when the support code is ready.
env.Append(LINKFLAGS=["-s", "INVOKE_RUN=0"])
# Allow use to take control of swapping WebGL buffers.
env.Append(LINKFLAGS=["-s", "OFFSCREEN_FRAMEBUFFER=1"])
- # callMain for manual start, FS for preloading, PATH and ERRNO_CODES for BrowserFS.
+ # callMain for manual start.
env.Append(LINKFLAGS=["-s", "EXTRA_EXPORTED_RUNTIME_METHODS=['callMain']"])
+
# Add code that allow exiting runtime.
env.Append(LINKFLAGS=["-s", "EXIT_RUNTIME=1"])
diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp
index af8800d565..92e13553fc 100644
--- a/platform/javascript/display_server_javascript.cpp
+++ b/platform/javascript/display_server_javascript.cpp
@@ -948,8 +948,8 @@ void DisplayServerJavaScript::window_set_size(const Size2i p_size, WindowID p_wi
last_width = p_size.x;
last_height = p_size.y;
double scale = godot_js_display_pixel_ratio_get();
- emscripten_set_canvas_element_size(canvas_id, p_size.x * scale, p_size.y * scale);
- emscripten_set_element_css_size(canvas_id, p_size.x, p_size.y);
+ emscripten_set_canvas_element_size(canvas_id, p_size.x, p_size.y);
+ emscripten_set_element_css_size(canvas_id, p_size.x / scale, p_size.y / scale);
}
Size2i DisplayServerJavaScript::window_get_size(WindowID p_window) const {
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index c3b7e0304e..37681b2484 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -37,16 +37,13 @@
#include "platform/javascript/logo.gen.h"
#include "platform/javascript/run_icon.gen.h"
-#define EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE "webassembly_release.zip"
-#define EXPORT_TEMPLATE_WEBASSEMBLY_DEBUG "webassembly_debug.zip"
-
class EditorHTTPServer : public Reference {
private:
Ref<TCP_Server> server;
Ref<StreamPeerTCP> connection;
- uint64_t time;
+ uint64_t time = 0;
uint8_t req_buf[4096];
- int req_pos;
+ int req_pos = 0;
void _clear_client() {
connection = Ref<StreamPeerTCP>();
@@ -85,36 +82,44 @@ public:
// Wrong protocol
ERR_FAIL_COND_MSG(req[0] != "GET" || req[2] != "HTTP/1.1", "Invalid method or HTTP version.");
- String filepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_js_export");
+ const String cache_path = EditorSettings::get_singleton()->get_cache_dir();
const String basereq = "/tmp_js_export";
- String ctype = "";
+ String filepath;
+ String ctype;
if (req[1] == basereq + ".html") {
- filepath += ".html";
+ filepath = cache_path.plus_file(req[1].get_file());
ctype = "text/html";
} else if (req[1] == basereq + ".js") {
- filepath += ".js";
+ filepath = cache_path.plus_file(req[1].get_file());
ctype = "application/javascript";
} else if (req[1] == basereq + ".audio.worklet.js") {
- filepath += ".audio.worklet.js";
+ filepath = cache_path.plus_file(req[1].get_file());
ctype = "application/javascript";
} else if (req[1] == basereq + ".worker.js") {
- filepath += ".worker.js";
+ filepath = cache_path.plus_file(req[1].get_file());
ctype = "application/javascript";
} else if (req[1] == basereq + ".pck") {
- filepath += ".pck";
+ filepath = cache_path.plus_file(req[1].get_file());
ctype = "application/octet-stream";
} else if (req[1] == basereq + ".png" || req[1] == "/favicon.png") {
// Also allow serving the generated favicon for a smoother loading experience.
if (req[1] == "/favicon.png") {
filepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("favicon.png");
} else {
- filepath += ".png";
+ filepath = basereq + ".png";
}
ctype = "image/png";
+ } else if (req[1] == basereq + ".side.wasm") {
+ filepath = cache_path.plus_file(req[1].get_file());
+ ctype = "application/wasm";
} else if (req[1] == basereq + ".wasm") {
- filepath += ".wasm";
+ filepath = cache_path.plus_file(req[1].get_file());
ctype = "application/wasm";
- } else {
+ } else if (req[1].ends_with(".wasm")) {
+ filepath = cache_path.plus_file(req[1].get_file()); // TODO dangerous?
+ ctype = "application/wasm";
+ }
+ if (filepath.empty() || !FileAccess::exists(filepath)) {
String s = "HTTP/1.1 404 Not Found\r\n";
s += "Connection: Close\r\n";
s += "\r\n";
@@ -203,15 +208,40 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform {
Ref<ImageTexture> logo;
Ref<ImageTexture> run_icon;
Ref<ImageTexture> stop_icon;
- int menu_options;
-
- void _fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags);
+ int menu_options = 0;
-private:
Ref<EditorHTTPServer> server;
- bool server_quit;
+ bool server_quit = false;
Mutex server_lock;
- Thread *server_thread;
+ Thread *server_thread = nullptr;
+
+ enum ExportMode {
+ EXPORT_MODE_NORMAL = 0,
+ EXPORT_MODE_THREADS = 1,
+ EXPORT_MODE_GDNATIVE = 2,
+ };
+
+ String _get_template_name(ExportMode p_mode, bool p_debug) const {
+ String name = "webassembly";
+ switch (p_mode) {
+ case EXPORT_MODE_THREADS:
+ name += "_threads";
+ break;
+ case EXPORT_MODE_GDNATIVE:
+ name += "_gdnative";
+ break;
+ default:
+ break;
+ }
+ if (p_debug) {
+ name += "_debug.zip";
+ } else {
+ name += "_release.zip";
+ }
+ return name;
+ }
+
+ void _fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects);
static void _server_thread_poll(void *data);
@@ -250,7 +280,7 @@ public:
~EditorExportPlatformJavaScript();
};
-void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags) {
+void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects) {
String str_template = String::utf8(reinterpret_cast<const char *>(p_html.ptr()), p_html.size());
String str_export;
Vector<String> lines = str_template.split("\n");
@@ -258,6 +288,10 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re
String flags_json;
gen_export_flags(flags, p_flags);
flags_json = JSON::print(flags);
+ String libs;
+ for (int i = 0; i < p_shared_objects.size(); i++) {
+ libs += "\"" + p_shared_objects[i].path.get_file() + "\",";
+ }
for (int i = 0; i < lines.size(); i++) {
String current_line = lines[i];
@@ -265,6 +299,7 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re
current_line = current_line.replace("$GODOT_PROJECT_NAME", ProjectSettings::get_singleton()->get_setting("application/config/name"));
current_line = current_line.replace("$GODOT_HEAD_INCLUDE", p_preset->get("html/head_include"));
current_line = current_line.replace("$GODOT_FULL_WINDOW", p_preset->get("html/full_window_size") ? "true" : "false");
+ current_line = current_line.replace("$GODOT_GDNATIVE_LIBS", libs);
current_line = current_line.replace("$GODOT_DEBUG_ENABLED", p_debug ? "true" : "false");
current_line = current_line.replace("$GODOT_ARGS", flags_json);
str_export += current_line + "\n";
@@ -291,12 +326,19 @@ void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportP
r_features->push_back("etc2");
}
}
+ ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
+ if (mode == EXPORT_MODE_THREADS) {
+ r_features->push_back("threads");
+ } else if (mode == EXPORT_MODE_GDNATIVE) {
+ r_features->push_back("wasm32");
+ }
}
void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_options) {
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "variant/export_type", PROPERTY_HINT_ENUM, "Regular,Threads,GDNative"), 0)); // Export type.
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_desktop"), true)); // S3TC
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_mobile"), false)); // ETC or ETC2, depending on renderer
@@ -320,11 +362,11 @@ Ref<Texture2D> EditorExportPlatformJavaScript::get_logo() const {
bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
String err;
bool valid = false;
+ ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
// Look for export templates (first official, and if defined custom templates).
-
- bool dvalid = exists_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_DEBUG, &err);
- bool rvalid = exists_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE, &err);
+ bool dvalid = exists_export_template(_get_template_name(mode, true), &err);
+ bool rvalid = exists_export_template(_get_template_name(mode, false), &err);
if (p_preset->get("custom_template/debug") != "") {
dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
@@ -377,11 +419,8 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
template_path = template_path.strip_edges();
if (template_path == String()) {
- if (p_debug) {
- template_path = find_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_DEBUG);
- } else {
- template_path = find_export_template(EXPORT_TEMPLATE_WEBASSEMBLY_RELEASE);
- }
+ ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
+ template_path = find_export_template(_get_template_name(mode, p_debug));
}
if (!DirAccess::exists(p_path.get_base_dir())) {
@@ -393,12 +432,24 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
return ERR_FILE_NOT_FOUND;
}
+ Vector<SharedObject> shared_objects;
String pck_path = p_path.get_basename() + ".pck";
- Error error = save_pack(p_preset, pck_path);
+ Error error = save_pack(p_preset, pck_path, &shared_objects);
if (error != OK) {
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + pck_path);
return error;
}
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ for (int i = 0; i < shared_objects.size(); i++) {
+ String dst = p_path.get_base_dir().plus_file(shared_objects[i].path.get_file());
+ error = da->copy(shared_objects[i].path, dst);
+ if (error != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + shared_objects[i].path.get_file());
+ memdelete(da);
+ return error;
+ }
+ }
+ memdelete(da);
FileAccess *src_f = nullptr;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
@@ -437,14 +488,18 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
if (!custom_html.empty()) {
continue;
}
- _fix_html(data, p_preset, p_path.get_file().get_basename(), p_debug, p_flags);
+ _fix_html(data, p_preset, p_path.get_file().get_basename(), p_debug, p_flags, shared_objects);
file = p_path.get_file();
} else if (file == "godot.js") {
file = p_path.get_file().get_basename() + ".js";
+
} else if (file == "godot.worker.js") {
file = p_path.get_file().get_basename() + ".worker.js";
+ } else if (file == "godot.side.wasm") {
+ file = p_path.get_file().get_basename() + ".side.wasm";
+
} else if (file == "godot.audio.worklet.js") {
file = p_path.get_file().get_basename() + ".audio.worklet.js";
@@ -475,7 +530,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
buf.resize(f->get_len());
f->get_buffer(buf.ptrw(), buf.size());
memdelete(f);
- _fix_html(buf, p_preset, p_path.get_file().get_basename(), p_debug, p_flags);
+ _fix_html(buf, p_preset, p_path.get_file().get_basename(), p_debug, p_flags, shared_objects);
f = FileAccess::open(p_path, FileAccess::WRITE);
if (!f) {
@@ -577,6 +632,7 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
DirAccess::remove_file_or_error(basepath + ".audio.worklet.js");
DirAccess::remove_file_or_error(basepath + ".pck");
DirAccess::remove_file_or_error(basepath + ".png");
+ DirAccess::remove_file_or_error(basepath + ".side.wasm");
DirAccess::remove_file_or_error(basepath + ".wasm");
DirAccess::remove_file_or_error(EditorSettings::get_singleton()->get_cache_dir().plus_file("favicon.png"));
return err;
@@ -625,7 +681,6 @@ void EditorExportPlatformJavaScript::_server_thread_poll(void *data) {
EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() {
server.instance();
- server_quit = false;
server_thread = Thread::create(_server_thread_poll, this);
Ref<Image> img = memnew(Image(_javascript_logo));
@@ -642,8 +697,6 @@ EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() {
} else {
stop_icon.instance();
}
-
- menu_options = 0;
}
EditorExportPlatformJavaScript::~EditorExportPlatformJavaScript() {
diff --git a/platform/javascript/godot_audio.h b/platform/javascript/godot_audio.h
index 7ebda3ad39..aeb234269e 100644
--- a/platform/javascript/godot_audio.h
+++ b/platform/javascript/godot_audio.h
@@ -41,14 +41,14 @@ extern int godot_audio_is_available();
extern int godot_audio_init(int p_mix_rate, int p_latency, void (*_state_cb)(int), void (*_latency_cb)(float));
extern void godot_audio_resume();
-extern void godot_audio_capture_start();
+extern int godot_audio_capture_start();
extern void godot_audio_capture_stop();
// Worklet
typedef int32_t GodotAudioState[4];
extern void godot_audio_worklet_create(int p_channels);
extern void godot_audio_worklet_start(float *p_in_buf, int p_in_size, float *p_out_buf, int p_out_size, GodotAudioState p_state);
-extern void godot_audio_worklet_state_add(GodotAudioState p_state, int p_idx, int p_value);
+extern int godot_audio_worklet_state_add(GodotAudioState p_state, int p_idx, int p_value);
extern int godot_audio_worklet_state_get(GodotAudioState p_state, int p_idx);
extern int godot_audio_worklet_state_wait(int32_t *p_state, int p_idx, int32_t p_expected, int p_timeout);
diff --git a/platform/javascript/http_request.h b/platform/javascript/http_request.h
index 54e98c1927..41e4749216 100644
--- a/platform/javascript/http_request.h
+++ b/platform/javascript/http_request.h
@@ -47,7 +47,7 @@ typedef enum {
extern int godot_xhr_new();
extern void godot_xhr_reset(int p_xhr_id);
-extern bool godot_xhr_free(int p_xhr_id);
+extern void godot_xhr_free(int p_xhr_id);
extern int godot_xhr_open(int p_xhr_id, const char *p_method, const char *p_url, const char *p_user = nullptr, const char *p_password = nullptr);
diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp
index 2d28a63566..b4985a4f36 100644
--- a/platform/javascript/javascript_main.cpp
+++ b/platform/javascript/javascript_main.cpp
@@ -75,7 +75,7 @@ void main_loop_callback() {
}
/// When calling main, it is assumed FS is setup and synced.
-int main(int argc, char *argv[]) {
+extern EMSCRIPTEN_KEEPALIVE int godot_js_main(int argc, char *argv[]) {
os = new OS_JavaScript();
// We must override main when testing is enabled
diff --git a/platform/javascript/javascript_runtime.cpp b/platform/javascript/javascript_runtime.cpp
new file mode 100644
index 0000000000..bfe9fbd1bc
--- /dev/null
+++ b/platform/javascript/javascript_runtime.cpp
@@ -0,0 +1,35 @@
+/*************************************************************************/
+/* javascript_runtime.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+extern int godot_js_main(int argc, char *argv[]);
+
+int main(int argc, char *argv[]) {
+ return godot_js_main(argc, argv);
+}
diff --git a/platform/javascript/js/dynlink.pre.js b/platform/javascript/js/dynlink.pre.js
new file mode 100644
index 0000000000..34bc371ea9
--- /dev/null
+++ b/platform/javascript/js/dynlink.pre.js
@@ -0,0 +1 @@
+Module['dynamicLibraries'] = [Module['thisProgram'] + '.side.wasm'].concat(Module['dynamicLibraries'] ? Module['dynamicLibraries'] : []);
diff --git a/platform/javascript/js/engine/engine.js b/platform/javascript/js/engine/engine.js
index 74153b672a..4b8a7dde69 100644
--- a/platform/javascript/js/engine/engine.js
+++ b/platform/javascript/js/engine/engine.js
@@ -34,6 +34,7 @@ const Engine = (function () {
this.onExecute = null;
this.onExit = null;
this.persistentPaths = ['/userfs'];
+ this.gdnativeLibs = [];
}
Engine.prototype.init = /** @param {string=} basePath */ function (basePath) {
@@ -58,6 +59,10 @@ const Engine = (function () {
initPromise = new Promise(function (resolve, reject) {
config['locateFile'] = Utils.createLocateRewrite(loadPath);
config['instantiateWasm'] = Utils.createInstantiatePromise(loadPromise);
+ // Emscripten configuration.
+ config['thisProgram'] = me.executableName;
+ config['noExitRuntime'] = true;
+ config['dynamicLibraries'] = me.gdnativeLibs;
Godot(config).then(function (module) {
module['initFS'](me.persistentPaths).then(function (fs_err) {
me.rtenv = module;
@@ -119,9 +124,6 @@ const Engine = (function () {
locale = navigator.languages ? navigator.languages[0] : navigator.language;
locale = locale.split('.')[0];
}
- // Emscripten configuration.
- me.rtenv['thisProgram'] = me.executableName;
- me.rtenv['noExitRuntime'] = true;
// Godot configuration.
me.rtenv['initConfig']({
'resizeCanvasOnStart': me.resizeCanvasOnStart,
@@ -249,6 +251,10 @@ const Engine = (function () {
this.persistentPaths = persistentPaths;
};
+ Engine.prototype.setGDNativeLibraries = function (gdnativeLibs) {
+ this.gdnativeLibs = gdnativeLibs;
+ };
+
Engine.prototype.requestQuit = function () {
if (this.rtenv) {
this.rtenv['request_quit']();
@@ -277,6 +283,7 @@ const Engine = (function () {
Engine.prototype['setOnExit'] = Engine.prototype.setOnExit;
Engine.prototype['copyToFS'] = Engine.prototype.copyToFS;
Engine.prototype['setPersistentPaths'] = Engine.prototype.setPersistentPaths;
+ Engine.prototype['setGDNativeLibraries'] = Engine.prototype.setGDNativeLibraries;
Engine.prototype['requestQuit'] = Engine.prototype.requestQuit;
return Engine;
}());
diff --git a/platform/javascript/js/engine/utils.js b/platform/javascript/js/engine/utils.js
index d0fca4e1cb..9273bbad42 100644
--- a/platform/javascript/js/engine/utils.js
+++ b/platform/javascript/js/engine/utils.js
@@ -8,6 +8,8 @@ const Utils = { // eslint-disable-line no-unused-vars
return `${execName}.audio.worklet.js`;
} else if (path.endsWith('.js')) {
return `${execName}.js`;
+ } else if (path.endsWith('.side.wasm')) {
+ return `${execName}.side.wasm`;
} else if (path.endsWith('.wasm')) {
return `${execName}.wasm`;
}
diff --git a/platform/javascript/js/libs/library_godot_audio.js b/platform/javascript/js/libs/library_godot_audio.js
index 0c1f477f34..d01b8d887b 100644
--- a/platform/javascript/js/libs/library_godot_audio.js
+++ b/platform/javascript/js/libs/library_godot_audio.js
@@ -77,28 +77,37 @@ const GodotAudio = {
create_input: function (callback) {
if (GodotAudio.input) {
- return; // Already started.
+ return 0; // Already started.
}
function gotMediaInput(stream) {
- GodotAudio.input = GodotAudio.ctx.createMediaStreamSource(stream);
- callback(GodotAudio.input);
+ try {
+ GodotAudio.input = GodotAudio.ctx.createMediaStreamSource(stream);
+ callback(GodotAudio.input);
+ } catch (e) {
+ GodotRuntime.error('Failed creaating input.', e);
+ }
}
- if (navigator.mediaDevices.getUserMedia) {
+ if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({
'audio': true,
}).then(gotMediaInput, function (e) {
- GodotRuntime.print(e);
+ GodotRuntime.error('Error getting user media.', e);
});
} else {
if (!navigator.getUserMedia) {
navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
}
+ if (!navigator.getUserMedia) {
+ GodotRuntime.error('getUserMedia not available.');
+ return 1;
+ }
navigator.getUserMedia({
'audio': true,
}, gotMediaInput, function (e) {
GodotRuntime.print(e);
});
}
+ return 0;
},
close_async: function (resolve, reject) {
@@ -137,6 +146,7 @@ const GodotAudio = {
},
},
+ godot_audio_is_available__sig: 'i',
godot_audio_is_available__proxy: 'sync',
godot_audio_is_available: function () {
if (!(window.AudioContext || window.webkitAudioContext)) {
@@ -145,12 +155,14 @@ const GodotAudio = {
return 1;
},
+ godot_audio_init__sig: 'iiiii',
godot_audio_init: function (p_mix_rate, p_latency, p_state_change, p_latency_update) {
const statechange = GodotRuntime.get_func(p_state_change);
const latencyupdate = GodotRuntime.get_func(p_latency_update);
return GodotAudio.init(p_mix_rate, p_latency, statechange, latencyupdate);
},
+ godot_audio_resume__sig: 'v',
godot_audio_resume: function () {
if (GodotAudio.ctx && GodotAudio.ctx.state !== 'running') {
GodotAudio.ctx.resume();
@@ -158,16 +170,15 @@ const GodotAudio = {
},
godot_audio_capture_start__proxy: 'sync',
+ godot_audio_capture_start__sig: 'i',
godot_audio_capture_start: function () {
- if (GodotAudio.input) {
- return; // Already started.
- }
- GodotAudio.create_input(function (input) {
+ return GodotAudio.create_input(function (input) {
input.connect(GodotAudio.driver.get_node());
});
},
godot_audio_capture_stop__proxy: 'sync',
+ godot_audio_capture_stop__sig: 'v',
godot_audio_capture_stop: function () {
if (GodotAudio.input) {
const tracks = GodotAudio.input['mediaStream']['getTracks']();
@@ -241,10 +252,12 @@ const GodotAudioWorklet = {
},
},
+ godot_audio_worklet_create__sig: 'vi',
godot_audio_worklet_create: function (channels) {
GodotAudioWorklet.create(channels);
},
+ godot_audio_worklet_start__sig: 'viiiii',
godot_audio_worklet_start: function (p_in_buf, p_in_size, p_out_buf, p_out_size, p_state) {
const out_buffer = GodotRuntime.heapSub(HEAPF32, p_out_buf, p_out_size);
const in_buffer = GodotRuntime.heapSub(HEAPF32, p_in_buf, p_in_size);
@@ -252,15 +265,18 @@ const GodotAudioWorklet = {
GodotAudioWorklet.start(in_buffer, out_buffer, state);
},
+ godot_audio_worklet_state_wait__sig: 'iiii',
godot_audio_worklet_state_wait: function (p_state, p_idx, p_expected, p_timeout) {
Atomics.wait(HEAP32, (p_state >> 2) + p_idx, p_expected, p_timeout);
return Atomics.load(HEAP32, (p_state >> 2) + p_idx);
},
+ godot_audio_worklet_state_add__sig: 'iiii',
godot_audio_worklet_state_add: function (p_state, p_idx, p_value) {
return Atomics.add(HEAP32, (p_state >> 2) + p_idx, p_value);
},
+ godot_audio_worklet_state_get__sig: 'iii',
godot_audio_worklet_state_get: function (p_state, p_idx) {
return Atomics.load(HEAP32, (p_state >> 2) + p_idx);
},
@@ -330,10 +346,12 @@ const GodotAudioScript = {
},
},
+ godot_audio_script_create__sig: 'iii',
godot_audio_script_create: function (buffer_length, channel_count) {
return GodotAudioScript.create(buffer_length, channel_count);
},
+ godot_audio_script_start__sig: 'viiiii',
godot_audio_script_start: function (p_in_buf, p_in_size, p_out_buf, p_out_size, p_cb) {
const onprocess = GodotRuntime.get_func(p_cb);
GodotAudioScript.start(p_in_buf, p_in_size, p_out_buf, p_out_size, onprocess);
diff --git a/platform/javascript/js/libs/library_godot_display.js b/platform/javascript/js/libs/library_godot_display.js
index 9651b48952..800d6f414f 100644
--- a/platform/javascript/js/libs/library_godot_display.js
+++ b/platform/javascript/js/libs/library_godot_display.js
@@ -280,6 +280,7 @@ const GodotDisplay = {
window_icon: '',
},
+ godot_js_display_is_swap_ok_cancel__sig: 'i',
godot_js_display_is_swap_ok_cancel: function () {
const win = (['Windows', 'Win64', 'Win32', 'WinCE']);
const plat = navigator.platform || '';
@@ -289,10 +290,12 @@ const GodotDisplay = {
return 0;
},
+ godot_js_display_alert__sig: 'vi',
godot_js_display_alert: function (p_text) {
window.alert(GodotRuntime.parseString(p_text)); // eslint-disable-line no-alert
},
+ godot_js_display_pixel_ratio_get__sig: 'f',
godot_js_display_pixel_ratio_get: function () {
return window.devicePixelRatio || 1;
},
@@ -300,14 +303,17 @@ const GodotDisplay = {
/*
* Canvas
*/
+ godot_js_display_canvas_focus__sig: 'v',
godot_js_display_canvas_focus: function () {
GodotConfig.canvas.focus();
},
+ godot_js_display_canvas_is_focused__sig: 'i',
godot_js_display_canvas_is_focused: function () {
return document.activeElement === GodotConfig.canvas;
},
+ godot_js_display_canvas_bounding_rect_position_get__sig: 'vii',
godot_js_display_canvas_bounding_rect_position_get: function (r_x, r_y) {
const brect = GodotConfig.canvas.getBoundingClientRect();
GodotRuntime.setHeapValue(r_x, brect.x, 'i32');
@@ -317,6 +323,7 @@ const GodotDisplay = {
/*
* Touchscreen
*/
+ godot_js_display_touchscreen_is_available__sig: 'i',
godot_js_display_touchscreen_is_available: function () {
return 'ontouchstart' in window;
},
@@ -324,6 +331,7 @@ const GodotDisplay = {
/*
* Clipboard
*/
+ godot_js_display_clipboard_set__sig: 'ii',
godot_js_display_clipboard_set: function (p_text) {
const text = GodotRuntime.parseString(p_text);
if (!navigator.clipboard || !navigator.clipboard.writeText) {
@@ -336,6 +344,7 @@ const GodotDisplay = {
return 0;
},
+ godot_js_display_clipboard_get__sig: 'ii',
godot_js_display_clipboard_get: function (callback) {
const func = GodotRuntime.get_func(callback);
try {
@@ -354,6 +363,7 @@ const GodotDisplay = {
/*
* Window
*/
+ godot_js_display_window_request_fullscreen__sig: 'v',
godot_js_display_window_request_fullscreen: function () {
const canvas = GodotConfig.canvas;
(canvas.requestFullscreen || canvas.msRequestFullscreen
@@ -362,10 +372,12 @@ const GodotDisplay = {
).call(canvas);
},
+ godot_js_display_window_title_set__sig: 'vi',
godot_js_display_window_title_set: function (p_data) {
document.title = GodotRuntime.parseString(p_data);
},
+ godot_js_display_window_icon_set__sig: 'vii',
godot_js_display_window_icon_set: function (p_ptr, p_len) {
let link = document.getElementById('-gd-engine-icon');
if (link === null) {
@@ -386,6 +398,7 @@ const GodotDisplay = {
/*
* Cursor
*/
+ godot_js_display_cursor_set_visible__sig: 'vi',
godot_js_display_cursor_set_visible: function (p_visible) {
const visible = p_visible !== 0;
if (visible === GodotDisplayCursor.visible) {
@@ -399,14 +412,17 @@ const GodotDisplay = {
}
},
+ godot_js_display_cursor_is_hidden__sig: 'i',
godot_js_display_cursor_is_hidden: function () {
return !GodotDisplayCursor.visible;
},
+ godot_js_display_cursor_set_shape__sig: 'vi',
godot_js_display_cursor_set_shape: function (p_string) {
GodotDisplayCursor.set_shape(GodotRuntime.parseString(p_string));
},
+ godot_js_display_cursor_set_custom_shape__sig: 'viiiii',
godot_js_display_cursor_set_custom_shape: function (p_shape, p_ptr, p_len, p_hotspot_x, p_hotspot_y) {
const shape = GodotRuntime.parseString(p_shape);
const old_shape = GodotDisplayCursor.cursors[shape];
@@ -432,6 +448,7 @@ const GodotDisplay = {
/*
* Listeners
*/
+ godot_js_display_notification_cb__sig: 'viiiii',
godot_js_display_notification_cb: function (callback, p_enter, p_exit, p_in, p_out) {
const canvas = GodotConfig.canvas;
const func = GodotRuntime.get_func(callback);
@@ -443,6 +460,7 @@ const GodotDisplay = {
});
},
+ godot_js_display_paste_cb__sig: 'vi',
godot_js_display_paste_cb: function (callback) {
const func = GodotRuntime.get_func(callback);
GodotDisplayListeners.add(window, 'paste', function (evt) {
@@ -453,6 +471,7 @@ const GodotDisplay = {
}, false);
},
+ godot_js_display_drop_files_cb__sig: 'vi',
godot_js_display_drop_files_cb: function (callback) {
const func = GodotRuntime.get_func(callback);
const dropFiles = function (files) {
diff --git a/platform/javascript/js/libs/library_godot_editor_tools.js b/platform/javascript/js/libs/library_godot_editor_tools.js
index f39fed04a8..12edc8e733 100644
--- a/platform/javascript/js/libs/library_godot_editor_tools.js
+++ b/platform/javascript/js/libs/library_godot_editor_tools.js
@@ -30,6 +30,7 @@
const GodotEditorTools = {
godot_js_editor_download_file__deps: ['$FS'],
+ godot_js_editor_download_file__sig: 'viii',
godot_js_editor_download_file: function (p_path, p_name, p_mime) {
const path = GodotRuntime.parseString(p_path);
const name = GodotRuntime.parseString(p_name);
diff --git a/platform/javascript/js/libs/library_godot_eval.js b/platform/javascript/js/libs/library_godot_eval.js
index 33ff231726..1a2440dd24 100644
--- a/platform/javascript/js/libs/library_godot_eval.js
+++ b/platform/javascript/js/libs/library_godot_eval.js
@@ -30,6 +30,7 @@
const GodotEval = {
godot_js_eval__deps: ['$GodotRuntime'],
+ godot_js_eval__sig: 'iiiiiii',
godot_js_eval: function (p_js, p_use_global_ctx, p_union_ptr, p_byte_arr, p_byte_arr_write, p_callback) {
const js_code = GodotRuntime.parseString(p_js);
let eval_ret = null;
diff --git a/platform/javascript/js/libs/library_godot_http_request.js b/platform/javascript/js/libs/library_godot_http_request.js
index 2b9aa88208..d4468bd5aa 100644
--- a/platform/javascript/js/libs/library_godot_http_request.js
+++ b/platform/javascript/js/libs/library_godot_http_request.js
@@ -50,6 +50,7 @@ const GodotHTTPRequest = {
},
},
+ godot_xhr_new__sig: 'i',
godot_xhr_new: function () {
const newId = GodotHTTPRequest.getUnusedRequestId();
GodotHTTPRequest.requests[newId] = new XMLHttpRequest();
@@ -57,30 +58,36 @@ const GodotHTTPRequest = {
return newId;
},
+ godot_xhr_reset__sig: 'vi',
godot_xhr_reset: function (xhrId) {
GodotHTTPRequest.requests[xhrId] = new XMLHttpRequest();
GodotHTTPRequest.setupRequest(GodotHTTPRequest.requests[xhrId]);
},
+ godot_xhr_free__sig: 'vi',
godot_xhr_free: function (xhrId) {
GodotHTTPRequest.requests[xhrId].abort();
GodotHTTPRequest.requests[xhrId] = null;
},
+ godot_xhr_open__sig: 'viiiii',
godot_xhr_open: function (xhrId, method, url, p_user, p_password) {
const user = p_user > 0 ? GodotRuntime.parseString(p_user) : null;
const password = p_password > 0 ? GodotRuntime.parseString(p_password) : null;
GodotHTTPRequest.requests[xhrId].open(GodotRuntime.parseString(method), GodotRuntime.parseString(url), true, user, password);
},
+ godot_xhr_set_request_header__sig: 'viii',
godot_xhr_set_request_header: function (xhrId, header, value) {
GodotHTTPRequest.requests[xhrId].setRequestHeader(GodotRuntime.parseString(header), GodotRuntime.parseString(value));
},
+ godot_xhr_send_null__sig: 'vi',
godot_xhr_send_null: function (xhrId) {
GodotHTTPRequest.requests[xhrId].send();
},
+ godot_xhr_send_string__sig: 'vii',
godot_xhr_send_string: function (xhrId, strPtr) {
if (!strPtr) {
GodotRuntime.error('Failed to send string per XHR: null pointer');
@@ -89,6 +96,7 @@ const GodotHTTPRequest = {
GodotHTTPRequest.requests[xhrId].send(GodotRuntime.parseString(strPtr));
},
+ godot_xhr_send_data__sig: 'viii',
godot_xhr_send_data: function (xhrId, ptr, len) {
if (!ptr) {
GodotRuntime.error('Failed to send data per XHR: null pointer');
@@ -101,23 +109,28 @@ const GodotHTTPRequest = {
GodotHTTPRequest.requests[xhrId].send(HEAPU8.subarray(ptr, ptr + len));
},
+ godot_xhr_abort__sig: 'vi',
godot_xhr_abort: function (xhrId) {
GodotHTTPRequest.requests[xhrId].abort();
},
+ godot_xhr_get_status__sig: 'ii',
godot_xhr_get_status: function (xhrId) {
return GodotHTTPRequest.requests[xhrId].status;
},
+ godot_xhr_get_ready_state__sig: 'ii',
godot_xhr_get_ready_state: function (xhrId) {
return GodotHTTPRequest.requests[xhrId].readyState;
},
+ godot_xhr_get_response_headers_length__sig: 'ii',
godot_xhr_get_response_headers_length: function (xhrId) {
const headers = GodotHTTPRequest.requests[xhrId].getAllResponseHeaders();
return headers === null ? 0 : GodotRuntime.strlen(headers);
},
+ godot_xhr_get_response_headers__sig: 'viii',
godot_xhr_get_response_headers: function (xhrId, dst, len) {
const str = GodotHTTPRequest.requests[xhrId].getAllResponseHeaders();
if (str === null) {
@@ -126,11 +139,13 @@ const GodotHTTPRequest = {
GodotRuntime.stringToHeap(str, dst, len);
},
+ godot_xhr_get_response_length__sig: 'ii',
godot_xhr_get_response_length: function (xhrId) {
const body = GodotHTTPRequest.requests[xhrId].response;
return body === null ? 0 : body.byteLength;
},
+ godot_xhr_get_response__sig: 'viii',
godot_xhr_get_response: function (xhrId, dst, len) {
let buf = GodotHTTPRequest.requests[xhrId].response;
if (buf === null) {
diff --git a/platform/javascript/js/libs/library_godot_os.js b/platform/javascript/js/libs/library_godot_os.js
index 488753d704..260cfbf97f 100644
--- a/platform/javascript/js/libs/library_godot_os.js
+++ b/platform/javascript/js/libs/library_godot_os.js
@@ -75,14 +75,17 @@ const GodotConfig = {
},
},
+ godot_js_config_canvas_id_get__sig: 'vii',
godot_js_config_canvas_id_get: function (p_ptr, p_ptr_max) {
GodotRuntime.stringToHeap(`#${GodotConfig.canvas.id}`, p_ptr, p_ptr_max);
},
+ godot_js_config_locale_get__sig: 'vii',
godot_js_config_locale_get: function (p_ptr, p_ptr_max) {
GodotRuntime.stringToHeap(GodotConfig.locale, p_ptr, p_ptr_max);
},
+ godot_js_config_is_resize_on_start__sig: 'i',
godot_js_config_is_resize_on_start: function () {
return GodotConfig.resize_on_start ? 1 : 0;
},
@@ -200,7 +203,7 @@ const GodotFS = {
}
FS.mkdirTree(dir);
}
- FS.writeFile(path, new Uint8Array(buffer), { 'flags': 'wx+' });
+ FS.writeFile(path, new Uint8Array(buffer));
},
},
};
@@ -239,19 +242,23 @@ const GodotOS = {
},
},
+ godot_js_os_finish_async__sig: 'vi',
godot_js_os_finish_async: function (p_callback) {
const func = GodotRuntime.get_func(p_callback);
GodotOS.finish_async(func);
},
+ godot_js_os_request_quit_cb__sig: 'vi',
godot_js_os_request_quit_cb: function (p_callback) {
GodotOS.request_quit = GodotRuntime.get_func(p_callback);
},
+ godot_js_os_fs_is_persistent__sig: 'i',
godot_js_os_fs_is_persistent: function () {
return GodotFS.is_persistent();
},
+ godot_js_os_fs_sync__sig: 'vi',
godot_js_os_fs_sync: function (callback) {
const func = GodotRuntime.get_func(callback);
GodotOS._fs_sync_promise = GodotFS.sync();
@@ -260,6 +267,7 @@ const GodotOS = {
});
},
+ godot_js_os_execute__sig: 'ii',
godot_js_os_execute: function (p_json) {
const json_args = GodotRuntime.parseString(p_json);
const args = JSON.parse(json_args);
@@ -270,6 +278,7 @@ const GodotOS = {
return 1;
},
+ godot_js_os_shell_open__sig: 'vi',
godot_js_os_shell_open: function (p_uri) {
window.open(GodotRuntime.parseString(p_uri), '_blank');
},
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 80723d54fc..8c976da58e 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -31,7 +31,6 @@
#include "os_javascript.h"
#include "core/debugger/engine_debugger.h"
-#include "core/io/file_access_buffered_fa.h"
#include "core/io/json.h"
#include "drivers/unix/dir_access_unix.h"
#include "drivers/unix/file_access_unix.h"
@@ -43,6 +42,7 @@
#include "modules/websocket/remote_debugger_peer_websocket.h"
#endif
+#include <dlfcn.h>
#include <emscripten.h>
#include <stdlib.h>
@@ -51,7 +51,6 @@
// Lifecycle
void OS_JavaScript::initialize() {
OS_Unix::initialize_core();
- FileAccess::make_default<FileAccessBufferedFA<FileAccessUnix>>(FileAccess::ACCESS_RESOURCES);
DisplayServerJavaScript::register_javascript_driver();
#ifdef MODULE_WEBSOCKET_ENABLED
@@ -127,12 +126,24 @@ int OS_JavaScript::get_process_id() const {
}
bool OS_JavaScript::_check_internal_feature_support(const String &p_feature) {
- if (p_feature == "HTML5" || p_feature == "web")
+ if (p_feature == "HTML5" || p_feature == "web") {
return true;
+ }
#ifdef JAVASCRIPT_EVAL_ENABLED
- if (p_feature == "JavaScript")
+ if (p_feature == "JavaScript") {
+ return true;
+ }
+#endif
+#ifndef NO_THREADS
+ if (p_feature == "threads") {
return true;
+ }
+#endif
+#if WASM_GDNATIVE
+ if (p_feature == "wasm32") {
+ return true;
+ }
#endif
return false;
@@ -187,6 +198,13 @@ bool OS_JavaScript::is_userfs_persistent() const {
return idb_available;
}
+Error OS_JavaScript::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
+ String path = p_path.get_file();
+ p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
+ ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ". Error: " + dlerror());
+ return OK;
+}
+
OS_JavaScript *OS_JavaScript::get_singleton() {
return static_cast<OS_JavaScript *>(OS::get_singleton());
}
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index 03a3053367..6682f8fd85 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -87,6 +87,7 @@ public:
String get_user_data_dir() const override;
bool is_userfs_persistent() const override;
+ Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) override;
void resume_audio();
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index a1bc5867c5..277aafc107 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -129,7 +129,6 @@ def configure(env):
if "clang++" not in os.path.basename(env["CXX"]):
env["CC"] = "clang"
env["CXX"] = "clang++"
- env.Append(CPPDEFINES=["TYPED_METHOD_BIND"])
env.extra_suffix = ".llvm" + env.extra_suffix
if env["use_lld"]:
@@ -206,14 +205,31 @@ def configure(env):
# freetype depends on libpng and zlib, so bundling one of them while keeping others
# as shared libraries leads to weird issues
- if env["builtin_freetype"] or env["builtin_libpng"] or env["builtin_zlib"]:
+ if (
+ env["builtin_freetype"]
+ or env["builtin_libpng"]
+ or env["builtin_zlib"]
+ or env["builtin_graphite"]
+ or env["builtin_harfbuzz"]
+ ):
env["builtin_freetype"] = True
env["builtin_libpng"] = True
env["builtin_zlib"] = True
+ env["builtin_graphite"] = True
+ env["builtin_harfbuzz"] = True
if not env["builtin_freetype"]:
env.ParseConfig("pkg-config freetype2 --cflags --libs")
+ if not env["builtin_graphite"]:
+ env.ParseConfig("pkg-config graphite2 --cflags --libs")
+
+ if not env["builtin_icu"]:
+ env.ParseConfig("pkg-config icu-uc --cflags --libs")
+
+ if not env["builtin_harfbuzz"]:
+ env.ParseConfig("pkg-config harfbuzz harfbuzz-icu --cflags --libs")
+
if not env["builtin_libpng"]:
env.ParseConfig("pkg-config libpng16 --cflags --libs")
diff --git a/platform/linuxbsd/detect_prime_x11.cpp b/platform/linuxbsd/detect_prime_x11.cpp
index e5a9bb4737..709523e836 100644
--- a/platform/linuxbsd/detect_prime_x11.cpp
+++ b/platform/linuxbsd/detect_prime_x11.cpp
@@ -56,7 +56,7 @@ typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLX
struct vendor {
const char *glxvendor;
- int priority;
+ int priority = 0;
};
vendor vendormap[] = {
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 5fa737af8e..136bee68e3 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -40,9 +40,10 @@
#include "scene/resources/texture.h"
#if defined(VULKAN_ENABLED)
-#include "servers/rendering/rasterizer_rd/rasterizer_rd.h"
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#endif
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -465,59 +466,138 @@ Bool DisplayServerX11::_predicate_clipboard_selection(Display *display, XEvent *
}
}
+Bool DisplayServerX11::_predicate_clipboard_incr(Display *display, XEvent *event, XPointer arg) {
+ if (event->type == PropertyNotify && event->xproperty.state == PropertyNewValue) {
+ return True;
+ } else {
+ return False;
+ }
+}
+
String DisplayServerX11::_clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const {
String ret;
- Atom type;
- Atom selection = XA_PRIMARY;
- int format, result;
- unsigned long len, bytes_left, dummy;
- unsigned char *data;
Window selection_owner = XGetSelectionOwner(x11_display, p_source);
-
if (selection_owner == x11_window) {
return internal_clipboard;
}
if (selection_owner != None) {
- {
- // Block events polling while processing selection events.
- MutexLock mutex_lock(events_mutex);
+ // Block events polling while processing selection events.
+ MutexLock mutex_lock(events_mutex);
- XConvertSelection(x11_display, p_source, target, selection,
- x11_window, CurrentTime);
+ Atom selection = XA_PRIMARY;
+ XConvertSelection(x11_display, p_source, target, selection,
+ x11_window, CurrentTime);
- XFlush(x11_display);
+ XFlush(x11_display);
- // Blocking wait for predicate to be True
- // and remove the event from the queue.
- XEvent event;
- XIfEvent(x11_display, &event, _predicate_clipboard_selection, (XPointer)&x11_window);
- }
+ // Blocking wait for predicate to be True and remove the event from the queue.
+ XEvent event;
+ XIfEvent(x11_display, &event, _predicate_clipboard_selection, (XPointer)&x11_window);
- //
- // Do not get any data, see how much data is there
- //
+ // Do not get any data, see how much data is there.
+ Atom type;
+ int format, result;
+ unsigned long len, bytes_left, dummy;
+ unsigned char *data;
XGetWindowProperty(x11_display, x11_window,
selection, // Tricky..
0, 0, // offset - len
0, // Delete 0==FALSE
- AnyPropertyType, //flag
+ AnyPropertyType, // flag
&type, // return type
&format, // return format
- &len, &bytes_left, //that
+ &len, &bytes_left, // data length
&data);
- // DATA is There
- if (bytes_left > 0) {
+
+ if (data) {
+ XFree(data);
+ }
+
+ if (type == XInternAtom(x11_display, "INCR", 0)) {
+ // Data is going to be received incrementally.
+ DEBUG_LOG_X11("INCR selection started.\n");
+
+ LocalVector<uint8_t> incr_data;
+ uint32_t data_size = 0;
+ bool success = false;
+
+ // Delete INCR property to notify the owner.
+ XDeleteProperty(x11_display, x11_window, type);
+
+ // Process events from the queue.
+ bool done = false;
+ while (!done) {
+ if (!_wait_for_events()) {
+ // Error or timeout, abort.
+ break;
+ }
+
+ // Non-blocking wait for next event and remove it from the queue.
+ XEvent ev;
+ while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_incr, nullptr)) {
+ result = XGetWindowProperty(x11_display, x11_window,
+ selection, // selection type
+ 0, LONG_MAX, // offset - len
+ True, // delete property to notify the owner
+ AnyPropertyType, // flag
+ &type, // return type
+ &format, // return format
+ &len, &bytes_left, // data length
+ &data);
+
+ DEBUG_LOG_X11("PropertyNotify: len=%lu, format=%i\n", len, format);
+
+ if (result == Success) {
+ if (data && (len > 0)) {
+ uint32_t prev_size = incr_data.size();
+ if (prev_size == 0) {
+ // First property contains initial data size.
+ unsigned long initial_size = *(unsigned long *)data;
+ incr_data.resize(initial_size);
+ } else {
+ // New chunk, resize to be safe and append data.
+ incr_data.resize(MAX(data_size + len, prev_size));
+ memcpy(incr_data.ptr() + data_size, data, len);
+ data_size += len;
+ }
+ } else {
+ // Last chunk, process finished.
+ done = true;
+ success = true;
+ }
+ } else {
+ printf("Failed to get selection data chunk.\n");
+ done = true;
+ }
+
+ if (data) {
+ XFree(data);
+ }
+
+ if (done) {
+ break;
+ }
+ }
+ }
+
+ if (success && (data_size > 0)) {
+ ret.parse_utf8((const char *)incr_data.ptr(), data_size);
+ }
+ } else if (bytes_left > 0) {
+ // Data is ready and can be processed all at once.
result = XGetWindowProperty(x11_display, x11_window,
selection, 0, bytes_left, 0,
AnyPropertyType, &type, &format,
&len, &dummy, &data);
+
if (result == Success) {
ret.parse_utf8((const char *)data);
} else {
- printf("FAIL\n");
+ printf("Failed to get selection data.\n");
}
+
if (data) {
XFree(data);
}
@@ -552,6 +632,60 @@ String DisplayServerX11::clipboard_get() const {
return ret;
}
+Bool DisplayServerX11::_predicate_clipboard_save_targets(Display *display, XEvent *event, XPointer arg) {
+ if (event->xany.window == *(Window *)arg) {
+ return (event->type == SelectionRequest) ||
+ (event->type == SelectionNotify);
+ } else {
+ return False;
+ }
+}
+
+void DisplayServerX11::_clipboard_transfer_ownership(Atom p_source, Window x11_window) const {
+ _THREAD_SAFE_METHOD_
+
+ Window selection_owner = XGetSelectionOwner(x11_display, p_source);
+
+ if (selection_owner != x11_window) {
+ return;
+ }
+
+ // Block events polling while processing selection events.
+ MutexLock mutex_lock(events_mutex);
+
+ Atom clipboard_manager = XInternAtom(x11_display, "CLIPBOARD_MANAGER", False);
+ Atom save_targets = XInternAtom(x11_display, "SAVE_TARGETS", False);
+ XConvertSelection(x11_display, clipboard_manager, save_targets, None,
+ x11_window, CurrentTime);
+
+ // Process events from the queue.
+ while (true) {
+ if (!_wait_for_events()) {
+ // Error or timeout, abort.
+ break;
+ }
+
+ // Non-blocking wait for next event and remove it from the queue.
+ XEvent ev;
+ while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_save_targets, (XPointer)&x11_window)) {
+ switch (ev.type) {
+ case SelectionRequest:
+ _handle_selection_request_event(&(ev.xselectionrequest));
+ break;
+
+ case SelectionNotify: {
+ if (ev.xselection.target == save_targets) {
+ // Once SelectionNotify is received, we're done whether it succeeded or not.
+ return;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+}
+
int DisplayServerX11::get_screen_count() const {
_THREAD_SAFE_METHOD_
@@ -2291,53 +2425,105 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
Input::get_singleton()->accumulate_input_event(k);
}
-void DisplayServerX11::_handle_selection_request_event(XSelectionRequestEvent *p_event) {
- XEvent respond;
- if (p_event->target == XInternAtom(x11_display, "UTF8_STRING", 0) ||
- p_event->target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
- p_event->target == XInternAtom(x11_display, "TEXT", 0) ||
- p_event->target == XA_STRING ||
- p_event->target == XInternAtom(x11_display, "text/plain;charset=utf-8", 0) ||
- p_event->target == XInternAtom(x11_display, "text/plain", 0)) {
- // Directly using internal clipboard because we know our window
- // is the owner during a selection request.
- CharString clip = internal_clipboard.utf8();
- XChangeProperty(x11_display,
- p_event->requestor,
- p_event->property,
- p_event->target,
- 8,
- PropModeReplace,
- (unsigned char *)clip.get_data(),
- clip.length());
- respond.xselection.property = p_event->property;
- } else if (p_event->target == XInternAtom(x11_display, "TARGETS", 0)) {
- Atom data[7];
+Atom DisplayServerX11::_process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property) const {
+ if (p_target == XInternAtom(x11_display, "TARGETS", 0)) {
+ // Request to list all supported targets.
+ Atom data[9];
data[0] = XInternAtom(x11_display, "TARGETS", 0);
- data[1] = XInternAtom(x11_display, "UTF8_STRING", 0);
- data[2] = XInternAtom(x11_display, "COMPOUND_TEXT", 0);
- data[3] = XInternAtom(x11_display, "TEXT", 0);
- data[4] = XA_STRING;
- data[5] = XInternAtom(x11_display, "text/plain;charset=utf-8", 0);
- data[6] = XInternAtom(x11_display, "text/plain", 0);
+ data[1] = XInternAtom(x11_display, "SAVE_TARGETS", 0);
+ data[2] = XInternAtom(x11_display, "MULTIPLE", 0);
+ data[3] = XInternAtom(x11_display, "UTF8_STRING", 0);
+ data[4] = XInternAtom(x11_display, "COMPOUND_TEXT", 0);
+ data[5] = XInternAtom(x11_display, "TEXT", 0);
+ data[6] = XA_STRING;
+ data[7] = XInternAtom(x11_display, "text/plain;charset=utf-8", 0);
+ data[8] = XInternAtom(x11_display, "text/plain", 0);
XChangeProperty(x11_display,
- p_event->requestor,
- p_event->property,
+ p_requestor,
+ p_property,
XA_ATOM,
32,
PropModeReplace,
(unsigned char *)&data,
sizeof(data) / sizeof(data[0]));
- respond.xselection.property = p_event->property;
-
+ return p_property;
+ } else if (p_target == XInternAtom(x11_display, "SAVE_TARGETS", 0)) {
+ // Request to check if SAVE_TARGETS is supported, nothing special to do.
+ XChangeProperty(x11_display,
+ p_requestor,
+ p_property,
+ XInternAtom(x11_display, "NULL", False),
+ 32,
+ PropModeReplace,
+ nullptr,
+ 0);
+ return p_property;
+ } else if (p_target == XInternAtom(x11_display, "UTF8_STRING", 0) ||
+ p_target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
+ p_target == XInternAtom(x11_display, "TEXT", 0) ||
+ p_target == XA_STRING ||
+ p_target == XInternAtom(x11_display, "text/plain;charset=utf-8", 0) ||
+ p_target == XInternAtom(x11_display, "text/plain", 0)) {
+ // Directly using internal clipboard because we know our window
+ // is the owner during a selection request.
+ CharString clip = internal_clipboard.utf8();
+ XChangeProperty(x11_display,
+ p_requestor,
+ p_property,
+ p_target,
+ 8,
+ PropModeReplace,
+ (unsigned char *)clip.get_data(),
+ clip.length());
+ return p_property;
} else {
- char *targetname = XGetAtomName(x11_display, p_event->target);
- printf("No Target '%s'\n", targetname);
- if (targetname) {
- XFree(targetname);
+ char *target_name = XGetAtomName(x11_display, p_target);
+ printf("Target '%s' not supported.\n", target_name);
+ if (target_name) {
+ XFree(target_name);
}
+ return None;
+ }
+}
+
+void DisplayServerX11::_handle_selection_request_event(XSelectionRequestEvent *p_event) const {
+ XEvent respond;
+ if (p_event->target == XInternAtom(x11_display, "MULTIPLE", 0)) {
+ // Request for multiple target conversions at once.
+ Atom atom_pair = XInternAtom(x11_display, "ATOM_PAIR", False);
respond.xselection.property = None;
+
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = nullptr;
+ if (XGetWindowProperty(x11_display, p_event->requestor, p_event->property, 0, LONG_MAX, False, atom_pair, &type, &format, &len, &remaining, &data) == Success) {
+ if ((len >= 2) && data) {
+ Atom *targets = (Atom *)data;
+ for (uint64_t i = 0; i < len; i += 2) {
+ Atom target = targets[i];
+ Atom &property = targets[i + 1];
+ property = _process_selection_request_target(target, p_event->requestor, property);
+ }
+
+ XChangeProperty(x11_display,
+ p_event->requestor,
+ p_event->property,
+ atom_pair,
+ 32,
+ PropModeReplace,
+ (unsigned char *)targets,
+ len);
+
+ respond.xselection.property = p_event->property;
+ }
+ XFree(data);
+ }
+ } else {
+ // Request for target conversion.
+ respond.xselection.property = _process_selection_request_target(p_event->target, p_event->requestor, p_event->property);
}
respond.xselection.type = SelectionNotify;
@@ -2473,32 +2659,43 @@ Bool DisplayServerX11::_predicate_all_events(Display *display, XEvent *event, XP
return True;
}
-void DisplayServerX11::_poll_events() {
+bool DisplayServerX11::_wait_for_events() const {
int x11_fd = ConnectionNumber(x11_display);
fd_set in_fds;
- while (!events_thread_done) {
- XFlush(x11_display);
+ XFlush(x11_display);
- FD_ZERO(&in_fds);
- FD_SET(x11_fd, &in_fds);
+ FD_ZERO(&in_fds);
+ FD_SET(x11_fd, &in_fds);
- struct timeval tv;
- tv.tv_usec = 0;
- tv.tv_sec = 1;
+ struct timeval tv;
+ tv.tv_usec = 0;
+ tv.tv_sec = 1;
- // Wait for next event or timeout.
- int num_ready_fds = select(x11_fd + 1, &in_fds, NULL, NULL, &tv);
+ // Wait for next event or timeout.
+ int num_ready_fds = select(x11_fd + 1, &in_fds, NULL, NULL, &tv);
+
+ if (num_ready_fds > 0) {
+ // Event received.
+ return true;
+ } else {
+ // Error or timeout.
if (num_ready_fds < 0) {
- ERR_PRINT("_poll_events: select error: " + itos(errno));
+ ERR_PRINT("_wait_for_events: select error: " + itos(errno));
}
+ return false;
+ }
+}
+
+void DisplayServerX11::_poll_events() {
+ while (!events_thread_done) {
+ _wait_for_events();
// Process events from the queue.
{
MutexLock mutex_lock(events_mutex);
- // Non-blocking wait for next event
- // and remove it from the queue.
+ // Non-blocking wait for next event and remove it from the queue.
XEvent ev;
while (XCheckIfEvent(x11_display, &ev, _predicate_all_events, nullptr)) {
// Check if the input manager wants to process the event.
@@ -3891,12 +4088,12 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
rendering_device_vulkan = memnew(RenderingDeviceVulkan);
rendering_device_vulkan->initialize(context_vulkan);
- RasterizerRD::make_current();
+ RendererCompositorRD::make_current();
}
#endif
/*
- rendering_server = memnew(RenderingServerRaster);
+ rendering_server = memnew(RenderingServerDefault);
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
rendering_server = memnew(RenderingServerWrapMT(rendering_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
}
@@ -4068,6 +4265,11 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
DisplayServerX11::~DisplayServerX11() {
+ // Send owned clipboard data to clipboard manager before exit.
+ Window x11_main_window = windows[MAIN_WINDOW_ID].x11_window;
+ _clipboard_transfer_ownership(XA_PRIMARY, x11_main_window);
+ _clipboard_transfer_ownership(XInternAtom(x11_display, "CLIPBOARD", 0), x11_main_window);
+
events_thread_done = true;
Thread::wait_to_finish(events_thread);
memdelete(events_thread);
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 9ff28b9ed2..0507ef3fff 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -43,7 +43,7 @@
#include "drivers/unix/os_unix.h"
#include "joypad_linux.h"
#include "servers/audio_server.h"
-#include "servers/rendering/rasterizer.h"
+#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering_server.h"
#if defined(OPENGL_ENABLED)
@@ -63,25 +63,25 @@
// Hints for X11 fullscreen
typedef struct {
- unsigned long flags;
- unsigned long functions;
- unsigned long decorations;
- long inputMode;
- unsigned long status;
+ unsigned long flags = 0;
+ unsigned long functions = 0;
+ unsigned long decorations = 0;
+ long inputMode = 0;
+ unsigned long status = 0;
} Hints;
typedef struct _xrr_monitor_info {
Atom name;
- Bool primary;
- Bool automatic;
- int noutput;
- int x;
- int y;
- int width;
- int height;
- int mwidth;
- int mheight;
- RROutput *outputs;
+ Bool primary = false;
+ Bool automatic = false;
+ int noutput = 0;
+ int x = 0;
+ int y = 0;
+ int width = 0;
+ int height = 0;
+ int mwidth = 0;
+ int mheight = 0;
+ RROutput *outputs = nullptr;
} xrr_monitor_info;
#undef CursorShape
@@ -204,10 +204,13 @@ class DisplayServerX11 : public DisplayServer {
Point2i center;
void _handle_key_event(WindowID p_window, XKeyEvent *p_event, LocalVector<XEvent> &p_events, uint32_t &p_event_index, bool p_echo = false);
- void _handle_selection_request_event(XSelectionRequestEvent *p_event);
+
+ Atom _process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property) const;
+ void _handle_selection_request_event(XSelectionRequestEvent *p_event) const;
String _clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const;
String _clipboard_get(Atom p_source, Window x11_window) const;
+ void _clipboard_transfer_ownership(Atom p_source, Window x11_window) const;
//bool minimized;
//bool window_has_focus;
@@ -262,10 +265,13 @@ class DisplayServerX11 : public DisplayServer {
bool events_thread_done = false;
LocalVector<XEvent> polled_events;
static void _poll_events_thread(void *ud);
+ bool _wait_for_events() const;
void _poll_events();
static Bool _predicate_all_events(Display *display, XEvent *event, XPointer arg);
static Bool _predicate_clipboard_selection(Display *display, XEvent *event, XPointer arg);
+ static Bool _predicate_clipboard_incr(Display *display, XEvent *event, XPointer arg);
+ static Bool _predicate_clipboard_save_targets(Display *display, XEvent *event, XPointer arg);
protected:
void _window_changed(XEvent *event);
diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp
index 4a9d0a8181..0676587f7a 100644
--- a/platform/linuxbsd/joypad_linux.cpp
+++ b/platform/linuxbsd/joypad_linux.cpp
@@ -49,15 +49,6 @@
static const char *ignore_str = "/dev/input/js";
#endif
-JoypadLinux::Joypad::Joypad() {
- fd = -1;
- dpad = 0;
- devpath = "";
- for (int i = 0; i < MAX_ABS; i++) {
- abs_info[i] = nullptr;
- }
-}
-
JoypadLinux::Joypad::~Joypad() {
for (int i = 0; i < MAX_ABS; i++) {
if (abs_info[i]) {
diff --git a/platform/linuxbsd/joypad_linux.h b/platform/linuxbsd/joypad_linux.h
index 0d175193a5..71eab78f99 100644
--- a/platform/linuxbsd/joypad_linux.h
+++ b/platform/linuxbsd/joypad_linux.h
@@ -56,17 +56,16 @@ private:
Input::JoyAxis curr_axis[MAX_ABS];
int key_map[MAX_KEY];
int abs_map[MAX_ABS];
- int dpad;
- int fd;
+ int dpad = 0;
+ int fd = -1;
String devpath;
- input_absinfo *abs_info[MAX_ABS];
+ input_absinfo *abs_info[MAX_ABS] = {};
- bool force_feedback;
- int ff_effect_id;
- uint64_t ff_effect_timestamp;
+ bool force_feedback = false;
+ int ff_effect_id = 0;
+ uint64_t ff_effect_timestamp = 0;
- Joypad();
~Joypad();
void reset();
};
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index e569aa03d7..ac88d457a7 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -303,65 +303,147 @@ static String get_mountpoint(const String &p_path) {
}
Error OS_LinuxBSD::move_to_trash(const String &p_path) {
- String trash_can = "";
+ int err_code;
+ List<String> args;
+ args.push_back(p_path);
+ args.push_front("trash"); // The command is `gio trash <file_name>` so we need to add it to args.
+ Error result = execute("gio", args, true, nullptr, nullptr, &err_code); // For GNOME based machines.
+ if (result == OK && !err_code) {
+ return OK;
+ } else if (err_code == 2) {
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ args.pop_front();
+ args.push_front("move");
+ args.push_back("trash:/"); // The command is `kioclient5 move <file_name> trash:/`.
+ result = execute("kioclient5", args, true, nullptr, nullptr, &err_code); // For KDE based machines.
+ if (result == OK && !err_code) {
+ return OK;
+ } else if (err_code == 2) {
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ args.pop_front();
+ args.pop_back();
+ result = execute("gvfs-trash", args, true, nullptr, nullptr, &err_code); // For older Linux machines.
+ if (result == OK && !err_code) {
+ return OK;
+ } else if (err_code == 2) {
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ // If the commands `kioclient5`, `gio` or `gvfs-trash` don't exist on the system we do it manually.
+ String trash_path = "";
String mnt = get_mountpoint(p_path);
- // If there is a directory "[Mountpoint]/.Trash-[UID]/files", use it as the trash can.
+ // If there is a directory "[Mountpoint]/.Trash-[UID], use it as the trash can.
if (mnt != "") {
- String path(mnt + "/.Trash-" + itos(getuid()) + "/files");
+ String path(mnt + "/.Trash-" + itos(getuid()));
struct stat s;
if (!stat(path.utf8().get_data(), &s)) {
- trash_can = path;
+ trash_path = path;
}
}
- // Otherwise, if ${XDG_DATA_HOME} is defined, use "${XDG_DATA_HOME}/Trash/files" as the trash can.
- if (trash_can == "") {
+ // Otherwise, if ${XDG_DATA_HOME} is defined, use "${XDG_DATA_HOME}/Trash" as the trash can.
+ if (trash_path == "") {
char *dhome = getenv("XDG_DATA_HOME");
if (dhome) {
- trash_can = String(dhome) + "/Trash/files";
+ trash_path = String(dhome) + "/Trash";
}
}
- // Otherwise, if ${HOME} is defined, use "${HOME}/.local/share/Trash/files" as the trash can.
- if (trash_can == "") {
+ // Otherwise, if ${HOME} is defined, use "${HOME}/.local/share/Trash" as the trash can.
+ if (trash_path == "") {
char *home = getenv("HOME");
if (home) {
- trash_can = String(home) + "/.local/share/Trash/files";
+ trash_path = String(home) + "/.local/share/Trash";
}
}
// Issue an error if none of the previous locations is appropriate for the trash can.
- if (trash_can == "") {
- ERR_PRINT("move_to_trash: Could not determine the trash can location");
- return FAILED;
- }
+ ERR_FAIL_COND_V_MSG(trash_path == "", FAILED, "Could not determine the trash can location");
// Create needed directories for decided trash can location.
- DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- Error err = dir_access->make_dir_recursive(trash_can);
- memdelete(dir_access);
+ {
+ DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ Error err = dir_access->make_dir_recursive(trash_path);
+
+ // Issue an error if trash can is not created proprely.
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Could not create the trash path \"" + trash_path + "\"");
+ err = dir_access->make_dir_recursive(trash_path + "/files");
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Could not create the trash path \"" + trash_path + "\"/files");
+ err = dir_access->make_dir_recursive(trash_path + "/info");
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Could not create the trash path \"" + trash_path + "\"/info");
+ memdelete(dir_access);
+ }
- // Issue an error if trash can is not created proprely.
- if (err != OK) {
- ERR_PRINT("move_to_trash: Could not create the trash can \"" + trash_can + "\"");
- return err;
+ // The trash can is successfully created, now we check that we don't exceed our file name length limit.
+ // If the file name is too long trim it so we can add the identifying number and ".trashinfo".
+ // Assumes that the file name length limit is 255 characters.
+ String file_name = basename(p_path.utf8().get_data());
+ if (file_name.length() > 240) {
+ file_name = file_name.substr(0, file_name.length() - 15);
+ }
+
+ String dest_path = trash_path + "/files/" + file_name;
+ struct stat buff;
+ int id_number = 0;
+ String fn = file_name;
+
+ // Checks if a resource with the same name already exist in the trash can,
+ // if there is, add an identifying number to our resource's name.
+ while (stat(dest_path.utf8().get_data(), &buff) == 0) {
+ id_number++;
+
+ // Added a limit to check for identically named files already on the trash can
+ // if there are too many it could make the editor unresponsive.
+ ERR_FAIL_COND_V_MSG(id_number > 99, FAILED, "Too many identically named resources already in the trash can.");
+ fn = file_name + "." + itos(id_number);
+ dest_path = trash_path + "/files/" + fn;
+ }
+ file_name = fn;
+
+ // Generates the .trashinfo file
+ OS::Date date = OS::get_singleton()->get_date(false);
+ OS::Time time = OS::get_singleton()->get_time(false);
+ String timestamp = vformat("%04d-%02d-%02dT%02d:%02d:", date.year, date.month, date.day, time.hour, time.min);
+ timestamp = vformat("%s%02d", timestamp, time.sec); // vformat only supports up to 6 arguments.
+ String trash_info = "[Trash Info]\nPath=" + p_path.http_escape() + "\nDeletionDate=" + timestamp + "\n";
+ {
+ Error err;
+ FileAccess *file = FileAccess::open(trash_path + "/info/" + file_name + ".trashinfo", FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Can't create trashinfo file:" + trash_path + "/info/" + file_name + ".trashinfo");
+ file->store_string(trash_info);
+ file->close();
+
+ // Rename our resource before moving it to the trash can.
+ DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ err = dir_access->rename(p_path, p_path.get_base_dir() + "/" + file_name);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Can't rename file \"" + p_path + "\"");
+ memdelete(dir_access);
}
- // The trash can is successfully created, now move the given resource to it.
+ // Move the given resource to the trash can.
// Do not use DirAccess:rename() because it can't move files across multiple mountpoints.
List<String> mv_args;
- mv_args.push_back(p_path);
- mv_args.push_back(trash_can);
- int retval;
- err = execute("mv", mv_args, true, nullptr, nullptr, &retval);
-
- // Issue an error if "mv" failed to move the given resource to the trash can.
- if (err != OK || retval != 0) {
- ERR_PRINT("move_to_trash: Could not move the resource \"" + p_path + "\" to the trash can \"" + trash_can + "\"");
- return FAILED;
+ mv_args.push_back(p_path.get_base_dir() + "/" + file_name);
+ mv_args.push_back(trash_path + "/files");
+ {
+ int retval;
+ Error err = execute("mv", mv_args, true, nullptr, nullptr, &retval);
+
+ // Issue an error if "mv" failed to move the given resource to the trash can.
+ if (err != OK || retval != 0) {
+ ERR_PRINT("move_to_trash: Could not move the resource \"" + p_path + "\" to the trash can \"" + trash_path + "/files\"");
+ DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ err = dir_access->rename(p_path.get_base_dir() + "/" + file_name, p_path);
+ memdelete(dir_access);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Could not rename " + p_path.get_base_dir() + "/" + file_name + " back to its original name:" + p_path);
+ return FAILED;
+ }
}
-
return OK;
}
diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h
index cd4fbd9db5..6e93bf6ef2 100644
--- a/platform/linuxbsd/os_linuxbsd.h
+++ b/platform/linuxbsd/os_linuxbsd.h
@@ -39,7 +39,7 @@
#include "drivers/unix/os_unix.h"
#include "joypad_linux.h"
#include "servers/audio_server.h"
-#include "servers/rendering/rasterizer.h"
+#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering_server.h"
class OS_LinuxBSD : public OS_Unix {
diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h
index 073d35008b..ea55a3ff28 100644
--- a/platform/osx/display_server_osx.h
+++ b/platform/osx/display_server_osx.h
@@ -77,13 +77,13 @@ public:
struct KeyEvent {
WindowID window_id;
- unsigned int osx_state;
- bool pressed;
- bool echo;
- bool raw;
- uint32_t keycode;
- uint32_t physical_keycode;
- uint32_t unicode;
+ unsigned int osx_state = false;
+ bool pressed = false;
+ bool echo = false;
+ bool raw = false;
+ uint32_t keycode = 0;
+ uint32_t physical_keycode = 0;
+ uint32_t unicode = 0;
};
struct WarpEvent {
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index 1ad7117b39..c4c2426f1f 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -52,7 +52,7 @@
#endif
#if defined(VULKAN_ENABLED)
-#include "servers/rendering/rasterizer_rd/rasterizer_rd.h"
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include <QuartzCore/CAMetalLayer.h>
#endif
@@ -701,8 +701,6 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
characters = (NSString *)aString;
}
- NSUInteger i, length = [characters length];
-
NSCharacterSet *ctrlChars = [NSCharacterSet controlCharacterSet];
NSCharacterSet *wsnlChars = [NSCharacterSet whitespaceAndNewlineCharacterSet];
if ([characters rangeOfCharacterFromSet:ctrlChars].length && [characters rangeOfCharacterFromSet:wsnlChars].length == 0) {
@@ -712,8 +710,15 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
return;
}
- for (i = 0; i < length; i++) {
- const unichar codepoint = [characters characterAtIndex:i];
+ Char16String text;
+ text.resize([characters length] + 1);
+ [characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])];
+
+ String u32text;
+ u32text.parse_utf16(text.ptr(), text.length());
+
+ for (int i = 0; i < u32text.length(); i++) {
+ const char32_t codepoint = u32text[i];
if ((codepoint & 0xFF00) == 0xF700) {
continue;
}
@@ -1315,7 +1320,16 @@ static int remapKey(unsigned int key, unsigned int state) {
if (!wd.im_active && length > 0 && keycode_has_unicode(remapKey([event keyCode], [event modifierFlags]))) {
// Fallback unicode character handler used if IME is not active
- for (NSUInteger i = 0; i < length; i++) {
+ Char16String text;
+ text.resize([characters length] + 1);
+ [characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])];
+
+ String u32text;
+ u32text.parse_utf16(text.ptr(), text.length());
+
+ for (int i = 0; i < u32text.length(); i++) {
+ const char32_t codepoint = u32text[i];
+
DisplayServerOSX::KeyEvent ke;
ke.window_id = window_id;
@@ -1325,7 +1339,7 @@ static int remapKey(unsigned int key, unsigned int state) {
ke.keycode = remapKey([event keyCode], [event modifierFlags]);
ke.physical_keycode = translateKey([event keyCode]);
ke.raw = true;
- ke.unicode = [characters characterAtIndex:i];
+ ke.unicode = codepoint;
_push_to_key_event_buffer(ke);
}
@@ -1417,7 +1431,15 @@ static int remapKey(unsigned int key, unsigned int state) {
// Fallback unicode character handler used if IME is not active
if (!wd.im_active && length > 0 && keycode_has_unicode(remapKey([event keyCode], [event modifierFlags]))) {
- for (NSUInteger i = 0; i < length; i++) {
+ Char16String text;
+ text.resize([characters length] + 1);
+ [characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])];
+
+ String u32text;
+ u32text.parse_utf16(text.ptr(), text.length());
+
+ for (int i = 0; i < u32text.length(); i++) {
+ const char32_t codepoint = u32text[i];
DisplayServerOSX::KeyEvent ke;
ke.window_id = window_id;
@@ -1427,7 +1449,7 @@ static int remapKey(unsigned int key, unsigned int state) {
ke.keycode = remapKey([event keyCode], [event modifierFlags]);
ke.physical_keycode = translateKey([event keyCode]);
ke.raw = true;
- ke.unicode = [characters characterAtIndex:i];
+ ke.unicode = codepoint;
_push_to_key_event_buffer(ke);
}
@@ -3848,7 +3870,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
rendering_device_vulkan = memnew(RenderingDeviceVulkan);
rendering_device_vulkan->initialize(context_vulkan);
- RasterizerRD::make_current();
+ RendererCompositorRD::make_current();
}
#endif
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index e988e51e72..eecd2ed641 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -42,13 +42,13 @@
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "platform/osx/logo.gen.h"
-#include "string.h"
+
#include <sys/stat.h>
class EditorExportPlatformOSX : public EditorExportPlatform {
GDCLASS(EditorExportPlatformOSX, EditorExportPlatform);
- int version_code;
+ int version_code = 0;
Ref<ImageTexture> logo;
@@ -572,36 +572,36 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
pkg_name = "Unnamed";
}
- String pkg_name_safe = OS::get_singleton()->get_safe_dir_name(pkg_name);
-
- Error err = OK;
- String tmp_app_path_name = "";
+ pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name);
- DirAccess *tmp_app_path = nullptr;
String export_format = use_dmg() && p_path.ends_with("dmg") ? "dmg" : "zip";
// Create our application bundle.
- tmp_app_path_name = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".app");
+ String tmp_app_dir_name = pkg_name + ".app";
+ String tmp_app_path_name = EditorSettings::get_singleton()->get_cache_dir().plus_file(tmp_app_dir_name);
print_line("Exporting to " + tmp_app_path_name);
- tmp_app_path = DirAccess::create_for_path(tmp_app_path_name);
- if (!tmp_app_path) {
+
+ Error err = OK;
+
+ DirAccessRef tmp_app_dir = DirAccess::create_for_path(tmp_app_path_name);
+ if (!tmp_app_dir) {
err = ERR_CANT_CREATE;
}
// Create our folder structure.
if (err == OK) {
print_line("Creating " + tmp_app_path_name + "/Contents/MacOS");
- err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS");
+ err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS");
}
if (err == OK) {
print_line("Creating " + tmp_app_path_name + "/Contents/Frameworks");
- err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks");
+ err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks");
}
if (err == OK) {
print_line("Creating " + tmp_app_path_name + "/Contents/Resources");
- err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/Resources");
+ err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Resources");
}
// Now process our template.
@@ -678,14 +678,14 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
ret = unzGoToNextFile(src_pkg_zip);
continue; // skip
}
- file = file.replace("/data.mono.osx.64.release_debug/", "/data_" + pkg_name_safe + "/");
+ file = file.replace("/data.mono.osx.64.release_debug/", "/data_" + pkg_name + "/");
}
if (file.find("/data.mono.osx.64.release/") != -1) {
if (p_debug) {
ret = unzGoToNextFile(src_pkg_zip);
continue; // skip
}
- file = file.replace("/data.mono.osx.64.release/", "/data_" + pkg_name_safe + "/");
+ file = file.replace("/data.mono.osx.64.release/", "/data_" + pkg_name + "/");
}
print_line("ADDING: " + file + " size: " + itos(data.size()));
@@ -694,7 +694,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
// Write it into our application bundle.
file = tmp_app_path_name.plus_file(file);
if (err == OK) {
- err = tmp_app_path->make_dir_recursive(file.get_base_dir());
+ err = tmp_app_dir->make_dir_recursive(file.get_base_dir());
}
if (err == OK) {
FileAccess *f = FileAccess::open(file, FileAccess::WRITE);
@@ -797,7 +797,10 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
}
// Clean up temporary .app dir.
- OS::get_singleton()->move_to_trash(tmp_app_path_name);
+ tmp_app_dir->change_dir(tmp_app_path_name);
+ tmp_app_dir->erase_contents_recursive();
+ tmp_app_dir->change_dir("..");
+ tmp_app_dir->remove(tmp_app_dir_name);
}
return err;
diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp
index cfc371710b..b2871b261e 100644
--- a/platform/osx/joypad_osx.cpp
+++ b/platform/osx/joypad_osx.cpp
@@ -37,14 +37,6 @@
static JoypadOSX *self = nullptr;
joypad::joypad() {
- device_ref = nullptr;
- ff_device = nullptr;
- ff_axes = nullptr;
- ff_directions = nullptr;
- ffservice = 0;
- ff_timestamp = 0;
- id = 0;
-
ff_constant_force.lMagnitude = 10000;
ff_effect.dwDuration = 0;
ff_effect.dwSamplePeriod = 0;
diff --git a/platform/osx/joypad_osx.h b/platform/osx/joypad_osx.h
index dc238e68e4..6c2a1ea70b 100644
--- a/platform/osx/joypad_osx.h
+++ b/platform/osx/joypad_osx.h
@@ -46,10 +46,10 @@ struct rec_element {
IOHIDElementRef ref;
IOHIDElementCookie cookie;
- uint32_t usage;
+ uint32_t usage = 0;
- int min;
- int max;
+ int min = 0;
+ int max = 0;
struct Comparator {
bool operator()(const rec_element p_a, const rec_element p_b) const { return p_a.usage < p_b.usage; }
@@ -57,22 +57,22 @@ struct rec_element {
};
struct joypad {
- IOHIDDeviceRef device_ref;
+ IOHIDDeviceRef device_ref = nullptr;
Vector<rec_element> axis_elements;
Vector<rec_element> button_elements;
Vector<rec_element> hat_elements;
- int id;
+ int id = 0;
- io_service_t ffservice; /* Interface for force feedback, 0 = no ff */
+ io_service_t ffservice = 0; /* Interface for force feedback, 0 = no ff */
FFCONSTANTFORCE ff_constant_force;
FFDeviceObjectReference ff_device;
FFEffectObjectReference ff_object;
- uint64_t ff_timestamp;
- LONG *ff_directions;
+ uint64_t ff_timestamp = 0;
+ LONG *ff_directions = nullptr;
FFEFFECT ff_effect;
- DWORD *ff_axes;
+ DWORD *ff_axes = nullptr;
void add_hid_elements(CFArrayRef p_array);
void add_hid_element(IOHIDElementRef p_element);
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 399a29cbe0..ed03e953a5 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -286,7 +286,7 @@ Error OS_OSX::shell_open(String p_uri) {
String OS_OSX::get_locale() const {
NSString *locale_code = [[NSLocale preferredLanguages] objectAtIndex:0];
- return [locale_code UTF8String];
+ return String([locale_code UTF8String]).replace("-", "_");
}
String OS_OSX::get_executable_path() const {
diff --git a/platform/server/detect.py b/platform/server/detect.py
index a3f60b0710..bf4744a234 100644
--- a/platform/server/detect.py
+++ b/platform/server/detect.py
@@ -94,7 +94,6 @@ def configure(env):
if "clang++" not in os.path.basename(env["CXX"]):
env["CC"] = "clang"
env["CXX"] = "clang++"
- env.Append(CPPDEFINES=["TYPED_METHOD_BIND"])
env.extra_suffix = ".llvm" + env.extra_suffix
if env["use_coverage"]:
@@ -139,14 +138,31 @@ def configure(env):
# freetype depends on libpng and zlib, so bundling one of them while keeping others
# as shared libraries leads to weird issues
- if env["builtin_freetype"] or env["builtin_libpng"] or env["builtin_zlib"]:
+ if (
+ env["builtin_freetype"]
+ or env["builtin_libpng"]
+ or env["builtin_zlib"]
+ or env["builtin_graphite"]
+ or env["builtin_harfbuzz"]
+ ):
env["builtin_freetype"] = True
env["builtin_libpng"] = True
env["builtin_zlib"] = True
+ env["builtin_graphite"] = True
+ env["builtin_harfbuzz"] = True
if not env["builtin_freetype"]:
env.ParseConfig("pkg-config freetype2 --cflags --libs")
+ if not env["builtin_graphite"]:
+ env.ParseConfig("pkg-config graphite2 --cflags --libs")
+
+ if not env["builtin_icu"]:
+ env.ParseConfig("pkg-config icu-uc --cflags --libs")
+
+ if not env["builtin_harfbuzz"]:
+ env.ParseConfig("pkg-config harfbuzz harfbuzz-icu --cflags --libs")
+
if not env["builtin_libpng"]:
env.ParseConfig("pkg-config libpng16 --cflags --libs")
@@ -234,7 +250,17 @@ def configure(env):
env.Append(CPPDEFINES=["SERVER_ENABLED", "UNIX_ENABLED"])
if platform.system() == "Darwin":
- env.Append(LINKFLAGS=["-framework", "Cocoa", "-framework", "Carbon", "-lz", "-framework", "IOKit"])
+ env.Append(
+ LINKFLAGS=[
+ "-framework",
+ "Cocoa",
+ "-framework",
+ "Carbon",
+ "-lz",
+ "-framework",
+ "IOKit",
+ ]
+ )
env.Append(LIBS=["pthread"])
diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp
index 9937ae5b62..f8b420b1c8 100644
--- a/platform/server/os_server.cpp
+++ b/platform/server/os_server.cpp
@@ -33,7 +33,7 @@
#include "core/string/print_string.h"
#include "drivers/dummy/rasterizer_dummy.h"
#include "drivers/dummy/texture_loader_dummy.h"
-#include "servers/rendering/rendering_server_raster.h"
+#include "servers/rendering/rendering_server_default.h"
#include "main/main.h"
@@ -49,14 +49,6 @@ const char *OS_Server::get_video_driver_name(int p_driver) const {
return "Dummy";
}
-int OS_Server::get_audio_driver_count() const {
- return 1;
-}
-
-const char *OS_Server::get_audio_driver_name(int p_driver) const {
- return "Dummy";
-}
-
int OS_Server::get_current_video_driver() const {
return video_driver_index;
}
@@ -76,7 +68,7 @@ Error OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int
video_driver_index = p_video_driver; // unused in server platform, but should still be initialized
- rendering_server = memnew(RenderingServerRaster);
+ rendering_server = memnew(RenderingServerDefault);
rendering_server->init();
AudioDriverManager::initialize(p_audio_driver);
diff --git a/platform/server/os_server.h b/platform/server/os_server.h
index 06ea483fd4..95b6b5143b 100644
--- a/platform/server/os_server.h
+++ b/platform/server/os_server.h
@@ -41,28 +41,28 @@
#include "platform/x11/crash_handler_linuxbsd.h"
#endif
#include "servers/audio_server.h"
-#include "servers/rendering/rasterizer.h"
+#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering_server.h"
#undef CursorShape
class OS_Server : public OS_Unix {
- RenderingServer *rendering_server;
+ RenderingServer *rendering_server = nullptr;
VideoMode current_videomode;
List<String> args;
- MainLoop *main_loop;
+ MainLoop *main_loop = nullptr;
- bool grab;
+ bool grab = false;
virtual void delete_main_loop();
- bool force_quit;
+ bool force_quit = false;
- InputDefault *input;
+ InputDefault *input = nullptr;
CrashHandler crash_handler;
- int video_driver_index;
+ int video_driver_index = 0;
Ref<ResourceFormatDummyTexture> resource_loader_dummy;
@@ -70,8 +70,6 @@ protected:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
virtual int get_current_video_driver() const;
- virtual int get_audio_driver_count() const;
- virtual const char *get_audio_driver_name(int p_driver) const;
virtual void initialize_core();
virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
diff --git a/platform/uwp/context_egl_uwp.cpp b/platform/uwp/context_egl_uwp.cpp
index 2da6c5897a..a6607ed42c 100644
--- a/platform/uwp/context_egl_uwp.cpp
+++ b/platform/uwp/context_egl_uwp.cpp
@@ -204,7 +204,8 @@ ContextEGL_UWP::ContextEGL_UWP(CoreWindow ^ p_window, Driver p_driver) :
mEglContext(EGL_NO_CONTEXT),
mEglSurface(EGL_NO_SURFACE),
driver(p_driver),
- window(p_window) {}
+ window(p_window),
+ vsync(false) {}
ContextEGL_UWP::~ContextEGL_UWP() {
cleanup();
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index 30568241a9..00b57c48f3 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -108,7 +108,7 @@ class AppxPackager {
struct BlockHash {
String base64_hash;
- size_t compressed_size;
+ size_t compressed_size = 0;
};
struct FileMeta {
@@ -120,12 +120,10 @@ class AppxPackager {
Vector<BlockHash> hashes;
uLong file_crc32 = 0;
ZPOS64_T zip_offset = 0;
-
- FileMeta() {}
};
String progress_task;
- FileAccess *package;
+ FileAccess *package = nullptr;
Set<String> mime_types;
diff --git a/platform/uwp/joypad_uwp.h b/platform/uwp/joypad_uwp.h
index 13f246a438..2df87d6fd5 100644
--- a/platform/uwp/joypad_uwp.h
+++ b/platform/uwp/joypad_uwp.h
@@ -58,21 +58,12 @@ private:
struct ControllerDevice {
Windows::Gaming::Input::IGameController ^ controller_reference;
- int id;
- bool connected;
- ControllerType type;
- float ff_timestamp;
- float ff_end_timestamp;
- bool vibrating;
-
- ControllerDevice() {
- id = -1;
- connected = false;
- type = ControllerType::GAMEPAD_CONTROLLER;
- ff_timestamp = 0.0f;
- ff_end_timestamp = 0.0f;
- vibrating = false;
- }
+ int id = -1;
+ bool connected = false;
+ ControllerType type = ControllerType::GAMEPAD_CONTROLLER;
+ float ff_timestamp = 0;
+ float ff_end_timestamp = 0;
+ bool vibrating = false;
};
ControllerDevice controllers[MAX_CONTROLLERS];
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 79508055e5..780eba8407 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -44,7 +44,7 @@
#include "main/main.h"
#include "platform/windows/windows_terminal_logger.h"
#include "servers/audio_server.h"
-#include "servers/rendering/rendering_server_raster.h"
+#include "servers/rendering/rendering_server_default.h"
#include "servers/rendering/rendering_server_wrap_mt.h"
#include "thread_uwp.h"
@@ -240,7 +240,7 @@ Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
set_video_mode(vm);
- rendering_server = memnew(RenderingServerRaster);
+ rendering_server = memnew(RenderingServerDefault);
// FIXME: Reimplement threaded rendering
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
rendering_server = memnew(RenderingServerWrapMT(rendering_server, false));
diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h
index 88961bf143..fd25cefe2b 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -39,7 +39,7 @@
#include "drivers/xaudio2/audio_driver_xaudio2.h"
#include "joypad_uwp.h"
#include "servers/audio_server.h"
-#include "servers/rendering/rasterizer.h"
+#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering_server.h"
#include <fcntl.h>
@@ -55,13 +55,13 @@ public:
CHAR_EVENT_MESSAGE
};
- bool alt, shift, control;
- MessageType type;
- bool pressed;
- unsigned int keycode;
- unsigned int physical_keycode;
- unsigned int unicode;
- bool echo;
+ bool alt = false, shift = false, control = false;
+ MessageType type = KEY_EVENT_MESSAGE;
+ bool pressed = false;
+ unsigned int keycode = 0;
+ unsigned int physical_keycode = 0;
+ unsigned int unicode = 0;
+ bool echo = false;
CorePhysicalKeyStatus status;
};
diff --git a/platform/windows/context_gl_windows.cpp b/platform/windows/context_gl_windows.cpp
index 1c32639a38..54251fc66c 100644
--- a/platform/windows/context_gl_windows.cpp
+++ b/platform/windows/context_gl_windows.cpp
@@ -211,6 +211,7 @@ ContextGL_Windows::ContextGL_Windows(HWND hwnd, bool p_opengl_3_context) {
hWnd = hwnd;
use_vsync = false;
vsync_via_compositor = false;
+ pixel_format = 0;
}
ContextGL_Windows::~ContextGL_Windows() {
diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp
index 7abf451062..0f2f49c5ce 100644
--- a/platform/windows/crash_handler_windows.cpp
+++ b/platform/windows/crash_handler_windows.cpp
@@ -57,7 +57,7 @@
struct module_data {
std::string image_name;
std::string module_name;
- void *base_address;
+ void *base_address = nullptr;
DWORD load_size;
};
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index e0b2a52014..859051ede9 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -71,6 +71,7 @@ def get_opts():
BoolVariable("use_mingw", "Use the Mingw compiler, even if MSVC is installed. Only used on Windows.", False),
BoolVariable("use_llvm", "Use the LLVM compiler", False),
BoolVariable("use_thinlto", "Use ThinLTO", False),
+ BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True),
]
@@ -94,7 +95,7 @@ def build_res_file(target, source, env):
out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
if len(out[1]):
return 1
- except:
+ except Exception:
return 1
return 0
@@ -221,7 +222,11 @@ def configure_msvc(env, manual_msvc_config):
## Compile/link flags
- env.AppendUnique(CCFLAGS=["/MT", "/Gd", "/GR", "/nologo"])
+ if env["use_static_cpp"]:
+ env.AppendUnique(CCFLAGS=["/MT"])
+ else:
+ env.AppendUnique(CCFLAGS=["/MD"])
+ env.AppendUnique(CCFLAGS=["/Gd", "/GR", "/nologo"])
# Force to use Unicode encoding
env.AppendUnique(CCFLAGS=["/utf-8"])
env.AppendUnique(CXXFLAGS=["/TP"]) # assume all sources are C++
@@ -373,12 +378,14 @@ def configure_mingw(env):
mingw_prefix = ""
if env["bits"] == "32":
- env.Append(LINKFLAGS=["-static"])
- env.Append(LINKFLAGS=["-static-libgcc"])
- env.Append(LINKFLAGS=["-static-libstdc++"])
+ if env["use_static_cpp"]:
+ env.Append(LINKFLAGS=["-static"])
+ env.Append(LINKFLAGS=["-static-libgcc"])
+ env.Append(LINKFLAGS=["-static-libstdc++"])
mingw_prefix = env["mingw_prefix_32"]
else:
- env.Append(LINKFLAGS=["-static"])
+ if env["use_static_cpp"]:
+ env.Append(LINKFLAGS=["-static"])
mingw_prefix = env["mingw_prefix_64"]
if env["use_llvm"]:
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index dfbb734ee4..62fcd20f61 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -2792,6 +2792,24 @@ void DisplayServerWindows::_process_key_events() {
case WM_CHAR: {
// extended keys should only be processed as WM_KEYDOWN message.
if (!KeyMappingWindows::is_extended_key(ke.wParam) && ((i == 0 && ke.uMsg == WM_CHAR) || (i > 0 && key_event_buffer[i - 1].uMsg == WM_CHAR))) {
+ static char32_t prev_wc = 0;
+ char32_t unicode = ke.wParam;
+ if ((unicode & 0xfffffc00) == 0xd800) {
+ if (prev_wc != 0) {
+ ERR_PRINT("invalid utf16 surrogate input");
+ }
+ prev_wc = unicode;
+ break; // Skip surrogate.
+ } else if ((unicode & 0xfffffc00) == 0xdc00) {
+ if (prev_wc == 0) {
+ ERR_PRINT("invalid utf16 surrogate input");
+ break; // Skip invalid surrogate.
+ }
+ unicode = (prev_wc << 10UL) + unicode - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
+ prev_wc = 0;
+ } else {
+ prev_wc = 0;
+ }
Ref<InputEventKey> k;
k.instance();
@@ -2803,7 +2821,7 @@ void DisplayServerWindows::_process_key_events() {
k->set_pressed(true);
k->set_keycode(KeyMappingWindows::get_keysym(ke.wParam));
k->set_physical_keycode(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24)));
- k->set_unicode(ke.wParam);
+ k->set_unicode(unicode);
if (k->get_unicode() && gr_mem) {
k->set_alt(false);
k->set_control(false);
@@ -2840,7 +2858,25 @@ void DisplayServerWindows::_process_key_events() {
k->set_physical_keycode(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24)));
if (i + 1 < key_event_pos && key_event_buffer[i + 1].uMsg == WM_CHAR) {
- k->set_unicode(key_event_buffer[i + 1].wParam);
+ char32_t unicode = key_event_buffer[i + 1].wParam;
+ static char32_t prev_wck = 0;
+ if ((unicode & 0xfffffc00) == 0xd800) {
+ if (prev_wck != 0) {
+ ERR_PRINT("invalid utf16 surrogate input");
+ }
+ prev_wck = unicode;
+ break; // Skip surrogate.
+ } else if ((unicode & 0xfffffc00) == 0xdc00) {
+ if (prev_wck == 0) {
+ ERR_PRINT("invalid utf16 surrogate input");
+ break; // Skip invalid surrogate.
+ }
+ unicode = (prev_wck << 10UL) + unicode - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
+ prev_wck = 0;
+ } else {
+ prev_wck = 0;
+ }
+ k->set_unicode(unicode);
}
if (k->get_unicode() && gr_mem) {
k->set_alt(false);
@@ -3169,7 +3205,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
rendering_device_vulkan = memnew(RenderingDeviceVulkan);
rendering_device_vulkan->initialize(context_vulkan);
- RasterizerRD::make_current();
+ RendererCompositorRD::make_current();
}
#endif
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index c64a1b3b09..684746919a 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -43,8 +43,8 @@
#include "joypad_windows.h"
#include "key_mapping_windows.h"
#include "servers/audio_server.h"
-#include "servers/rendering/rasterizer.h"
-#include "servers/rendering/rasterizer_rd/rasterizer_rd.h"
+#include "servers/rendering/renderer_compositor.h"
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering_server.h"
#ifdef XAUDIO2_ENABLED
diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp
index 2a5c8a7763..ae5e846dac 100644
--- a/platform/windows/joypad_windows.cpp
+++ b/platform/windows/joypad_windows.cpp
@@ -151,7 +151,7 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
const DWORD devtype = (instance->dwDevType & 0xFF);
- if ((devtype != DI8DEVTYPE_JOYSTICK) && (devtype != DI8DEVTYPE_GAMEPAD) && (devtype != DI8DEVTYPE_1STPERSON)) {
+ if ((devtype != DI8DEVTYPE_JOYSTICK) && (devtype != DI8DEVTYPE_GAMEPAD) && (devtype != DI8DEVTYPE_1STPERSON) && (devtype != DI8DEVTYPE_DRIVING)) {
return false;
}
diff --git a/platform/windows/joypad_windows.h b/platform/windows/joypad_windows.h
index 223b44fcd6..08adc6b663 100644
--- a/platform/windows/joypad_windows.h
+++ b/platform/windows/joypad_windows.h
@@ -92,21 +92,13 @@ private:
};
struct xinput_gamepad {
- int id;
- bool attached;
- bool vibrating;
- DWORD last_packet;
+ int id = 0;
+ bool attached = false;
+ bool vibrating = false;
+ DWORD last_packet = 0;
XINPUT_STATE state;
- uint64_t ff_timestamp;
- uint64_t ff_end_timestamp;
-
- xinput_gamepad() {
- attached = false;
- vibrating = false;
- ff_timestamp = 0;
- ff_end_timestamp = 0;
- last_packet = 0;
- }
+ uint64_t ff_timestamp = 0;
+ uint64_t ff_end_timestamp = 0;
};
typedef DWORD(WINAPI *XInputGetState_t)(DWORD dwUserIndex, XINPUT_STATE *pState);
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 646bc3aa4c..451f3bf18c 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -46,7 +46,7 @@
#include "main/main.h"
#include "platform/windows/display_server_windows.h"
#include "servers/audio_server.h"
-#include "servers/rendering/rendering_server_raster.h"
+#include "servers/rendering/rendering_server_default.h"
#include "servers/rendering/rendering_server_wrap_mt.h"
#include "windows_terminal_logger.h"
@@ -183,7 +183,6 @@ void OS_Windows::initialize() {
FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_RESOURCES);
FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_USERDATA);
FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_FILESYSTEM);
- //FileAccessBufferedFA<FileAccessWindows>::make_default();
DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_RESOURCES);
DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_USERDATA);
DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_FILESYSTEM);
@@ -562,21 +561,21 @@ String OS_Windows::get_locale() const {
LANGID langid = GetUserDefaultUILanguage();
String neutral;
- int lang = langid & ((1 << 9) - 1);
- int sublang = langid & ~((1 << 9) - 1);
+ int lang = PRIMARYLANGID(langid);
+ int sublang = SUBLANGID(langid);
while (wl->locale) {
if (wl->main_lang == lang && wl->sublang == SUBLANG_NEUTRAL)
neutral = wl->locale;
if (lang == wl->main_lang && sublang == wl->sublang)
- return wl->locale;
+ return String(wl->locale).replace("-", "_");
wl++;
}
if (neutral != "")
- return neutral;
+ return String(neutral).replace("-", "_");
return "en";
}
@@ -802,6 +801,11 @@ void OS_Windows::set_current_tablet_driver(const String &p_driver) {
}
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
+ ticks_per_second = 0;
+ ticks_start = 0;
+ main_loop = nullptr;
+ process_map = nullptr;
+
//Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink.
HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll");
if (wintab_lib) {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index a3dbb23182..5451e15d36 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -40,7 +40,7 @@
#include "drivers/winmidi/midi_driver_winmidi.h"
#include "key_mapping_windows.h"
#include "servers/audio_server.h"
-#include "servers/rendering/rasterizer.h"
+#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering_server.h"
#ifdef XAUDIO2_ENABLED
#include "drivers/xaudio2/audio_driver_xaudio2.h"