summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/README.md14
-rw-r--r--platform/android/android_input_handler.cpp76
-rw-r--r--platform/android/android_input_handler.h6
-rw-r--r--platform/android/android_keys_utils.cpp6
-rw-r--r--platform/android/android_keys_utils.h228
-rw-r--r--platform/android/audio_driver_opensl.h4
-rw-r--r--platform/android/detect.py27
-rw-r--r--platform/android/display_server_android.cpp18
-rw-r--r--platform/android/export/export_plugin.cpp124
-rw-r--r--platform/android/export/export_plugin.h7
-rw-r--r--platform/android/export/godot_plugin_config.cpp7
-rw-r--r--platform/android/export/gradle_export_util.cpp46
-rw-r--r--platform/android/export/gradle_export_util.h21
-rw-r--r--platform/android/java/app/AndroidManifest.xml5
-rw-r--r--platform/android/java/app/assetPacks/installTime/build.gradle8
-rw-r--r--platform/android/java/app/build.gradle5
-rw-r--r--platform/android/java/app/config.gradle14
-rw-r--r--platform/android/java/app/settings.gradle4
-rw-r--r--platform/android/java/build.gradle14
-rw-r--r--platform/android/java/gradle/wrapper/gradle-wrapper.jarbin54329 -> 59203 bytes
-rw-r--r--platform/android/java/gradle/wrapper/gradle-wrapper.properties5
-rwxr-xr-xplatform/android/java/gradlew53
-rw-r--r--platform/android/java/gradlew.bat47
-rw-r--r--platform/android/java/lib/AndroidManifest.xml3
-rw-r--r--platform/android/java/lib/build.gradle3
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java15
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotDownloaderService.java22
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java25
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotIO.java29
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java3
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java4
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java1
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularFallbackConfigChooser.java3
-rw-r--r--platform/android/java/settings.gradle3
-rw-r--r--platform/android/java_godot_lib_jni.cpp29
-rw-r--r--platform/android/java_godot_lib_jni.h2
-rw-r--r--platform/android/logo.pngbin951 -> 968 bytes
-rw-r--r--platform/android/os_android.cpp20
-rw-r--r--platform/android/os_android.h5
-rw-r--r--platform/iphone/app_delegate.h4
-rw-r--r--platform/iphone/app_delegate.mm6
-rw-r--r--platform/iphone/detect.py5
-rw-r--r--platform/iphone/display_layer.mm2
-rw-r--r--platform/iphone/display_server_iphone.mm16
-rw-r--r--platform/iphone/export/export_plugin.cpp20
-rw-r--r--platform/iphone/export/export_plugin.h2
-rw-r--r--platform/iphone/godot_iphone.mm4
-rw-r--r--platform/iphone/joypad_iphone.mm44
-rw-r--r--platform/iphone/keyboard_input_view.mm8
-rw-r--r--platform/iphone/os_iphone.h5
-rw-r--r--platform/iphone/os_iphone.mm7
-rw-r--r--platform/iphone/platform_config.h2
-rw-r--r--platform/javascript/.eslintrc.js8
-rw-r--r--platform/javascript/.eslintrc.libs.js1
-rw-r--r--platform/javascript/README.md15
-rw-r--r--platform/javascript/SCsub1
-rw-r--r--platform/javascript/api/javascript_tools_editor_plugin.cpp7
-rw-r--r--platform/javascript/audio_driver_javascript.cpp146
-rw-r--r--platform/javascript/audio_driver_javascript.h157
-rw-r--r--platform/javascript/detect.py23
-rw-r--r--platform/javascript/display_server_javascript.cpp475
-rw-r--r--platform/javascript/display_server_javascript.h52
-rw-r--r--platform/javascript/dom_keys.inc26
-rw-r--r--platform/javascript/export/export_plugin.cpp10
-rw-r--r--platform/javascript/export/export_plugin.h2
-rw-r--r--platform/javascript/godot_audio.h9
-rw-r--r--platform/javascript/godot_js.h30
-rw-r--r--platform/javascript/js/libs/audio.worklet.js61
-rw-r--r--platform/javascript/js/libs/library_godot_audio.js137
-rw-r--r--platform/javascript/js/libs/library_godot_display.js482
-rw-r--r--platform/javascript/js/libs/library_godot_input.js536
-rw-r--r--platform/javascript/js/libs/library_godot_os.js40
-rw-r--r--platform/javascript/os_javascript.cpp25
-rw-r--r--platform/javascript/os_javascript.h4
-rw-r--r--platform/javascript/package-lock.json6
-rw-r--r--platform/linuxbsd/README.md11
-rw-r--r--platform/linuxbsd/SCsub2
-rw-r--r--platform/linuxbsd/context_gl_x11.cpp257
-rw-r--r--platform/linuxbsd/crash_handler_linuxbsd.cpp2
-rw-r--r--platform/linuxbsd/detect.py77
-rw-r--r--platform/linuxbsd/detect_prime_x11.cpp4
-rw-r--r--platform/linuxbsd/detect_prime_x11.h2
-rw-r--r--platform/linuxbsd/display_server_x11.cpp833
-rw-r--r--platform/linuxbsd/display_server_x11.h28
-rw-r--r--platform/linuxbsd/export/export.cpp2
-rw-r--r--platform/linuxbsd/freedesktop_screensaver.cpp4
-rw-r--r--platform/linuxbsd/gl_manager_x11.cpp384
-rw-r--r--platform/linuxbsd/gl_manager_x11.h (renamed from platform/linuxbsd/context_gl_x11.h)86
-rw-r--r--platform/linuxbsd/joypad_linux.cpp16
-rw-r--r--platform/linuxbsd/joypad_linux.h2
-rw-r--r--platform/linuxbsd/key_mapping_x11.cpp506
-rw-r--r--platform/linuxbsd/key_mapping_x11.h5
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp5
-rw-r--r--platform/linuxbsd/platform_config.h2
-rw-r--r--platform/osx/SCsub2
-rw-r--r--platform/osx/context_gl_osx.mm161
-rw-r--r--platform/osx/crash_handler_osx.mm7
-rw-r--r--platform/osx/detect.py18
-rw-r--r--platform/osx/display_server_osx.h24
-rw-r--r--platform/osx/display_server_osx.mm619
-rw-r--r--platform/osx/export/export_plugin.cpp82
-rw-r--r--platform/osx/export/export_plugin.h2
-rw-r--r--platform/osx/gl_manager_osx.h (renamed from platform/osx/context_gl_osx.h)74
-rw-r--r--platform/osx/gl_manager_osx.mm233
-rw-r--r--platform/osx/joypad_osx.cpp43
-rw-r--r--platform/osx/joypad_osx.h5
-rw-r--r--platform/osx/os_osx.h5
-rw-r--r--platform/osx/os_osx.mm123
-rw-r--r--platform/osx/platform_config.h1
-rw-r--r--platform/uwp/SCsub2
-rw-r--r--platform/uwp/app_uwp.cpp (renamed from platform/uwp/app.cpp)7
-rw-r--r--platform/uwp/app_uwp.h (renamed from platform/uwp/app.h)6
-rw-r--r--platform/uwp/detect.py2
-rw-r--r--platform/uwp/export/export_plugin.cpp4
-rw-r--r--platform/uwp/export/export_plugin.h14
-rw-r--r--platform/uwp/joypad_uwp.cpp12
-rw-r--r--platform/uwp/os_uwp.cpp23
-rw-r--r--platform/uwp/os_uwp.h14
-rw-r--r--platform/windows/SCsub2
-rw-r--r--platform/windows/context_gl_windows.cpp186
-rw-r--r--platform/windows/crash_handler_windows.h1
-rw-r--r--platform/windows/detect.py19
-rw-r--r--platform/windows/display_server_windows.cpp525
-rw-r--r--platform/windows/display_server_windows.h20
-rw-r--r--platform/windows/gl_manager_windows.cpp346
-rw-r--r--platform/windows/gl_manager_windows.h (renamed from platform/windows/context_gl_windows.h)93
-rw-r--r--platform/windows/joypad_windows.cpp30
-rw-r--r--platform/windows/key_mapping_windows.cpp564
-rw-r--r--platform/windows/key_mapping_windows.h7
-rw-r--r--platform/windows/os_windows.cpp78
-rw-r--r--platform/windows/os_windows.h10
-rw-r--r--platform/windows/platform_config.h2
-rw-r--r--platform/windows/vulkan_context_win.h2
-rw-r--r--platform/windows/windows_terminal_logger.cpp1
137 files changed, 5332 insertions, 3555 deletions
diff --git a/platform/android/README.md b/platform/android/README.md
new file mode 100644
index 0000000000..343e588553
--- /dev/null
+++ b/platform/android/README.md
@@ -0,0 +1,14 @@
+# Android platform port
+
+This folder contains the Java and C++ (JNI) code for the Android platform port,
+using [Gradle](https://gradle.org/) as a build system.
+
+## Artwork license
+
+[`logo.png`](logo.png) and [`run_icon.png`](run_icon.png) are licensed under
+[Creative Commons Attribution 3.0 Unported](https://developer.android.com/distribute/marketing-tools/brand-guidelines#android_robot)
+per the Android logo usage guidelines:
+
+> The Android robot is reproduced or modified from work created and shared by
+> Google and used according to terms described in the Creative Commons 3.0
+> Attribution License.
diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp
index e03375e8d9..52f80b3080 100644
--- a/platform/android/android_input_handler.cpp
+++ b/platform/android/android_input_handler.cpp
@@ -45,7 +45,7 @@ void AndroidInputHandler::process_joy_event(AndroidInputHandler::JoypadEvent p_e
Input::get_singleton()->joy_axis(p_event.device, (JoyAxis)p_event.index, value);
break;
case JOY_EVENT_HAT:
- Input::get_singleton()->joy_hat(p_event.device, (HatMask)p_event.hat);
+ Input::get_singleton()->joy_hat(p_event.device, p_event.hat);
break;
default:
return;
@@ -82,37 +82,37 @@ void AndroidInputHandler::process_key_event(int p_keycode, int p_scancode, int p
Ref<InputEventKey> ev;
ev.instantiate();
int val = unicode;
- int keycode = android_get_keysym(p_keycode);
- int phy_keycode = android_get_keysym(p_scancode);
+ Key keycode = android_get_keysym(p_keycode);
+ Key phy_keycode = android_get_keysym(p_scancode);
- if (keycode == KEY_SHIFT) {
+ if (keycode == Key::SHIFT) {
shift_mem = p_pressed;
}
- if (keycode == KEY_ALT) {
+ if (keycode == Key::ALT) {
alt_mem = p_pressed;
}
- if (keycode == KEY_CTRL) {
+ if (keycode == Key::CTRL) {
control_mem = p_pressed;
}
- if (keycode == KEY_META) {
+ if (keycode == Key::META) {
meta_mem = p_pressed;
}
- ev->set_keycode((Key)keycode);
- ev->set_physical_keycode((Key)phy_keycode);
+ ev->set_keycode(keycode);
+ ev->set_physical_keycode(phy_keycode);
ev->set_unicode(val);
ev->set_pressed(p_pressed);
_set_key_modifier_state(ev);
if (val == '\n') {
- ev->set_keycode(KEY_ENTER);
+ ev->set_keycode(Key::ENTER);
} else if (val == 61448) {
- ev->set_keycode(KEY_BACKSPACE);
- ev->set_unicode(KEY_BACKSPACE);
+ ev->set_keycode(Key::BACKSPACE);
+ ev->set_unicode((char32_t)Key::BACKSPACE);
} else if (val == 61453) {
- ev->set_keycode(KEY_ENTER);
- ev->set_unicode(KEY_ENTER);
+ ev->set_keycode(Key::ENTER);
+ ev->set_unicode((char32_t)Key::ENTER);
} else if (p_keycode == 4) {
if (DisplayServerAndroid *dsa = Object::cast_to<DisplayServerAndroid>(DisplayServer::get_singleton())) {
dsa->send_window_event(DisplayServer::WINDOW_EVENT_GO_BACK_REQUEST, true);
@@ -223,7 +223,7 @@ void AndroidInputHandler::process_touch(int p_event, int p_pointer, const Vector
ev->set_pressed(false);
ev->set_position(touch[i].pos);
Input::get_singleton()->parse_input_event(ev);
- touch.remove(i);
+ touch.remove_at(i);
break;
}
@@ -305,15 +305,15 @@ void AndroidInputHandler::process_mouse_event(int input_device, int event_action
ev->set_pressed(true);
buttons_state = event_buttons_mask;
if (event_vertical_factor > 0) {
- _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_UP, event_vertical_factor);
+ _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_UP, event_vertical_factor);
} else if (event_vertical_factor < 0) {
- _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_DOWN, -event_vertical_factor);
+ _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_DOWN, -event_vertical_factor);
}
if (event_horizontal_factor > 0) {
- _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_RIGHT, event_horizontal_factor);
+ _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_RIGHT, event_horizontal_factor);
} else if (event_horizontal_factor < 0) {
- _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_LEFT, -event_horizontal_factor);
+ _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_LEFT, -event_horizontal_factor);
}
} break;
}
@@ -323,7 +323,7 @@ void AndroidInputHandler::_wheel_button_click(MouseButton event_buttons_mask, co
Ref<InputEventMouseButton> evd = ev->duplicate();
_set_key_modifier_state(evd);
evd->set_button_index(wheel_button);
- evd->set_button_mask(MouseButton(event_buttons_mask ^ (1 << (wheel_button - 1))));
+ evd->set_button_mask(MouseButton(event_buttons_mask ^ mouse_button_to_mask(wheel_button)));
evd->set_factor(factor);
Input::get_singleton()->parse_input_event(evd);
Ref<InputEventMouseButton> evdd = evd->duplicate();
@@ -339,7 +339,7 @@ void AndroidInputHandler::process_double_tap(int event_android_button_mask, Poin
_set_key_modifier_state(ev);
ev->set_position(p_pos);
ev->set_global_position(p_pos);
- ev->set_pressed(event_button_mask != 0);
+ ev->set_pressed(event_button_mask != MouseButton::NONE);
ev->set_button_index(_button_index_from_mask(event_button_mask));
ev->set_button_mask(event_button_mask);
ev->set_double_click(true);
@@ -348,37 +348,37 @@ void AndroidInputHandler::process_double_tap(int event_android_button_mask, Poin
MouseButton AndroidInputHandler::_button_index_from_mask(MouseButton button_mask) {
switch (button_mask) {
- case MOUSE_BUTTON_MASK_LEFT:
- return MOUSE_BUTTON_LEFT;
- case MOUSE_BUTTON_MASK_RIGHT:
- return MOUSE_BUTTON_RIGHT;
- case MOUSE_BUTTON_MASK_MIDDLE:
- return MOUSE_BUTTON_MIDDLE;
- case MOUSE_BUTTON_MASK_XBUTTON1:
- return MOUSE_BUTTON_XBUTTON1;
- case MOUSE_BUTTON_MASK_XBUTTON2:
- return MOUSE_BUTTON_XBUTTON2;
+ case MouseButton::MASK_LEFT:
+ return MouseButton::LEFT;
+ case MouseButton::MASK_RIGHT:
+ return MouseButton::RIGHT;
+ case MouseButton::MASK_MIDDLE:
+ return MouseButton::MIDDLE;
+ case MouseButton::MASK_XBUTTON1:
+ return MouseButton::MB_XBUTTON1;
+ case MouseButton::MASK_XBUTTON2:
+ return MouseButton::MB_XBUTTON2;
default:
- return MOUSE_BUTTON_NONE;
+ return MouseButton::NONE;
}
}
MouseButton AndroidInputHandler::_android_button_mask_to_godot_button_mask(int android_button_mask) {
- MouseButton godot_button_mask = MOUSE_BUTTON_NONE;
+ MouseButton godot_button_mask = MouseButton::NONE;
if (android_button_mask & AMOTION_EVENT_BUTTON_PRIMARY) {
- godot_button_mask |= MOUSE_BUTTON_MASK_LEFT;
+ godot_button_mask |= MouseButton::MASK_LEFT;
}
if (android_button_mask & AMOTION_EVENT_BUTTON_SECONDARY) {
- godot_button_mask |= MOUSE_BUTTON_MASK_RIGHT;
+ godot_button_mask |= MouseButton::MASK_RIGHT;
}
if (android_button_mask & AMOTION_EVENT_BUTTON_TERTIARY) {
- godot_button_mask |= MOUSE_BUTTON_MASK_MIDDLE;
+ godot_button_mask |= MouseButton::MASK_MIDDLE;
}
if (android_button_mask & AMOTION_EVENT_BUTTON_BACK) {
- godot_button_mask |= MOUSE_BUTTON_MASK_XBUTTON1;
+ godot_button_mask |= MouseButton::MASK_XBUTTON1;
}
if (android_button_mask & AMOTION_EVENT_BUTTON_FORWARD) {
- godot_button_mask |= MOUSE_BUTTON_MASK_XBUTTON2;
+ godot_button_mask |= MouseButton::MASK_XBUTTON2;
}
return godot_button_mask;
diff --git a/platform/android/android_input_handler.h b/platform/android/android_input_handler.h
index 2918ca300b..e0b4196f14 100644
--- a/platform/android/android_input_handler.h
+++ b/platform/android/android_input_handler.h
@@ -53,10 +53,10 @@ public:
struct JoypadEvent {
int device = 0;
int type = 0;
- int index = 0;
+ int index = 0; // Can be either JoyAxis or JoyButton.
bool pressed = false;
float value = 0;
- int hat = 0;
+ HatMask hat = HatMask::CENTER;
};
private:
@@ -65,7 +65,7 @@ private:
bool control_mem = false;
bool meta_mem = false;
- MouseButton buttons_state = MOUSE_BUTTON_NONE;
+ MouseButton buttons_state = MouseButton::NONE;
Vector<TouchPos> touch;
Point2 hover_prev_pos; // needed to calculate the relative position on hover events
diff --git a/platform/android/android_keys_utils.cpp b/platform/android/android_keys_utils.cpp
index 5aa546c17b..0cea0589ce 100644
--- a/platform/android/android_keys_utils.cpp
+++ b/platform/android/android_keys_utils.cpp
@@ -30,12 +30,12 @@
#include "android_keys_utils.h"
-unsigned int android_get_keysym(unsigned int p_code) {
- for (int i = 0; _ak_to_keycode[i].keysym != KEY_UNKNOWN; i++) {
+Key android_get_keysym(unsigned int p_code) {
+ for (int i = 0; _ak_to_keycode[i].keysym != Key::UNKNOWN; i++) {
if (_ak_to_keycode[i].keycode == p_code) {
return _ak_to_keycode[i].keysym;
}
}
- return KEY_UNKNOWN;
+ return Key::UNKNOWN;
}
diff --git a/platform/android/android_keys_utils.h b/platform/android/android_keys_utils.h
index 6d25a366a4..bac9bab6db 100644
--- a/platform/android/android_keys_utils.h
+++ b/platform/android/android_keys_utils.h
@@ -35,128 +35,128 @@
#include <core/os/keyboard.h>
struct _WinTranslatePair {
- unsigned int keysym = 0;
+ Key keysym = Key::NONE;
unsigned int keycode = 0;
};
static _WinTranslatePair _ak_to_keycode[] = {
- { KEY_TAB, AKEYCODE_TAB },
- { KEY_ENTER, AKEYCODE_ENTER },
- { KEY_SHIFT, AKEYCODE_SHIFT_LEFT },
- { KEY_SHIFT, AKEYCODE_SHIFT_RIGHT },
- { KEY_ALT, AKEYCODE_ALT_LEFT },
- { KEY_ALT, AKEYCODE_ALT_RIGHT },
- { KEY_MENU, AKEYCODE_MENU },
- { KEY_PAUSE, AKEYCODE_MEDIA_PLAY_PAUSE },
- { KEY_ESCAPE, AKEYCODE_BACK },
- { KEY_SPACE, AKEYCODE_SPACE },
- { KEY_PAGEUP, AKEYCODE_PAGE_UP },
- { KEY_PAGEDOWN, AKEYCODE_PAGE_DOWN },
- { KEY_HOME, AKEYCODE_HOME }, //(0x24)
- { KEY_LEFT, AKEYCODE_DPAD_LEFT },
- { KEY_UP, AKEYCODE_DPAD_UP },
- { KEY_RIGHT, AKEYCODE_DPAD_RIGHT },
- { KEY_DOWN, AKEYCODE_DPAD_DOWN },
- { KEY_PERIODCENTERED, AKEYCODE_DPAD_CENTER },
- { KEY_BACKSPACE, AKEYCODE_DEL },
- { KEY_0, AKEYCODE_0 }, ////0 key
- { KEY_1, AKEYCODE_1 }, ////1 key
- { KEY_2, AKEYCODE_2 }, ////2 key
- { KEY_3, AKEYCODE_3 }, ////3 key
- { KEY_4, AKEYCODE_4 }, ////4 key
- { KEY_5, AKEYCODE_5 }, ////5 key
- { KEY_6, AKEYCODE_6 }, ////6 key
- { KEY_7, AKEYCODE_7 }, ////7 key
- { KEY_8, AKEYCODE_8 }, ////8 key
- { KEY_9, AKEYCODE_9 }, ////9 key
- { KEY_A, AKEYCODE_A }, ////A key
- { KEY_B, AKEYCODE_B }, ////B key
- { KEY_C, AKEYCODE_C }, ////C key
- { KEY_D, AKEYCODE_D }, ////D key
- { KEY_E, AKEYCODE_E }, ////E key
- { KEY_F, AKEYCODE_F }, ////F key
- { KEY_G, AKEYCODE_G }, ////G key
- { KEY_H, AKEYCODE_H }, ////H key
- { KEY_I, AKEYCODE_I }, ////I key
- { KEY_J, AKEYCODE_J }, ////J key
- { KEY_K, AKEYCODE_K }, ////K key
- { KEY_L, AKEYCODE_L }, ////L key
- { KEY_M, AKEYCODE_M }, ////M key
- { KEY_N, AKEYCODE_N }, ////N key
- { KEY_O, AKEYCODE_O }, ////O key
- { KEY_P, AKEYCODE_P }, ////P key
- { KEY_Q, AKEYCODE_Q }, ////Q key
- { KEY_R, AKEYCODE_R }, ////R key
- { KEY_S, AKEYCODE_S }, ////S key
- { KEY_T, AKEYCODE_T }, ////T key
- { KEY_U, AKEYCODE_U }, ////U key
- { KEY_V, AKEYCODE_V }, ////V key
- { KEY_W, AKEYCODE_W }, ////W key
- { KEY_X, AKEYCODE_X }, ////X key
- { KEY_Y, AKEYCODE_Y }, ////Y key
- { KEY_Z, AKEYCODE_Z }, ////Z key
- { KEY_HOMEPAGE, AKEYCODE_EXPLORER },
- { KEY_LAUNCH0, AKEYCODE_BUTTON_A },
- { KEY_LAUNCH1, AKEYCODE_BUTTON_B },
- { KEY_LAUNCH2, AKEYCODE_BUTTON_C },
- { KEY_LAUNCH3, AKEYCODE_BUTTON_X },
- { KEY_LAUNCH4, AKEYCODE_BUTTON_Y },
- { KEY_LAUNCH5, AKEYCODE_BUTTON_Z },
- { KEY_LAUNCH6, AKEYCODE_BUTTON_L1 },
- { KEY_LAUNCH7, AKEYCODE_BUTTON_R1 },
- { KEY_LAUNCH8, AKEYCODE_BUTTON_L2 },
- { KEY_LAUNCH9, AKEYCODE_BUTTON_R2 },
- { KEY_LAUNCHA, AKEYCODE_BUTTON_THUMBL },
- { KEY_LAUNCHB, AKEYCODE_BUTTON_THUMBR },
- { KEY_LAUNCHC, AKEYCODE_BUTTON_START },
- { KEY_LAUNCHD, AKEYCODE_BUTTON_SELECT },
- { KEY_LAUNCHE, AKEYCODE_BUTTON_MODE },
- { KEY_VOLUMEMUTE, AKEYCODE_MUTE },
- { KEY_VOLUMEDOWN, AKEYCODE_VOLUME_DOWN },
- { KEY_VOLUMEUP, AKEYCODE_VOLUME_UP },
- { KEY_BACK, AKEYCODE_MEDIA_REWIND },
- { KEY_FORWARD, AKEYCODE_MEDIA_FAST_FORWARD },
- { KEY_MEDIANEXT, AKEYCODE_MEDIA_NEXT },
- { KEY_MEDIAPREVIOUS, AKEYCODE_MEDIA_PREVIOUS },
- { KEY_MEDIASTOP, AKEYCODE_MEDIA_STOP },
- { KEY_PLUS, AKEYCODE_PLUS },
- { KEY_EQUAL, AKEYCODE_EQUALS }, // the '+' key
- { KEY_COMMA, AKEYCODE_COMMA }, // the ',' key
- { KEY_MINUS, AKEYCODE_MINUS }, // the '-' key
- { KEY_SLASH, AKEYCODE_SLASH }, // the '/?' key
- { KEY_BACKSLASH, AKEYCODE_BACKSLASH },
- { KEY_BRACKETLEFT, AKEYCODE_LEFT_BRACKET },
- { KEY_BRACKETRIGHT, AKEYCODE_RIGHT_BRACKET },
- { KEY_CTRL, AKEYCODE_CTRL_LEFT },
- { KEY_CTRL, AKEYCODE_CTRL_RIGHT },
- { KEY_UNKNOWN, 0 }
+ { Key::TAB, AKEYCODE_TAB },
+ { Key::ENTER, AKEYCODE_ENTER },
+ { Key::SHIFT, AKEYCODE_SHIFT_LEFT },
+ { Key::SHIFT, AKEYCODE_SHIFT_RIGHT },
+ { Key::ALT, AKEYCODE_ALT_LEFT },
+ { Key::ALT, AKEYCODE_ALT_RIGHT },
+ { Key::MENU, AKEYCODE_MENU },
+ { Key::PAUSE, AKEYCODE_MEDIA_PLAY_PAUSE },
+ { Key::ESCAPE, AKEYCODE_BACK },
+ { Key::SPACE, AKEYCODE_SPACE },
+ { Key::PAGEUP, AKEYCODE_PAGE_UP },
+ { Key::PAGEDOWN, AKEYCODE_PAGE_DOWN },
+ { Key::HOME, AKEYCODE_HOME }, //(0x24)
+ { Key::LEFT, AKEYCODE_DPAD_LEFT },
+ { Key::UP, AKEYCODE_DPAD_UP },
+ { Key::RIGHT, AKEYCODE_DPAD_RIGHT },
+ { Key::DOWN, AKEYCODE_DPAD_DOWN },
+ { Key::PERIODCENTERED, AKEYCODE_DPAD_CENTER },
+ { Key::BACKSPACE, AKEYCODE_DEL },
+ { Key::KEY_0, AKEYCODE_0 },
+ { Key::KEY_1, AKEYCODE_1 },
+ { Key::KEY_2, AKEYCODE_2 },
+ { Key::KEY_3, AKEYCODE_3 },
+ { Key::KEY_4, AKEYCODE_4 },
+ { Key::KEY_5, AKEYCODE_5 },
+ { Key::KEY_6, AKEYCODE_6 },
+ { Key::KEY_7, AKEYCODE_7 },
+ { Key::KEY_8, AKEYCODE_8 },
+ { Key::KEY_9, AKEYCODE_9 },
+ { Key::A, AKEYCODE_A },
+ { Key::B, AKEYCODE_B },
+ { Key::C, AKEYCODE_C },
+ { Key::D, AKEYCODE_D },
+ { Key::E, AKEYCODE_E },
+ { Key::F, AKEYCODE_F },
+ { Key::G, AKEYCODE_G },
+ { Key::H, AKEYCODE_H },
+ { Key::I, AKEYCODE_I },
+ { Key::J, AKEYCODE_J },
+ { Key::K, AKEYCODE_K },
+ { Key::L, AKEYCODE_L },
+ { Key::M, AKEYCODE_M },
+ { Key::N, AKEYCODE_N },
+ { Key::O, AKEYCODE_O },
+ { Key::P, AKEYCODE_P },
+ { Key::Q, AKEYCODE_Q },
+ { Key::R, AKEYCODE_R },
+ { Key::S, AKEYCODE_S },
+ { Key::T, AKEYCODE_T },
+ { Key::U, AKEYCODE_U },
+ { Key::V, AKEYCODE_V },
+ { Key::W, AKEYCODE_W },
+ { Key::X, AKEYCODE_X },
+ { Key::Y, AKEYCODE_Y },
+ { Key::Z, AKEYCODE_Z },
+ { Key::HOMEPAGE, AKEYCODE_EXPLORER },
+ { Key::LAUNCH0, AKEYCODE_BUTTON_A },
+ { Key::LAUNCH1, AKEYCODE_BUTTON_B },
+ { Key::LAUNCH2, AKEYCODE_BUTTON_C },
+ { Key::LAUNCH3, AKEYCODE_BUTTON_X },
+ { Key::LAUNCH4, AKEYCODE_BUTTON_Y },
+ { Key::LAUNCH5, AKEYCODE_BUTTON_Z },
+ { Key::LAUNCH6, AKEYCODE_BUTTON_L1 },
+ { Key::LAUNCH7, AKEYCODE_BUTTON_R1 },
+ { Key::LAUNCH8, AKEYCODE_BUTTON_L2 },
+ { Key::LAUNCH9, AKEYCODE_BUTTON_R2 },
+ { Key::LAUNCHA, AKEYCODE_BUTTON_THUMBL },
+ { Key::LAUNCHB, AKEYCODE_BUTTON_THUMBR },
+ { Key::LAUNCHC, AKEYCODE_BUTTON_START },
+ { Key::LAUNCHD, AKEYCODE_BUTTON_SELECT },
+ { Key::LAUNCHE, AKEYCODE_BUTTON_MODE },
+ { Key::VOLUMEMUTE, AKEYCODE_MUTE },
+ { Key::VOLUMEDOWN, AKEYCODE_VOLUME_DOWN },
+ { Key::VOLUMEUP, AKEYCODE_VOLUME_UP },
+ { Key::BACK, AKEYCODE_MEDIA_REWIND },
+ { Key::FORWARD, AKEYCODE_MEDIA_FAST_FORWARD },
+ { Key::MEDIANEXT, AKEYCODE_MEDIA_NEXT },
+ { Key::MEDIAPREVIOUS, AKEYCODE_MEDIA_PREVIOUS },
+ { Key::MEDIASTOP, AKEYCODE_MEDIA_STOP },
+ { Key::PLUS, AKEYCODE_PLUS },
+ { Key::EQUAL, AKEYCODE_EQUALS }, // the '+' key
+ { Key::COMMA, AKEYCODE_COMMA }, // the ',' key
+ { Key::MINUS, AKEYCODE_MINUS }, // the '-' key
+ { Key::SLASH, AKEYCODE_SLASH }, // the '/?' key
+ { Key::BACKSLASH, AKEYCODE_BACKSLASH },
+ { Key::BRACKETLEFT, AKEYCODE_LEFT_BRACKET },
+ { Key::BRACKETRIGHT, AKEYCODE_RIGHT_BRACKET },
+ { Key::CTRL, AKEYCODE_CTRL_LEFT },
+ { Key::CTRL, AKEYCODE_CTRL_RIGHT },
+ { Key::UNKNOWN, 0 }
};
/*
TODO: map these android key:
- AKEYCODE_SOFT_LEFT = 1,
- AKEYCODE_SOFT_RIGHT = 2,
- AKEYCODE_CALL = 5,
- AKEYCODE_ENDCALL = 6,
- AKEYCODE_STAR = 17,
- AKEYCODE_POUND = 18,
- AKEYCODE_POWER = 26,
- AKEYCODE_CAMERA = 27,
- AKEYCODE_CLEAR = 28,
- AKEYCODE_SYM = 63,
- AKEYCODE_ENVELOPE = 65,
- AKEYCODE_GRAVE = 68,
- AKEYCODE_SEMICOLON = 74,
- AKEYCODE_APOSTROPHE = 75,
- AKEYCODE_AT = 77,
- AKEYCODE_NUM = 78,
- AKEYCODE_HEADSETHOOK = 79,
- AKEYCODE_FOCUS = 80, // *Camera* focus
- AKEYCODE_NOTIFICATION = 83,
- AKEYCODE_SEARCH = 84,
- AKEYCODE_PICTSYMBOLS = 94,
- AKEYCODE_SWITCH_CHARSET = 95,
+ AKEYCODE_SOFT_LEFT = 1,
+ AKEYCODE_SOFT_RIGHT = 2,
+ AKEYCODE_CALL = 5,
+ AKEYCODE_ENDCALL = 6,
+ AKEYCODE_STAR = 17,
+ AKEYCODE_POUND = 18,
+ AKEYCODE_POWER = 26,
+ AKEYCODE_CAMERA = 27,
+ AKEYCODE_CLEAR = 28,
+ AKEYCODE_SYM = 63,
+ AKEYCODE_ENVELOPE = 65,
+ AKEYCODE_GRAVE = 68,
+ AKEYCODE_SEMICOLON = 74,
+ AKEYCODE_APOSTROPHE = 75,
+ AKEYCODE_AT = 77,
+ AKEYCODE_NUM = 78,
+ AKEYCODE_HEADSETHOOK = 79,
+ AKEYCODE_FOCUS = 80, // *Camera* focus
+ AKEYCODE_NOTIFICATION = 83,
+ AKEYCODE_SEARCH = 84,
+ AKEYCODE_PICTSYMBOLS = 94,
+ AKEYCODE_SWITCH_CHARSET = 95,
*/
-unsigned int android_get_keysym(unsigned int p_code);
+Key android_get_keysym(unsigned int p_code);
#endif // ANDROID_KEYS_UTILS_H
diff --git a/platform/android/audio_driver_opensl.h b/platform/android/audio_driver_opensl.h
index e3efaddba2..fcc2513f3f 100644
--- a/platform/android/audio_driver_opensl.h
+++ b/platform/android/audio_driver_opensl.h
@@ -59,7 +59,6 @@ class AudioDriverOpenSL : public AudioDriver {
SLObjectItf sl;
SLEngineItf EngineItf;
SLObjectItf OutputMix;
- SLVolumeItf volumeItf;
SLObjectItf player;
SLObjectItf recorder;
SLAndroidSimpleBufferQueueItf bufferQueueItf;
@@ -68,7 +67,6 @@ class AudioDriverOpenSL : public AudioDriver {
SLDataFormat_PCM pcm;
SLDataSink audioSink;
SLDataLocator_OutputMix locator_outputmix;
- SLBufferQueueState state;
static AudioDriverOpenSL *s_ad;
@@ -89,8 +87,6 @@ class AudioDriverOpenSL : public AudioDriver {
virtual Error capture_init_device();
public:
- void set_singleton();
-
virtual const char *get_name() const;
virtual Error init();
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 61ccad9ac3..6f98dab2cc 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -27,8 +27,7 @@ def get_opts():
("ANDROID_NDK_ROOT", "Path to the Android NDK", get_android_ndk_root()),
("ANDROID_SDK_ROOT", "Path to the Android SDK", get_android_sdk_root()),
("ndk_platform", 'Target platform (android-<api>, e.g. "android-24")', "android-24"),
- EnumVariable("android_arch", "Target architecture", "armv7", ("armv7", "arm64v8", "x86", "x86_64")),
- BoolVariable("android_neon", "Enable NEON support (armv7 only)", True),
+ EnumVariable("android_arch", "Target architecture", "arm64v8", ("armv7", "arm64v8", "x86", "x86_64")),
]
@@ -143,10 +142,7 @@ def configure(env):
if env["android_arch"] not in ["armv7", "arm64v8", "x86", "x86_64"]:
env["android_arch"] = "armv7"
- neon_text = ""
- if env["android_arch"] == "armv7" and env["android_neon"]:
- neon_text = " (with NEON)"
- print("Building for Android, platform " + env["ndk_platform"] + " (" + env["android_arch"] + ")" + neon_text)
+ print("Building for Android, platform " + env["ndk_platform"] + " (" + env["android_arch"] + ")")
can_vectorize = True
if env["android_arch"] == "x86":
@@ -174,10 +170,7 @@ def configure(env):
target_subpath = "arm-linux-androideabi-4.9"
abi_subpath = "arm-linux-androideabi"
arch_subpath = "armeabi-v7a"
- if env["android_neon"]:
- env.extra_suffix = ".armv7.neon" + env.extra_suffix
- else:
- env.extra_suffix = ".armv7" + env.extra_suffix
+ env.extra_suffix = ".armv7" + env.extra_suffix
elif env["android_arch"] == "arm64v8":
if get_platform(env["ndk_platform"]) < 21:
print(
@@ -204,12 +197,10 @@ def configure(env):
env.Append(CPPDEFINES=["NDEBUG"])
if can_vectorize:
env.Append(CCFLAGS=["-ftree-vectorize"])
- if env["target"] == "release_debug":
- env.Append(CPPDEFINES=["DEBUG_ENABLED"])
elif env["target"] == "debug":
env.Append(LINKFLAGS=["-O0"])
env.Append(CCFLAGS=["-O0", "-g", "-fno-limit-debug-info"])
- env.Append(CPPDEFINES=["_DEBUG", "DEBUG_ENABLED"])
+ env.Append(CPPDEFINES=["_DEBUG"])
env.Append(CPPFLAGS=["-UNDEBUG"])
# Compiler configuration
@@ -288,7 +279,6 @@ def configure(env):
if get_platform(env["ndk_platform"]) >= 24:
env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)])
- env["neon_enabled"] = False
if env["android_arch"] == "x86":
target_opts = ["-target", "i686-none-linux-android"]
# The NDK adds this if targeting API < 21, so we can drop it when Godot targets it at least
@@ -301,12 +291,9 @@ def configure(env):
target_opts = ["-target", "armv7-none-linux-androideabi"]
env.Append(CCFLAGS="-march=armv7-a -mfloat-abi=softfp".split())
env.Append(CPPDEFINES=["__ARM_ARCH_7__", "__ARM_ARCH_7A__"])
- if env["android_neon"]:
- env["neon_enabled"] = True
- env.Append(CCFLAGS=["-mfpu=neon"])
- env.Append(CPPDEFINES=["__ARM_NEON__"])
- else:
- env.Append(CCFLAGS=["-mfpu=vfpv3-d16"])
+ # Enable ARM NEON instructions to compile more optimized code.
+ env.Append(CCFLAGS=["-mfpu=neon"])
+ env.Append(CPPDEFINES=["__ARM_NEON__"])
elif env["android_arch"] == "arm64v8":
target_opts = ["-target", "aarch64-none-linux-android"]
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index 720752d28f..505e7ac0eb 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -119,7 +119,9 @@ DisplayServer::ScreenOrientation DisplayServerAndroid::screen_get_orientation(in
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
ERR_FAIL_COND_V(!godot_io_java, SCREEN_LANDSCAPE);
- return (ScreenOrientation)godot_io_java->get_screen_orientation();
+ const int orientation = godot_io_java->get_screen_orientation();
+ ERR_FAIL_INDEX_V_MSG(orientation, 7, SCREEN_LANDSCAPE, "Unrecognized screen orientation");
+ return (ScreenOrientation)orientation;
}
int DisplayServerAndroid::get_screen_count() const {
@@ -344,8 +346,8 @@ void DisplayServerAndroid::process_events() {
Vector<String> DisplayServerAndroid::get_rendering_drivers_func() {
Vector<String> drivers;
-#ifdef OPENGL_ENABLED
- drivers.push_back("opengl");
+#ifdef GLES3_ENABLED
+ drivers.push_back("opengl3");
#endif
#ifdef VULKAN_ENABLED
drivers.push_back("vulkan");
@@ -407,13 +409,13 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
keep_screen_on = GLOBAL_GET("display/window/energy_saving/keep_screen_on");
-#if defined(OPENGL_ENABLED)
- if (rendering_driver == "opengl") {
+#if defined(GLES3_ENABLED)
+ if (rendering_driver == "opengl3") {
bool gl_initialization_error = false;
- if (RasterizerGLES2::is_viable() == OK) {
- RasterizerGLES2::register_config();
- RasterizerGLES2::make_current();
+ if (RasterizerGLES3::is_viable() == OK) {
+ RasterizerGLES3::register_config();
+ RasterizerGLES3::make_current();
} else {
gl_initialization_error = true;
}
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 6b4a326ba7..c5d3cbd966 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -221,6 +221,9 @@ static const LauncherIcon launcher_adaptive_icon_backgrounds[icon_densities_coun
static const int EXPORT_FORMAT_APK = 0;
static const int EXPORT_FORMAT_AAB = 1;
+static const char *APK_ASSETS_DIRECTORY = "res://android/build/assets";
+static const char *AAB_ASSETS_DIRECTORY = "res://android/build/assetPacks/installTime/src/main/assets";
+
void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) {
EditorExportPlatformAndroid *ea = (EditorExportPlatformAndroid *)ud;
@@ -426,6 +429,10 @@ String EditorExportPlatformAndroid::get_package_name(const String &p_package) co
return pname;
}
+String EditorExportPlatformAndroid::get_assets_directory(const Ref<EditorExportPreset> &p_preset, int p_export_format) const {
+ return p_export_format == EXPORT_FORMAT_AAB ? AAB_ASSETS_DIRECTORY : APK_ASSETS_DIRECTORY;
+}
+
bool EditorExportPlatformAndroid::is_package_name_valid(const String &p_package, String *r_error) const {
String pname = p_package;
@@ -491,11 +498,11 @@ bool EditorExportPlatformAndroid::is_package_name_valid(const String &p_package,
bool EditorExportPlatformAndroid::_should_compress_asset(const String &p_path, const Vector<uint8_t> &p_data) {
/*
- * By not compressing files with little or not benefit in doing so,
- * a performance gain is expected attime. Moreover, if the APK is
- * zip-aligned, assets stored as they are can be efficiently read by
- * Android by memory-mapping them.
- */
+ * By not compressing files with little or not benefit in doing so,
+ * a performance gain is expected attime. Moreover, if the APK is
+ * zip-aligned, assets stored as they are can be efficiently read by
+ * Android by memory-mapping them.
+ */
// -- Unconditional uncompress to mimic AAPT plus some other
@@ -744,9 +751,9 @@ void EditorExportPlatformAndroid::_get_permissions(const Ref<EditorExportPreset>
}
int xr_mode_index = p_preset->get("xr_features/xr_mode");
- if (xr_mode_index == 1 /* XRMode.OVR */) {
+ if (xr_mode_index == XR_MODE_OPENXR) {
int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
- if (hand_tracking_index > 0) {
+ if (hand_tracking_index > XR_HAND_TRACKING_NONE) {
if (r_permissions.find("com.oculus.permission.HAND_TRACKING") == -1) {
r_permissions.push_back("com.oculus.permission.HAND_TRACKING");
}
@@ -844,16 +851,11 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p
int iofs = ofs + 8;
string_count = decode_uint32(&p_manifest[iofs]);
- //styles_count = decode_uint32(&p_manifest[iofs + 4]);
+ // iofs + 4 is `styles_count`.
string_flags = decode_uint32(&p_manifest[iofs + 8]);
string_data_offset = decode_uint32(&p_manifest[iofs + 12]);
- //styles_offset = decode_uint32(&p_manifest[iofs + 16]);
- /*
- printf("string count: %i\n",string_count);
- printf("flags: %i\n",string_flags);
- printf("sdata ofs: %i\n",string_data_offset);
- printf("styles ofs: %i\n",styles_offset);
- */
+ // iofs + 16 is `styles_offset`.
+
uint32_t st_offset = iofs + 20;
string_table.resize(string_count);
uint32_t string_end = 0;
@@ -962,6 +964,20 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p
}
}
+ if (tname == "meta-data" && attrname == "name" && value == "xr_mode_metadata_name") {
+ // Update the meta-data 'android:name' attribute based on the selected XR mode.
+ if (xr_mode_index == XR_MODE_OPENXR) {
+ string_table.write[attr_value] = "com.samsung.android.vr.application.mode";
+ }
+ }
+
+ if (tname == "meta-data" && attrname == "value" && value == "xr_mode_metadata_value") {
+ // Update the meta-data 'android:value' attribute based on the selected XR mode.
+ if (xr_mode_index == XR_MODE_OPENXR) {
+ string_table.write[attr_value] = "vr_only";
+ }
+ }
+
iofs += 20;
}
@@ -976,7 +992,7 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p
Vector<bool> feature_required_list;
Vector<int> feature_versions;
- if (xr_mode_index == 1 /* XRMode.OVR */) {
+ if (xr_mode_index == XR_MODE_OPENXR) {
// Set degrees of freedom
feature_names.push_back("android.hardware.vr.headtracking");
feature_required_list.push_back(true);
@@ -984,11 +1000,19 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p
// Check for hand tracking
int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
- if (hand_tracking_index > 0) {
+ if (hand_tracking_index > XR_HAND_TRACKING_NONE) {
feature_names.push_back("oculus.software.handtracking");
- feature_required_list.push_back(hand_tracking_index == 2);
+ feature_required_list.push_back(hand_tracking_index == XR_HAND_TRACKING_REQUIRED);
feature_versions.push_back(-1); // no version attribute should be added.
}
+
+ // Check for passthrough
+ int passthrough_mode = p_preset->get("xr_features/passthrough");
+ if (passthrough_mode > XR_PASSTHROUGH_NONE) {
+ feature_names.push_back("com.oculus.feature.PASSTHROUGH");
+ feature_required_list.push_back(passthrough_mode == XR_PASSTHROUGH_REQUIRED);
+ feature_versions.push_back(-1);
+ }
}
if (feature_names.size() > 0) {
@@ -1610,11 +1634,11 @@ Vector<String> EditorExportPlatformAndroid::get_enabled_abis(const Ref<EditorExp
void EditorExportPlatformAndroid::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
- if (driver == "GLES2") {
+ if (driver == "opengl3") {
r_features->push_back("etc");
}
// FIXME: Review what texture formats are used for Vulkan.
- if (driver == "Vulkan") {
+ if (driver == "vulkan") {
r_features->push_back("etc2");
}
@@ -1637,10 +1661,12 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
}
plugins_changed.clear();
- Vector<String> abis = get_abis();
+ const Vector<String> abis = get_abis();
for (int i = 0; i < abis.size(); ++i) {
- String abi = abis[i];
- bool is_default = (abi == "armeabi-v7a" || abi == "arm64-v8a");
+ const String abi = abis[i];
+ // All Android devices supporting Vulkan run 64-bit Android,
+ // so there is usually no point in exporting for 32-bit Android.
+ const bool is_default = abi == "arm64-v8a";
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architectures/" + abi), is_default));
}
@@ -1663,11 +1689,11 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_adaptive_icon_foreground_option, PROPERTY_HINT_FILE, "*.png"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_adaptive_icon_background_option, PROPERTY_HINT_FILE, "*.png"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/32_bits_framebuffer"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/opengl_debug"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/xr_mode", PROPERTY_HINT_ENUM, "Regular,Oculus Mobile VR"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/xr_mode", PROPERTY_HINT_ENUM, "Regular,OpenXR"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/hand_tracking", PROPERTY_HINT_ENUM, "None,Optional,Required"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/passthrough", PROPERTY_HINT_ENUM, "None,Optional,Required"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_small"), true));
@@ -2134,10 +2160,17 @@ bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_pr
// Validate the Xr features are properly populated
int xr_mode_index = p_preset->get("xr_features/xr_mode");
int hand_tracking = p_preset->get("xr_features/hand_tracking");
- if (xr_mode_index != /* XRMode.OVR*/ 1) {
- if (hand_tracking > 0) {
+ int passthrough_mode = p_preset->get("xr_features/passthrough");
+ if (xr_mode_index != XR_MODE_OPENXR) {
+ if (hand_tracking > XR_HAND_TRACKING_NONE) {
+ valid = false;
+ err += TTR("\"Hand Tracking\" is only valid when \"Xr Mode\" is \"OpenXR\".");
+ err += "\n";
+ }
+
+ if (passthrough_mode > XR_PASSTHROUGH_NONE) {
valid = false;
- err += TTR("\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\".");
+ err += TTR("\"Passthrough\" is only valid when \"Xr Mode\" is \"OpenXR\".");
err += "\n";
}
}
@@ -2179,7 +2212,7 @@ void EditorExportPlatformAndroid::get_command_line_flags(const Ref<EditorExportP
Vector<String> command_line_strings = cmdline.strip_edges().split(" ");
for (int i = 0; i < command_line_strings.size(); i++) {
if (command_line_strings[i].strip_edges().length() == 0) {
- command_line_strings.remove(i);
+ command_line_strings.remove_at(i);
i--;
}
}
@@ -2199,17 +2232,12 @@ void EditorExportPlatformAndroid::get_command_line_flags(const Ref<EditorExportP
}
int xr_mode_index = p_preset->get("xr_features/xr_mode");
- if (xr_mode_index == 1) {
- command_line_strings.push_back("--xr_mode_ovr");
+ if (xr_mode_index == XR_MODE_OPENXR) {
+ command_line_strings.push_back("--xr_mode_openxr");
} else { // XRMode.REGULAR is the default.
command_line_strings.push_back("--xr_mode_regular");
}
- bool use_32_bit_framebuffer = p_preset->get("graphics/32_bits_framebuffer");
- if (use_32_bit_framebuffer) {
- command_line_strings.push_back("--use_depth_32");
- }
-
bool immersive = p_preset->get("screen/immersive_mode");
if (immersive) {
command_line_strings.push_back("--use_immersive");
@@ -2335,11 +2363,21 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
void EditorExportPlatformAndroid::_clear_assets_directory() {
DirAccessRef da_res = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- if (da_res->dir_exists("res://android/build/assets")) {
- print_verbose("Clearing assets directory..");
- DirAccessRef da_assets = DirAccess::open("res://android/build/assets");
+
+ // Clear the APK assets directory
+ if (da_res->dir_exists(APK_ASSETS_DIRECTORY)) {
+ print_verbose("Clearing APK assets directory..");
+ DirAccessRef da_assets = DirAccess::open(APK_ASSETS_DIRECTORY);
+ da_assets->erase_contents_recursive();
+ da_res->remove(APK_ASSETS_DIRECTORY);
+ }
+
+ // Clear the AAB assets directory
+ if (da_res->dir_exists(AAB_ASSETS_DIRECTORY)) {
+ print_verbose("Clearing AAB assets directory..");
+ DirAccessRef da_assets = DirAccess::open(AAB_ASSETS_DIRECTORY);
da_assets->erase_contents_recursive();
- da_res->remove("res://android/build/assets");
+ da_res->remove(AAB_ASSETS_DIRECTORY);
}
}
@@ -2459,6 +2497,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
return ERR_UNCONFIGURED;
}
}
+ const String assets_directory = get_assets_directory(p_preset, export_format);
String sdk_path = EDITOR_GET("export/android/android_sdk_path");
ERR_FAIL_COND_V_MSG(sdk_path.is_empty(), ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/android_sdk_path'.");
print_verbose("Android sdk path: " + sdk_path);
@@ -2480,6 +2519,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
if (!apk_expansion) {
print_verbose("Exporting project files..");
CustomExportData user_data;
+ user_data.assets_directory = assets_directory;
user_data.debug = p_debug;
err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, &user_data, copy_gradle_so);
if (err != OK) {
@@ -2501,7 +2541,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
}
}
print_verbose("Storing command line flags..");
- store_file_at_path("res://android/build/assets/_cl_", command_line_flags);
+ store_file_at_path(assets_directory + "/_cl_", command_line_flags);
print_verbose("Updating ANDROID_HOME environment to " + sdk_path);
OS::get_singleton()->set_environment("ANDROID_HOME", sdk_path); //set and overwrite if required
@@ -2942,7 +2982,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
void EditorExportPlatformAndroid::get_platform_features(List<String> *r_features) {
r_features->push_back("mobile");
- r_features->push_back("Android");
+ r_features->push_back("android");
}
void EditorExportPlatformAndroid::resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) {
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
index b061ee4e04..e0ffaa718b 100644
--- a/platform/android/export/export_plugin.h
+++ b/platform/android/export/export_plugin.h
@@ -87,11 +87,6 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
EditorProgress *ep = nullptr;
};
- struct CustomExportData {
- bool debug;
- Vector<String> libs;
- };
-
Vector<PluginConfigAndroid> plugins;
String last_plugin_names;
uint64_t last_custom_build_time = 0;
@@ -109,6 +104,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
String get_package_name(const String &p_package) const;
+ String get_assets_directory(const Ref<EditorExportPreset> &p_preset, int p_export_format) const;
+
bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const;
static bool _should_compress_asset(const String &p_path, const Vector<uint8_t> &p_data);
diff --git a/platform/android/export/godot_plugin_config.cpp b/platform/android/export/godot_plugin_config.cpp
index ba7b8ce6c7..205cba3350 100644
--- a/platform/android/export/godot_plugin_config.cpp
+++ b/platform/android/export/godot_plugin_config.cpp
@@ -78,14 +78,13 @@ Vector<PluginConfigAndroid> PluginConfigAndroid::get_prebuilt_plugins(String plu
bool PluginConfigAndroid::is_plugin_config_valid(PluginConfigAndroid plugin_config) {
bool valid_name = !plugin_config.name.is_empty();
bool valid_binary_type = plugin_config.binary_type == PluginConfigAndroid::BINARY_TYPE_LOCAL ||
- plugin_config.binary_type == PluginConfigAndroid::BINARY_TYPE_REMOTE;
+ plugin_config.binary_type == PluginConfigAndroid::BINARY_TYPE_REMOTE;
bool valid_binary = false;
if (valid_binary_type) {
valid_binary = !plugin_config.binary.is_empty() &&
- (plugin_config.binary_type == PluginConfigAndroid::BINARY_TYPE_REMOTE ||
-
- FileAccess::exists(plugin_config.binary));
+ (plugin_config.binary_type == PluginConfigAndroid::BINARY_TYPE_REMOTE ||
+ FileAccess::exists(plugin_config.binary));
}
bool valid_local_dependencies = true;
diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp
index 6fbdf73cd0..658c0ecd0a 100644
--- a/platform/android/export/gradle_export_util.cpp
+++ b/platform/android/export/gradle_export_util.cpp
@@ -121,17 +121,33 @@ Error store_string_at_path(const String &p_path, const String &p_data) {
// It's functionality mirrors that of the method save_apk_file.
// This method will be called ONLY when custom build is enabled.
Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
- String dst_path = p_path.replace_first("res://", "res://android/build/assets/");
+ CustomExportData *export_data = (CustomExportData *)p_userdata;
+ String dst_path = p_path.replace_first("res://", export_data->assets_directory + "/");
print_verbose("Saving project files from " + p_path + " into " + dst_path);
Error err = store_file_at_path(dst_path, p_data);
return err;
}
+String _android_xml_escape(const String &p_string) {
+ // Android XML requires strings to be both valid XML (`xml_escape()`) but also
+ // to escape characters which are valid XML but have special meaning in Android XML.
+ // https://developer.android.com/guide/topics/resources/string-resource.html#FormattingAndStyling
+ // Note: Didn't handle U+XXXX unicode chars, could be done if needed.
+ return p_string
+ .replace("@", "\\@")
+ .replace("?", "\\?")
+ .replace("'", "\\'")
+ .replace("\"", "\\\"")
+ .replace("\n", "\\n")
+ .replace("\t", "\\t")
+ .xml_escape(false);
+}
+
// Creates strings.xml files inside the gradle project for different locales.
Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset, const String &project_name) {
print_verbose("Creating strings resources for supported locales for project " + project_name);
// Stores the string into the default values directory.
- String processed_default_xml_string = vformat(godot_project_name_xml_string, project_name.xml_escape(true));
+ String processed_default_xml_string = vformat(godot_project_name_xml_string, _android_xml_escape(project_name));
store_string_at_path("res://android/build/res/values/godot_project_name_string.xml", processed_default_xml_string);
// Searches the Gradle project res/ directory to find all supported locales
@@ -157,7 +173,7 @@ Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset
String locale_directory = "res://android/build/res/" + file + "/godot_project_name_string.xml";
if (ProjectSettings::get_singleton()->has_setting(property_name)) {
String locale_project_name = ProjectSettings::get_singleton()->get(property_name);
- String processed_xml_string = vformat(godot_project_name_xml_string, locale_project_name.xml_escape(true));
+ String processed_xml_string = vformat(godot_project_name_xml_string, _android_xml_escape(locale_project_name));
print_verbose("Storing project name for locale " + locale + " under " + locale_directory);
store_string_at_path(locale_directory, processed_xml_string);
} else {
@@ -175,7 +191,7 @@ String bool_to_string(bool v) {
String _get_gles_tag() {
bool min_gles3 = ProjectSettings::get_singleton()->get("rendering/driver/driver_name") == "GLES3" &&
- !ProjectSettings::get_singleton()->get("rendering/driver/fallback_to_gles2");
+ !ProjectSettings::get_singleton()->get("rendering/driver/fallback_to_gles2");
return min_gles3 ? " <uses-feature android:glEsVersion=\"0x00030000\" android:required=\"true\" />\n" : "";
}
@@ -195,16 +211,24 @@ String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset) {
String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset) {
String manifest_xr_features;
- bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
+ int xr_mode_index = (int)(p_preset->get("xr_features/xr_mode"));
+ bool uses_xr = xr_mode_index == XR_MODE_OPENXR;
if (uses_xr) {
manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vr.headtracking\" android:required=\"true\" android:version=\"1\" />\n";
int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
- if (hand_tracking_index == 1) {
+ if (hand_tracking_index == XR_HAND_TRACKING_OPTIONAL) {
manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"false\" />\n";
- } else if (hand_tracking_index == 2) {
+ } else if (hand_tracking_index == XR_HAND_TRACKING_REQUIRED) {
manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"true\" />\n";
}
+
+ int passthrough_mode = p_preset->get("xr_features/passthrough");
+ if (passthrough_mode == XR_PASSTHROUGH_OPTIONAL) {
+ manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"com.oculus.feature.PASSTHROUGH\" android:required=\"false\" />\n";
+ } else if (passthrough_mode == XR_PASSTHROUGH_REQUIRED) {
+ manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"com.oculus.feature.PASSTHROUGH\" android:required=\"true\" />\n";
+ }
}
return manifest_xr_features;
}
@@ -223,7 +247,8 @@ String _get_instrumentation_tag(const Ref<EditorExportPreset> &p_preset) {
}
String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) {
- bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
+ int xr_mode_index = (int)(p_preset->get("xr_features/xr_mode"));
+ bool uses_xr = xr_mode_index == XR_MODE_OPENXR;
String orientation = _get_android_orientation_label(DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation"))));
String manifest_activity_text = vformat(
" <activity android:name=\"com.godot.game.GodotApp\" "
@@ -240,6 +265,8 @@ String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) {
}
String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_storage_permission) {
+ int xr_mode_index = (int)(p_preset->get("xr_features/xr_mode"));
+ bool uses_xr = xr_mode_index == XR_MODE_OPENXR;
String manifest_application_text = vformat(
" <application android:label=\"@string/godot_project_name_string\"\n"
" android:allowBackup=\"%s\"\n"
@@ -254,6 +281,9 @@ String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_
bool_to_string(p_preset->get("package/retain_data_on_uninstall")),
bool_to_string(p_has_storage_permission));
+ if (uses_xr) {
+ manifest_application_text += " <meta-data tools:node=\"replace\" android:name=\"com.samsung.android.vr.application.mode\" android:value=\"vr_only\" />\n";
+ }
manifest_application_text += _get_activity_tag(p_preset);
manifest_application_text += " </application>\n";
return manifest_application_text;
diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h
index 8a93c25d79..db05c7534c 100644
--- a/platform/android/export/gradle_export_util.h
+++ b/platform/android/export/gradle_export_util.h
@@ -44,6 +44,27 @@ const String godot_project_name_xml_string = R"(<?xml version="1.0" encoding="ut
</resources>
)";
+// Supported XR modes.
+// This should match the entries in 'platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java'
+static const int XR_MODE_REGULAR = 0;
+static const int XR_MODE_OPENXR = 1;
+
+// Supported XR hand tracking modes.
+static const int XR_HAND_TRACKING_NONE = 0;
+static const int XR_HAND_TRACKING_OPTIONAL = 1;
+static const int XR_HAND_TRACKING_REQUIRED = 2;
+
+// Supported XR passthrough modes.
+static const int XR_PASSTHROUGH_NONE = 0;
+static const int XR_PASSTHROUGH_OPTIONAL = 1;
+static const int XR_PASSTHROUGH_REQUIRED = 2;
+
+struct CustomExportData {
+ String assets_directory;
+ bool debug;
+ Vector<String> libs;
+};
+
int _get_android_orientation_value(DisplayServer::ScreenOrientation screen_orientation);
String _get_android_orientation_label(DisplayServer::ScreenOrientation screen_orientation);
diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml
index d7bf6cef30..9ae6367b42 100644
--- a/platform/android/java/app/AndroidManifest.xml
+++ b/platform/android/java/app/AndroidManifest.xml
@@ -33,6 +33,11 @@
<!-- The following metadata values are replaced when Godot exports, modifying them here has no effect. -->
<!-- Do these changes in the export preset. Adding new ones is fine. -->
+ <!-- XR mode metadata. This is modified by the exporter based on the selected xr mode. DO NOT CHANGE the values here. -->
+ <meta-data
+ android:name="xr_mode_metadata_name"
+ android:value="xr_mode_metadata_value" />
+
<activity
android:name=".GodotApp"
android:label="@string/godot_project_name_string"
diff --git a/platform/android/java/app/assetPacks/installTime/build.gradle b/platform/android/java/app/assetPacks/installTime/build.gradle
new file mode 100644
index 0000000000..b06faac374
--- /dev/null
+++ b/platform/android/java/app/assetPacks/installTime/build.gradle
@@ -0,0 +1,8 @@
+apply plugin: 'com.android.asset-pack'
+
+assetPack {
+ packName = "installTime" // Directory name for the asset pack
+ dynamicDelivery {
+ deliveryType = "install-time" // Delivery mode
+ }
+}
diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle
index 18e07c3762..a391a3ca9a 100644
--- a/platform/android/java/app/build.gradle
+++ b/platform/android/java/app/build.gradle
@@ -34,9 +34,8 @@ allprojects {
}
dependencies {
- implementation libraries.supportCoreUtils
implementation libraries.kotlinStdLib
- implementation libraries.v4Support
+ implementation libraries.androidxFragment
if (rootProject.findProject(":lib")) {
implementation project(":lib")
@@ -73,6 +72,8 @@ android {
targetCompatibility versions.javaVersion
}
+ assetPacks = [":assetPacks:installTime"]
+
defaultConfig {
// The default ignore pattern for the 'assets' directory includes hidden files and directories which are used by Godot projects.
aaptOptions {
diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle
index fad64c675f..2a2850df0f 100644
--- a/platform/android/java/app/config.gradle
+++ b/platform/android/java/app/config.gradle
@@ -1,23 +1,21 @@
ext.versions = [
- androidGradlePlugin: '4.2.2',
+ androidGradlePlugin: '7.0.3',
compileSdk : 30,
- minSdk : 19,
- targetSdk : 30,
+ minSdk : 19, // Also update 'platform/android/java/lib/AndroidManifest.xml#minSdkVersion' value
+ targetSdk : 30, // Also update 'platform/android/java/lib/AndroidManifest.xml#targetSdkVersion' value
buildTools : '30.0.3',
- supportCoreUtils : '1.0.0',
kotlinVersion : '1.5.10',
- v4Support : '1.0.0',
- javaVersion : 1.8,
+ fragmentVersion : '1.3.6',
+ javaVersion : 11,
ndkVersion : '21.4.7075529' // Also update 'platform/android/detect.py#get_project_ndk_version()' when this is updated.
]
ext.libraries = [
androidGradlePlugin: "com.android.tools.build:gradle:$versions.androidGradlePlugin",
- supportCoreUtils : "androidx.legacy:legacy-support-core-utils:$versions.supportCoreUtils",
kotlinGradlePlugin : "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlinVersion",
kotlinStdLib : "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlinVersion",
- v4Support : "androidx.legacy:legacy-support-v4:$versions.v4Support"
+ androidxFragment : "androidx.fragment:fragment:$versions.fragmentVersion",
]
ext.getExportPackageName = { ->
diff --git a/platform/android/java/app/settings.gradle b/platform/android/java/app/settings.gradle
index 33b863c7bf..e38d7b2ba6 100644
--- a/platform/android/java/app/settings.gradle
+++ b/platform/android/java/app/settings.gradle
@@ -1,2 +1,2 @@
-// Empty settings.gradle file to denote this directory as being the root project
-// of the Godot custom build.
+// This is the root directory of the Godot custom build.
+include ':assetPacks:installTime'
diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle
index 87bb2ea218..efdcc6c77b 100644
--- a/platform/android/java/build.gradle
+++ b/platform/android/java/build.gradle
@@ -158,9 +158,9 @@ def templateBuildTasks() {
/**
* Master task used to coordinate the tasks defined above to generate the set of Godot templates.
*/
-task generateGodotTemplates(type: GradleBuild) {
- startParameter.excludedTaskNames = templateExcludedBuildTask()
- tasks = templateBuildTasks()
+task generateGodotTemplates {
+ gradle.startParameter.excludedTaskNames += templateExcludedBuildTask()
+ dependsOn = templateBuildTasks()
finalizedBy 'zipCustomBuild'
}
@@ -168,12 +168,12 @@ task generateGodotTemplates(type: GradleBuild) {
/**
* Generates the same output as generateGodotTemplates but with dev symbols
*/
-task generateDevTemplate (type: GradleBuild) {
+task generateDevTemplate {
// add parameter to set symbols to true
- startParameter.projectProperties += [doNotStrip: true]
+ gradle.startParameter.projectProperties += [doNotStrip: true]
- startParameter.excludedTaskNames = templateExcludedBuildTask()
- tasks = templateBuildTasks()
+ gradle.startParameter.excludedTaskNames += templateExcludedBuildTask()
+ dependsOn = templateBuildTasks()
finalizedBy 'zipCustomBuild'
}
diff --git a/platform/android/java/gradle/wrapper/gradle-wrapper.jar b/platform/android/java/gradle/wrapper/gradle-wrapper.jar
index f6b961fd5a..e708b1c023 100644
--- a/platform/android/java/gradle/wrapper/gradle-wrapper.jar
+++ b/platform/android/java/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/platform/android/java/gradle/wrapper/gradle-wrapper.properties b/platform/android/java/gradle/wrapper/gradle-wrapper.properties
index 74c5636f8a..ffed3a254e 100644
--- a/platform/android/java/gradle/wrapper/gradle-wrapper.properties
+++ b/platform/android/java/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Wed Jun 23 23:42:22 PDT 2021
distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
distributionPath=wrapper/dists
-zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/platform/android/java/gradlew b/platform/android/java/gradlew
index cccdd3d517..4f906e0c81 100755
--- a/platform/android/java/gradlew
+++ b/platform/android/java/gradlew
@@ -1,5 +1,21 @@
#!/usr/bin/env sh
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
##############################################################################
##
## Gradle start up script for UN*X
@@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
@@ -66,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -109,10 +126,11 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
@@ -138,19 +156,19 @@ if $cygwin ; then
else
eval `echo args$i`="\"$arg\""
fi
- i=$((i+1))
+ i=`expr $i + 1`
done
case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@@ -159,14 +177,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
-APP_ARGS=$(save "$@")
+APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
- cd "$(dirname "$0")"
-fi
-
exec "$JAVACMD" "$@"
diff --git a/platform/android/java/gradlew.bat b/platform/android/java/gradlew.bat
index 11cc30edb0..107acd32c4 100644
--- a/platform/android/java/gradlew.bat
+++ b/platform/android/java/gradlew.bat
@@ -1,7 +1,23 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
-@rem Gradle startup script for Windows
+@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -35,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -45,28 +64,14 @@ echo location of your Java installation.
goto fail
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
@@ -75,7 +80,7 @@ if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
diff --git a/platform/android/java/lib/AndroidManifest.xml b/platform/android/java/lib/AndroidManifest.xml
index 3034794d69..2de62271c4 100644
--- a/platform/android/java/lib/AndroidManifest.xml
+++ b/platform/android/java/lib/AndroidManifest.xml
@@ -4,6 +4,9 @@
android:versionCode="1"
android:versionName="1.0">
+ <!-- Should match the mindSdk and targetSdk values in platform/android/java/app/config.gradle -->
+ <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="30" />
+
<application>
<!-- Records the version of the Godot library -->
diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle
index 663ba73d40..fbed4ed078 100644
--- a/platform/android/java/lib/build.gradle
+++ b/platform/android/java/lib/build.gradle
@@ -2,9 +2,8 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
dependencies {
- implementation libraries.supportCoreUtils
implementation libraries.kotlinStdLib
- implementation libraries.v4Support
+ implementation libraries.androidxFragment
}
def pathToRootDir = "../../../../"
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 70bc73b9ad..17ff3c75c0 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -119,7 +119,6 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
private Button mWiFiSettingsButton;
private XRMode xrMode = XRMode.REGULAR;
- private boolean use_32_bits = false;
private boolean use_immersive = false;
private boolean use_debug_opengl = false;
private boolean mStatePaused;
@@ -263,11 +262,10 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
GodotLib.setup(command_line);
final String videoDriver = GodotLib.getGlobal("rendering/driver/driver_name");
- if (videoDriver.equals("Vulkan")) {
+ if (videoDriver.equals("vulkan")) {
mRenderView = new GodotVulkanRenderView(activity, this);
} else {
- mRenderView = new GodotGLRenderView(activity, this, xrMode, use_32_bits,
- use_debug_opengl);
+ mRenderView = new GodotGLRenderView(activity, this, xrMode, use_debug_opengl);
}
View view = mRenderView.getView();
@@ -504,10 +502,8 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
boolean has_extra = i < command_line.length - 1;
if (command_line[i].equals(XRMode.REGULAR.cmdLineArg)) {
xrMode = XRMode.REGULAR;
- } else if (command_line[i].equals(XRMode.OVR.cmdLineArg)) {
- xrMode = XRMode.OVR;
- } else if (command_line[i].equals("--use_depth_32")) {
- use_32_bits = true;
+ } else if (command_line[i].equals(XRMode.OPENXR.cmdLineArg)) {
+ xrMode = XRMode.OPENXR;
} else if (command_line[i].equals("--debug_opengl")) {
use_debug_opengl = true;
} else if (command_line[i].equals("--use_immersive")) {
@@ -578,8 +574,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
if (!pack_valid) {
Intent notifierIntent = new Intent(activity, activity.getClass());
- notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(activity, 0,
notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT);
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotDownloaderService.java b/platform/android/java/lib/src/org/godotengine/godot/GodotDownloaderService.java
index d33faab641..09337ef989 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotDownloaderService.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotDownloaderService.java
@@ -50,9 +50,9 @@ public class GodotDownloaderService extends DownloaderService {
};
/**
- * This public key comes from your Android Market publisher account, and it
- * used by the LVL to validate responses from Market on your behalf.
- */
+ * This public key comes from your Android Market publisher account, and it
+ * used by the LVL to validate responses from Market on your behalf.
+ */
@Override
public String getPublicKey() {
SharedPreferences prefs = getApplicationContext().getSharedPreferences("app_data_keys", Context.MODE_PRIVATE);
@@ -63,20 +63,20 @@ public class GodotDownloaderService extends DownloaderService {
}
/**
- * This is used by the preference obfuscater to make sure that your
- * obfuscated preferences are different than the ones used by other
- * applications.
- */
+ * This is used by the preference obfuscater to make sure that your
+ * obfuscated preferences are different than the ones used by other
+ * applications.
+ */
@Override
public byte[] getSALT() {
return SALT;
}
/**
- * Fill this in with the class name for your alarm receiver. We do this
- * because receivers must be unique across all of Android (it's a good idea
- * to make sure that your receiver is in your unique package)
- */
+ * Fill this in with the class name for your alarm receiver. We do this
+ * because receivers must be unique across all of Android (it's a good idea
+ * to make sure that your receiver is in your unique package)
+ */
@Override
public String getAlarmReceiverClassName() {
Log.d("GODOT", "getAlarmReceiverClassName()");
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 a9d45c943b..d5b0b67903 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
@@ -78,10 +78,8 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
private final GodotRenderer godotRenderer;
private PointerIcon pointerIcon;
- public GodotGLRenderView(Context context, Godot godot, XRMode xrMode, boolean p_use_32_bits,
- boolean p_use_debug_opengl) {
+ public GodotGLRenderView(Context context, Godot godot, XRMode xrMode, boolean p_use_debug_opengl) {
super(context);
- GLUtils.use_32 = p_use_32_bits;
GLUtils.use_debug_opengl = p_use_debug_opengl;
this.godot = godot;
@@ -91,7 +89,7 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
pointerIcon = PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT);
}
- init(xrMode, false, 16, 0);
+ init(xrMode, false);
}
@Override
@@ -172,11 +170,11 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
return pointerIcon;
}
- private void init(XRMode xrMode, boolean translucent, int depth, int stencil) {
+ private void init(XRMode xrMode, boolean translucent) {
setPreserveEGLContextOnPause(true);
setFocusableInTouchMode(true);
switch (xrMode) {
- case OVR:
+ case OPENXR:
// Replace the default egl config chooser.
setEGLConfigChooser(new OvrConfigChooser());
@@ -209,18 +207,9 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
* below.
*/
- if (GLUtils.use_32) {
- setEGLConfigChooser(translucent ?
- new RegularFallbackConfigChooser(8, 8, 8, 8, 24, stencil,
- new RegularConfigChooser(8, 8, 8, 8, 16, stencil)) :
- new RegularFallbackConfigChooser(8, 8, 8, 8, 24, stencil,
- new RegularConfigChooser(5, 6, 5, 0, 16, stencil)));
-
- } else {
- setEGLConfigChooser(translucent ?
- new RegularConfigChooser(8, 8, 8, 8, 16, stencil) :
- new RegularConfigChooser(5, 6, 5, 0, 16, stencil));
- }
+ setEGLConfigChooser(
+ new RegularFallbackConfigChooser(8, 8, 8, 8, 24, 0,
+ new RegularConfigChooser(8, 8, 8, 8, 16, 0)));
break;
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
index d85d88ec6c..5f354b6b4c 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
@@ -288,7 +288,34 @@ public class GodotIO {
}
public int getScreenOrientation() {
- return activity.getRequestedOrientation();
+ int orientation = activity.getRequestedOrientation();
+ switch (orientation) {
+ case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
+ return SCREEN_LANDSCAPE;
+ case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
+ return SCREEN_PORTRAIT;
+ case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
+ return SCREEN_REVERSE_LANDSCAPE;
+ case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
+ return SCREEN_REVERSE_PORTRAIT;
+ case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
+ case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
+ return SCREEN_SENSOR_LANDSCAPE;
+ case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
+ case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
+ return SCREEN_SENSOR_PORTRAIT;
+ case ActivityInfo.SCREEN_ORIENTATION_SENSOR:
+ case ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR:
+ case ActivityInfo.SCREEN_ORIENTATION_FULL_USER:
+ return SCREEN_SENSOR;
+ case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED:
+ case ActivityInfo.SCREEN_ORIENTATION_USER:
+ case ActivityInfo.SCREEN_ORIENTATION_BEHIND:
+ case ActivityInfo.SCREEN_ORIENTATION_NOSENSOR:
+ case ActivityInfo.SCREEN_ORIENTATION_LOCKED:
+ default:
+ return -1;
+ }
}
public void setEdit(GodotEditText _edit) {
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
index 95870acda1..a23d030d4c 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -75,9 +75,8 @@ public class GodotLib {
/**
* Invoked on the render thread when the underlying Android surface is created or recreated.
* @param p_surface
- * @param p_32_bits
*/
- public static native void newcontext(Surface p_surface, boolean p_32_bits);
+ public static native void newcontext(Surface p_surface);
/**
* Forward {@link Activity#onBackPressed()} event from the main thread to the GL thread.
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java
index 878a119c5c..12e452fc99 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java
@@ -70,7 +70,7 @@ class GodotRenderer implements GLSurfaceView.Renderer {
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
- GodotLib.newcontext(null, GLUtils.use_32);
+ GodotLib.newcontext(null);
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
plugin.onGLSurfaceCreated(gl, config);
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
index d1e8ae5ca9..a98ecad594 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
@@ -191,9 +191,9 @@ public class GodotEditText extends EditText {
private boolean needHandlingInGodot(int keyCode, KeyEvent keyEvent) {
boolean isArrowKey = keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
- keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT;
+ keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT;
boolean isModifiedKey = keyEvent.isAltPressed() || keyEvent.isCtrlPressed() || keyEvent.isSymPressed() ||
- keyEvent.isFunctionPressed() || keyEvent.isMetaPressed();
+ keyEvent.isFunctionPressed() || keyEvent.isMetaPressed();
return isArrowKey || keyCode == KeyEvent.KEYCODE_TAB || KeyEvent.isModifierKey(keyCode) ||
isModifiedKey;
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java b/platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java
index 19588f8465..09820fad5f 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java
@@ -44,7 +44,6 @@ public class GLUtils {
public static final boolean DEBUG = false;
- public static boolean use_32 = false;
public static boolean use_debug_opengl = false;
private static final String[] ATTRIBUTES_NAMES = new String[] {
diff --git a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt
index a35f6ec5a7..b13f9bfeab 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt
@@ -58,7 +58,7 @@ internal class VkRenderer {
* Called when the surface is created and signals the beginning of rendering.
*/
fun onVkSurfaceCreated(surface: Surface) {
- GodotLib.newcontext(surface, false)
+ GodotLib.newcontext(surface)
for (plugin in pluginRegistry.getAllPlugins()) {
plugin.onVkSurfaceCreated(surface)
diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java b/platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java
index 0995477baf..58f02b0396 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java
@@ -35,7 +35,7 @@ package org.godotengine.godot.xr;
*/
public enum XRMode {
REGULAR(0, "Regular", "--xr_mode_regular", "Default Android Gamepad"), // Regular/flatscreen
- OVR(1, "Oculus Mobile VR", "--xr_mode_ovr", "");
+ OPENXR(1, "OpenXR", "--xr_mode_openxr", "");
final int index;
final String label;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularFallbackConfigChooser.java b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularFallbackConfigChooser.java
index e690c5b695..63c5381994 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularFallbackConfigChooser.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularFallbackConfigChooser.java
@@ -38,7 +38,7 @@ import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLDisplay;
-/* Fallback if 32bit View is not supported*/
+/* Fallback if the requested configuration is not supported */
public class RegularFallbackConfigChooser extends RegularConfigChooser {
private static final String TAG = RegularFallbackConfigChooser.class.getSimpleName();
@@ -55,7 +55,6 @@ public class RegularFallbackConfigChooser extends RegularConfigChooser {
if (ec == null) {
Log.w(TAG, "Trying ConfigChooser fallback");
ec = fallback.chooseConfig(egl, display, configs);
- GLUtils.use_32 = false;
}
return ec;
}
diff --git a/platform/android/java/settings.gradle b/platform/android/java/settings.gradle
index 524031d93f..584b626900 100644
--- a/platform/android/java/settings.gradle
+++ b/platform/android/java/settings.gradle
@@ -4,3 +4,6 @@ rootProject.name = "Godot"
include ':app'
include ':lib'
include ':nativeSrcsConfigs'
+
+include ':assetPacks:installTime'
+project(':assetPacks:installTime').projectDir = file("app/assetPacks/installTime")
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index d971727269..3236512f5c 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -182,11 +182,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, j
}
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jobject p_surface, jboolean p_32_bits) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jobject p_surface) {
if (os_android) {
if (step.get() == 0) {
// During startup
- os_android->set_context_is_16_bits(!p_32_bits);
if (p_surface) {
ANativeWindow *native_window = ANativeWindow_fromSurface(env, p_surface);
os_android->set_native_window(native_window);
@@ -318,8 +317,9 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env
// Called on the UI thread
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value) {
- if (step.get() <= 0)
+ if (step.get() <= 0) {
return;
+ }
AndroidInputHandler::JoypadEvent jevent;
jevent.device = p_device;
@@ -332,24 +332,27 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env,
// Called on the UI thread
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jclass clazz, jint p_device, jint p_hat_x, jint p_hat_y) {
- if (step.get() <= 0)
+ if (step.get() <= 0) {
return;
+ }
AndroidInputHandler::JoypadEvent jevent;
jevent.device = p_device;
jevent.type = AndroidInputHandler::JOY_EVENT_HAT;
- int hat = 0;
+ HatMask hat = HatMask::CENTER;
if (p_hat_x != 0) {
- if (p_hat_x < 0)
- hat |= HatMask::HAT_MASK_LEFT;
- else
- hat |= HatMask::HAT_MASK_RIGHT;
+ if (p_hat_x < 0) {
+ hat |= HatMask::LEFT;
+ } else {
+ hat |= HatMask::RIGHT;
+ }
}
if (p_hat_y != 0) {
- if (p_hat_y < 0)
- hat |= HatMask::HAT_MASK_UP;
- else
- hat |= HatMask::HAT_MASK_DOWN;
+ if (p_hat_y < 0) {
+ hat |= HatMask::UP;
+ } else {
+ hat |= HatMask::DOWN;
+ }
}
jevent.hat = hat;
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index 63e9e6d8e5..7ea74480cb 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -41,7 +41,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jclass clazz, jobject p_surface, jint p_width, jint p_height);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jobject p_surface, jboolean p_32_bits);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jobject p_surface);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz);
void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask = 0, jfloat vertical_factor = 0, jfloat horizontal_factor = 0);
diff --git a/platform/android/logo.png b/platform/android/logo.png
index f44d360a25..9c8be93646 100644
--- a/platform/android/logo.png
+++ b/platform/android/logo.png
Binary files differ
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 21fb31d991..0e5e10bc0a 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -230,10 +230,13 @@ String OS_Android::get_user_data_dir() const {
}
String OS_Android::get_cache_path() const {
+ if (cache_dir_cache != String())
+ return cache_dir_cache;
+
String cache_dir = godot_io_java->get_cache_dir();
if (cache_dir != "") {
- cache_dir = _remove_symlink(cache_dir);
- return cache_dir;
+ cache_dir_cache = _remove_symlink(cache_dir);
+ return cache_dir_cache;
}
return ".";
}
@@ -258,16 +261,8 @@ Size2i OS_Android::get_display_size() const {
return display_size;
}
-void OS_Android::set_context_is_16_bits(bool p_is_16) {
-#if defined(OPENGL_ENABLED)
- //use_16bits_fbo = p_is_16;
- //if (rasterizer)
- // rasterizer->set_force_16_bits_fbo(p_is_16);
-#endif
-}
-
void OS_Android::set_opengl_extensions(const char *p_gl_extensions) {
-#if defined(OPENGL_ENABLED)
+#if defined(GLES3_ENABLED)
ERR_FAIL_COND(!p_gl_extensions);
gl_extensions = p_gl_extensions;
#endif
@@ -319,10 +314,9 @@ OS_Android::OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_god
main_loop = nullptr;
-#if defined(OPENGL_ENABLED)
+#if defined(GLES3_ENABLED)
gl_extensions = nullptr;
use_gl2 = false;
- use_16bits_fbo = false;
#endif
#if defined(VULKAN_ENABLED)
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index c938297821..a62f79952c 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -47,8 +47,7 @@ private:
bool use_apk_expansion;
-#if defined(OPENGL_ENABLED)
- bool use_16bits_fbo;
+#if defined(GLES3_ENABLED)
const char *gl_extensions;
#endif
@@ -57,6 +56,7 @@ private:
#endif
mutable String data_dir_cache;
+ mutable String cache_dir_cache;
AudioDriverOpenSL audio_driver_android;
@@ -102,7 +102,6 @@ public:
void set_display_size(const Size2i &p_size);
Size2i get_display_size() const;
- void set_context_is_16_bits(bool p_is_16);
void set_opengl_extensions(const char *p_gl_extensions);
void set_native_window(ANativeWindow *p_native_window);
diff --git a/platform/iphone/app_delegate.h b/platform/iphone/app_delegate.h
index d6a2292dd2..76c28b2272 100644
--- a/platform/iphone/app_delegate.h
+++ b/platform/iphone/app_delegate.h
@@ -32,9 +32,9 @@
@class ViewController;
-// FIXME: Add support for both GLES2 and Vulkan when GLES2 is implemented again,
+// FIXME: Add support for both OpenGL and Vulkan when OpenGL is implemented again,
// so it can't be done with compilation time branching.
-//#if defined(OPENGL_ENABLED)
+//#if defined(GLES3_ENABLED)
//@interface AppDelegate : NSObject <UIApplicationDelegate, GLViewDelegate> {
//#endif
//#if defined(VULKAN_ENABLED)
diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm
index d10ea5c68c..c6f91665c5 100644
--- a/platform/iphone/app_delegate.mm
+++ b/platform/iphone/app_delegate.mm
@@ -44,7 +44,7 @@
extern int gargc;
extern char **gargv;
-extern int iphone_main(int, char **, String);
+extern int iphone_main(int, char **, String, String);
extern void iphone_finish();
@implementation AppDelegate
@@ -67,8 +67,10 @@ static ViewController *mainViewController = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
+ paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
+ NSString *cacheDirectory = [paths objectAtIndex:0];
- int err = iphone_main(gargc, gargv, String::utf8([documentsDirectory UTF8String]));
+ int err = iphone_main(gargc, gargv, String::utf8([documentsDirectory UTF8String]), String::utf8([cacheDirectory UTF8String]));
if (err != 0) {
// bail, things did not go very well for us, should probably output a message on screen with our error code...
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
index 05e24c5003..0d28aa2f06 100644
--- a/platform/iphone/detect.py
+++ b/platform/iphone/detect.py
@@ -53,12 +53,9 @@ def configure(env):
env.Append(CCFLAGS=["-Os", "-ftree-vectorize"])
env.Append(LINKFLAGS=["-Os"])
- if env["target"] == "release_debug":
- env.Append(CPPDEFINES=["DEBUG_ENABLED"])
-
elif env["target"] == "debug":
env.Append(CCFLAGS=["-gdwarf-2", "-O0"])
- env.Append(CPPDEFINES=["_DEBUG", ("DEBUG", 1), "DEBUG_ENABLED"])
+ env.Append(CPPDEFINES=["_DEBUG", ("DEBUG", 1)])
if env["use_lto"]:
env.Append(CCFLAGS=["-flto"])
diff --git a/platform/iphone/display_layer.mm b/platform/iphone/display_layer.mm
index b8df81b89a..afe612e1a5 100644
--- a/platform/iphone/display_layer.mm
+++ b/platform/iphone/display_layer.mm
@@ -89,7 +89,7 @@
// FIXME: Add Vulkan support via MoltenVK. Add fallback code back?
// Create GL ES 2 context
- if (GLOBAL_GET("rendering/driver/driver_name") == "GLES2") {
+ if (GLOBAL_GET("rendering/driver/driver_name") == "opengl3") {
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
NSLog(@"Setting up an OpenGL ES 2.0 context.");
if (!context) {
diff --git a/platform/iphone/display_server_iphone.mm b/platform/iphone/display_server_iphone.mm
index e18448fb6d..b746c60d4e 100644
--- a/platform/iphone/display_server_iphone.mm
+++ b/platform/iphone/display_server_iphone.mm
@@ -51,8 +51,8 @@ DisplayServerIPhone *DisplayServerIPhone::get_singleton() {
DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
rendering_driver = p_rendering_driver;
-#if defined(OPENGL_ENABLED)
- // FIXME: Add support for both GLES2 and Vulkan when GLES2 is implemented
+#if defined(GLES3_ENABLED)
+ // FIXME: Add support for both OpenGL and Vulkan when OpenGL is implemented
// again,
if (rendering_driver == "opengl_es") {
@@ -60,9 +60,9 @@ DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, Windo
// FIXME: Add Vulkan support via MoltenVK. Add fallback code back?
- if (RasterizerGLES2::is_viable() == OK) {
- RasterizerGLES2::register_config();
- RasterizerGLES2::make_current();
+ if (RasterizerGLES3::is_viable() == OK) {
+ RasterizerGLES3::register_config();
+ RasterizerGLES3::make_current();
} else {
gl_initialization_error = true;
}
@@ -83,7 +83,7 @@ DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, Windo
// reset this to what it should be, it will have been set to 0 after
// rendering_server->init() is called
- // RasterizerStorageGLES2::system_fbo = gl_view_base_fb;
+ // RasterizerStorageGLES3system_fbo = gl_view_base_fb;
}
#endif
@@ -157,7 +157,7 @@ Vector<String> DisplayServerIPhone::get_rendering_drivers_func() {
#if defined(VULKAN_ENABLED)
drivers.push_back("vulkan");
#endif
-#if defined(OPENGL_ENABLED)
+#if defined(GLES3_ENABLED)
drivers.push_back("opengl_es");
#endif
@@ -261,7 +261,7 @@ void DisplayServerIPhone::key(Key p_key, bool p_pressed) {
ev->set_pressed(p_pressed);
ev->set_keycode(p_key);
ev->set_physical_keycode(p_key);
- ev->set_unicode(p_key);
+ ev->set_unicode((char32_t)p_key);
perform_event(ev);
};
diff --git a/platform/iphone/export/export_plugin.cpp b/platform/iphone/export/export_plugin.cpp
index 69a8203e9f..7450215cfb 100644
--- a/platform/iphone/export/export_plugin.cpp
+++ b/platform/iphone/export/export_plugin.cpp
@@ -33,7 +33,7 @@
void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
r_features->push_back("pvrtc");
- if (driver == "Vulkan") {
+ if (driver == "vulkan") {
// FIXME: Review if this is correct.
r_features->push_back("etc2");
}
@@ -841,7 +841,7 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPrese
String pbx_embeded_frameworks;
const String file_info_format = String("$build_id = {isa = PBXBuildFile; fileRef = $ref_id; };\n") +
- "$ref_id = {isa = PBXFileReference; lastKnownFileType = $file_type; name = \"$name\"; path = \"$file_path\"; sourceTree = \"<group>\"; };\n";
+ "$ref_id = {isa = PBXFileReference; lastKnownFileType = $file_type; name = \"$name\"; path = \"$file_path\"; sourceTree = \"<group>\"; };\n";
for (int i = 0; i < p_additional_assets.size(); ++i) {
String additional_asset_info_format = file_info_format;
@@ -1105,7 +1105,7 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir
for (int j = 0; j < project_static_libs.size(); j++) {
project_static_libs.write[j] = project_static_libs[j].get_file(); // Only the file name as it's copied to the project
}
- err = _export_additional_assets(p_out_dir, project_static_libs, true, true, r_exported_assets);
+ err = _export_additional_assets(p_out_dir, project_static_libs, true, false, r_exported_assets);
ERR_FAIL_COND_V(err, err);
Vector<String> ios_bundle_files = export_plugins[i]->get_ios_bundle_files();
@@ -1261,8 +1261,8 @@ Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset>
String deinitialization_method = plugin.deinitialization_method + "();\n";
plugin_definition_cpp_code += definition_comment +
- "extern void " + initialization_method +
- "extern void " + deinitialization_method + "\n";
+ "extern void " + initialization_method +
+ "extern void " + deinitialization_method + "\n";
plugin_initialization_cpp_code += "\t" + initialization_method;
plugin_deinitialization_cpp_code += "\t" + deinitialization_method;
@@ -1427,7 +1427,6 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
}
bool found_library = false;
- int total_size = 0;
const String project_file = "godot_ios.xcodeproj/project.pbxproj";
Set<String> files_to_parse;
@@ -1523,7 +1522,6 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
file = file.replace("godot_ios", binary_name);
print_line("ADDING: " + file + " size: " + itos(data.size()));
- total_size += data.size();
/* write it into our folder structure */
file = dest_dir + file;
@@ -1687,8 +1685,10 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
archive_args.push_back("archive");
archive_args.push_back("-archivePath");
archive_args.push_back(archive_path);
- err = OS::get_singleton()->execute("xcodebuild", archive_args);
+ String archive_str;
+ err = OS::get_singleton()->execute("xcodebuild", archive_args, &archive_str, nullptr, true);
ERR_FAIL_COND_V(err, err);
+ print_line("xcodebuild (.xcarchive):\n" + archive_str);
if (ep.step("Making .ipa", 4)) {
return ERR_SKIP;
@@ -1702,8 +1702,10 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
export_args.push_back("-allowProvisioningUpdates");
export_args.push_back("-exportPath");
export_args.push_back(dest_dir);
- err = OS::get_singleton()->execute("xcodebuild", export_args);
+ String export_str;
+ err = OS::get_singleton()->execute("xcodebuild", export_args, &export_str, nullptr, true);
ERR_FAIL_COND_V(err, err);
+ print_line("xcodebuild (.ipa):\n" + export_str);
#else
print_line(".ipa can only be built on macOS. Leaving Xcode project without building the package.");
#endif
diff --git a/platform/iphone/export/export_plugin.h b/platform/iphone/export/export_plugin.h
index 8d3af6e057..359f855d86 100644
--- a/platform/iphone/export/export_plugin.h
+++ b/platform/iphone/export/export_plugin.h
@@ -204,7 +204,7 @@ public:
virtual void get_platform_features(List<String> *r_features) override {
r_features->push_back("mobile");
- r_features->push_back("iOS");
+ r_features->push_back("ios");
}
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override {
diff --git a/platform/iphone/godot_iphone.mm b/platform/iphone/godot_iphone.mm
index 6c3e1eabde..6f6f9d0708 100644
--- a/platform/iphone/godot_iphone.mm
+++ b/platform/iphone/godot_iphone.mm
@@ -74,7 +74,7 @@ int add_cmdline(int p_argc, char **p_args) {
return p_argc;
};
-int iphone_main(int argc, char **argv, String data_dir) {
+int iphone_main(int argc, char **argv, String data_dir, String cache_dir) {
size_t len = strlen(argv[0]);
while (len--) {
@@ -95,7 +95,7 @@ int iphone_main(int argc, char **argv, String data_dir) {
char cwd[512];
getcwd(cwd, sizeof(cwd));
printf("cwd %s\n", cwd);
- os = new OSIPhone(data_dir);
+ os = new OSIPhone(data_dir, cache_dir);
// We must override main when testing is enabled
TEST_MAIN_OVERRIDE
diff --git a/platform/iphone/joypad_iphone.mm b/platform/iphone/joypad_iphone.mm
index 45842b38aa..1bf5462d91 100644
--- a/platform/iphone/joypad_iphone.mm
+++ b/platform/iphone/joypad_iphone.mm
@@ -259,31 +259,31 @@ void JoypadIPhone::start_processing() {
int joy_id = [self getJoyIdForController:controller];
if (element == gamepad.buttonA) {
- Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_A,
+ Input::get_singleton()->joy_button(joy_id, JoyButton::A,
gamepad.buttonA.isPressed);
} else if (element == gamepad.buttonB) {
- Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_B,
+ Input::get_singleton()->joy_button(joy_id, JoyButton::B,
gamepad.buttonB.isPressed);
} else if (element == gamepad.buttonX) {
- Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_X,
+ Input::get_singleton()->joy_button(joy_id, JoyButton::X,
gamepad.buttonX.isPressed);
} else if (element == gamepad.buttonY) {
- Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_Y,
+ Input::get_singleton()->joy_button(joy_id, JoyButton::Y,
gamepad.buttonY.isPressed);
} else if (element == gamepad.leftShoulder) {
- Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_LEFT_SHOULDER,
+ Input::get_singleton()->joy_button(joy_id, JoyButton::LEFT_SHOULDER,
gamepad.leftShoulder.isPressed);
} else if (element == gamepad.rightShoulder) {
- Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_RIGHT_SHOULDER,
+ Input::get_singleton()->joy_button(joy_id, JoyButton::RIGHT_SHOULDER,
gamepad.rightShoulder.isPressed);
} else if (element == gamepad.dpad) {
- Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_UP,
+ Input::get_singleton()->joy_button(joy_id, JoyButton::DPAD_UP,
gamepad.dpad.up.isPressed);
- Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_DOWN,
+ Input::get_singleton()->joy_button(joy_id, JoyButton::DPAD_DOWN,
gamepad.dpad.down.isPressed);
- Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_LEFT,
+ Input::get_singleton()->joy_button(joy_id, JoyButton::DPAD_LEFT,
gamepad.dpad.left.isPressed);
- Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_RIGHT,
+ Input::get_singleton()->joy_button(joy_id, JoyButton::DPAD_RIGHT,
gamepad.dpad.right.isPressed);
};
@@ -291,20 +291,20 @@ void JoypadIPhone::start_processing() {
jx.min = -1;
if (element == gamepad.leftThumbstick) {
jx.value = gamepad.leftThumbstick.xAxis.value;
- Input::get_singleton()->joy_axis(joy_id, JOY_AXIS_LEFT_X, jx);
+ Input::get_singleton()->joy_axis(joy_id, JoyAxis::LEFT_X, jx);
jx.value = -gamepad.leftThumbstick.yAxis.value;
- Input::get_singleton()->joy_axis(joy_id, JOY_AXIS_LEFT_Y, jx);
+ Input::get_singleton()->joy_axis(joy_id, JoyAxis::LEFT_Y, jx);
} else if (element == gamepad.rightThumbstick) {
jx.value = gamepad.rightThumbstick.xAxis.value;
- Input::get_singleton()->joy_axis(joy_id, JOY_AXIS_RIGHT_X, jx);
+ Input::get_singleton()->joy_axis(joy_id, JoyAxis::RIGHT_X, jx);
jx.value = -gamepad.rightThumbstick.yAxis.value;
- Input::get_singleton()->joy_axis(joy_id, JOY_AXIS_RIGHT_Y, jx);
+ Input::get_singleton()->joy_axis(joy_id, JoyAxis::RIGHT_Y, jx);
} else if (element == gamepad.leftTrigger) {
jx.value = gamepad.leftTrigger.value;
- Input::get_singleton()->joy_axis(joy_id, JOY_AXIS_TRIGGER_LEFT, jx);
+ Input::get_singleton()->joy_axis(joy_id, JoyAxis::TRIGGER_LEFT, jx);
} else if (element == gamepad.rightTrigger) {
jx.value = gamepad.rightTrigger.value;
- Input::get_singleton()->joy_axis(joy_id, JOY_AXIS_TRIGGER_RIGHT, jx);
+ Input::get_singleton()->joy_axis(joy_id, JoyAxis::TRIGGER_RIGHT, jx);
};
};
} else if (controller.microGamepad != nil) {
@@ -319,18 +319,18 @@ void JoypadIPhone::start_processing() {
int joy_id = [self getJoyIdForController:controller];
if (element == gamepad.buttonA) {
- Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_A,
+ Input::get_singleton()->joy_button(joy_id, JoyButton::A,
gamepad.buttonA.isPressed);
} else if (element == gamepad.buttonX) {
- Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_X,
+ Input::get_singleton()->joy_button(joy_id, JoyButton::X,
gamepad.buttonX.isPressed);
} else if (element == gamepad.dpad) {
- Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_UP,
+ Input::get_singleton()->joy_button(joy_id, JoyButton::DPAD_UP,
gamepad.dpad.up.isPressed);
- Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_DOWN,
+ Input::get_singleton()->joy_button(joy_id, JoyButton::DPAD_DOWN,
gamepad.dpad.down.isPressed);
- Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_LEFT, gamepad.dpad.left.isPressed);
- Input::get_singleton()->joy_button(joy_id, JOY_BUTTON_DPAD_RIGHT, gamepad.dpad.right.isPressed);
+ Input::get_singleton()->joy_button(joy_id, JoyButton::DPAD_LEFT, gamepad.dpad.left.isPressed);
+ Input::get_singleton()->joy_button(joy_id, JoyButton::DPAD_RIGHT, gamepad.dpad.right.isPressed);
};
};
}
diff --git a/platform/iphone/keyboard_input_view.mm b/platform/iphone/keyboard_input_view.mm
index e2bd0acff4..b11d04181e 100644
--- a/platform/iphone/keyboard_input_view.mm
+++ b/platform/iphone/keyboard_input_view.mm
@@ -115,8 +115,8 @@
- (void)deleteText:(NSInteger)charactersToDelete {
for (int i = 0; i < charactersToDelete; i++) {
- DisplayServerIPhone::get_singleton()->key(KEY_BACKSPACE, true);
- DisplayServerIPhone::get_singleton()->key(KEY_BACKSPACE, false);
+ DisplayServerIPhone::get_singleton()->key(Key::BACKSPACE, true);
+ DisplayServerIPhone::get_singleton()->key(Key::BACKSPACE, false);
}
}
@@ -129,10 +129,10 @@
switch (character) {
case 10:
- character = KEY_ENTER;
+ character = (int)Key::ENTER;
break;
case 8198:
- character = KEY_SPACE;
+ character = (int)Key::SPACE;
break;
default:
break;
diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h
index 248369369d..7a81d8f593 100644
--- a/platform/iphone/os_iphone.h
+++ b/platform/iphone/os_iphone.h
@@ -72,6 +72,7 @@ private:
virtual void finalize() override;
String user_data_dir;
+ String cache_dir;
bool is_focused = false;
@@ -80,7 +81,7 @@ private:
public:
static OSIPhone *get_singleton();
- OSIPhone(String p_data_dir);
+ OSIPhone(String p_data_dir, String p_cache_dir);
~OSIPhone();
void initialize_modules();
@@ -103,6 +104,8 @@ public:
void set_user_data_dir(String p_dir);
virtual String get_user_data_dir() const override;
+ virtual String get_cache_path() const override;
+
virtual String get_locale() const override;
virtual String get_unique_id() const override;
diff --git a/platform/iphone/os_iphone.mm b/platform/iphone/os_iphone.mm
index c88d253691..fc07d321b7 100644
--- a/platform/iphone/os_iphone.mm
+++ b/platform/iphone/os_iphone.mm
@@ -87,7 +87,7 @@ OSIPhone *OSIPhone::get_singleton() {
return (OSIPhone *)OS::get_singleton();
}
-OSIPhone::OSIPhone(String p_data_dir) {
+OSIPhone::OSIPhone(String p_data_dir, String p_cache_dir) {
for (int i = 0; i < ios_init_callbacks_count; ++i) {
ios_init_callbacks[i]();
}
@@ -101,6 +101,7 @@ OSIPhone::OSIPhone(String p_data_dir) {
// can't call set_data_dir from here, since it requires DirAccess
// which is initialized in initialize_core
user_data_dir = p_data_dir;
+ cache_dir = p_cache_dir;
Vector<Logger *> loggers;
loggers.push_back(memnew(SyslogLogger));
@@ -266,6 +267,10 @@ String OSIPhone::get_user_data_dir() const {
return user_data_dir;
}
+String OSIPhone::get_cache_path() const {
+ return cache_dir;
+}
+
String OSIPhone::get_locale() const {
NSString *preferedLanguage = [NSLocale preferredLanguages].firstObject;
diff --git a/platform/iphone/platform_config.h b/platform/iphone/platform_config.h
index 88ad4a3f67..68ef4e31a7 100644
--- a/platform/iphone/platform_config.h
+++ b/platform/iphone/platform_config.h
@@ -30,6 +30,8 @@
#include <alloca.h>
+#define OPENGL_INCLUDE_H <ES3/gl.h>
+
#define PLATFORM_REFCOUNT
#define PTHREAD_RENAME_SELF
diff --git a/platform/javascript/.eslintrc.js b/platform/javascript/.eslintrc.js
index 0ff9d67d26..2c81f1f02d 100644
--- a/platform/javascript/.eslintrc.js
+++ b/platform/javascript/.eslintrc.js
@@ -39,5 +39,13 @@ module.exports = {
// Closure compiler (exported properties)
"quote-props": ["error", "consistent"],
"dot-notation": "off",
+ // No comma dangle for functions (it's madness, and ES2017)
+ "comma-dangle": ["error", {
+ "arrays": "always-multiline",
+ "objects": "always-multiline",
+ "imports": "always-multiline",
+ "exports": "always-multiline",
+ "functions": "never"
+ }],
}
};
diff --git a/platform/javascript/.eslintrc.libs.js b/platform/javascript/.eslintrc.libs.js
index 81b1b8c864..8e579fd462 100644
--- a/platform/javascript/.eslintrc.libs.js
+++ b/platform/javascript/.eslintrc.libs.js
@@ -15,6 +15,7 @@ module.exports = {
"IDBFS": true,
"GodotOS": true,
"GodotConfig": true,
+ "GodotEventListeners": true,
"GodotRuntime": true,
"GodotFS": true,
"IDHandler": true,
diff --git a/platform/javascript/README.md b/platform/javascript/README.md
new file mode 100644
index 0000000000..f181bea9e0
--- /dev/null
+++ b/platform/javascript/README.md
@@ -0,0 +1,15 @@
+# HTML5 platform port
+
+This folder contains the C++ and JavaScript code for the HTML5/WebAssembly platform port,
+compiled using [Emscripten](https://emscripten.org/).
+
+It also contains a ESLint linting setup (see [`package.json`](package.json)).
+
+See also [`misc/dist/html`](/misc/dist/html) folder for files used by this platform
+such as the HTML5 shell.
+
+## Artwork license
+
+[`logo.png`](logo.png) and [`run_icon.png`](run_icon.png) are licensed under
+[Creative Commons Attribution 3.0 Unported](https://www.w3.org/html/logo/faq.html#how-licenced)
+per the HTML5 logo usage guidelines.
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index 62a8660ae4..fa9e6eed15 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -20,6 +20,7 @@ sys_env.AddJSLibraries(
"js/libs/library_godot_fetch.js",
"js/libs/library_godot_os.js",
"js/libs/library_godot_runtime.js",
+ "js/libs/library_godot_input.js",
]
)
diff --git a/platform/javascript/api/javascript_tools_editor_plugin.cpp b/platform/javascript/api/javascript_tools_editor_plugin.cpp
index c50195639c..df4c790755 100644
--- a/platform/javascript/api/javascript_tools_editor_plugin.cpp
+++ b/platform/javascript/api/javascript_tools_editor_plugin.cpp
@@ -71,8 +71,8 @@ void JavaScriptToolsEditorPlugin::_download_zip(Variant p_v) {
// Replace characters not allowed (or risky) in Windows file names with safe characters.
// In the project name, all invalid characters become an empty string so that a name
// like "Platformer 2: Godette's Revenge" becomes "platformer_2-_godette-s_revenge".
- const String project_name_safe =
- GLOBAL_GET("application/config/name").to_lower().replace(" ", "_");
+ const String project_name = GLOBAL_GET("application/config/name");
+ const String project_name_safe = project_name.to_lower().replace(" ", "_");
const String datetime_safe =
Time::get_singleton()->get_datetime_string_from_system(false, true).replace(" ", "_");
const String output_name = OS::get_singleton()->get_safe_dir_name(vformat("%s_%s.zip"));
@@ -131,9 +131,10 @@ void JavaScriptToolsEditorPlugin::_zip_recursive(String p_path, String p_base_pa
}
dir->list_dir_begin();
String cur = dir->get_next();
+ String project_data_dir_name = ProjectSettings::get_singleton()->get_project_data_dir_name();
while (!cur.is_empty()) {
String cs = p_path.plus_file(cur);
- if (cur == "." || cur == ".." || cur == ".import") {
+ if (cur == "." || cur == ".." || cur == project_data_dir_name) {
// Skip
} else if (dir->current_is_dir()) {
String path = cs.replace_first(p_base_path, "") + "/";
diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp
index 478e848675..626aef3c60 100644
--- a/platform/javascript/audio_driver_javascript.cpp
+++ b/platform/javascript/audio_driver_javascript.cpp
@@ -34,22 +34,18 @@
#include <emscripten.h>
-AudioDriverJavaScript *AudioDriverJavaScript::singleton = nullptr;
+AudioDriverJavaScript::AudioContext AudioDriverJavaScript::audio_context;
bool AudioDriverJavaScript::is_available() {
return godot_audio_is_available() != 0;
}
-const char *AudioDriverJavaScript::get_name() const {
- return "JavaScript";
-}
-
void AudioDriverJavaScript::_state_change_callback(int p_state) {
- singleton->state = p_state;
+ AudioDriverJavaScript::audio_context.state = p_state;
}
void AudioDriverJavaScript::_latency_update_callback(float p_latency) {
- singleton->output_latency = p_latency;
+ AudioDriverJavaScript::audio_context.output_latency = p_latency;
}
void AudioDriverJavaScript::_audio_driver_process(int p_from, int p_samples) {
@@ -105,28 +101,31 @@ void AudioDriverJavaScript::_audio_driver_capture(int p_from, int p_samples) {
}
Error AudioDriverJavaScript::init() {
- mix_rate = GLOBAL_GET("audio/driver/mix_rate");
int latency = GLOBAL_GET("audio/driver/output_latency");
-
- channel_count = godot_audio_init(mix_rate, latency, &_state_change_callback, &_latency_update_callback);
+ if (!audio_context.inited) {
+ audio_context.mix_rate = GLOBAL_GET("audio/driver/mix_rate");
+ audio_context.channel_count = godot_audio_init(&audio_context.mix_rate, latency, &_state_change_callback, &_latency_update_callback);
+ audio_context.inited = true;
+ }
+ mix_rate = audio_context.mix_rate;
+ channel_count = audio_context.channel_count;
buffer_length = closest_power_of_2((latency * mix_rate / 1000));
-#ifndef NO_THREADS
- node = memnew(WorkletNode);
-#else
- node = memnew(ScriptProcessorNode);
-#endif
- buffer_length = node->create(buffer_length, channel_count);
+ Error err = create(buffer_length, channel_count);
+ if (err != OK) {
+ return err;
+ }
if (output_rb) {
memdelete_arr(output_rb);
}
- output_rb = memnew_arr(float, buffer_length *channel_count);
+ const size_t array_size = buffer_length * (size_t)channel_count;
+ output_rb = memnew_arr(float, array_size);
if (!output_rb) {
return ERR_OUT_OF_MEMORY;
}
if (input_rb) {
memdelete_arr(input_rb);
}
- input_rb = memnew_arr(float, buffer_length *channel_count);
+ input_rb = memnew_arr(float, array_size);
if (!input_rb) {
return ERR_OUT_OF_MEMORY;
}
@@ -134,19 +133,17 @@ Error AudioDriverJavaScript::init() {
}
void AudioDriverJavaScript::start() {
- if (node) {
- node->start(output_rb, memarr_len(output_rb), input_rb, memarr_len(input_rb));
- }
+ start(output_rb, memarr_len(output_rb), input_rb, memarr_len(input_rb));
}
void AudioDriverJavaScript::resume() {
- if (state == 0) { // 'suspended'
+ if (audio_context.state == 0) { // 'suspended'
godot_audio_resume();
}
}
float AudioDriverJavaScript::get_latency() {
- return output_latency + (float(buffer_length) / mix_rate);
+ return audio_context.output_latency + (float(buffer_length) / mix_rate);
}
int AudioDriverJavaScript::get_mix_rate() const {
@@ -157,24 +154,8 @@ AudioDriver::SpeakerMode AudioDriverJavaScript::get_speaker_mode() const {
return get_speaker_mode_by_total_channels(channel_count);
}
-void AudioDriverJavaScript::lock() {
- if (node) {
- node->unlock();
- }
-}
-
-void AudioDriverJavaScript::unlock() {
- if (node) {
- node->unlock();
- }
-}
-
void AudioDriverJavaScript::finish() {
- if (node) {
- node->finish();
- memdelete(node);
- node = nullptr;
- }
+ finish_driver();
if (output_rb) {
memdelete_arr(output_rb);
output_rb = nullptr;
@@ -203,41 +184,66 @@ Error AudioDriverJavaScript::capture_stop() {
return OK;
}
-AudioDriverJavaScript::AudioDriverJavaScript() {
- singleton = this;
-}
-
#ifdef NO_THREADS
/// ScriptProcessorNode implementation
-void AudioDriverJavaScript::ScriptProcessorNode::_process_callback() {
- AudioDriverJavaScript::singleton->_audio_driver_capture();
- AudioDriverJavaScript::singleton->_audio_driver_process();
+AudioDriverScriptProcessor *AudioDriverScriptProcessor::singleton = nullptr;
+
+void AudioDriverScriptProcessor::_process_callback() {
+ AudioDriverScriptProcessor::singleton->_audio_driver_capture();
+ AudioDriverScriptProcessor::singleton->_audio_driver_process();
}
-int AudioDriverJavaScript::ScriptProcessorNode::create(int p_buffer_samples, int p_channels) {
- return godot_audio_script_create(p_buffer_samples, p_channels);
+Error AudioDriverScriptProcessor::create(int &p_buffer_samples, int p_channels) {
+ if (!godot_audio_has_script_processor()) {
+ return ERR_UNAVAILABLE;
+ }
+ return (Error)godot_audio_script_create(&p_buffer_samples, p_channels);
}
-void AudioDriverJavaScript::ScriptProcessorNode::start(float *p_out_buf, int p_out_buf_size, float *p_in_buf, int p_in_buf_size) {
+void AudioDriverScriptProcessor::start(float *p_out_buf, int p_out_buf_size, float *p_in_buf, int p_in_buf_size) {
godot_audio_script_start(p_in_buf, p_in_buf_size, p_out_buf, p_out_buf_size, &_process_callback);
}
+
+/// AudioWorkletNode implementation (no threads)
+AudioDriverWorklet *AudioDriverWorklet::singleton = nullptr;
+
+Error AudioDriverWorklet::create(int &p_buffer_size, int p_channels) {
+ if (!godot_audio_has_worklet()) {
+ return ERR_UNAVAILABLE;
+ }
+ return (Error)godot_audio_worklet_create(p_channels);
+}
+
+void AudioDriverWorklet::start(float *p_out_buf, int p_out_buf_size, float *p_in_buf, int p_in_buf_size) {
+ _audio_driver_process();
+ godot_audio_worklet_start_no_threads(p_out_buf, p_out_buf_size, &_process_callback, p_in_buf, p_in_buf_size, &_capture_callback);
+}
+
+void AudioDriverWorklet::_process_callback(int p_pos, int p_samples) {
+ AudioDriverWorklet *driver = AudioDriverWorklet::singleton;
+ driver->_audio_driver_process(p_pos, p_samples);
+}
+
+void AudioDriverWorklet::_capture_callback(int p_pos, int p_samples) {
+ AudioDriverWorklet *driver = AudioDriverWorklet::singleton;
+ driver->_audio_driver_capture(p_pos, p_samples);
+}
#else
-/// AudioWorkletNode implementation
-void AudioDriverJavaScript::WorkletNode::_audio_thread_func(void *p_data) {
- AudioDriverJavaScript::WorkletNode *obj = static_cast<AudioDriverJavaScript::WorkletNode *>(p_data);
- AudioDriverJavaScript *driver = AudioDriverJavaScript::singleton;
- const int out_samples = memarr_len(driver->output_rb);
- const int in_samples = memarr_len(driver->input_rb);
+/// AudioWorkletNode implementation (threads)
+void AudioDriverWorklet::_audio_thread_func(void *p_data) {
+ AudioDriverWorklet *driver = static_cast<AudioDriverWorklet *>(p_data);
+ const int out_samples = memarr_len(driver->get_output_rb());
+ const int in_samples = memarr_len(driver->get_input_rb());
int wpos = 0;
int to_write = out_samples;
int rpos = 0;
int to_read = 0;
int32_t step = 0;
- while (!obj->quit) {
+ while (!driver->quit) {
if (to_read) {
driver->lock();
driver->_audio_driver_capture(rpos, to_read);
- godot_audio_worklet_state_add(obj->state, STATE_SAMPLES_IN, -to_read);
+ godot_audio_worklet_state_add(driver->state, STATE_SAMPLES_IN, -to_read);
driver->unlock();
rpos += to_read;
if (rpos >= in_samples) {
@@ -247,38 +253,40 @@ void AudioDriverJavaScript::WorkletNode::_audio_thread_func(void *p_data) {
if (to_write) {
driver->lock();
driver->_audio_driver_process(wpos, to_write);
- godot_audio_worklet_state_add(obj->state, STATE_SAMPLES_OUT, to_write);
+ godot_audio_worklet_state_add(driver->state, STATE_SAMPLES_OUT, to_write);
driver->unlock();
wpos += to_write;
if (wpos >= out_samples) {
wpos -= out_samples;
}
}
- step = godot_audio_worklet_state_wait(obj->state, STATE_PROCESS, step, 1);
- to_write = out_samples - godot_audio_worklet_state_get(obj->state, STATE_SAMPLES_OUT);
- to_read = godot_audio_worklet_state_get(obj->state, STATE_SAMPLES_IN);
+ step = godot_audio_worklet_state_wait(driver->state, STATE_PROCESS, step, 1);
+ to_write = out_samples - godot_audio_worklet_state_get(driver->state, STATE_SAMPLES_OUT);
+ to_read = godot_audio_worklet_state_get(driver->state, STATE_SAMPLES_IN);
}
}
-int AudioDriverJavaScript::WorkletNode::create(int p_buffer_size, int p_channels) {
- godot_audio_worklet_create(p_channels);
- return p_buffer_size;
+Error AudioDriverWorklet::create(int &p_buffer_size, int p_channels) {
+ if (!godot_audio_has_worklet()) {
+ return ERR_UNAVAILABLE;
+ }
+ return (Error)godot_audio_worklet_create(p_channels);
}
-void AudioDriverJavaScript::WorkletNode::start(float *p_out_buf, int p_out_buf_size, float *p_in_buf, int p_in_buf_size) {
+void AudioDriverWorklet::start(float *p_out_buf, int p_out_buf_size, float *p_in_buf, int p_in_buf_size) {
godot_audio_worklet_start(p_in_buf, p_in_buf_size, p_out_buf, p_out_buf_size, state);
thread.start(_audio_thread_func, this);
}
-void AudioDriverJavaScript::WorkletNode::lock() {
+void AudioDriverWorklet::lock() {
mutex.lock();
}
-void AudioDriverJavaScript::WorkletNode::unlock() {
+void AudioDriverWorklet::unlock() {
mutex.unlock();
}
-void AudioDriverJavaScript::WorkletNode::finish() {
+void AudioDriverWorklet::finish_driver() {
quit = true; // Ask thread to quit.
thread.wait_to_finish();
}
diff --git a/platform/javascript/audio_driver_javascript.h b/platform/javascript/audio_driver_javascript.h
index 393693640f..6a0b4bcb0e 100644
--- a/platform/javascript/audio_driver_javascript.h
+++ b/platform/javascript/audio_driver_javascript.h
@@ -38,52 +38,15 @@
#include "godot_audio.h"
class AudioDriverJavaScript : public AudioDriver {
-public:
- class AudioNode {
- public:
- virtual int create(int p_buffer_size, int p_output_channels) = 0;
- virtual void start(float *p_out_buf, int p_out_buf_size, float *p_in_buf, int p_in_buf_size) = 0;
- virtual void finish() {}
- virtual void lock() {}
- virtual void unlock() {}
- virtual ~AudioNode() {}
- };
-
- class WorkletNode : public AudioNode {
- private:
- enum {
- STATE_LOCK,
- STATE_PROCESS,
- STATE_SAMPLES_IN,
- STATE_SAMPLES_OUT,
- STATE_MAX,
- };
- Mutex mutex;
- Thread thread;
- bool quit = false;
- int32_t state[STATE_MAX] = { 0 };
-
- static void _audio_thread_func(void *p_data);
-
- public:
- int create(int p_buffer_size, int p_output_channels) override;
- void start(float *p_out_buf, int p_out_buf_size, float *p_in_buf, int p_in_buf_size) override;
- void finish() override;
- void lock() override;
- void unlock() override;
- };
-
- class ScriptProcessorNode : public AudioNode {
- private:
- static void _process_callback();
-
- public:
- int create(int p_buffer_samples, int p_channels) override;
- void start(float *p_out_buf, int p_out_buf_size, float *p_in_buf, int p_in_buf_size) override;
- };
-
private:
- AudioNode *node = nullptr;
+ struct AudioContext {
+ bool inited = false;
+ float output_latency = 0.0;
+ int state = -1;
+ int channel_count = 0;
+ int mix_rate = 0;
+ };
+ static AudioContext audio_context;
float *output_rb = nullptr;
float *input_rb = nullptr;
@@ -91,36 +54,108 @@ private:
int buffer_length = 0;
int mix_rate = 0;
int channel_count = 0;
- int state = 0;
- float output_latency = 0.0;
static void _state_change_callback(int p_state);
static void _latency_update_callback(float p_latency);
+ static AudioDriverJavaScript *singleton;
+
protected:
void _audio_driver_process(int p_from = 0, int p_samples = 0);
void _audio_driver_capture(int p_from = 0, int p_samples = 0);
+ float *get_output_rb() const { return output_rb; }
+ float *get_input_rb() const { return input_rb; }
+
+ virtual Error create(int &p_buffer_samples, int p_channels) = 0;
+ virtual void start(float *p_out_buf, int p_out_buf_size, float *p_in_buf, int p_in_buf_size) = 0;
+ virtual void finish_driver() {}
public:
static bool is_available();
- static AudioDriverJavaScript *singleton;
+ virtual Error init() final;
+ virtual void start() final;
+ virtual void finish() final;
+
+ virtual float get_latency() override;
+ virtual int get_mix_rate() const override;
+ virtual SpeakerMode get_speaker_mode() const override;
+
+ virtual Error capture_start() override;
+ virtual Error capture_stop() override;
+
+ static void resume();
+
+ AudioDriverJavaScript() {}
+};
+
+#ifdef NO_THREADS
+class AudioDriverScriptProcessor : public AudioDriverJavaScript {
+private:
+ static void _process_callback();
+
+ static AudioDriverScriptProcessor *singleton;
+
+protected:
+ Error create(int &p_buffer_samples, int p_channels) override;
+ void start(float *p_out_buf, int p_out_buf_size, float *p_in_buf, int p_in_buf_size) override;
+
+public:
+ virtual const char *get_name() const override { return "ScriptProcessor"; }
+
+ virtual void lock() override {}
+ virtual void unlock() override {}
+
+ AudioDriverScriptProcessor() { singleton = this; }
+};
+
+class AudioDriverWorklet : public AudioDriverJavaScript {
+private:
+ static void _process_callback(int p_pos, int p_samples);
+ static void _capture_callback(int p_pos, int p_samples);
+
+ static AudioDriverWorklet *singleton;
+
+protected:
+ virtual Error create(int &p_buffer_size, int p_output_channels) override;
+ virtual void start(float *p_out_buf, int p_out_buf_size, float *p_in_buf, int p_in_buf_size) override;
- virtual const char *get_name() const;
+public:
+ virtual const char *get_name() const override { return "AudioWorklet"; }
+
+ virtual void lock() override {}
+ virtual void unlock() override {}
- virtual Error init();
- virtual void start();
- void resume();
- virtual float get_latency();
- virtual int get_mix_rate() const;
- virtual SpeakerMode get_speaker_mode() const;
- virtual void lock();
- virtual void unlock();
- virtual void finish();
+ AudioDriverWorklet() { singleton = this; }
+};
+#else
+class AudioDriverWorklet : public AudioDriverJavaScript {
+private:
+ enum {
+ STATE_LOCK,
+ STATE_PROCESS,
+ STATE_SAMPLES_IN,
+ STATE_SAMPLES_OUT,
+ STATE_MAX,
+ };
+ Mutex mutex;
+ Thread thread;
+ bool quit = false;
+ int32_t state[STATE_MAX] = { 0 };
- virtual Error capture_start();
- virtual Error capture_stop();
+ static void _audio_thread_func(void *p_data);
- AudioDriverJavaScript();
+protected:
+ virtual Error create(int &p_buffer_size, int p_output_channels) override;
+ virtual void start(float *p_out_buf, int p_out_buf_size, float *p_in_buf, int p_in_buf_size) override;
+ virtual void finish_driver() override;
+
+public:
+ virtual const char *get_name() const override { return "AudioWorklet"; }
+
+ void lock() override;
+ void unlock() override;
};
#endif
+
+#endif
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 173b558b6d..b57f3b3f16 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -77,11 +77,9 @@ def configure(env):
env.Append(LINKFLAGS=["-Os"])
if env["target"] == "release_debug":
- env.Append(CPPDEFINES=["DEBUG_ENABLED"])
# Retain function names for backtraces at the cost of file size.
env.Append(LINKFLAGS=["--profiling-funcs"])
else: # "debug"
- env.Append(CPPDEFINES=["DEBUG_ENABLED"])
env.Append(CCFLAGS=["-O1", "-g"])
env.Append(LINKFLAGS=["-O1", "-g"])
env["use_assertions"] = True
@@ -182,6 +180,13 @@ def configure(env):
env.Prepend(CPPPATH=["#platform/javascript"])
env.Append(CPPDEFINES=["JAVASCRIPT_ENABLED", "UNIX_ENABLED"])
+ if env["opengl3"]:
+ env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"])
+ # This setting just makes WebGL 2 APIs available, it does NOT disable WebGL 1.
+ env.Append(LINKFLAGS=["-s", "USE_WEBGL2=1"])
+ # Allow use to take control of swapping WebGL buffers.
+ env.Append(LINKFLAGS=["-s", "OFFSCREEN_FRAMEBUFFER=1"])
+
if env["javascript_eval"]:
env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"])
@@ -220,25 +225,11 @@ def configure(env):
# us since we don't know requirements at compile-time.
env.Append(LINKFLAGS=["-s", "ALLOW_MEMORY_GROWTH=1"])
- # 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, cwrap for the mono version.
env.Append(LINKFLAGS=["-s", "EXPORTED_RUNTIME_METHODS=['callMain','cwrap']"])
# Add code that allow exiting runtime.
env.Append(LINKFLAGS=["-s", "EXIT_RUNTIME=1"])
-
- # TODO remove once we have GLES support back (temporary fix undefined symbols due to dead code elimination).
- env.Append(
- LINKFLAGS=[
- "-s",
- "EXPORTED_FUNCTIONS=['_main', '_emscripten_webgl_get_current_context']",
- ]
- )
diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp
index fda18a5c19..7648ddaf43 100644
--- a/platform/javascript/display_server_javascript.cpp
+++ b/platform/javascript/display_server_javascript.cpp
@@ -30,6 +30,9 @@
#include "platform/javascript/display_server_javascript.h"
+#ifdef GLES3_ENABLED
+#include "drivers/gles3/rasterizer_gles3.h"
+#endif
#include "platform/javascript/os_javascript.h"
#include "servers/rendering/rasterizer_dummy.h"
@@ -50,38 +53,17 @@ DisplayServerJavaScript *DisplayServerJavaScript::get_singleton() {
}
// Window (canvas)
-void DisplayServerJavaScript::focus_canvas() {
- godot_js_display_canvas_focus();
-}
-
-bool DisplayServerJavaScript::is_canvas_focused() {
- return godot_js_display_canvas_is_focused() != 0;
-}
-
bool DisplayServerJavaScript::check_size_force_redraw() {
return godot_js_display_size_update() != 0;
}
-Point2 DisplayServerJavaScript::compute_position_in_canvas(int p_x, int p_y) {
- int point[2];
- godot_js_display_compute_position(p_x, p_y, point, point + 1);
- return Point2(point[0], point[1]);
-}
-
-EM_BOOL DisplayServerJavaScript::fullscreen_change_callback(int p_event_type, const EmscriptenFullscreenChangeEvent *p_event, void *p_user_data) {
+void DisplayServerJavaScript::fullscreen_change_callback(int p_fullscreen) {
DisplayServerJavaScript *display = get_singleton();
- // Empty ID is canvas.
- String target_id = String::utf8(p_event->id);
- if (target_id.is_empty() || target_id == String::utf8(&(display->canvas_id[1]))) {
- // This event property is the only reliable data on
- // browser fullscreen state.
- if (p_event->isFullscreen) {
- display->window_mode = WINDOW_MODE_FULLSCREEN;
- } else {
- display->window_mode = WINDOW_MODE_WINDOWED;
- }
+ if (p_fullscreen) {
+ display->window_mode = WINDOW_MODE_FULLSCREEN;
+ } else {
+ display->window_mode = WINDOW_MODE_WINDOWED;
}
- return false;
}
// Drag and drop callback.
@@ -118,125 +100,97 @@ void DisplayServerJavaScript::request_quit_callback() {
// Keys
-template <typename T>
-void DisplayServerJavaScript::dom2godot_mod(T *emscripten_event_ptr, Ref<InputEventWithModifiers> godot_event) {
- godot_event->set_shift_pressed(emscripten_event_ptr->shiftKey);
- godot_event->set_alt_pressed(emscripten_event_ptr->altKey);
- godot_event->set_ctrl_pressed(emscripten_event_ptr->ctrlKey);
- godot_event->set_meta_pressed(emscripten_event_ptr->metaKey);
+void DisplayServerJavaScript::dom2godot_mod(Ref<InputEventWithModifiers> ev, int p_mod) {
+ ev->set_shift_pressed(p_mod & 1);
+ ev->set_alt_pressed(p_mod & 2);
+ ev->set_ctrl_pressed(p_mod & 4);
+ ev->set_meta_pressed(p_mod & 8);
}
-Ref<InputEventKey> DisplayServerJavaScript::setup_key_event(const EmscriptenKeyboardEvent *emscripten_event) {
+void DisplayServerJavaScript::key_callback(int p_pressed, int p_repeat, int p_modifiers) {
+ DisplayServerJavaScript *ds = get_singleton();
+ JSKeyEvent &key_event = ds->key_event;
+ // Resume audio context after input in case autoplay was denied.
+ OS_JavaScript::get_singleton()->resume_audio();
+
Ref<InputEventKey> ev;
ev.instantiate();
- ev->set_echo(emscripten_event->repeat);
- dom2godot_mod(emscripten_event, ev);
- ev->set_keycode(dom_code2godot_scancode(emscripten_event->code, emscripten_event->key, false));
- ev->set_physical_keycode(dom_code2godot_scancode(emscripten_event->code, emscripten_event->key, true));
-
- String unicode = String::utf8(emscripten_event->key);
- // Check if empty or multi-character (e.g. `CapsLock`).
- if (unicode.length() != 1) {
- // Might be empty as well, but better than nonsense.
- unicode = String::utf8(emscripten_event->charValue);
- }
+ ev->set_echo(p_repeat);
+ ev->set_keycode(dom_code2godot_scancode(key_event.code, key_event.key, false));
+ ev->set_physical_keycode(dom_code2godot_scancode(key_event.code, key_event.key, true));
+ ev->set_pressed(p_pressed);
+ dom2godot_mod(ev, p_modifiers);
+
+ String unicode = String::utf8(key_event.key);
if (unicode.length() == 1) {
ev->set_unicode(unicode[0]);
}
-
- return ev;
-}
-
-EM_BOOL DisplayServerJavaScript::keydown_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data) {
- DisplayServerJavaScript *display = get_singleton();
- Ref<InputEventKey> ev = setup_key_event(p_event);
- ev->set_pressed(true);
- if (ev->get_unicode() == 0 && keycode_has_unicode(ev->get_keycode())) {
- // Defer to keypress event for legacy unicode retrieval.
- display->deferred_key_event = ev;
- // Do not suppress keypress event.
- return false;
- }
Input::get_singleton()->parse_input_event(ev);
- return true;
-}
-
-EM_BOOL DisplayServerJavaScript::keypress_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data) {
- DisplayServerJavaScript *display = get_singleton();
- display->deferred_key_event->set_unicode(p_event->charCode);
- Input::get_singleton()->parse_input_event(display->deferred_key_event);
- return true;
-}
-EM_BOOL DisplayServerJavaScript::keyup_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data) {
- Ref<InputEventKey> ev = setup_key_event(p_event);
- ev->set_pressed(false);
- Input::get_singleton()->parse_input_event(ev);
- return ev->get_keycode() != KEY_UNKNOWN && ev->get_keycode() != (Key)0;
+ // Make sure to flush all events so we can call restricted APIs inside the event.
+ Input::get_singleton()->flush_buffered_events();
}
// Mouse
-EM_BOOL DisplayServerJavaScript::mouse_button_callback(int p_event_type, const EmscriptenMouseEvent *p_event, void *p_user_data) {
- DisplayServerJavaScript *display = get_singleton();
+int DisplayServerJavaScript::mouse_button_callback(int p_pressed, int p_button, double p_x, double p_y, int p_modifiers) {
+ DisplayServerJavaScript *ds = get_singleton();
+ Point2 pos(p_x, p_y);
+ Input::get_singleton()->set_mouse_position(pos);
Ref<InputEventMouseButton> ev;
ev.instantiate();
- ev->set_pressed(p_event_type == EMSCRIPTEN_EVENT_MOUSEDOWN);
- ev->set_position(compute_position_in_canvas(p_event->clientX, p_event->clientY));
- ev->set_global_position(ev->get_position());
- dom2godot_mod(p_event, ev);
+ ev->set_position(pos);
+ ev->set_global_position(pos);
+ ev->set_pressed(p_pressed);
+ dom2godot_mod(ev, p_modifiers);
- switch (p_event->button) {
+ switch (p_button) {
case DOM_BUTTON_LEFT:
- ev->set_button_index(MOUSE_BUTTON_LEFT);
+ ev->set_button_index(MouseButton::LEFT);
break;
case DOM_BUTTON_MIDDLE:
- ev->set_button_index(MOUSE_BUTTON_MIDDLE);
+ ev->set_button_index(MouseButton::MIDDLE);
break;
case DOM_BUTTON_RIGHT:
- ev->set_button_index(MOUSE_BUTTON_RIGHT);
+ ev->set_button_index(MouseButton::RIGHT);
break;
case DOM_BUTTON_XBUTTON1:
- ev->set_button_index(MOUSE_BUTTON_XBUTTON1);
+ ev->set_button_index(MouseButton::MB_XBUTTON1);
break;
case DOM_BUTTON_XBUTTON2:
- ev->set_button_index(MOUSE_BUTTON_XBUTTON2);
+ ev->set_button_index(MouseButton::MB_XBUTTON2);
break;
default:
return false;
}
- if (ev->is_pressed()) {
- double diff = emscripten_get_now() - display->last_click_ms;
+ if (p_pressed) {
+ uint64_t diff = (OS::get_singleton()->get_ticks_usec() / 1000) - ds->last_click_ms;
- if (ev->get_button_index() == display->last_click_button_index) {
- if (diff < 400 && Point2(display->last_click_pos).distance_to(ev->get_position()) < 5) {
- display->last_click_ms = 0;
- display->last_click_pos = Point2(-100, -100);
- display->last_click_button_index = -1;
+ if (ev->get_button_index() == ds->last_click_button_index) {
+ if (diff < 400 && Point2(ds->last_click_pos).distance_to(ev->get_position()) < 5) {
+ ds->last_click_ms = 0;
+ ds->last_click_pos = Point2(-100, -100);
+ ds->last_click_button_index = MouseButton::NONE;
ev->set_double_click(true);
}
} else {
- display->last_click_button_index = ev->get_button_index();
+ ds->last_click_button_index = ev->get_button_index();
}
if (!ev->is_double_click()) {
- display->last_click_ms += diff;
- display->last_click_pos = ev->get_position();
+ ds->last_click_ms += diff;
+ ds->last_click_pos = ev->get_position();
}
}
- Input *input = Input::get_singleton();
- int mask = input->get_mouse_button_mask();
- MouseButton button_flag = MouseButton(1 << (ev->get_button_index() - 1));
+ MouseButton mask = Input::get_singleton()->get_mouse_button_mask();
+ MouseButton button_flag = mouse_button_to_mask(ev->get_button_index());
if (ev->is_pressed()) {
- // Since the event is consumed, focus manually. The containing iframe,
- // if exists, may not have focus yet, so focus even if already focused.
- focus_canvas();
mask |= button_flag;
- } else if (mask & button_flag) {
+ } else if ((mask & button_flag) != MouseButton::NONE) {
mask &= ~button_flag;
} else {
// Received release event, but press was outside the canvas, so ignore.
@@ -244,37 +198,41 @@ EM_BOOL DisplayServerJavaScript::mouse_button_callback(int p_event_type, const E
}
ev->set_button_mask(mask);
- input->parse_input_event(ev);
+ Input::get_singleton()->parse_input_event(ev);
+ // Resume audio context after input in case autoplay was denied.
+ OS_JavaScript::get_singleton()->resume_audio();
+
+ // Make sure to flush all events so we can call restricted APIs inside the event.
+ Input::get_singleton()->flush_buffered_events();
+
// Prevent multi-click text selection and wheel-click scrolling anchor.
// Context menu is prevented through contextmenu event.
return true;
}
-EM_BOOL DisplayServerJavaScript::mousemove_callback(int p_event_type, const EmscriptenMouseEvent *p_event, void *p_user_data) {
- DisplayServerJavaScript *ds = get_singleton();
- Input *input = Input::get_singleton();
- int input_mask = input->get_mouse_button_mask();
- Point2 pos = compute_position_in_canvas(p_event->clientX, p_event->clientY);
+void DisplayServerJavaScript::mouse_move_callback(double p_x, double p_y, double p_rel_x, double p_rel_y, int p_modifiers) {
+ MouseButton input_mask = Input::get_singleton()->get_mouse_button_mask();
// For motion outside the canvas, only read mouse movement if dragging
// started inside the canvas; imitating desktop app behaviour.
- if (!ds->cursor_inside_canvas && !input_mask)
- return false;
+ if (!get_singleton()->cursor_inside_canvas && input_mask == MouseButton::NONE) {
+ return;
+ }
+ Point2 pos(p_x, p_y);
+ Input::get_singleton()->set_mouse_position(pos);
Ref<InputEventMouseMotion> ev;
ev.instantiate();
- dom2godot_mod(p_event, ev);
+ dom2godot_mod(ev, p_modifiers);
ev->set_button_mask(input_mask);
ev->set_position(pos);
- ev->set_global_position(ev->get_position());
+ ev->set_global_position(pos);
- ev->set_relative(Vector2(p_event->movementX, p_event->movementY));
- input->set_mouse_position(ev->get_position());
- ev->set_speed(input->get_last_mouse_speed());
+ ev->set_relative(Vector2(p_rel_x, p_rel_y));
+ Input::get_singleton()->set_mouse_position(ev->get_position());
+ ev->set_speed(Input::get_singleton()->get_last_mouse_speed());
- input->parse_input_event(ev);
- // Don't suppress mouseover/-leave events.
- return false;
+ Input::get_singleton()->parse_input_event(ev);
}
// Cursor
@@ -414,17 +372,15 @@ void DisplayServerJavaScript::mouse_set_mode(MouseMode p_mode) {
if (p_mode == MOUSE_MODE_VISIBLE) {
godot_js_display_cursor_set_visible(1);
- emscripten_exit_pointerlock();
+ godot_js_display_cursor_lock_set(0);
} else if (p_mode == MOUSE_MODE_HIDDEN) {
godot_js_display_cursor_set_visible(0);
- emscripten_exit_pointerlock();
+ godot_js_display_cursor_lock_set(0);
} else if (p_mode == MOUSE_MODE_CAPTURED) {
godot_js_display_cursor_set_visible(1);
- EMSCRIPTEN_RESULT result = emscripten_request_pointerlock(canvas_id, false);
- ERR_FAIL_COND_MSG(result == EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED, "MOUSE_MODE_CAPTURED can only be entered from within an appropriate input callback.");
- ERR_FAIL_COND_MSG(result != EMSCRIPTEN_RESULT_SUCCESS, "MOUSE_MODE_CAPTURED can only be entered from within an appropriate input callback.");
+ godot_js_display_cursor_lock_set(1);
}
}
@@ -433,18 +389,21 @@ DisplayServer::MouseMode DisplayServerJavaScript::mouse_get_mode() const {
return MOUSE_MODE_HIDDEN;
}
- EmscriptenPointerlockChangeEvent ev;
- emscripten_get_pointerlock_status(&ev);
- return (ev.isActive && String::utf8(ev.id) == String::utf8(&canvas_id[1])) ? MOUSE_MODE_CAPTURED : MOUSE_MODE_VISIBLE;
+ if (godot_js_display_cursor_is_locked()) {
+ return MOUSE_MODE_CAPTURED;
+ }
+ return MOUSE_MODE_VISIBLE;
+}
+
+Point2i DisplayServerJavaScript::mouse_get_position() const {
+ return Input::get_singleton()->get_mouse_position();
}
// Wheel
-EM_BOOL DisplayServerJavaScript::wheel_callback(int p_event_type, const EmscriptenWheelEvent *p_event, void *p_user_data) {
- ERR_FAIL_COND_V(p_event_type != EMSCRIPTEN_EVENT_WHEEL, false);
- DisplayServerJavaScript *ds = get_singleton();
- if (!is_canvas_focused()) {
- if (ds->cursor_inside_canvas) {
- focus_canvas();
+int DisplayServerJavaScript::mouse_wheel_callback(double p_delta_x, double p_delta_y) {
+ if (!godot_js_display_canvas_is_focused()) {
+ if (get_singleton()->cursor_inside_canvas) {
+ godot_js_display_canvas_focus();
} else {
return false;
}
@@ -456,81 +415,78 @@ EM_BOOL DisplayServerJavaScript::wheel_callback(int p_event_type, const Emscript
ev->set_position(input->get_mouse_position());
ev->set_global_position(ev->get_position());
- ev->set_shift_pressed(input->is_key_pressed(KEY_SHIFT));
- ev->set_alt_pressed(input->is_key_pressed(KEY_ALT));
- ev->set_ctrl_pressed(input->is_key_pressed(KEY_CTRL));
- ev->set_meta_pressed(input->is_key_pressed(KEY_META));
-
- if (p_event->deltaY < 0)
- ev->set_button_index(MOUSE_BUTTON_WHEEL_UP);
- else if (p_event->deltaY > 0)
- ev->set_button_index(MOUSE_BUTTON_WHEEL_DOWN);
- else if (p_event->deltaX > 0)
- ev->set_button_index(MOUSE_BUTTON_WHEEL_LEFT);
- else if (p_event->deltaX < 0)
- ev->set_button_index(MOUSE_BUTTON_WHEEL_RIGHT);
- else
+ ev->set_shift_pressed(input->is_key_pressed(Key::SHIFT));
+ ev->set_alt_pressed(input->is_key_pressed(Key::ALT));
+ ev->set_ctrl_pressed(input->is_key_pressed(Key::CTRL));
+ ev->set_meta_pressed(input->is_key_pressed(Key::META));
+
+ if (p_delta_y < 0) {
+ ev->set_button_index(MouseButton::WHEEL_UP);
+ } else if (p_delta_y > 0) {
+ ev->set_button_index(MouseButton::WHEEL_DOWN);
+ } else if (p_delta_x > 0) {
+ ev->set_button_index(MouseButton::WHEEL_LEFT);
+ } else if (p_delta_x < 0) {
+ ev->set_button_index(MouseButton::WHEEL_RIGHT);
+ } else {
return false;
+ }
// Different browsers give wildly different delta values, and we can't
// interpret deltaMode, so use default value for wheel events' factor.
- int button_flag = 1 << (ev->get_button_index() - 1);
+ MouseButton button_flag = mouse_button_to_mask(ev->get_button_index());
ev->set_pressed(true);
- ev->set_button_mask(MouseButton(input->get_mouse_button_mask() | button_flag));
+ ev->set_button_mask(input->get_mouse_button_mask() | button_flag);
input->parse_input_event(ev);
- ev->set_pressed(false);
- ev->set_button_mask(MouseButton(input->get_mouse_button_mask() & ~button_flag));
- input->parse_input_event(ev);
+ Ref<InputEventMouseButton> release = ev->duplicate();
+ release->set_pressed(false);
+ release->set_button_mask(MouseButton(input->get_mouse_button_mask() & ~button_flag));
+ input->parse_input_event(release);
return true;
}
// Touch
-EM_BOOL DisplayServerJavaScript::touch_press_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data) {
- DisplayServerJavaScript *display = get_singleton();
- Ref<InputEventScreenTouch> ev;
- ev.instantiate();
- int lowest_id_index = -1;
- for (int i = 0; i < p_event->numTouches; ++i) {
- const EmscriptenTouchPoint &touch = p_event->touches[i];
- if (lowest_id_index == -1 || touch.identifier < p_event->touches[lowest_id_index].identifier)
- lowest_id_index = i;
- if (!touch.isChanged)
- continue;
- ev->set_index(touch.identifier);
- ev->set_position(compute_position_in_canvas(touch.clientX, touch.clientY));
- display->touches[i] = ev->get_position();
- ev->set_pressed(p_event_type == EMSCRIPTEN_EVENT_TOUCHSTART);
+void DisplayServerJavaScript::touch_callback(int p_type, int p_count) {
+ DisplayServerJavaScript *ds = get_singleton();
- Input::get_singleton()->parse_input_event(ev);
- }
- // Resume audio context after input in case autoplay was denied.
- return true;
-}
+ const JSTouchEvent &touch_event = ds->touch_event;
+ for (int i = 0; i < p_count; i++) {
+ Point2 point(touch_event.coords[i * 2], touch_event.coords[i * 2 + 1]);
+ if (p_type == 2) {
+ // touchmove
+ Ref<InputEventScreenDrag> ev;
+ ev.instantiate();
+ ev->set_index(touch_event.identifier[i]);
+ ev->set_position(point);
+
+ Point2 &prev = ds->touches[i];
+ ev->set_relative(ev->get_position() - prev);
+ prev = ev->get_position();
+
+ Input::get_singleton()->parse_input_event(ev);
+ } else {
+ // touchstart/touchend
+ Ref<InputEventScreenTouch> ev;
-EM_BOOL DisplayServerJavaScript::touchmove_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data) {
- DisplayServerJavaScript *display = get_singleton();
- Ref<InputEventScreenDrag> ev;
- ev.instantiate();
- int lowest_id_index = -1;
- for (int i = 0; i < p_event->numTouches; ++i) {
- const EmscriptenTouchPoint &touch = p_event->touches[i];
- if (lowest_id_index == -1 || touch.identifier < p_event->touches[lowest_id_index].identifier)
- lowest_id_index = i;
- if (!touch.isChanged)
- continue;
- ev->set_index(touch.identifier);
- ev->set_position(compute_position_in_canvas(touch.clientX, touch.clientY));
- Point2 &prev = display->touches[i];
- ev->set_relative(ev->get_position() - prev);
- prev = ev->get_position();
+ // Resume audio context after input in case autoplay was denied.
+ OS_JavaScript::get_singleton()->resume_audio();
- Input::get_singleton()->parse_input_event(ev);
+ ev.instantiate();
+ ev->set_index(touch_event.identifier[i]);
+ ev->set_position(point);
+ ev->set_pressed(p_type == 0);
+ ds->touches[i] = point;
+
+ Input::get_singleton()->parse_input_event(ev);
+
+ // Make sure to flush all events so we can call restricted APIs inside the event.
+ Input::get_singleton()->flush_buffered_events();
+ }
}
- return true;
}
bool DisplayServerJavaScript::screen_is_touchscreen(int p_screen) const {
@@ -556,12 +512,12 @@ void DisplayServerJavaScript::vk_input_text_callback(const char *p_text, int p_c
k.instantiate();
k->set_pressed(true);
k->set_echo(false);
- k->set_keycode(KEY_RIGHT);
+ k->set_keycode(Key::RIGHT);
input->parse_input_event(k);
k.instantiate();
k->set_pressed(false);
k->set_echo(false);
- k->set_keycode(KEY_RIGHT);
+ k->set_keycode(Key::RIGHT);
input->parse_input_event(k);
}
}
@@ -574,6 +530,10 @@ void DisplayServerJavaScript::virtual_keyboard_hide() {
godot_js_display_vk_hide();
}
+void DisplayServerJavaScript::window_blur_callback() {
+ Input::get_singleton()->release_pressed_events();
+}
+
// Gamepad
void DisplayServerJavaScript::gamepad_callback(int p_index, int p_connected, const char *p_id, const char *p_guid) {
Input *input = Input::get_singleton();
@@ -586,26 +546,26 @@ void DisplayServerJavaScript::gamepad_callback(int p_index, int p_connected, con
void DisplayServerJavaScript::process_joypads() {
Input *input = Input::get_singleton();
- int32_t pads = godot_js_display_gamepad_sample_count();
+ int32_t pads = godot_js_input_gamepad_sample_count();
int32_t s_btns_num = 0;
int32_t s_axes_num = 0;
int32_t s_standard = 0;
float s_btns[16];
float s_axes[10];
for (int idx = 0; idx < pads; idx++) {
- int err = godot_js_display_gamepad_sample_get(idx, s_btns, &s_btns_num, s_axes, &s_axes_num, &s_standard);
+ int err = godot_js_input_gamepad_sample_get(idx, s_btns, &s_btns_num, s_axes, &s_axes_num, &s_standard);
if (err) {
continue;
}
for (int b = 0; b < s_btns_num; b++) {
float value = s_btns[b];
// Buttons 6 and 7 in the standard mapping need to be
- // axis to be handled as JOY_AXIS_TRIGGER by Godot.
+ // axis to be handled as JoyAxis::TRIGGER by Godot.
if (s_standard && (b == 6 || b == 7)) {
Input::JoyAxisValue joy_axis;
joy_axis.min = 0;
joy_axis.value = value;
- JoyAxis a = b == 6 ? JOY_AXIS_TRIGGER_LEFT : JOY_AXIS_TRIGGER_RIGHT;
+ JoyAxis a = b == 6 ? JoyAxis::TRIGGER_LEFT : JoyAxis::TRIGGER_RIGHT;
input->joy_axis(idx, a, joy_axis);
} else {
input->joy_button(idx, (JoyButton)b, value);
@@ -622,7 +582,9 @@ void DisplayServerJavaScript::process_joypads() {
Vector<String> DisplayServerJavaScript::get_rendering_drivers_func() {
Vector<String> drivers;
- drivers.push_back("dummy");
+#ifdef GLES3_ENABLED
+ drivers.push_back("opengl3");
+#endif
return drivers;
}
@@ -691,11 +653,6 @@ void DisplayServerJavaScript::set_icon(const Ref<Image> &p_icon) {
}
void DisplayServerJavaScript::_dispatch_input_event(const Ref<InputEvent> &p_event) {
- OS_JavaScript *os = OS_JavaScript::get_singleton();
-
- // Resume audio context after input in case autoplay was denied.
- os->resume_audio();
-
Callable cb = get_singleton()->input_event_callback;
if (!cb.is_null()) {
Variant ev = p_event;
@@ -725,87 +682,66 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive
// Expose method for requesting quit.
godot_js_os_request_quit_cb(request_quit_callback);
- RasterizerDummy::make_current(); // TODO GLES2 in Godot 4.0... or webgpu?
-#if 0
- EmscriptenWebGLContextAttributes attributes;
- emscripten_webgl_init_context_attributes(&attributes);
- attributes.alpha = GLOBAL_GET("display/window/per_pixel_transparency/allowed");
- attributes.antialias = false;
- ERR_FAIL_INDEX_V(p_video_driver, VIDEO_DRIVER_MAX, ERR_INVALID_PARAMETER);
-
- if (p_desired.layered) {
- set_window_per_pixel_transparency_enabled(true);
- }
-
- bool gl_initialization_error = false;
-
- if (RasterizerGLES2::is_viable() == OK) {
- attributes.majorVersion = 1;
- RasterizerGLES2::register_config();
- RasterizerGLES2::make_current();
- } else {
- gl_initialization_error = true;
- }
-
- EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(canvas_id, &attributes);
- if (emscripten_webgl_make_context_current(ctx) != EMSCRIPTEN_RESULT_SUCCESS) {
- gl_initialization_error = true;
+#ifdef GLES3_ENABLED
+ // TODO "vulkan" defaults to webgl2 for now.
+ bool wants_webgl2 = p_rendering_driver == "opengl3" || p_rendering_driver == "vulkan";
+ bool webgl2_init_failed = wants_webgl2 && !godot_js_display_has_webgl(2);
+ if (wants_webgl2 && !webgl2_init_failed) {
+ EmscriptenWebGLContextAttributes attributes;
+ emscripten_webgl_init_context_attributes(&attributes);
+ //attributes.alpha = GLOBAL_GET("display/window/per_pixel_transparency/allowed");
+ attributes.alpha = true;
+ attributes.antialias = false;
+ attributes.majorVersion = 2;
+
+ webgl_ctx = emscripten_webgl_create_context(canvas_id, &attributes);
+ if (emscripten_webgl_make_context_current(webgl_ctx) != EMSCRIPTEN_RESULT_SUCCESS) {
+ webgl2_init_failed = true;
+ } else {
+ RasterizerGLES3::make_current();
+ }
}
-
- if (gl_initialization_error) {
- OS::get_singleton()->alert("Your browser does not seem to support WebGL. Please update your browser version.",
+ if (webgl2_init_failed) {
+ OS::get_singleton()->alert("Your browser does not seem to support WebGL2. Please update your browser version.",
"Unable to initialize video driver");
- return ERR_UNAVAILABLE;
}
-
- video_driver_index = p_video_driver;
+ if (!wants_webgl2 || webgl2_init_failed) {
+ RasterizerDummy::make_current();
+ }
+#else
+ RasterizerDummy::make_current();
#endif
- EMSCRIPTEN_RESULT result;
-#define EM_CHECK(ev) \
- if (result != EMSCRIPTEN_RESULT_SUCCESS) \
- ERR_PRINT("Error while setting " #ev " callback: Code " + itos(result));
-#define SET_EM_CALLBACK(target, ev, cb) \
- result = emscripten_set_##ev##_callback(target, nullptr, true, &cb); \
- EM_CHECK(ev)
-#define SET_EM_WINDOW_CALLBACK(ev, cb) \
- result = emscripten_set_##ev##_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, false, &cb); \
- EM_CHECK(ev)
- // These callbacks from Emscripten's html5.h suffice to access most
- // JavaScript APIs.
- SET_EM_CALLBACK(canvas_id, mousedown, mouse_button_callback)
- SET_EM_WINDOW_CALLBACK(mousemove, mousemove_callback)
- SET_EM_WINDOW_CALLBACK(mouseup, mouse_button_callback)
- SET_EM_CALLBACK(canvas_id, wheel, wheel_callback)
- SET_EM_CALLBACK(canvas_id, touchstart, touch_press_callback)
- SET_EM_CALLBACK(canvas_id, touchmove, touchmove_callback)
- SET_EM_CALLBACK(canvas_id, touchend, touch_press_callback)
- SET_EM_CALLBACK(canvas_id, touchcancel, touch_press_callback)
- SET_EM_CALLBACK(canvas_id, keydown, keydown_callback)
- SET_EM_CALLBACK(canvas_id, keypress, keypress_callback)
- SET_EM_CALLBACK(canvas_id, keyup, keyup_callback)
- SET_EM_CALLBACK(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, fullscreenchange, fullscreen_change_callback)
-#undef SET_EM_CALLBACK
-#undef EM_CHECK
-
- // For APIs that are not (sufficiently) exposed, a
- // library is used below (implemented in library_godot_display.js).
+ // JS Input interface (js/libs/library_godot_input.js)
+ godot_js_input_mouse_button_cb(&DisplayServerJavaScript::mouse_button_callback);
+ godot_js_input_mouse_move_cb(&DisplayServerJavaScript::mouse_move_callback);
+ godot_js_input_mouse_wheel_cb(&DisplayServerJavaScript::mouse_wheel_callback);
+ godot_js_input_touch_cb(&DisplayServerJavaScript::touch_callback, touch_event.identifier, touch_event.coords);
+ godot_js_input_key_cb(&DisplayServerJavaScript::key_callback, key_event.code, key_event.key);
+ godot_js_input_paste_cb(update_clipboard_callback);
+ godot_js_input_drop_files_cb(drop_files_js_callback);
+ godot_js_input_gamepad_cb(&DisplayServerJavaScript::gamepad_callback);
+
+ // JS Display interface (js/libs/library_godot_display.js)
+ godot_js_display_fullscreen_cb(&DisplayServerJavaScript::fullscreen_change_callback);
+ godot_js_display_window_blur_cb(&window_blur_callback);
godot_js_display_notification_cb(&send_window_event_callback,
WINDOW_EVENT_MOUSE_ENTER,
WINDOW_EVENT_MOUSE_EXIT,
WINDOW_EVENT_FOCUS_IN,
WINDOW_EVENT_FOCUS_OUT);
- godot_js_display_paste_cb(update_clipboard_callback);
- godot_js_display_drop_files_cb(drop_files_js_callback);
- godot_js_display_gamepad_cb(&DisplayServerJavaScript::gamepad_callback);
godot_js_display_vk_cb(&vk_input_text_callback);
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_event);
}
DisplayServerJavaScript::~DisplayServerJavaScript() {
- //emscripten_webgl_commit_frame();
- //emscripten_webgl_destroy_context(webgl_ctx);
+#ifdef GLES3_ENABLED
+ if (webgl_ctx) {
+ emscripten_webgl_commit_frame();
+ emscripten_webgl_destroy_context(webgl_ctx);
+ }
+#endif
}
bool DisplayServerJavaScript::has_feature(Feature p_feature) const {
@@ -1019,7 +955,8 @@ bool DisplayServerJavaScript::can_any_window_draw() const {
}
void DisplayServerJavaScript::process_events() {
- if (godot_js_display_gamepad_sample() == OK) {
+ Input::get_singleton()->flush_buffered_events();
+ if (godot_js_input_gamepad_sample() == OK) {
process_joypads();
}
}
@@ -1033,5 +970,9 @@ bool DisplayServerJavaScript::get_swap_cancel_ok() {
}
void DisplayServerJavaScript::swap_buffers() {
- //emscripten_webgl_commit_frame();
+#ifdef GLES3_ENABLED
+ if (webgl_ctx) {
+ emscripten_webgl_commit_frame();
+ }
+#endif
}
diff --git a/platform/javascript/display_server_javascript.h b/platform/javascript/display_server_javascript.h
index bf5e229c9a..843bb61984 100644
--- a/platform/javascript/display_server_javascript.h
+++ b/platform/javascript/display_server_javascript.h
@@ -38,6 +38,23 @@
class DisplayServerJavaScript : public DisplayServer {
private:
+ struct JSTouchEvent {
+ uint32_t identifier[32] = { 0 };
+ double coords[64] = { 0 };
+ };
+ JSTouchEvent touch_event;
+
+ struct JSKeyEvent {
+ char code[32] = { 0 };
+ char key[32] = { 0 };
+ uint8_t modifiers[4] = { 0 };
+ };
+ JSKeyEvent key_event;
+
+#ifdef GLES3_ENABLED
+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE webgl_ctx = 0;
+#endif
+
WindowMode window_mode = WINDOW_MODE_WINDOWED;
ObjectID window_attached_instance_id = {};
@@ -47,44 +64,29 @@ private:
Callable drop_files_callback;
String clipboard;
- Ref<InputEventKey> deferred_key_event;
Point2 touches[32];
char canvas_id[256] = { 0 };
bool cursor_inside_canvas = true;
CursorShape cursor_shape = CURSOR_ARROW;
Point2i last_click_pos = Point2(-100, -100); // TODO check this again.
- double last_click_ms = 0;
- int last_click_button_index = -1;
+ uint64_t last_click_ms = 0;
+ MouseButton last_click_button_index = MouseButton::NONE;
bool swap_cancel_ok = false;
// utilities
- static Point2 compute_position_in_canvas(int p_x, int p_y);
- static void focus_canvas();
- static bool is_canvas_focused();
- template <typename T>
- static void dom2godot_mod(T *emscripten_event_ptr, Ref<InputEventWithModifiers> godot_event);
- static Ref<InputEventKey> setup_key_event(const EmscriptenKeyboardEvent *emscripten_event);
+ static void dom2godot_mod(Ref<InputEventWithModifiers> ev, int p_mod);
static const char *godot2dom_cursor(DisplayServer::CursorShape p_shape);
// events
- static EM_BOOL fullscreen_change_callback(int p_event_type, const EmscriptenFullscreenChangeEvent *p_event, void *p_user_data);
-
- static EM_BOOL keydown_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data);
- static EM_BOOL keypress_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data);
- static EM_BOOL keyup_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data);
-
+ static void fullscreen_change_callback(int p_fullscreen);
+ static int mouse_button_callback(int p_pressed, int p_button, double p_x, double p_y, int p_modifiers);
+ static void mouse_move_callback(double p_x, double p_y, double p_rel_x, double p_rel_y, int p_modifiers);
+ static int mouse_wheel_callback(double p_delta_x, double p_delta_y);
+ static void touch_callback(int p_type, int p_count);
+ static void key_callback(int p_pressed, int p_repeat, int p_modifiers);
static void vk_input_text_callback(const char *p_text, int p_cursor);
-
- static EM_BOOL mousemove_callback(int p_event_type, const EmscriptenMouseEvent *p_event, void *p_user_data);
- static EM_BOOL mouse_button_callback(int p_event_type, const EmscriptenMouseEvent *p_event, void *p_user_data);
-
- static EM_BOOL wheel_callback(int p_event_type, const EmscriptenWheelEvent *p_event, void *p_user_data);
-
- static EM_BOOL touch_press_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data);
- static EM_BOOL touchmove_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data);
-
static void gamepad_callback(int p_index, int p_connected, const char *p_id, const char *p_guid);
void process_joypads();
@@ -94,6 +96,7 @@ private:
static void _dispatch_input_event(const Ref<InputEvent> &p_event);
static void request_quit_callback();
+ static void window_blur_callback();
static void update_clipboard_callback(const char *p_text);
static void send_window_event_callback(int p_notification);
static void drop_files_js_callback(char **p_filev, int p_filec);
@@ -120,6 +123,7 @@ public:
// mouse
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
+ virtual Point2i mouse_get_position() const override;
// touch
virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
diff --git a/platform/javascript/dom_keys.inc b/platform/javascript/dom_keys.inc
index 0e62776923..31589f3f40 100644
--- a/platform/javascript/dom_keys.inc
+++ b/platform/javascript/dom_keys.inc
@@ -34,7 +34,7 @@
Key dom_code2godot_scancode(EM_UTF8 const p_code[32], EM_UTF8 const p_key[32], bool p_physical) {
#define DOM2GODOT(p_str, p_godot_code) \
if (memcmp((const void *)p_str, (void *)p_code, strlen(p_str) + 1) == 0) { \
- return KEY_##p_godot_code; \
+ return Key::p_godot_code; \
}
// Numpad section.
@@ -105,16 +105,16 @@ Key dom_code2godot_scancode(EM_UTF8 const p_code[32], EM_UTF8 const p_key[32], b
DOM2GODOT("BracketLeft", BRACKETLEFT);
DOM2GODOT("BracketRight", BRACKETRIGHT);
DOM2GODOT("Comma", COMMA);
- DOM2GODOT("Digit0", 0);
- DOM2GODOT("Digit1", 1);
- DOM2GODOT("Digit2", 2);
- DOM2GODOT("Digit3", 3);
- DOM2GODOT("Digit4", 4);
- DOM2GODOT("Digit5", 5);
- DOM2GODOT("Digit6", 6);
- DOM2GODOT("Digit7", 7);
- DOM2GODOT("Digit8", 8);
- DOM2GODOT("Digit9", 9);
+ DOM2GODOT("Digit0", KEY_0);
+ DOM2GODOT("Digit1", KEY_1);
+ DOM2GODOT("Digit2", KEY_2);
+ DOM2GODOT("Digit3", KEY_3);
+ DOM2GODOT("Digit4", KEY_4);
+ DOM2GODOT("Digit5", KEY_5);
+ DOM2GODOT("Digit6", KEY_6);
+ DOM2GODOT("Digit7", KEY_7);
+ DOM2GODOT("Digit8", KEY_8);
+ DOM2GODOT("Digit9", KEY_9);
DOM2GODOT("Equal", EQUAL);
DOM2GODOT("IntlBackslash", BACKSLASH);
//DOM2GODOT("IntlRo", UNKNOWN);
@@ -170,7 +170,7 @@ Key dom_code2godot_scancode(EM_UTF8 const p_code[32], EM_UTF8 const p_key[32], b
DOM2GODOT("Tab", TAB);
// ControlPad section.
- DOM2GODOT("Delete", DELETE);
+ DOM2GODOT("Delete", KEY_DELETE);
DOM2GODOT("End", END);
DOM2GODOT("Help", HELP);
DOM2GODOT("Home", HOME);
@@ -227,6 +227,6 @@ Key dom_code2godot_scancode(EM_UTF8 const p_code[32], EM_UTF8 const p_key[32], b
DOM2GODOT("AudioVolumeMute", VOLUMEMUTE);
DOM2GODOT("AudioVolumeUp", VOLUMEUP);
//DOM2GODOT("WakeUp", UNKNOWN);
- return KEY_UNKNOWN;
+ return Key::UNKNOWN;
#undef DOM2GODOT
}
diff --git a/platform/javascript/export/export_plugin.cpp b/platform/javascript/export/export_plugin.cpp
index 5d285a6e60..018dd3b664 100644
--- a/platform/javascript/export/export_plugin.cpp
+++ b/platform/javascript/export/export_plugin.cpp
@@ -99,8 +99,8 @@ void EditorExportPlatformJavaScript::_replace_strings(Map<String, String> p_repl
Vector<String> lines = str_template.split("\n");
for (int i = 0; i < lines.size(); i++) {
String current_line = lines[i];
- for (Map<String, String>::Element *E = p_replaces.front(); E; E = E->next()) {
- current_line = current_line.replace(E->key(), E->get());
+ for (const KeyValue<String, String> &E : p_replaces) {
+ current_line = current_line.replace(E.key, E.value);
}
out += current_line + "\n";
}
@@ -140,7 +140,7 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re
if (p_preset->get("progressive_web_app/enabled")) {
head_include += "<link rel='manifest' href='" + p_name + ".manifest.json'>\n";
head_include += "<script type='application/javascript'>window.addEventListener('load', () => {if ('serviceWorker' in navigator) {navigator.serviceWorker.register('" +
- p_name + ".service.worker.js');}});</script>\n";
+ p_name + ".service.worker.js');}});</script>\n";
}
// Replaces HTML string
@@ -300,9 +300,9 @@ void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportP
if (p_preset->get("vram_texture_compression/for_mobile")) {
String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
- if (driver == "GLES2") {
+ if (driver == "opengl3") {
r_features->push_back("etc");
- } else if (driver == "Vulkan") {
+ } else if (driver == "vulkan") {
// FIXME: Review if this is correct.
r_features->push_back("etc2");
}
diff --git a/platform/javascript/export/export_plugin.h b/platform/javascript/export/export_plugin.h
index 736edfe3a8..bdd1235259 100644
--- a/platform/javascript/export/export_plugin.h
+++ b/platform/javascript/export/export_plugin.h
@@ -134,7 +134,7 @@ public:
virtual void get_platform_features(List<String> *r_features) override {
r_features->push_back("web");
- r_features->push_back(get_os_name());
+ r_features->push_back(get_os_name().to_lower());
}
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override {
diff --git a/platform/javascript/godot_audio.h b/platform/javascript/godot_audio.h
index 54fc8fa3b5..eba025ab63 100644
--- a/platform/javascript/godot_audio.h
+++ b/platform/javascript/godot_audio.h
@@ -38,7 +38,9 @@ extern "C" {
#include "stddef.h"
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 int godot_audio_has_worklet();
+extern int godot_audio_has_script_processor();
+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 int godot_audio_capture_start();
@@ -46,14 +48,15 @@ extern void godot_audio_capture_stop();
// Worklet
typedef int32_t GodotAudioState[4];
-extern void godot_audio_worklet_create(int p_channels);
+extern int 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_start_no_threads(float *p_out_buf, int p_out_size, void (*p_out_cb)(int p_pos, int p_frames), float *p_in_buf, int p_in_size, void (*p_in_cb)(int p_pos, int p_frames));
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);
// Script
-extern int godot_audio_script_create(int p_buffer_size, int p_channels);
+extern int godot_audio_script_create(int *p_buffer_size, int p_channels);
extern void godot_audio_script_start(float *p_in_buf, int p_in_size, float *p_out_buf, int p_out_size, void (*p_cb)());
#ifdef __cplusplus
diff --git a/platform/javascript/godot_js.h b/platform/javascript/godot_js.h
index d332af2c31..8051b270e6 100644
--- a/platform/javascript/godot_js.h
+++ b/platform/javascript/godot_js.h
@@ -50,12 +50,28 @@ extern int godot_js_os_execute(const char *p_json);
extern void godot_js_os_shell_open(const char *p_uri);
extern int godot_js_os_hw_concurrency_get();
+// Input
+extern void godot_js_input_mouse_button_cb(int (*p_callback)(int p_pressed, int p_button, double p_x, double p_y, int p_modifiers));
+extern void godot_js_input_mouse_move_cb(void (*p_callback)(double p_x, double p_y, double p_rel_x, double p_rel_y, int p_modifiers));
+extern void godot_js_input_mouse_wheel_cb(int (*p_callback)(double p_delta_x, double p_delta_y));
+extern void godot_js_input_touch_cb(void (*p_callback)(int p_type, int p_count), uint32_t *r_identifiers, double *r_coords);
+extern void godot_js_input_key_cb(void (*p_callback)(int p_type, int p_repeat, int p_modifiers), char r_code[32], char r_key[32]);
+
+// Input gamepad
+extern void godot_js_input_gamepad_cb(void (*p_on_change)(int p_index, int p_connected, const char *p_id, const char *p_guid));
+extern int godot_js_input_gamepad_sample();
+extern int godot_js_input_gamepad_sample_count();
+extern int godot_js_input_gamepad_sample_get(int p_idx, float r_btns[16], int32_t *r_btns_num, float r_axes[10], int32_t *r_axes_num, int32_t *r_standard);
+extern void godot_js_input_paste_cb(void (*p_callback)(const char *p_text));
+extern void godot_js_input_drop_files_cb(void (*p_callback)(char **p_filev, int p_filec));
+
// Display
extern int godot_js_display_screen_dpi_get();
extern double godot_js_display_pixel_ratio_get();
extern void godot_js_display_alert(const char *p_text);
extern int godot_js_display_touchscreen_is_available();
extern int godot_js_display_is_swap_ok_cancel();
+extern void godot_js_display_setup_canvas(int p_width, int p_height, int p_fullscreen, int p_hidpi);
// Display canvas
extern void godot_js_display_canvas_focus();
@@ -68,7 +84,6 @@ extern void godot_js_display_window_size_get(int32_t *p_x, int32_t *p_y);
extern void godot_js_display_screen_size_get(int32_t *p_x, int32_t *p_y);
extern int godot_js_display_fullscreen_request();
extern int godot_js_display_fullscreen_exit();
-extern void godot_js_display_compute_position(int p_x, int p_y, int32_t *r_x, int32_t *r_y);
extern void godot_js_display_window_title_set(const char *p_text);
extern void godot_js_display_window_icon_set(const uint8_t *p_ptr, int p_len);
extern int godot_js_display_has_webgl(int p_version);
@@ -82,18 +97,13 @@ extern void godot_js_display_cursor_set_shape(const char *p_cursor);
extern int godot_js_display_cursor_is_hidden();
extern void godot_js_display_cursor_set_custom_shape(const char *p_shape, const uint8_t *p_ptr, int p_len, int p_hotspot_x, int p_hotspot_y);
extern void godot_js_display_cursor_set_visible(int p_visible);
-
-// Display gamepad
-extern void godot_js_display_gamepad_cb(void (*p_on_change)(int p_index, int p_connected, const char *p_id, const char *p_guid));
-extern int godot_js_display_gamepad_sample();
-extern int godot_js_display_gamepad_sample_count();
-extern int godot_js_display_gamepad_sample_get(int p_idx, float r_btns[16], int32_t *r_btns_num, float r_axes[10], int32_t *r_axes_num, int32_t *r_standard);
+extern void godot_js_display_cursor_lock_set(int p_lock);
+extern int godot_js_display_cursor_is_locked();
// Display listeners
+extern void godot_js_display_fullscreen_cb(void (*p_callback)(int p_fullscreen));
+extern void godot_js_display_window_blur_cb(void (*p_callback)());
extern void godot_js_display_notification_cb(void (*p_callback)(int p_notification), int p_enter, int p_exit, int p_in, int p_out);
-extern void godot_js_display_paste_cb(void (*p_callback)(const char *p_text));
-extern void godot_js_display_drop_files_cb(void (*p_callback)(char **p_filev, int p_filec));
-extern void godot_js_display_setup_canvas(int p_width, int p_height, int p_fullscreen, int p_hidpi);
// Display Virtual Keyboard
extern int godot_js_display_vk_available();
diff --git a/platform/javascript/js/libs/audio.worklet.js b/platform/javascript/js/libs/audio.worklet.js
index 866f845139..52b3aedf8c 100644
--- a/platform/javascript/js/libs/audio.worklet.js
+++ b/platform/javascript/js/libs/audio.worklet.js
@@ -29,15 +29,16 @@
/*************************************************************************/
class RingBuffer {
- constructor(p_buffer, p_state) {
+ constructor(p_buffer, p_state, p_threads) {
this.buffer = p_buffer;
this.avail = p_state;
+ this.threads = p_threads;
this.rpos = 0;
this.wpos = 0;
}
data_left() {
- return Atomics.load(this.avail, 0);
+ return this.threads ? Atomics.load(this.avail, 0) : this.avail;
}
space_left() {
@@ -55,10 +56,16 @@ class RingBuffer {
to_write -= high;
this.rpos = 0;
}
- output.set(this.buffer.subarray(this.rpos, this.rpos + to_write), from);
+ if (to_write) {
+ output.set(this.buffer.subarray(this.rpos, this.rpos + to_write), from);
+ }
this.rpos += to_write;
- Atomics.add(this.avail, 0, -output.length);
- Atomics.notify(this.avail, 0);
+ if (this.threads) {
+ Atomics.add(this.avail, 0, -output.length);
+ Atomics.notify(this.avail, 0);
+ } else {
+ this.avail -= output.length;
+ }
}
write(p_buffer) {
@@ -66,25 +73,30 @@ class RingBuffer {
const mw = this.buffer.length - this.wpos;
if (mw >= to_write) {
this.buffer.set(p_buffer, this.wpos);
+ this.wpos += to_write;
+ if (mw === to_write) {
+ this.wpos = 0;
+ }
} else {
- const high = p_buffer.subarray(0, to_write - mw);
- const low = p_buffer.subarray(to_write - mw);
+ const high = p_buffer.subarray(0, mw);
+ const low = p_buffer.subarray(mw);
this.buffer.set(high, this.wpos);
this.buffer.set(low);
+ this.wpos = low.length;
}
- let diff = to_write;
- if (this.wpos + diff >= this.buffer.length) {
- diff -= this.buffer.length;
+ if (this.threads) {
+ Atomics.add(this.avail, 0, to_write);
+ Atomics.notify(this.avail, 0);
+ } else {
+ this.avail += to_write;
}
- this.wpos += diff;
- Atomics.add(this.avail, 0, to_write);
- Atomics.notify(this.avail, 0);
}
}
class GodotProcessor extends AudioWorkletProcessor {
constructor() {
super();
+ this.threads = false;
this.running = true;
this.lock = null;
this.notifier = null;
@@ -100,24 +112,31 @@ class GodotProcessor extends AudioWorkletProcessor {
}
process_notify() {
- Atomics.add(this.notifier, 0, 1);
- Atomics.notify(this.notifier, 0);
+ if (this.notifier) {
+ Atomics.add(this.notifier, 0, 1);
+ Atomics.notify(this.notifier, 0);
+ }
}
parse_message(p_cmd, p_data) {
if (p_cmd === 'start' && p_data) {
const state = p_data[0];
let idx = 0;
+ this.threads = true;
this.lock = state.subarray(idx, ++idx);
this.notifier = state.subarray(idx, ++idx);
const avail_in = state.subarray(idx, ++idx);
const avail_out = state.subarray(idx, ++idx);
- this.input = new RingBuffer(p_data[1], avail_in);
- this.output = new RingBuffer(p_data[2], avail_out);
+ this.input = new RingBuffer(p_data[1], avail_in, true);
+ this.output = new RingBuffer(p_data[2], avail_out, true);
} else if (p_cmd === 'stop') {
this.running = false;
this.output = null;
this.input = null;
+ } else if (p_cmd === 'start_nothreads') {
+ this.output = new RingBuffer(p_data[0], p_data[0].length, false);
+ } else if (p_cmd === 'chunk') {
+ this.output.write(p_data);
}
}
@@ -139,7 +158,10 @@ class GodotProcessor extends AudioWorkletProcessor {
if (this.input_buffer.length !== chunk) {
this.input_buffer = new Float32Array(chunk);
}
- if (this.input.space_left() >= chunk) {
+ if (!this.threads) {
+ GodotProcessor.write_input(this.input_buffer, input);
+ this.port.postMessage({ 'cmd': 'input', 'data': this.input_buffer });
+ } else if (this.input.space_left() >= chunk) {
GodotProcessor.write_input(this.input_buffer, input);
this.input.write(this.input_buffer);
} else {
@@ -156,6 +178,9 @@ class GodotProcessor extends AudioWorkletProcessor {
if (this.output.data_left() >= chunk) {
this.output.read(this.output_buffer);
GodotProcessor.write_output(output, this.output_buffer);
+ if (!this.threads) {
+ this.port.postMessage({ 'cmd': 'read', 'data': chunk });
+ }
} else {
this.port.postMessage('Output buffer has not enough frames! Skipping output frame.');
}
diff --git a/platform/javascript/js/libs/library_godot_audio.js b/platform/javascript/js/libs/library_godot_audio.js
index 45c3a3fe2e..6cbb0567f4 100644
--- a/platform/javascript/js/libs/library_godot_audio.js
+++ b/platform/javascript/js/libs/library_godot_audio.js
@@ -37,10 +37,14 @@ const GodotAudio = {
interval: 0,
init: function (mix_rate, latency, onstatechange, onlatencyupdate) {
- const ctx = new (window.AudioContext || window.webkitAudioContext)({
- sampleRate: mix_rate,
- // latencyHint: latency / 1000 // Do not specify, leave 'interactive' for good performance.
- });
+ const opts = {};
+ // If mix_rate is 0, let the browser choose.
+ if (mix_rate) {
+ opts['sampleRate'] = mix_rate;
+ }
+ // Do not specify, leave 'interactive' for good performance.
+ // opts['latencyHint'] = latency / 1000;
+ const ctx = new (window.AudioContext || window.webkitAudioContext)(opts);
GodotAudio.ctx = ctx;
ctx.onstatechange = function () {
let state = 0;
@@ -155,11 +159,24 @@ const GodotAudio = {
return 1;
},
+ godot_audio_has_worklet__sig: 'i',
+ godot_audio_has_worklet: function () {
+ return (GodotAudio.ctx && GodotAudio.ctx.audioWorklet) ? 1 : 0;
+ },
+
+ godot_audio_has_script_processor__sig: 'i',
+ godot_audio_has_script_processor: function () {
+ return (GodotAudio.ctx && GodotAudio.ctx.createScriptProcessor) ? 1 : 0;
+ },
+
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);
+ const mix_rate = GodotRuntime.getHeapValue(p_mix_rate, 'i32');
+ const channels = GodotAudio.init(mix_rate, p_latency, statechange, latencyupdate);
+ GodotRuntime.setHeapValue(p_mix_rate, GodotAudio.ctx.sampleRate, 'i32');
+ return channels;
},
godot_audio_resume__sig: 'v',
@@ -202,6 +219,7 @@ const GodotAudioWorklet = {
$GodotAudioWorklet: {
promise: null,
worklet: null,
+ ring_buffer: null,
create: function (channels) {
const path = GodotConfig.locate_file('godot.audio.worklet.js');
@@ -211,7 +229,7 @@ const GodotAudioWorklet = {
'godot-processor',
{
'outputChannelCount': [channels],
- },
+ }
);
return Promise.resolve();
});
@@ -232,6 +250,86 @@ const GodotAudioWorklet = {
});
},
+ start_no_threads: function (p_out_buf, p_out_size, out_callback, p_in_buf, p_in_size, in_callback) {
+ function RingBuffer() {
+ let wpos = 0;
+ let rpos = 0;
+ let pending_samples = 0;
+ const wbuf = new Float32Array(p_out_size);
+
+ function send(port) {
+ if (pending_samples === 0) {
+ return;
+ }
+ const buffer = GodotRuntime.heapSub(HEAPF32, p_out_buf, p_out_size);
+ const size = buffer.length;
+ const tot_sent = pending_samples;
+ out_callback(wpos, pending_samples);
+ if (wpos + pending_samples >= size) {
+ const high = size - wpos;
+ wbuf.set(buffer.subarray(wpos, size));
+ pending_samples -= high;
+ wpos = 0;
+ }
+ if (pending_samples > 0) {
+ wbuf.set(buffer.subarray(wpos, wpos + pending_samples), tot_sent - pending_samples);
+ }
+ port.postMessage({ 'cmd': 'chunk', 'data': wbuf.subarray(0, tot_sent) });
+ wpos += pending_samples;
+ pending_samples = 0;
+ }
+ this.receive = function (recv_buf) {
+ const buffer = GodotRuntime.heapSub(HEAPF32, p_in_buf, p_in_size);
+ const from = rpos;
+ let to_write = recv_buf.length;
+ let high = 0;
+ if (rpos + to_write >= p_in_size) {
+ high = p_in_size - rpos;
+ buffer.set(recv_buf.subarray(0, high), rpos);
+ to_write -= high;
+ rpos = 0;
+ }
+ if (to_write) {
+ buffer.set(recv_buf.subarray(high, to_write), rpos);
+ }
+ in_callback(from, recv_buf.length);
+ rpos += to_write;
+ };
+ this.consumed = function (size, port) {
+ pending_samples += size;
+ send(port);
+ };
+ }
+ GodotAudioWorklet.ring_buffer = new RingBuffer();
+ GodotAudioWorklet.promise.then(function () {
+ const node = GodotAudioWorklet.worklet;
+ const buffer = GodotRuntime.heapSlice(HEAPF32, p_out_buf, p_out_size);
+ node.connect(GodotAudio.ctx.destination);
+ node.port.postMessage({
+ 'cmd': 'start_nothreads',
+ 'data': [buffer, p_in_size],
+ });
+ node.port.onmessage = function (event) {
+ if (!GodotAudioWorklet.worklet) {
+ return;
+ }
+ if (event.data['cmd'] === 'read') {
+ const read = event.data['data'];
+ GodotAudioWorklet.ring_buffer.consumed(read, GodotAudioWorklet.worklet.port);
+ } else if (event.data['cmd'] === 'input') {
+ const buf = event.data['data'];
+ if (buf.length > p_in_size) {
+ GodotRuntime.error('Input chunk is too big');
+ return;
+ }
+ GodotAudioWorklet.ring_buffer.receive(buf);
+ } else {
+ GodotRuntime.error(event.data);
+ }
+ };
+ });
+ },
+
get_node: function () {
return GodotAudioWorklet.worklet;
},
@@ -255,9 +353,15 @@ const GodotAudioWorklet = {
},
},
- godot_audio_worklet_create__sig: 'vi',
+ godot_audio_worklet_create__sig: 'ii',
godot_audio_worklet_create: function (channels) {
- GodotAudioWorklet.create(channels);
+ try {
+ GodotAudioWorklet.create(channels);
+ } catch (e) {
+ GodotRuntime.error('Error starting AudioDriverWorklet', e);
+ return 1;
+ }
+ return 0;
},
godot_audio_worklet_start__sig: 'viiiii',
@@ -268,6 +372,13 @@ const GodotAudioWorklet = {
GodotAudioWorklet.start(in_buffer, out_buffer, state);
},
+ godot_audio_worklet_start_no_threads__sig: 'viiiiii',
+ godot_audio_worklet_start_no_threads: function (p_out_buf, p_out_size, p_out_callback, p_in_buf, p_in_size, p_in_callback) {
+ const out_callback = GodotRuntime.get_func(p_out_callback);
+ const in_callback = GodotRuntime.get_func(p_in_callback);
+ GodotAudioWorklet.start_no_threads(p_out_buf, p_out_size, out_callback, p_in_buf, p_in_size, in_callback);
+ },
+
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);
@@ -351,7 +462,15 @@ const GodotAudioScript = {
godot_audio_script_create__sig: 'iii',
godot_audio_script_create: function (buffer_length, channel_count) {
- return GodotAudioScript.create(buffer_length, channel_count);
+ const buf_len = GodotRuntime.getHeapValue(buffer_length, 'i32');
+ try {
+ const out_len = GodotAudioScript.create(buf_len, channel_count);
+ GodotRuntime.setHeapValue(buffer_length, out_len, 'i32');
+ } catch (e) {
+ GodotRuntime.error('Error starting AudioDriverScriptProcessor', e);
+ return 1;
+ }
+ return 0;
},
godot_audio_script_start__sig: 'viiiii',
diff --git a/platform/javascript/js/libs/library_godot_display.js b/platform/javascript/js/libs/library_godot_display.js
index affae90370..2689f1c22c 100644
--- a/platform/javascript/js/libs/library_godot_display.js
+++ b/platform/javascript/js/libs/library_godot_display.js
@@ -28,224 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-/*
- * Display Server listeners.
- * Keeps track of registered event listeners so it can remove them on shutdown.
- */
-const GodotDisplayListeners = {
- $GodotDisplayListeners__deps: ['$GodotOS'],
- $GodotDisplayListeners__postset: 'GodotOS.atexit(function(resolve, reject) { GodotDisplayListeners.clear(); resolve(); });',
- $GodotDisplayListeners: {
- handlers: [],
-
- has: function (target, event, method, capture) {
- return GodotDisplayListeners.handlers.findIndex(function (e) {
- return e.target === target && e.event === event && e.method === method && e.capture === capture;
- }) !== -1;
- },
-
- add: function (target, event, method, capture) {
- if (GodotDisplayListeners.has(target, event, method, capture)) {
- return;
- }
- function Handler(p_target, p_event, p_method, p_capture) {
- this.target = p_target;
- this.event = p_event;
- this.method = p_method;
- this.capture = p_capture;
- }
- GodotDisplayListeners.handlers.push(new Handler(target, event, method, capture));
- target.addEventListener(event, method, capture);
- },
-
- clear: function () {
- GodotDisplayListeners.handlers.forEach(function (h) {
- h.target.removeEventListener(h.event, h.method, h.capture);
- });
- GodotDisplayListeners.handlers.length = 0;
- },
- },
-};
-mergeInto(LibraryManager.library, GodotDisplayListeners);
-
-/*
- * Drag and drop handler.
- * This is pretty big, but basically detect dropped files on GodotConfig.canvas,
- * process them one by one (recursively for directories), and copies them to
- * the temporary FS path '/tmp/drop-[random]/' so it can be emitted as a godot
- * event (that requires a string array of paths).
- *
- * NOTE: The temporary files are removed after the callback. This means that
- * deferred callbacks won't be able to access the files.
- */
-const GodotDisplayDragDrop = {
- $GodotDisplayDragDrop__deps: ['$FS', '$GodotFS'],
- $GodotDisplayDragDrop: {
- promises: [],
- pending_files: [],
-
- add_entry: function (entry) {
- if (entry.isDirectory) {
- GodotDisplayDragDrop.add_dir(entry);
- } else if (entry.isFile) {
- GodotDisplayDragDrop.add_file(entry);
- } else {
- GodotRuntime.error('Unrecognized entry...', entry);
- }
- },
-
- add_dir: function (entry) {
- GodotDisplayDragDrop.promises.push(new Promise(function (resolve, reject) {
- const reader = entry.createReader();
- reader.readEntries(function (entries) {
- for (let i = 0; i < entries.length; i++) {
- GodotDisplayDragDrop.add_entry(entries[i]);
- }
- resolve();
- });
- }));
- },
-
- add_file: function (entry) {
- GodotDisplayDragDrop.promises.push(new Promise(function (resolve, reject) {
- entry.file(function (file) {
- const reader = new FileReader();
- reader.onload = function () {
- const f = {
- 'path': file.relativePath || file.webkitRelativePath,
- 'name': file.name,
- 'type': file.type,
- 'size': file.size,
- 'data': reader.result,
- };
- if (!f['path']) {
- f['path'] = f['name'];
- }
- GodotDisplayDragDrop.pending_files.push(f);
- resolve();
- };
- reader.onerror = function () {
- GodotRuntime.print('Error reading file');
- reject();
- };
- reader.readAsArrayBuffer(file);
- }, function (err) {
- GodotRuntime.print('Error!');
- reject();
- });
- }));
- },
-
- process: function (resolve, reject) {
- if (GodotDisplayDragDrop.promises.length === 0) {
- resolve();
- return;
- }
- GodotDisplayDragDrop.promises.pop().then(function () {
- setTimeout(function () {
- GodotDisplayDragDrop.process(resolve, reject);
- }, 0);
- });
- },
-
- _process_event: function (ev, callback) {
- ev.preventDefault();
- if (ev.dataTransfer.items) {
- // Use DataTransferItemList interface to access the file(s)
- for (let i = 0; i < ev.dataTransfer.items.length; i++) {
- const item = ev.dataTransfer.items[i];
- let entry = null;
- if ('getAsEntry' in item) {
- entry = item.getAsEntry();
- } else if ('webkitGetAsEntry' in item) {
- entry = item.webkitGetAsEntry();
- }
- if (entry) {
- GodotDisplayDragDrop.add_entry(entry);
- }
- }
- } else {
- GodotRuntime.error('File upload not supported');
- }
- new Promise(GodotDisplayDragDrop.process).then(function () {
- const DROP = `/tmp/drop-${parseInt(Math.random() * (1 << 30), 10)}/`;
- const drops = [];
- const files = [];
- FS.mkdir(DROP);
- GodotDisplayDragDrop.pending_files.forEach((elem) => {
- const path = elem['path'];
- GodotFS.copy_to_fs(DROP + path, elem['data']);
- let idx = path.indexOf('/');
- if (idx === -1) {
- // Root file
- drops.push(DROP + path);
- } else {
- // Subdir
- const sub = path.substr(0, idx);
- idx = sub.indexOf('/');
- if (idx < 0 && drops.indexOf(DROP + sub) === -1) {
- drops.push(DROP + sub);
- }
- }
- files.push(DROP + path);
- });
- GodotDisplayDragDrop.promises = [];
- GodotDisplayDragDrop.pending_files = [];
- callback(drops);
- if (GodotConfig.persistent_drops) {
- // Delay removal at exit.
- GodotOS.atexit(function (resolve, reject) {
- GodotDisplayDragDrop.remove_drop(files, DROP);
- resolve();
- });
- } else {
- GodotDisplayDragDrop.remove_drop(files, DROP);
- }
- });
- },
-
- remove_drop: function (files, drop_path) {
- const dirs = [drop_path.substr(0, drop_path.length - 1)];
- // Remove temporary files
- files.forEach(function (file) {
- FS.unlink(file);
- let dir = file.replace(drop_path, '');
- let idx = dir.lastIndexOf('/');
- while (idx > 0) {
- dir = dir.substr(0, idx);
- if (dirs.indexOf(drop_path + dir) === -1) {
- dirs.push(drop_path + dir);
- }
- idx = dir.lastIndexOf('/');
- }
- });
- // Remove dirs.
- dirs.sort(function (a, b) {
- const al = (a.match(/\//g) || []).length;
- const bl = (b.match(/\//g) || []).length;
- if (al > bl) {
- return -1;
- } else if (al < bl) {
- return 1;
- }
- return 0;
- }).forEach(function (dir) {
- FS.rmdir(dir);
- });
- },
-
- handler: function (callback) {
- return function (ev) {
- GodotDisplayDragDrop._process_event(ev, callback);
- };
- },
- },
-};
-mergeInto(LibraryManager.library, GodotDisplayDragDrop);
-
const GodotDisplayVK = {
- $GodotDisplayVK__deps: ['$GodotRuntime', '$GodotConfig', '$GodotDisplayListeners'],
+ $GodotDisplayVK__deps: ['$GodotRuntime', '$GodotConfig', '$GodotEventListeners'],
$GodotDisplayVK__postset: 'GodotOS.atexit(function(resolve, reject) { GodotDisplayVK.clear(); resolve(); });',
$GodotDisplayVK: {
textinput: null,
@@ -271,12 +56,12 @@ const GodotDisplayVK = {
elem.style.outline = 'none';
elem.readonly = true;
elem.disabled = true;
- GodotDisplayListeners.add(elem, 'input', function (evt) {
+ GodotEventListeners.add(elem, 'input', function (evt) {
const c_str = GodotRuntime.allocString(elem.value);
input_cb(c_str, elem.selectionEnd);
GodotRuntime.free(c_str);
}, false);
- GodotDisplayListeners.add(elem, 'blur', function (evt) {
+ GodotEventListeners.add(elem, 'blur', function (evt) {
elem.style.display = 'none';
elem.readonly = true;
elem.disabled = true;
@@ -376,136 +161,23 @@ const GodotDisplayCursor = {
delete GodotDisplayCursor.cursors[key];
});
},
- },
-};
-mergeInto(LibraryManager.library, GodotDisplayCursor);
-
-/*
- * Display Gamepad API helper.
- */
-const GodotDisplayGamepads = {
- $GodotDisplayGamepads__deps: ['$GodotRuntime', '$GodotDisplayListeners'],
- $GodotDisplayGamepads: {
- samples: [],
-
- get_pads: function () {
- try {
- // Will throw in iframe when permission is denied.
- // Will throw/warn in the future for insecure contexts.
- // See https://github.com/w3c/gamepad/pull/120
- const pads = navigator.getGamepads();
- if (pads) {
- return pads;
- }
- return [];
- } catch (e) {
- return [];
- }
- },
-
- get_samples: function () {
- return GodotDisplayGamepads.samples;
- },
-
- get_sample: function (index) {
- const samples = GodotDisplayGamepads.samples;
- return index < samples.length ? samples[index] : null;
- },
-
- sample: function () {
- const pads = GodotDisplayGamepads.get_pads();
- const samples = [];
- for (let i = 0; i < pads.length; i++) {
- const pad = pads[i];
- if (!pad) {
- samples.push(null);
- continue;
- }
- const s = {
- standard: pad.mapping === 'standard',
- buttons: [],
- axes: [],
- connected: pad.connected,
- };
- for (let b = 0; b < pad.buttons.length; b++) {
- s.buttons.push(pad.buttons[b].value);
- }
- for (let a = 0; a < pad.axes.length; a++) {
- s.axes.push(pad.axes[a]);
- }
- samples.push(s);
+ lockPointer: function () {
+ const canvas = GodotConfig.canvas;
+ if (canvas.requestPointerLock) {
+ canvas.requestPointerLock();
}
- GodotDisplayGamepads.samples = samples;
},
-
- init: function (onchange) {
- GodotDisplayListeners.samples = [];
- function add(pad) {
- const guid = GodotDisplayGamepads.get_guid(pad);
- const c_id = GodotRuntime.allocString(pad.id);
- const c_guid = GodotRuntime.allocString(guid);
- onchange(pad.index, 1, c_id, c_guid);
- GodotRuntime.free(c_id);
- GodotRuntime.free(c_guid);
+ releasePointer: function () {
+ if (document.exitPointerLock) {
+ document.exitPointerLock();
}
- const pads = GodotDisplayGamepads.get_pads();
- for (let i = 0; i < pads.length; i++) {
- // Might be reserved space.
- if (pads[i]) {
- add(pads[i]);
- }
- }
- GodotDisplayListeners.add(window, 'gamepadconnected', function (evt) {
- add(evt.gamepad);
- }, false);
- GodotDisplayListeners.add(window, 'gamepaddisconnected', function (evt) {
- onchange(evt.gamepad.index, 0);
- }, false);
},
-
- get_guid: function (pad) {
- if (pad.mapping) {
- return pad.mapping;
- }
- const ua = navigator.userAgent;
- let os = 'Unknown';
- if (ua.indexOf('Android') >= 0) {
- os = 'Android';
- } else if (ua.indexOf('Linux') >= 0) {
- os = 'Linux';
- } else if (ua.indexOf('iPhone') >= 0) {
- os = 'iOS';
- } else if (ua.indexOf('Macintosh') >= 0) {
- // Updated iPads will fall into this category.
- os = 'MacOSX';
- } else if (ua.indexOf('Windows') >= 0) {
- os = 'Windows';
- }
-
- const id = pad.id;
- // Chrom* style: NAME (Vendor: xxxx Product: xxxx)
- const exp1 = /vendor: ([0-9a-f]{4}) product: ([0-9a-f]{4})/i;
- // Firefox/Safari style (safari may remove leading zeores)
- const exp2 = /^([0-9a-f]+)-([0-9a-f]+)-/i;
- let vendor = '';
- let product = '';
- if (exp1.test(id)) {
- const match = exp1.exec(id);
- vendor = match[1].padStart(4, '0');
- product = match[2].padStart(4, '0');
- } else if (exp2.test(id)) {
- const match = exp2.exec(id);
- vendor = match[1].padStart(4, '0');
- product = match[2].padStart(4, '0');
- }
- if (!vendor || !product) {
- return `${os}Unknown`;
- }
- return os + vendor + product;
+ isPointerLocked: function () {
+ return document.pointerLockElement === GodotConfig.canvas;
},
},
};
-mergeInto(LibraryManager.library, GodotDisplayGamepads);
+mergeInto(LibraryManager.library, GodotDisplayCursor);
const GodotDisplayScreen = {
$GodotDisplayScreen__deps: ['$GodotConfig', '$GodotOS', '$GL', 'emscripten_webgl_get_current_context'],
@@ -622,7 +294,7 @@ mergeInto(LibraryManager.library, GodotDisplayScreen);
* Exposes all the functions needed by DisplayServer implementation.
*/
const GodotDisplay = {
- $GodotDisplay__deps: ['$GodotConfig', '$GodotRuntime', '$GodotDisplayCursor', '$GodotDisplayListeners', '$GodotDisplayDragDrop', '$GodotDisplayGamepads', '$GodotDisplayScreen', '$GodotDisplayVK'],
+ $GodotDisplay__deps: ['$GodotConfig', '$GodotRuntime', '$GodotDisplayCursor', '$GodotEventListeners', '$GodotDisplayScreen', '$GodotDisplayVK'],
$GodotDisplay: {
window_icon: '',
findDPI: function () {
@@ -710,15 +382,6 @@ const GodotDisplay = {
GodotRuntime.setHeapValue(p_height, GodotConfig.canvas.height, 'i32');
},
- godot_js_display_compute_position: function (x, y, r_x, r_y) {
- const canvas = GodotConfig.canvas;
- const rect = canvas.getBoundingClientRect();
- const rw = canvas.width / rect.width;
- const rh = canvas.height / rect.height;
- GodotRuntime.setHeapValue(r_x, (x - rect.x) * rw, 'i32');
- GodotRuntime.setHeapValue(r_y, (y - rect.y) * rh, 'i32');
- },
-
godot_js_display_has_webgl__sig: 'ii',
godot_js_display_has_webgl: function (p_version) {
if (p_version !== 1 && p_version !== 2) {
@@ -859,60 +522,64 @@ const GodotDisplay = {
}
},
+ godot_js_display_cursor_lock_set__sig: 'vi',
+ godot_js_display_cursor_lock_set: function (p_lock) {
+ if (p_lock) {
+ GodotDisplayCursor.lockPointer();
+ } else {
+ GodotDisplayCursor.releasePointer();
+ }
+ },
+
+ godot_js_display_cursor_is_locked__sig: 'i',
+ godot_js_display_cursor_is_locked: function () {
+ return GodotDisplayCursor.isPointerLocked() ? 1 : 0;
+ },
+
/*
* Listeners
*/
- godot_js_display_notification_cb__sig: 'viiiii',
- godot_js_display_notification_cb: function (callback, p_enter, p_exit, p_in, p_out) {
+ godot_js_display_fullscreen_cb__sig: 'vi',
+ godot_js_display_fullscreen_cb: function (callback) {
const canvas = GodotConfig.canvas;
const func = GodotRuntime.get_func(callback);
- const notif = [p_enter, p_exit, p_in, p_out];
- ['mouseover', 'mouseleave', 'focus', 'blur'].forEach(function (evt_name, idx) {
- GodotDisplayListeners.add(canvas, evt_name, function () {
- func(notif[idx]);
- }, true);
- });
+ function change_cb(evt) {
+ if (evt.target === canvas) {
+ func(GodotDisplayScreen.isFullscreen());
+ }
+ }
+ GodotEventListeners.add(document, 'fullscreenchange', change_cb, false);
+ GodotEventListeners.add(document, 'mozfullscreenchange', change_cb, false);
+ GodotEventListeners.add(document, 'webkitfullscreenchange', change_cb, false);
},
- godot_js_display_paste_cb__sig: 'vi',
- godot_js_display_paste_cb: function (callback) {
+ godot_js_display_window_blur_cb__sig: 'vi',
+ godot_js_display_window_blur_cb: function (callback) {
const func = GodotRuntime.get_func(callback);
- GodotDisplayListeners.add(window, 'paste', function (evt) {
- const text = evt.clipboardData.getData('text');
- const ptr = GodotRuntime.allocString(text);
- func(ptr);
- GodotRuntime.free(ptr);
+ GodotEventListeners.add(window, 'blur', function () {
+ func();
}, 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) {
- const args = files || [];
- if (!args.length) {
- return;
- }
- const argc = args.length;
- const argv = GodotRuntime.allocStringArray(args);
- func(argv, argc);
- GodotRuntime.freeStringArray(argv, argc);
- };
+ 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;
- GodotDisplayListeners.add(canvas, 'dragover', function (ev) {
- // Prevent default behavior (which would try to open the file(s))
- ev.preventDefault();
- }, false);
- GodotDisplayListeners.add(canvas, 'drop', GodotDisplayDragDrop.handler(dropFiles));
+ const func = GodotRuntime.get_func(callback);
+ const notif = [p_enter, p_exit, p_in, p_out];
+ ['mouseover', 'mouseleave', 'focus', 'blur'].forEach(function (evt_name, idx) {
+ GodotEventListeners.add(canvas, evt_name, function () {
+ func(notif[idx]);
+ }, true);
+ });
},
godot_js_display_setup_canvas__sig: 'viiii',
godot_js_display_setup_canvas: function (p_width, p_height, p_fullscreen, p_hidpi) {
const canvas = GodotConfig.canvas;
- GodotDisplayListeners.add(canvas, 'contextmenu', function (ev) {
+ GodotEventListeners.add(canvas, 'contextmenu', function (ev) {
ev.preventDefault();
}, false);
- GodotDisplayListeners.add(canvas, 'webglcontextlost', function (ev) {
+ GodotEventListeners.add(canvas, 'webglcontextlost', function (ev) {
alert('WebGL context lost, please reload the page'); // eslint-disable-line no-alert
ev.preventDefault();
}, false);
@@ -965,49 +632,6 @@ const GodotDisplay = {
GodotDisplayVK.init(input_cb);
}
},
-
- /*
- * Gamepads
- */
- godot_js_display_gamepad_cb__sig: 'vi',
- godot_js_display_gamepad_cb: function (change_cb) {
- const onchange = GodotRuntime.get_func(change_cb);
- GodotDisplayGamepads.init(onchange);
- },
-
- godot_js_display_gamepad_sample_count__sig: 'i',
- godot_js_display_gamepad_sample_count: function () {
- return GodotDisplayGamepads.get_samples().length;
- },
-
- godot_js_display_gamepad_sample__sig: 'i',
- godot_js_display_gamepad_sample: function () {
- GodotDisplayGamepads.sample();
- return 0;
- },
-
- godot_js_display_gamepad_sample_get__sig: 'iiiiiii',
- godot_js_display_gamepad_sample_get: function (p_index, r_btns, r_btns_num, r_axes, r_axes_num, r_standard) {
- const sample = GodotDisplayGamepads.get_sample(p_index);
- if (!sample || !sample.connected) {
- return 1;
- }
- const btns = sample.buttons;
- const btns_len = btns.length < 16 ? btns.length : 16;
- for (let i = 0; i < btns_len; i++) {
- GodotRuntime.setHeapValue(r_btns + (i << 2), btns[i], 'float');
- }
- GodotRuntime.setHeapValue(r_btns_num, btns_len, 'i32');
- const axes = sample.axes;
- const axes_len = axes.length < 10 ? axes.length : 10;
- for (let i = 0; i < axes_len; i++) {
- GodotRuntime.setHeapValue(r_axes + (i << 2), axes[i], 'float');
- }
- GodotRuntime.setHeapValue(r_axes_num, axes_len, 'i32');
- const is_standard = sample.standard ? 1 : 0;
- GodotRuntime.setHeapValue(r_standard, is_standard, 'i32');
- return 0;
- },
};
autoAddDeps(GodotDisplay, '$GodotDisplay');
diff --git a/platform/javascript/js/libs/library_godot_input.js b/platform/javascript/js/libs/library_godot_input.js
new file mode 100644
index 0000000000..d85d0d5335
--- /dev/null
+++ b/platform/javascript/js/libs/library_godot_input.js
@@ -0,0 +1,536 @@
+/*************************************************************************/
+/* library_godot_input.js */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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. */
+/*************************************************************************/
+
+/*
+ * Gamepad API helper.
+ */
+const GodotInputGamepads = {
+ $GodotInputGamepads__deps: ['$GodotRuntime', '$GodotEventListeners'],
+ $GodotInputGamepads: {
+ samples: [],
+
+ get_pads: function () {
+ try {
+ // Will throw in iframe when permission is denied.
+ // Will throw/warn in the future for insecure contexts.
+ // See https://github.com/w3c/gamepad/pull/120
+ const pads = navigator.getGamepads();
+ if (pads) {
+ return pads;
+ }
+ return [];
+ } catch (e) {
+ return [];
+ }
+ },
+
+ get_samples: function () {
+ return GodotInputGamepads.samples;
+ },
+
+ get_sample: function (index) {
+ const samples = GodotInputGamepads.samples;
+ return index < samples.length ? samples[index] : null;
+ },
+
+ sample: function () {
+ const pads = GodotInputGamepads.get_pads();
+ const samples = [];
+ for (let i = 0; i < pads.length; i++) {
+ const pad = pads[i];
+ if (!pad) {
+ samples.push(null);
+ continue;
+ }
+ const s = {
+ standard: pad.mapping === 'standard',
+ buttons: [],
+ axes: [],
+ connected: pad.connected,
+ };
+ for (let b = 0; b < pad.buttons.length; b++) {
+ s.buttons.push(pad.buttons[b].value);
+ }
+ for (let a = 0; a < pad.axes.length; a++) {
+ s.axes.push(pad.axes[a]);
+ }
+ samples.push(s);
+ }
+ GodotInputGamepads.samples = samples;
+ },
+
+ init: function (onchange) {
+ GodotEventListeners.samples = [];
+ function add(pad) {
+ const guid = GodotInputGamepads.get_guid(pad);
+ const c_id = GodotRuntime.allocString(pad.id);
+ const c_guid = GodotRuntime.allocString(guid);
+ onchange(pad.index, 1, c_id, c_guid);
+ GodotRuntime.free(c_id);
+ GodotRuntime.free(c_guid);
+ }
+ const pads = GodotInputGamepads.get_pads();
+ for (let i = 0; i < pads.length; i++) {
+ // Might be reserved space.
+ if (pads[i]) {
+ add(pads[i]);
+ }
+ }
+ GodotEventListeners.add(window, 'gamepadconnected', function (evt) {
+ if (evt.gamepad) {
+ add(evt.gamepad);
+ }
+ }, false);
+ GodotEventListeners.add(window, 'gamepaddisconnected', function (evt) {
+ if (evt.gamepad) {
+ onchange(evt.gamepad.index, 0);
+ }
+ }, false);
+ },
+
+ get_guid: function (pad) {
+ if (pad.mapping) {
+ return pad.mapping;
+ }
+ const ua = navigator.userAgent;
+ let os = 'Unknown';
+ if (ua.indexOf('Android') >= 0) {
+ os = 'Android';
+ } else if (ua.indexOf('Linux') >= 0) {
+ os = 'Linux';
+ } else if (ua.indexOf('iPhone') >= 0) {
+ os = 'iOS';
+ } else if (ua.indexOf('Macintosh') >= 0) {
+ // Updated iPads will fall into this category.
+ os = 'MacOSX';
+ } else if (ua.indexOf('Windows') >= 0) {
+ os = 'Windows';
+ }
+
+ const id = pad.id;
+ // Chrom* style: NAME (Vendor: xxxx Product: xxxx)
+ const exp1 = /vendor: ([0-9a-f]{4}) product: ([0-9a-f]{4})/i;
+ // Firefox/Safari style (safari may remove leading zeores)
+ const exp2 = /^([0-9a-f]+)-([0-9a-f]+)-/i;
+ let vendor = '';
+ let product = '';
+ if (exp1.test(id)) {
+ const match = exp1.exec(id);
+ vendor = match[1].padStart(4, '0');
+ product = match[2].padStart(4, '0');
+ } else if (exp2.test(id)) {
+ const match = exp2.exec(id);
+ vendor = match[1].padStart(4, '0');
+ product = match[2].padStart(4, '0');
+ }
+ if (!vendor || !product) {
+ return `${os}Unknown`;
+ }
+ return os + vendor + product;
+ },
+ },
+};
+mergeInto(LibraryManager.library, GodotInputGamepads);
+
+/*
+ * Drag and drop helper.
+ * This is pretty big, but basically detect dropped files on GodotConfig.canvas,
+ * process them one by one (recursively for directories), and copies them to
+ * the temporary FS path '/tmp/drop-[random]/' so it can be emitted as a godot
+ * event (that requires a string array of paths).
+ *
+ * NOTE: The temporary files are removed after the callback. This means that
+ * deferred callbacks won't be able to access the files.
+ */
+const GodotInputDragDrop = {
+ $GodotInputDragDrop__deps: ['$FS', '$GodotFS'],
+ $GodotInputDragDrop: {
+ promises: [],
+ pending_files: [],
+
+ add_entry: function (entry) {
+ if (entry.isDirectory) {
+ GodotInputDragDrop.add_dir(entry);
+ } else if (entry.isFile) {
+ GodotInputDragDrop.add_file(entry);
+ } else {
+ GodotRuntime.error('Unrecognized entry...', entry);
+ }
+ },
+
+ add_dir: function (entry) {
+ GodotInputDragDrop.promises.push(new Promise(function (resolve, reject) {
+ const reader = entry.createReader();
+ reader.readEntries(function (entries) {
+ for (let i = 0; i < entries.length; i++) {
+ GodotInputDragDrop.add_entry(entries[i]);
+ }
+ resolve();
+ });
+ }));
+ },
+
+ add_file: function (entry) {
+ GodotInputDragDrop.promises.push(new Promise(function (resolve, reject) {
+ entry.file(function (file) {
+ const reader = new FileReader();
+ reader.onload = function () {
+ const f = {
+ 'path': file.relativePath || file.webkitRelativePath,
+ 'name': file.name,
+ 'type': file.type,
+ 'size': file.size,
+ 'data': reader.result,
+ };
+ if (!f['path']) {
+ f['path'] = f['name'];
+ }
+ GodotInputDragDrop.pending_files.push(f);
+ resolve();
+ };
+ reader.onerror = function () {
+ GodotRuntime.print('Error reading file');
+ reject();
+ };
+ reader.readAsArrayBuffer(file);
+ }, function (err) {
+ GodotRuntime.print('Error!');
+ reject();
+ });
+ }));
+ },
+
+ process: function (resolve, reject) {
+ if (GodotInputDragDrop.promises.length === 0) {
+ resolve();
+ return;
+ }
+ GodotInputDragDrop.promises.pop().then(function () {
+ setTimeout(function () {
+ GodotInputDragDrop.process(resolve, reject);
+ }, 0);
+ });
+ },
+
+ _process_event: function (ev, callback) {
+ ev.preventDefault();
+ if (ev.dataTransfer.items) {
+ // Use DataTransferItemList interface to access the file(s)
+ for (let i = 0; i < ev.dataTransfer.items.length; i++) {
+ const item = ev.dataTransfer.items[i];
+ let entry = null;
+ if ('getAsEntry' in item) {
+ entry = item.getAsEntry();
+ } else if ('webkitGetAsEntry' in item) {
+ entry = item.webkitGetAsEntry();
+ }
+ if (entry) {
+ GodotInputDragDrop.add_entry(entry);
+ }
+ }
+ } else {
+ GodotRuntime.error('File upload not supported');
+ }
+ new Promise(GodotInputDragDrop.process).then(function () {
+ const DROP = `/tmp/drop-${parseInt(Math.random() * (1 << 30), 10)}/`;
+ const drops = [];
+ const files = [];
+ FS.mkdir(DROP);
+ GodotInputDragDrop.pending_files.forEach((elem) => {
+ const path = elem['path'];
+ GodotFS.copy_to_fs(DROP + path, elem['data']);
+ let idx = path.indexOf('/');
+ if (idx === -1) {
+ // Root file
+ drops.push(DROP + path);
+ } else {
+ // Subdir
+ const sub = path.substr(0, idx);
+ idx = sub.indexOf('/');
+ if (idx < 0 && drops.indexOf(DROP + sub) === -1) {
+ drops.push(DROP + sub);
+ }
+ }
+ files.push(DROP + path);
+ });
+ GodotInputDragDrop.promises = [];
+ GodotInputDragDrop.pending_files = [];
+ callback(drops);
+ if (GodotConfig.persistent_drops) {
+ // Delay removal at exit.
+ GodotOS.atexit(function (resolve, reject) {
+ GodotInputDragDrop.remove_drop(files, DROP);
+ resolve();
+ });
+ } else {
+ GodotInputDragDrop.remove_drop(files, DROP);
+ }
+ });
+ },
+
+ remove_drop: function (files, drop_path) {
+ const dirs = [drop_path.substr(0, drop_path.length - 1)];
+ // Remove temporary files
+ files.forEach(function (file) {
+ FS.unlink(file);
+ let dir = file.replace(drop_path, '');
+ let idx = dir.lastIndexOf('/');
+ while (idx > 0) {
+ dir = dir.substr(0, idx);
+ if (dirs.indexOf(drop_path + dir) === -1) {
+ dirs.push(drop_path + dir);
+ }
+ idx = dir.lastIndexOf('/');
+ }
+ });
+ // Remove dirs.
+ dirs.sort(function (a, b) {
+ const al = (a.match(/\//g) || []).length;
+ const bl = (b.match(/\//g) || []).length;
+ if (al > bl) {
+ return -1;
+ } else if (al < bl) {
+ return 1;
+ }
+ return 0;
+ }).forEach(function (dir) {
+ FS.rmdir(dir);
+ });
+ },
+
+ handler: function (callback) {
+ return function (ev) {
+ GodotInputDragDrop._process_event(ev, callback);
+ };
+ },
+ },
+};
+mergeInto(LibraryManager.library, GodotInputDragDrop);
+
+/*
+ * Godot exposed input functions.
+ */
+const GodotInput = {
+ $GodotInput__deps: ['$GodotRuntime', '$GodotConfig', '$GodotEventListeners', '$GodotInputGamepads', '$GodotInputDragDrop'],
+ $GodotInput: {
+ getModifiers: function (evt) {
+ return (evt.shiftKey + 0) + ((evt.altKey + 0) << 1) + ((evt.ctrlKey + 0) << 2) + ((evt.metaKey + 0) << 3);
+ },
+ computePosition: function (evt, rect) {
+ const canvas = GodotConfig.canvas;
+ const rw = canvas.width / rect.width;
+ const rh = canvas.height / rect.height;
+ const x = (evt.clientX - rect.x) * rw;
+ const y = (evt.clientY - rect.y) * rh;
+ return [x, y];
+ },
+ },
+
+ /*
+ * Mouse API
+ */
+ godot_js_input_mouse_move_cb__sig: 'vi',
+ godot_js_input_mouse_move_cb: function (callback) {
+ const func = GodotRuntime.get_func(callback);
+ const canvas = GodotConfig.canvas;
+ function move_cb(evt) {
+ const rect = canvas.getBoundingClientRect();
+ const pos = GodotInput.computePosition(evt, rect);
+ // Scale movement
+ const rw = canvas.width / rect.width;
+ const rh = canvas.height / rect.height;
+ const rel_pos_x = evt.movementX * rw;
+ const rel_pos_y = evt.movementY * rh;
+ const modifiers = GodotInput.getModifiers(evt);
+ func(pos[0], pos[1], rel_pos_x, rel_pos_y, modifiers);
+ }
+ GodotEventListeners.add(window, 'mousemove', move_cb, false);
+ },
+
+ godot_js_input_mouse_wheel_cb__sig: 'vi',
+ godot_js_input_mouse_wheel_cb: function (callback) {
+ const func = GodotRuntime.get_func(callback);
+ function wheel_cb(evt) {
+ if (func(evt['deltaX'] || 0, evt['deltaY'] || 0)) {
+ evt.preventDefault();
+ }
+ }
+ GodotEventListeners.add(GodotConfig.canvas, 'wheel', wheel_cb, false);
+ },
+
+ godot_js_input_mouse_button_cb__sig: 'vi',
+ godot_js_input_mouse_button_cb: function (callback) {
+ const func = GodotRuntime.get_func(callback);
+ const canvas = GodotConfig.canvas;
+ function button_cb(p_pressed, evt) {
+ const rect = canvas.getBoundingClientRect();
+ const pos = GodotInput.computePosition(evt, rect);
+ const modifiers = GodotInput.getModifiers(evt);
+ if (p_pressed && document.activeElement !== GodotConfig.canvas) {
+ GodotConfig.canvas.focus();
+ }
+ if (func(p_pressed, evt.button, pos[0], pos[1], modifiers)) {
+ evt.preventDefault();
+ }
+ }
+ GodotEventListeners.add(canvas, 'mousedown', button_cb.bind(null, 1), false);
+ GodotEventListeners.add(window, 'mouseup', button_cb.bind(null, 0), false);
+ },
+
+ /*
+ * Touch API
+ */
+ godot_js_input_touch_cb__sig: 'viii',
+ godot_js_input_touch_cb: function (callback, ids, coords) {
+ const func = GodotRuntime.get_func(callback);
+ const canvas = GodotConfig.canvas;
+ function touch_cb(type, evt) {
+ if (type === 0 && document.activeElement !== GodotConfig.canvas) {
+ GodotConfig.canvas.focus();
+ }
+ const rect = canvas.getBoundingClientRect();
+ const touches = evt.changedTouches;
+ for (let i = 0; i < touches.length; i++) {
+ const touch = touches[i];
+ const pos = GodotInput.computePosition(touch, rect);
+ GodotRuntime.setHeapValue(coords + (i * 2), pos[0], 'double');
+ GodotRuntime.setHeapValue(coords + (i * 2 + 8), pos[1], 'double');
+ GodotRuntime.setHeapValue(ids + i, touch.identifier, 'i32');
+ }
+ func(type, touches.length);
+ if (evt.cancelable) {
+ evt.preventDefault();
+ }
+ }
+ GodotEventListeners.add(canvas, 'touchstart', touch_cb.bind(null, 0), false);
+ GodotEventListeners.add(canvas, 'touchend', touch_cb.bind(null, 1), false);
+ GodotEventListeners.add(canvas, 'touchcancel', touch_cb.bind(null, 1), false);
+ GodotEventListeners.add(canvas, 'touchmove', touch_cb.bind(null, 2), false);
+ },
+
+ /*
+ * Key API
+ */
+ godot_js_input_key_cb__sig: 'viii',
+ godot_js_input_key_cb: function (callback, code, key) {
+ const func = GodotRuntime.get_func(callback);
+ function key_cb(pressed, evt) {
+ const modifiers = GodotInput.getModifiers(evt);
+ GodotRuntime.stringToHeap(evt.code, code, 32);
+ GodotRuntime.stringToHeap(evt.key, key, 32);
+ func(pressed, evt.repeat, modifiers);
+ evt.preventDefault();
+ }
+ GodotEventListeners.add(GodotConfig.canvas, 'keydown', key_cb.bind(null, 1), false);
+ GodotEventListeners.add(GodotConfig.canvas, 'keyup', key_cb.bind(null, 0), false);
+ },
+
+ /*
+ * Gamepad API
+ */
+ godot_js_input_gamepad_cb__sig: 'vi',
+ godot_js_input_gamepad_cb: function (change_cb) {
+ const onchange = GodotRuntime.get_func(change_cb);
+ GodotInputGamepads.init(onchange);
+ },
+
+ godot_js_input_gamepad_sample_count__sig: 'i',
+ godot_js_input_gamepad_sample_count: function () {
+ return GodotInputGamepads.get_samples().length;
+ },
+
+ godot_js_input_gamepad_sample__sig: 'i',
+ godot_js_input_gamepad_sample: function () {
+ GodotInputGamepads.sample();
+ return 0;
+ },
+
+ godot_js_input_gamepad_sample_get__sig: 'iiiiiii',
+ godot_js_input_gamepad_sample_get: function (p_index, r_btns, r_btns_num, r_axes, r_axes_num, r_standard) {
+ const sample = GodotInputGamepads.get_sample(p_index);
+ if (!sample || !sample.connected) {
+ return 1;
+ }
+ const btns = sample.buttons;
+ const btns_len = btns.length < 16 ? btns.length : 16;
+ for (let i = 0; i < btns_len; i++) {
+ GodotRuntime.setHeapValue(r_btns + (i << 2), btns[i], 'float');
+ }
+ GodotRuntime.setHeapValue(r_btns_num, btns_len, 'i32');
+ const axes = sample.axes;
+ const axes_len = axes.length < 10 ? axes.length : 10;
+ for (let i = 0; i < axes_len; i++) {
+ GodotRuntime.setHeapValue(r_axes + (i << 2), axes[i], 'float');
+ }
+ GodotRuntime.setHeapValue(r_axes_num, axes_len, 'i32');
+ const is_standard = sample.standard ? 1 : 0;
+ GodotRuntime.setHeapValue(r_standard, is_standard, 'i32');
+ return 0;
+ },
+
+ /*
+ * Drag/Drop API
+ */
+ godot_js_input_drop_files_cb__sig: 'vi',
+ godot_js_input_drop_files_cb: function (callback) {
+ const func = GodotRuntime.get_func(callback);
+ const dropFiles = function (files) {
+ const args = files || [];
+ if (!args.length) {
+ return;
+ }
+ const argc = args.length;
+ const argv = GodotRuntime.allocStringArray(args);
+ func(argv, argc);
+ GodotRuntime.freeStringArray(argv, argc);
+ };
+ const canvas = GodotConfig.canvas;
+ GodotEventListeners.add(canvas, 'dragover', function (ev) {
+ // Prevent default behavior (which would try to open the file(s))
+ ev.preventDefault();
+ }, false);
+ GodotEventListeners.add(canvas, 'drop', GodotInputDragDrop.handler(dropFiles));
+ },
+
+ /* Paste API */
+ godot_js_input_paste_cb__sig: 'vi',
+ godot_js_input_paste_cb: function (callback) {
+ const func = GodotRuntime.get_func(callback);
+ GodotEventListeners.add(window, 'paste', function (evt) {
+ const text = evt.clipboardData.getData('text');
+ const ptr = GodotRuntime.allocString(text);
+ func(ptr);
+ GodotRuntime.free(ptr);
+ }, false);
+ },
+};
+
+autoAddDeps(GodotInput, '$GodotInput');
+mergeInto(LibraryManager.library, GodotInput);
diff --git a/platform/javascript/js/libs/library_godot_os.js b/platform/javascript/js/libs/library_godot_os.js
index 99e7ee8b5f..c552e99415 100644
--- a/platform/javascript/js/libs/library_godot_os.js
+++ b/platform/javascript/js/libs/library_godot_os.js
@@ -328,3 +328,43 @@ const GodotOS = {
autoAddDeps(GodotOS, '$GodotOS');
mergeInto(LibraryManager.library, GodotOS);
+
+/*
+ * Godot event listeners.
+ * Keeps track of registered event listeners so it can remove them on shutdown.
+ */
+const GodotEventListeners = {
+ $GodotEventListeners__deps: ['$GodotOS'],
+ $GodotEventListeners__postset: 'GodotOS.atexit(function(resolve, reject) { GodotEventListeners.clear(); resolve(); });',
+ $GodotEventListeners: {
+ handlers: [],
+
+ has: function (target, event, method, capture) {
+ return GodotEventListeners.handlers.findIndex(function (e) {
+ return e.target === target && e.event === event && e.method === method && e.capture === capture;
+ }) !== -1;
+ },
+
+ add: function (target, event, method, capture) {
+ if (GodotEventListeners.has(target, event, method, capture)) {
+ return;
+ }
+ function Handler(p_target, p_event, p_method, p_capture) {
+ this.target = p_target;
+ this.event = p_event;
+ this.method = p_method;
+ this.capture = p_capture;
+ }
+ GodotEventListeners.handlers.push(new Handler(target, event, method, capture));
+ target.addEventListener(event, method, capture);
+ },
+
+ clear: function () {
+ GodotEventListeners.handlers.forEach(function (h) {
+ h.target.removeEventListener(h.event, h.method, h.capture);
+ });
+ GodotEventListeners.handlers.length = 0;
+ },
+ },
+};
+mergeInto(LibraryManager.library, GodotEventListeners);
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 76102d941b..5da9a96a90 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -36,7 +36,7 @@
#include "main/main.h"
#include "platform/javascript/display_server_javascript.h"
-#include "modules/modules_enabled.gen.h"
+#include "modules/modules_enabled.gen.h" // For websocket.
#ifdef MODULE_WEBSOCKET_ENABLED
#include "modules/websocket/remote_debugger_peer_websocket.h"
#endif
@@ -63,9 +63,7 @@ void OS_JavaScript::initialize() {
}
void OS_JavaScript::resume_audio() {
- if (audio_driver_javascript) {
- audio_driver_javascript->resume();
- }
+ AudioDriverJavaScript::resume();
}
void OS_JavaScript::set_main_loop(MainLoop *p_main_loop) {
@@ -101,10 +99,10 @@ void OS_JavaScript::delete_main_loop() {
void OS_JavaScript::finalize() {
delete_main_loop();
- if (audio_driver_javascript) {
- memdelete(audio_driver_javascript);
- audio_driver_javascript = nullptr;
+ for (AudioDriverJavaScript *driver : audio_drivers) {
+ memdelete(driver);
}
+ audio_drivers.clear();
}
// Miscellaneous
@@ -137,12 +135,12 @@ int OS_JavaScript::get_processor_count() 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
@@ -229,8 +227,13 @@ OS_JavaScript::OS_JavaScript() {
setenv("LANG", locale_ptr, true);
if (AudioDriverJavaScript::is_available()) {
- audio_driver_javascript = memnew(AudioDriverJavaScript);
- AudioDriverManager::add_driver(audio_driver_javascript);
+#ifdef NO_THREADS
+ audio_drivers.push_back(memnew(AudioDriverScriptProcessor));
+#endif
+ audio_drivers.push_back(memnew(AudioDriverWorklet));
+ }
+ for (int i = 0; i < audio_drivers.size(); i++) {
+ AudioDriverManager::add_driver(audio_drivers[i]);
}
idb_available = godot_js_os_fs_is_persistent();
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index efac2dbca7..fbab95d33b 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -40,7 +40,7 @@
class OS_JavaScript : public OS_Unix {
MainLoop *main_loop = nullptr;
- AudioDriverJavaScript *audio_driver_javascript = nullptr;
+ List<AudioDriverJavaScript *> audio_drivers;
bool idb_is_syncing = false;
bool idb_available = false;
@@ -75,6 +75,7 @@ public:
Error kill(const ProcessID &p_pid) override;
int get_process_id() const override;
int get_processor_count() const override;
+ int get_default_thread_pool_size() const override { return 1; }
String get_executable_path() const override;
Error shell_open(String p_uri) override;
@@ -89,6 +90,7 @@ public:
String get_user_data_dir() const override;
bool is_userfs_persistent() const override;
+ bool is_single_window() const override { return true; }
void alert(const String &p_alert, const String &p_title = "ALERT!") override;
diff --git a/platform/javascript/package-lock.json b/platform/javascript/package-lock.json
index 8003619576..1bc11c7ccf 100644
--- a/platform/javascript/package-lock.json
+++ b/platform/javascript/package-lock.json
@@ -109,9 +109,9 @@
"dev": true
},
"ansi-regex": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
- "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true
},
"ansi-styles": {
diff --git a/platform/linuxbsd/README.md b/platform/linuxbsd/README.md
new file mode 100644
index 0000000000..0d3fb37be5
--- /dev/null
+++ b/platform/linuxbsd/README.md
@@ -0,0 +1,11 @@
+# Linux/*BSD platform port
+
+This folder contains the C++ code for the Linux/*BSD platform port.
+
+## Artwork license
+
+[`logo.png`](logo.png) is derived from the [Linux logo](https://isc.tamu.edu/~lewing/linux/):
+
+> Permission to use and/or modify this image is granted provided you acknowledge me
+ <lewing@isc.tamu.edu> and [The GIMP](https://isc.tamu.edu/~lewing/gimp/)
+ if someone asks.
diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub
index 8aebd57fd2..cec8706fbc 100644
--- a/platform/linuxbsd/SCsub
+++ b/platform/linuxbsd/SCsub
@@ -14,7 +14,7 @@ common_linuxbsd = [
if "x11" in env and env["x11"]:
common_linuxbsd += [
- "context_gl_x11.cpp",
+ "gl_manager_x11.cpp",
"detect_prime_x11.cpp",
"display_server_x11.cpp",
"key_mapping_x11.cpp",
diff --git a/platform/linuxbsd/context_gl_x11.cpp b/platform/linuxbsd/context_gl_x11.cpp
deleted file mode 100644
index 1f92370ab7..0000000000
--- a/platform/linuxbsd/context_gl_x11.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-/*************************************************************************/
-/* context_gl_x11.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 "context_gl_x11.h"
-
-#ifdef X11_ENABLED
-#if defined(OPENGL_ENABLED)
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#define GLX_GLXEXT_PROTOTYPES
-#include <GL/glx.h>
-#include <GL/glxext.h>
-
-#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
-#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
-
-typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *);
-
-struct ContextGL_X11_Private {
- ::GLXContext glx_context;
-};
-
-void ContextGL_X11::release_current() {
- glXMakeCurrent(x11_display, None, nullptr);
-}
-
-void ContextGL_X11::make_current() {
- glXMakeCurrent(x11_display, x11_window, p->glx_context);
-}
-
-void ContextGL_X11::swap_buffers() {
- glXSwapBuffers(x11_display, x11_window);
-}
-
-static bool ctxErrorOccurred = false;
-static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
- ctxErrorOccurred = true;
- return 0;
-}
-
-static void set_class_hint(Display *p_display, Window p_window) {
- XClassHint *classHint;
-
- /* set the name and class hints for the window manager to use */
- classHint = XAllocClassHint();
- if (classHint) {
- classHint->res_name = (char *)"Godot_Engine";
- classHint->res_class = (char *)"Godot";
- }
- XSetClassHint(p_display, p_window, classHint);
- XFree(classHint);
-}
-
-Error ContextGL_X11::initialize() {
- //const char *extensions = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display));
-
- GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte *)"glXCreateContextAttribsARB");
-
- ERR_FAIL_COND_V(!glXCreateContextAttribsARB, ERR_UNCONFIGURED);
-
- static int visual_attribs[] = {
- GLX_RENDER_TYPE, GLX_RGBA_BIT,
- GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
- GLX_DOUBLEBUFFER, true,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_DEPTH_SIZE, 24,
- None
- };
-
- static int visual_attribs_layered[] = {
- GLX_RENDER_TYPE, GLX_RGBA_BIT,
- GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
- GLX_DOUBLEBUFFER, true,
- GLX_RED_SIZE, 8,
- GLX_GREEN_SIZE, 8,
- GLX_BLUE_SIZE, 8,
- GLX_ALPHA_SIZE, 8,
- GLX_DEPTH_SIZE, 24,
- None
- };
-
- int fbcount;
- GLXFBConfig fbconfig = 0;
- XVisualInfo *vi = nullptr;
-
- XSetWindowAttributes swa;
- swa.event_mask = StructureNotifyMask;
- swa.border_pixel = 0;
- unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
-
- if (OS::get_singleton()->is_layered_allowed()) {
- GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs_layered, &fbcount);
- ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
-
- for (int i = 0; i < fbcount; i++) {
- vi = (XVisualInfo *)glXGetVisualFromFBConfig(x11_display, fbc[i]);
- if (!vi)
- continue;
-
- XRenderPictFormat *pict_format = XRenderFindVisualFormat(x11_display, vi->visual);
- if (!pict_format) {
- XFree(vi);
- vi = nullptr;
- continue;
- }
-
- fbconfig = fbc[i];
- if (pict_format->direct.alphaMask > 0) {
- break;
- }
- }
- XFree(fbc);
- ERR_FAIL_COND_V(!fbconfig, ERR_UNCONFIGURED);
-
- swa.background_pixmap = None;
- swa.background_pixel = 0;
- swa.border_pixmap = None;
- valuemask |= CWBackPixel;
-
- } else {
- GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
- ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
-
- vi = glXGetVisualFromFBConfig(x11_display, fbc[0]);
-
- fbconfig = fbc[0];
- XFree(fbc);
- }
-
- int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&ctxErrorHandler);
-
- switch (context_type) {
- case GLES_2_0_COMPATIBLE: {
- p->glx_context = glXCreateNewContext(x11_display, fbconfig, GLX_RGBA_TYPE, 0, true);
- ERR_FAIL_COND_V(!p->glx_context, ERR_UNCONFIGURED);
- } break;
- }
-
- swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
- x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, valuemask, &swa);
- XStoreName(x11_display, x11_window, "Godot Engine");
-
- ERR_FAIL_COND_V(!x11_window, ERR_UNCONFIGURED);
- set_class_hint(x11_display, x11_window);
- XMapWindow(x11_display, x11_window);
-
- XSync(x11_display, False);
- XSetErrorHandler(oldHandler);
-
- glXMakeCurrent(x11_display, x11_window, p->glx_context);
-
- XFree(vi);
-
- return OK;
-}
-
-int ContextGL_X11::get_window_width() {
- XWindowAttributes xwa;
- XGetWindowAttributes(x11_display, x11_window, &xwa);
-
- return xwa.width;
-}
-
-int ContextGL_X11::get_window_height() {
- XWindowAttributes xwa;
- XGetWindowAttributes(x11_display, x11_window, &xwa);
-
- return xwa.height;
-}
-
-void ContextGL_X11::set_use_vsync(bool p_use) {
- static bool setup = false;
- static PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = nullptr;
- static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalMESA = nullptr;
- static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = nullptr;
-
- if (!setup) {
- setup = true;
- String extensions = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display));
- if (extensions.find("GLX_EXT_swap_control") != -1)
- glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalEXT");
- if (extensions.find("GLX_MESA_swap_control") != -1)
- glXSwapIntervalMESA = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalMESA");
- if (extensions.find("GLX_SGI_swap_control") != -1)
- glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalSGI");
- }
- int val = p_use ? 1 : 0;
- if (glXSwapIntervalMESA) {
- glXSwapIntervalMESA(val);
- } else if (glXSwapIntervalSGI) {
- glXSwapIntervalSGI(val);
- } else if (glXSwapIntervalEXT) {
- GLXDrawable drawable = glXGetCurrentDrawable();
- glXSwapIntervalEXT(x11_display, drawable, val);
- } else
- return;
- use_vsync = p_use;
-}
-
-bool ContextGL_X11::is_using_vsync() const {
- return use_vsync;
-}
-
-ContextGL_X11::ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, const OS::VideoMode &p_default_video_mode, ContextType p_context_type) :
- x11_window(p_x11_window) {
- default_video_mode = p_default_video_mode;
- x11_display = p_x11_display;
-
- context_type = p_context_type;
-
- double_buffer = false;
- direct_render = false;
- glx_minor = glx_major = 0;
- p = memnew(ContextGL_X11_Private);
- p->glx_context = 0;
- use_vsync = false;
-}
-
-ContextGL_X11::~ContextGL_X11() {
- release_current();
- glXDestroyContext(x11_display, p->glx_context);
- memdelete(p);
-}
-
-#endif
-#endif
diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp
index 0e98af71fa..9b24b24cb4 100644
--- a/platform/linuxbsd/crash_handler_linuxbsd.cpp
+++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp
@@ -115,7 +115,7 @@ static void handle_crash(int sig) {
int ret;
Error err = OS::get_singleton()->execute(String("addr2line"), args, &output, &ret);
if (err == OK) {
- output.erase(output.length() - 1, 1);
+ output = output.substr(0, output.length() - 1);
}
fprintf(stderr, "[%ld] %s (%s)\n", (long int)i, fname, output.utf8().get_data());
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 3e3ed469ed..07e16a982b 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -18,40 +18,42 @@ def can_build():
# Check the minimal dependencies
x11_error = os.system("pkg-config --version > /dev/null")
if x11_error:
+ print("Error: pkg-config not found. Aborting.")
return False
- x11_error = os.system("pkg-config x11 --modversion > /dev/null ")
+ x11_error = os.system("pkg-config x11 --modversion > /dev/null")
if x11_error:
+ print("Error: X11 libraries not found. Aborting.")
return False
- x11_error = os.system("pkg-config xcursor --modversion > /dev/null ")
+ x11_error = os.system("pkg-config xcursor --modversion > /dev/null")
if x11_error:
- print("xcursor not found.. x11 disabled.")
+ print("Error: Xcursor library not found. Aborting.")
return False
- x11_error = os.system("pkg-config xinerama --modversion > /dev/null ")
+ x11_error = os.system("pkg-config xinerama --modversion > /dev/null")
if x11_error:
- print("xinerama not found.. x11 disabled.")
+ print("Error: Xinerama library not found. Aborting.")
return False
- x11_error = os.system("pkg-config xext --modversion > /dev/null ")
+ x11_error = os.system("pkg-config xext --modversion > /dev/null")
if x11_error:
- print("xext not found.. x11 disabled.")
+ print("Error: Xext library not found. Aborting.")
return False
- x11_error = os.system("pkg-config xrandr --modversion > /dev/null ")
+ x11_error = os.system("pkg-config xrandr --modversion > /dev/null")
if x11_error:
- print("xrandr not found.. x11 disabled.")
+ print("Error: XrandR library not found. Aborting.")
return False
- x11_error = os.system("pkg-config xrender --modversion > /dev/null ")
+ x11_error = os.system("pkg-config xrender --modversion > /dev/null")
if x11_error:
- print("xrender not found.. x11 disabled.")
+ print("Error: XRender library not found. Aborting.")
return False
- x11_error = os.system("pkg-config xi --modversion > /dev/null ")
+ x11_error = os.system("pkg-config xi --modversion > /dev/null")
if x11_error:
- print("xi not found.. Aborting.")
+ print("Error: Xi library not found. Aborting.")
return False
return True
@@ -103,14 +105,12 @@ def configure(env):
env.Prepend(CCFLAGS=["-O2"])
elif env["optimize"] == "size": # optimize for size
env.Prepend(CCFLAGS=["-Os"])
- env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
if env["debug_symbols"]:
env.Prepend(CCFLAGS=["-g2"])
elif env["target"] == "debug":
env.Prepend(CCFLAGS=["-g3"])
- env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
env.Append(LINKFLAGS=["-rdynamic"])
## Architecture
@@ -119,6 +119,21 @@ def configure(env):
if env["bits"] == "default":
env["bits"] = "64" if is64 else "32"
+ machines = {
+ "riscv64": "rv64",
+ "ppc64le": "ppc64",
+ "ppc64": "ppc64",
+ "ppcle": "ppc",
+ "ppc": "ppc",
+ }
+
+ if env["arch"] == "" and platform.machine() in machines:
+ env["arch"] = machines[platform.machine()]
+
+ if env["arch"] == "rv64":
+ # G = General-purpose extensions, C = Compression extension (very common).
+ env.Append(CCFLAGS=["-march=rv64gc"])
+
## Compiler configuration
if "CXX" in env and "clang" in os.path.basename(env["CXX"]):
@@ -138,7 +153,7 @@ def configure(env):
# A convenience so you don't need to write use_lto too when using SCons
env["use_lto"] = True
else:
- print("Using LLD with GCC is not supported yet, try compiling with 'use_llvm=yes'.")
+ print("Using LLD with GCC is not supported yet. Try compiling with 'use_llvm=yes'.")
sys.exit(255)
if env["use_coverage"]:
@@ -201,11 +216,6 @@ def configure(env):
env.Append(CCFLAGS=["-pipe"])
env.Append(LINKFLAGS=["-pipe"])
- # -fpie and -no-pie is supported on GCC 6+ and Clang 4+, both below our
- # minimal requirements.
- env.Append(CCFLAGS=["-fpie"])
- env.Append(LINKFLAGS=["-no-pie"])
-
## Dependencies
env.ParseConfig("pkg-config x11 --cflags --libs")
@@ -293,17 +303,10 @@ def configure(env):
if any(platform.machine() in s for s in list_of_x86):
env["x86_libtheora_opt_gcc"] = True
- if not env["builtin_libvpx"]:
- env.ParseConfig("pkg-config vpx --cflags --libs")
-
if not env["builtin_libvorbis"]:
env["builtin_libogg"] = False # Needed to link against system libvorbis
env.ParseConfig("pkg-config vorbis vorbisfile --cflags --libs")
- if not env["builtin_opus"]:
- env["builtin_libogg"] = False # Needed to link against system opus
- env.ParseConfig("pkg-config opus opusfile --cflags --libs")
-
if not env["builtin_libogg"]:
env.ParseConfig("pkg-config ogg --cflags --libs")
@@ -334,36 +337,32 @@ def configure(env):
## Flags
if os.system("pkg-config --exists alsa") == 0: # 0 means found
- print("Enabling ALSA")
env["alsa"] = True
env.Append(CPPDEFINES=["ALSA_ENABLED", "ALSAMIDI_ENABLED"])
else:
- print("ALSA libraries not found, disabling driver")
+ print("Warning: ALSA libraries not found. Disabling the ALSA audio driver.")
if env["pulseaudio"]:
if os.system("pkg-config --exists libpulse") == 0: # 0 means found
- print("Enabling PulseAudio")
env.Append(CPPDEFINES=["PULSEAUDIO_ENABLED"])
env.ParseConfig("pkg-config --cflags libpulse")
else:
- print("PulseAudio development libraries not found, disabling driver")
+ print("Warning: PulseAudio development libraries not found. Disabling the PulseAudio audio driver.")
if env["dbus"]:
if os.system("pkg-config --exists dbus-1") == 0: # 0 means found
- print("Enabling D-Bus")
env.Append(CPPDEFINES=["DBUS_ENABLED"])
env.ParseConfig("pkg-config --cflags --libs dbus-1")
else:
- print("D-Bus development libraries not found, disabling dependent features")
+ print("Warning: D-Bus development libraries not found. Disabling screensaver prevention.")
if platform.system() == "Linux":
env.Append(CPPDEFINES=["JOYDEV_ENABLED"])
if env["udev"]:
if os.system("pkg-config --exists libudev") == 0: # 0 means found
- print("Enabling udev support")
env.Append(CPPDEFINES=["UDEV_ENABLED"])
else:
- print("libudev development libraries not found, disabling udev support")
+ print("Warning: libudev development libraries not found. Disabling controller hotplugging support.")
else:
env["udev"] = False # Linux specific
@@ -390,8 +389,8 @@ def configure(env):
# No pkgconfig file for glslang so far
env.Append(LIBS=["glslang", "SPIRV"])
- # env.Append(CPPDEFINES=['OPENGL_ENABLED'])
- env.Append(LIBS=["GL"])
+ env.Append(CPPDEFINES=["GLES3_ENABLED"])
+ env.Append(LIBS=["GL"])
env.Append(LIBS=["pthread"])
@@ -412,7 +411,7 @@ def configure(env):
gnu_ld_version = re.search("^GNU ld [^$]*(\d+\.\d+)$", linker_version_str, re.MULTILINE)
if not gnu_ld_version:
print(
- "Warning: Creating template binaries enabled for PCK embedding is currently only supported with GNU ld"
+ "Warning: Creating template binaries enabled for PCK embedding is currently only supported with GNU ld, not gold or LLD."
)
else:
if float(gnu_ld_version.group(1)) >= 2.30:
diff --git a/platform/linuxbsd/detect_prime_x11.cpp b/platform/linuxbsd/detect_prime_x11.cpp
index da1c95a593..c775546f15 100644
--- a/platform/linuxbsd/detect_prime_x11.cpp
+++ b/platform/linuxbsd/detect_prime_x11.cpp
@@ -29,9 +29,9 @@
/*************************************************************************/
#ifdef X11_ENABLED
-#if defined(OPENGL_ENABLED)
+#if defined(GLES3_ENABLED)
-#include "detect_prime.h"
+#include "detect_prime_x11.h"
#include "core/string/print_string.h"
#include "core/string/ustring.h"
diff --git a/platform/linuxbsd/detect_prime_x11.h b/platform/linuxbsd/detect_prime_x11.h
index 0b548b849e..88d00b3acd 100644
--- a/platform/linuxbsd/detect_prime_x11.h
+++ b/platform/linuxbsd/detect_prime_x11.h
@@ -29,7 +29,7 @@
/*************************************************************************/
#ifdef X11_ENABLED
-#if defined(OPENGL_ENABLED)
+#if defined(GLES3_ENABLED)
int detect_prime();
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index a39941339a..74ec8b652f 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -34,6 +34,7 @@
#include "core/config/project_settings.h"
#include "core/string/print_string.h"
+#include "core/string/ustring.h"
#include "detect_prime_x11.h"
#include "key_mapping_x11.h"
#include "main/main.h"
@@ -43,6 +44,10 @@
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#endif
+#if defined(GLES3_ENABLED)
+#include "drivers/gles3/rasterizer_gles3.h"
+#endif
+
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@@ -124,6 +129,7 @@ bool DisplayServerX11::has_feature(Feature p_feature) const {
#ifdef DBUS_ENABLED
case FEATURE_KEEP_SCREEN_ON:
#endif
+ case FEATURE_CLIPBOARD_PRIMARY:
return true;
default: {
}
@@ -280,7 +286,7 @@ void DisplayServerX11::_flush_mouse_motion() {
XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
if (event_data->evtype == XI_RawMotion) {
XFreeEventData(x11_display, &event.xcookie);
- polled_events.remove(event_index--);
+ polled_events.remove_at(event_index--);
continue;
}
XFreeEventData(x11_display, &event.xcookie);
@@ -306,11 +312,11 @@ void DisplayServerX11::mouse_set_mode(MouseMode p_mode) {
// The only modes that show a cursor are VISIBLE and CONFINED
bool showCursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED);
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
if (showCursor) {
- XDefineCursor(x11_display, E->get().x11_window, cursors[current_cursor]); // show cursor
+ XDefineCursor(x11_display, E.value.x11_window, cursors[current_cursor]); // show cursor
} else {
- XDefineCursor(x11_display, E->get().x11_window, null_cursor); // hide cursor
+ XDefineCursor(x11_display, E.value.x11_window, null_cursor); // hide cursor
}
}
mouse_mode = p_mode;
@@ -406,6 +412,20 @@ void DisplayServerX11::clipboard_set(const String &p_text) {
XSetSelectionOwner(x11_display, XInternAtom(x11_display, "CLIPBOARD", 0), windows[MAIN_WINDOW_ID].x11_window, CurrentTime);
}
+void DisplayServerX11::clipboard_set_primary(const String &p_text) {
+ _THREAD_SAFE_METHOD_
+ if (!p_text.is_empty()) {
+ {
+ // The clipboard content can be accessed while polling for events.
+ MutexLock mutex_lock(events_mutex);
+ internal_clipboard_primary = p_text;
+ }
+
+ XSetSelectionOwner(x11_display, XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window, CurrentTime);
+ XSetSelectionOwner(x11_display, XInternAtom(x11_display, "PRIMARY", 0), windows[MAIN_WINDOW_ID].x11_window, CurrentTime);
+ }
+}
+
Bool DisplayServerX11::_predicate_clipboard_selection(Display *display, XEvent *event, XPointer arg) {
if (event->type == SelectionNotify && event->xselection.requestor == *(Window *)arg) {
return True;
@@ -427,7 +447,12 @@ String DisplayServerX11::_clipboard_get_impl(Atom p_source, Window x11_window, A
Window selection_owner = XGetSelectionOwner(x11_display, p_source);
if (selection_owner == x11_window) {
- return internal_clipboard;
+ static const char *target_type = "PRIMARY";
+ if (p_source != None && String(XGetAtomName(x11_display, p_source)) == target_type) {
+ return internal_clipboard_primary;
+ } else {
+ return internal_clipboard;
+ }
}
if (selection_owner != None) {
@@ -580,10 +605,23 @@ String DisplayServerX11::clipboard_get() const {
return ret;
}
+String DisplayServerX11::clipboard_get_primary() const {
+ _THREAD_SAFE_METHOD_
+
+ String ret;
+ ret = _clipboard_get(XInternAtom(x11_display, "PRIMARY", 0), windows[MAIN_WINDOW_ID].x11_window);
+
+ if (ret.is_empty()) {
+ ret = _clipboard_get(XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window);
+ }
+
+ 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);
+ (event->type == SelectionNotify);
} else {
return False;
}
@@ -650,35 +688,59 @@ int DisplayServerX11::get_screen_count() const {
return count;
}
-Point2i DisplayServerX11::screen_get_position(int p_screen) const {
- _THREAD_SAFE_METHOD_
+Rect2i DisplayServerX11::_screen_get_rect(int p_screen) const {
+ Rect2i rect(0, 0, 0, 0);
if (p_screen == SCREEN_OF_MAIN_WINDOW) {
p_screen = window_get_current_screen();
}
- // Using Xinerama Extension
+ ERR_FAIL_COND_V(p_screen < 0, rect);
+
+ // Using Xinerama Extension.
int event_base, error_base;
- const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
- if (!ext_okay) {
- return Point2i(0, 0);
+ if (XineramaQueryExtension(x11_display, &event_base, &error_base)) {
+ int count;
+ XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
+
+ // Check if screen is valid.
+ if (p_screen < count) {
+ rect.position.x = xsi[p_screen].x_org;
+ rect.position.y = xsi[p_screen].y_org;
+ rect.size.width = xsi[p_screen].width;
+ rect.size.height = xsi[p_screen].height;
+ } else {
+ ERR_PRINT("Invalid screen index: " + itos(p_screen) + "(count: " + itos(count) + ").");
+ }
+
+ if (xsi) {
+ XFree(xsi);
+ }
}
- int count;
- XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
+ return rect;
+}
- // Check if screen is valid
- ERR_FAIL_INDEX_V(p_screen, count, Point2i(0, 0));
+Point2i DisplayServerX11::screen_get_position(int p_screen) const {
+ _THREAD_SAFE_METHOD_
- Point2i position = Point2i(xsi[p_screen].x_org, xsi[p_screen].y_org);
+ return _screen_get_rect(p_screen).position;
+}
- XFree(xsi);
+Size2i DisplayServerX11::screen_get_size(int p_screen) const {
+ _THREAD_SAFE_METHOD_
- return position;
+ return _screen_get_rect(p_screen).size;
}
-Size2i DisplayServerX11::screen_get_size(int p_screen) const {
- return screen_get_usable_rect(p_screen).size;
+bool g_bad_window = false;
+int bad_window_error_handler(Display *display, XErrorEvent *error) {
+ if (error->error_code == BadWindow) {
+ g_bad_window = true;
+ } else {
+ ERR_PRINT("Unhandled XServer error code: " + itos(error->error_code));
+ }
+ return 0;
}
Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
@@ -688,21 +750,276 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
p_screen = window_get_current_screen();
}
- // Using Xinerama Extension
- int event_base, error_base;
- const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
- if (!ext_okay) {
- return Rect2i(0, 0, 0, 0);
+ int screen_count = get_screen_count();
+
+ // Check if screen is valid.
+ ERR_FAIL_INDEX_V(p_screen, screen_count, Rect2i(0, 0, 0, 0));
+
+ bool is_multiscreen = screen_count > 1;
+
+ // Use full monitor size as fallback.
+ Rect2i rect = _screen_get_rect(p_screen);
+
+ // There's generally only one screen reported by xlib even in multi-screen setup,
+ // in this case it's just one virtual screen composed of all physical monitors.
+ int x11_screen_count = ScreenCount(x11_display);
+ Window x11_window = RootWindow(x11_display, p_screen < x11_screen_count ? p_screen : 0);
+
+ Atom type;
+ int format = 0;
+ unsigned long remaining = 0;
+
+ // Find active desktop for the root window.
+ unsigned int desktop_index = 0;
+ Atom desktop_prop = XInternAtom(x11_display, "_NET_CURRENT_DESKTOP", True);
+ if (desktop_prop != None) {
+ unsigned long desktop_len = 0;
+ unsigned char *desktop_data = nullptr;
+ if (XGetWindowProperty(x11_display, x11_window, desktop_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &desktop_len, &remaining, &desktop_data) == Success) {
+ if ((format == 32) && (desktop_len > 0) && desktop_data) {
+ desktop_index = (unsigned int)desktop_data[0];
+ }
+ if (desktop_data) {
+ XFree(desktop_data);
+ }
+ }
}
- int count;
- XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
+ bool use_simple_method = true;
+
+ // First check for GTK work area, which is more accurate for multi-screen setup.
+ if (is_multiscreen) {
+ // Use already calculated work area when available.
+ Atom gtk_workareas_prop = XInternAtom(x11_display, "_GTK_WORKAREAS", False);
+ if (gtk_workareas_prop != None) {
+ char gtk_workarea_prop_name[32];
+ snprintf(gtk_workarea_prop_name, 32, "_GTK_WORKAREAS_D%d", desktop_index);
+ Atom gtk_workarea_prop = XInternAtom(x11_display, gtk_workarea_prop_name, True);
+ if (gtk_workarea_prop != None) {
+ unsigned long workarea_len = 0;
+ unsigned char *workarea_data = nullptr;
+ if (XGetWindowProperty(x11_display, x11_window, gtk_workarea_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &workarea_len, &remaining, &workarea_data) == Success) {
+ if ((format == 32) && (workarea_len % 4 == 0) && workarea_data) {
+ long *rect_data = (long *)workarea_data;
+ for (uint32_t data_offset = 0; data_offset < workarea_len; data_offset += 4) {
+ Rect2i workarea_rect;
+ workarea_rect.position.x = rect_data[data_offset];
+ workarea_rect.position.y = rect_data[data_offset + 1];
+ workarea_rect.size.x = rect_data[data_offset + 2];
+ workarea_rect.size.y = rect_data[data_offset + 3];
+
+ // Intersect with actual monitor size to find the correct area,
+ // because areas are not in the same order as screens from Xinerama.
+ if (rect.grow(-1).intersects(workarea_rect)) {
+ rect = rect.intersection(workarea_rect);
+ XFree(workarea_data);
+ return rect;
+ }
+ }
+ }
+ }
+ if (workarea_data) {
+ XFree(workarea_data);
+ }
+ }
+ }
- // Check if screen is valid
- ERR_FAIL_INDEX_V(p_screen, count, Rect2i(0, 0, 0, 0));
+ // Fallback to calculating work area by hand from struts.
+ Atom client_list_prop = XInternAtom(x11_display, "_NET_CLIENT_LIST", True);
+ if (client_list_prop != None) {
+ unsigned long clients_len = 0;
+ unsigned char *clients_data = nullptr;
+ if (XGetWindowProperty(x11_display, x11_window, client_list_prop, 0, LONG_MAX, False, XA_WINDOW, &type, &format, &clients_len, &remaining, &clients_data) == Success) {
+ if ((format == 32) && (clients_len > 0) && clients_data) {
+ Window *windows_data = (Window *)clients_data;
+
+ Rect2i desktop_rect;
+ bool desktop_valid = false;
+
+ // Get full desktop size.
+ {
+ Atom desktop_geometry_prop = XInternAtom(x11_display, "_NET_DESKTOP_GEOMETRY", True);
+ if (desktop_geometry_prop != None) {
+ unsigned long geom_len = 0;
+ unsigned char *geom_data = nullptr;
+ if (XGetWindowProperty(x11_display, x11_window, desktop_geometry_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &geom_len, &remaining, &geom_data) == Success) {
+ if ((format == 32) && (geom_len >= 2) && geom_data) {
+ desktop_valid = true;
+ long *size_data = (long *)geom_data;
+ desktop_rect.size.x = size_data[0];
+ desktop_rect.size.y = size_data[1];
+ }
+ }
+ if (geom_data) {
+ XFree(geom_data);
+ }
+ }
+ }
+
+ // Get full desktop position.
+ if (desktop_valid) {
+ Atom desktop_viewport_prop = XInternAtom(x11_display, "_NET_DESKTOP_VIEWPORT", True);
+ if (desktop_viewport_prop != None) {
+ unsigned long viewport_len = 0;
+ unsigned char *viewport_data = nullptr;
+ if (XGetWindowProperty(x11_display, x11_window, desktop_viewport_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &viewport_len, &remaining, &viewport_data) == Success) {
+ if ((format == 32) && (viewport_len >= 2) && viewport_data) {
+ desktop_valid = true;
+ long *pos_data = (long *)viewport_data;
+ desktop_rect.position.x = pos_data[0];
+ desktop_rect.position.y = pos_data[1];
+ }
+ }
+ if (viewport_data) {
+ XFree(viewport_data);
+ }
+ }
+ }
+
+ if (desktop_valid) {
+ use_simple_method = false;
+
+ // Handle bad window errors silently because there's no other way to check
+ // that one of the windows has been destroyed in the meantime.
+ int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&bad_window_error_handler);
+
+ for (unsigned long win_index = 0; win_index < clients_len; ++win_index) {
+ g_bad_window = false;
+
+ // Remove strut size from desktop size to get a more accurate result.
+ bool strut_found = false;
+ unsigned long strut_len = 0;
+ unsigned char *strut_data = nullptr;
+ Atom strut_partial_prop = XInternAtom(x11_display, "_NET_WM_STRUT_PARTIAL", True);
+ if (strut_partial_prop != None) {
+ if (XGetWindowProperty(x11_display, windows_data[win_index], strut_partial_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &strut_len, &remaining, &strut_data) == Success) {
+ strut_found = true;
+ }
+ }
+ // Fallback to older strut property.
+ if (!g_bad_window && !strut_found) {
+ Atom strut_prop = XInternAtom(x11_display, "_NET_WM_STRUT", True);
+ if (strut_prop != None) {
+ if (XGetWindowProperty(x11_display, windows_data[win_index], strut_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &strut_len, &remaining, &strut_data) == Success) {
+ strut_found = true;
+ }
+ }
+ }
+ if (!g_bad_window && strut_found && (format == 32) && (strut_len >= 4) && strut_data) {
+ long *struts = (long *)strut_data;
+
+ long left = struts[0];
+ long right = struts[1];
+ long top = struts[2];
+ long bottom = struts[3];
+
+ long left_start_y, left_end_y, right_start_y, right_end_y;
+ long top_start_x, top_end_x, bottom_start_x, bottom_end_x;
+
+ if (strut_len >= 12) {
+ left_start_y = struts[4];
+ left_end_y = struts[5];
+ right_start_y = struts[6];
+ right_end_y = struts[7];
+ top_start_x = struts[8];
+ top_end_x = struts[9];
+ bottom_start_x = struts[10];
+ bottom_end_x = struts[11];
+ } else {
+ left_start_y = 0;
+ left_end_y = desktop_rect.size.y;
+ right_start_y = 0;
+ right_end_y = desktop_rect.size.y;
+ top_start_x = 0;
+ top_end_x = desktop_rect.size.x;
+ bottom_start_x = 0;
+ bottom_end_x = desktop_rect.size.x;
+ }
+
+ const Point2i &pos = desktop_rect.position;
+ const Size2i &size = desktop_rect.size;
+
+ Rect2i left_rect(pos.x, pos.y + left_start_y, left, left_end_y - left_start_y);
+ if (left_rect.size.x > 0) {
+ Rect2i intersection = rect.intersection(left_rect);
+ if (!intersection.has_no_area() && intersection.size.x < rect.size.x) {
+ rect.position.x = left_rect.size.x;
+ rect.size.x = rect.size.x - intersection.size.x;
+ }
+ }
+
+ Rect2i right_rect(pos.x + size.x - right, pos.y + right_start_y, right, right_end_y - right_start_y);
+ if (right_rect.size.x > 0) {
+ Rect2i intersection = rect.intersection(right_rect);
+ if (!intersection.has_no_area() && right_rect.size.x < rect.size.x) {
+ rect.size.x = intersection.position.x - rect.position.x;
+ }
+ }
+
+ Rect2i top_rect(pos.x + top_start_x, pos.y, top_end_x - top_start_x, top);
+ if (top_rect.size.y > 0) {
+ Rect2i intersection = rect.intersection(top_rect);
+ if (!intersection.has_no_area() && intersection.size.y < rect.size.y) {
+ rect.position.y = top_rect.size.y;
+ rect.size.y = rect.size.y - intersection.size.y;
+ }
+ }
+
+ Rect2i bottom_rect(pos.x + bottom_start_x, pos.y + size.y - bottom, bottom_end_x - bottom_start_x, bottom);
+ if (bottom_rect.size.y > 0) {
+ Rect2i intersection = rect.intersection(bottom_rect);
+ if (!intersection.has_no_area() && right_rect.size.y < rect.size.y) {
+ rect.size.y = intersection.position.y - rect.position.y;
+ }
+ }
+ }
+ if (strut_data) {
+ XFree(strut_data);
+ }
+ }
+
+ // Restore default error handler.
+ XSetErrorHandler(oldHandler);
+ }
+ }
+ }
+ if (clients_data) {
+ XFree(clients_data);
+ }
+ }
+ }
+
+ // Single screen or fallback for multi screen.
+ if (use_simple_method) {
+ // Get desktop available size from the global work area.
+ Atom workarea_prop = XInternAtom(x11_display, "_NET_WORKAREA", True);
+ if (workarea_prop != None) {
+ unsigned long workarea_len = 0;
+ unsigned char *workarea_data = nullptr;
+ if (XGetWindowProperty(x11_display, x11_window, workarea_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &workarea_len, &remaining, &workarea_data) == Success) {
+ if ((format == 32) && (workarea_len >= ((desktop_index + 1) * 4)) && workarea_data) {
+ long *rect_data = (long *)workarea_data;
+ int data_offset = desktop_index * 4;
+ Rect2i workarea_rect;
+ workarea_rect.position.x = rect_data[data_offset];
+ workarea_rect.position.y = rect_data[data_offset + 1];
+ workarea_rect.size.x = rect_data[data_offset + 2];
+ workarea_rect.size.y = rect_data[data_offset + 3];
+
+ // Intersect with actual monitor size to get a proper approximation in multi-screen setup.
+ if (!is_multiscreen) {
+ rect = workarea_rect;
+ } else if (rect.intersects(workarea_rect)) {
+ rect = rect.intersection(workarea_rect);
+ }
+ }
+ }
+ if (workarea_data) {
+ XFree(workarea_data);
+ }
+ }
+ }
- Rect2i rect = Rect2i(xsi[p_screen].x_org, xsi[p_screen].y_org, xsi[p_screen].width, xsi[p_screen].height);
- XFree(xsi);
return rect;
}
@@ -785,8 +1102,8 @@ Vector<DisplayServer::WindowID> DisplayServerX11::get_window_list() const {
_THREAD_SAFE_METHOD_
Vector<int> ret;
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- ret.push_back(E->key());
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
+ ret.push_back(E.key);
}
return ret;
}
@@ -837,6 +1154,12 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) {
context_vulkan->window_destroy(p_id);
}
#endif
+#ifdef GLES3_ENABLED
+ if (gl_manager) {
+ gl_manager->window_destroy(p_id);
+ }
+#endif
+
XUnmapWindow(x11_display, wd.x11_window);
XDestroyWindow(x11_display, wd.x11_window);
if (wd.xic) {
@@ -864,8 +1187,8 @@ DisplayServerX11::WindowID DisplayServerX11::get_window_at_screen_position(const
WindowID found_window = INVALID_WINDOW_ID;
WindowID parent_window = INVALID_WINDOW_ID;
unsigned int focus_order = 0;
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- const WindowData &wd = E->get();
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
+ const WindowData &wd = E.value;
// Discard windows with no focus.
if (wd.focus_order == 0) {
@@ -873,7 +1196,7 @@ DisplayServerX11::WindowID DisplayServerX11::get_window_at_screen_position(const
}
// Find topmost window which contains the given position.
- WindowID window_id = E->key();
+ WindowID window_id = E.key;
Rect2i win_rect = Rect2i(window_get_position(window_id), window_get_size(window_id));
if (win_rect.has_point(p_position)) {
// For siblings, pick the window which was focused last.
@@ -978,22 +1301,38 @@ void DisplayServerX11::window_set_drop_files_callback(const Callable &p_callable
int DisplayServerX11::window_get_current_screen(WindowID p_window) const {
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V(!windows.has(p_window), -1);
+ int count = get_screen_count();
+ if (count < 2) {
+ // Early exit with single monitor.
+ return 0;
+ }
+
+ ERR_FAIL_COND_V(!windows.has(p_window), 0);
const WindowData &wd = windows[p_window];
- int x, y;
- Window child;
- XTranslateCoordinates(x11_display, wd.x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
+ const Rect2i window_rect(wd.position, wd.size);
- int count = get_screen_count();
+ // Find which monitor has the largest overlap with the given window.
+ int screen_index = 0;
+ int max_area = 0;
for (int i = 0; i < count; i++) {
- Point2i pos = screen_get_position(i);
- Size2i size = screen_get_size(i);
- if ((x >= pos.x && x < pos.x + size.width) && (y >= pos.y && y < pos.y + size.height)) {
- return i;
+ Rect2i screen_rect = _screen_get_rect(i);
+ Rect2i intersection = screen_rect.intersection(window_rect);
+ int area = intersection.get_area();
+ if (area > max_area) {
+ max_area = area;
+ screen_index = i;
}
}
- return 0;
+
+ return screen_index;
+}
+
+void DisplayServerX11::gl_window_make_current(DisplayServer::WindowID p_window_id) {
+#if defined(GLES3_ENABLED)
+ if (gl_manager)
+ gl_manager->window_make_current(p_window_id);
+#endif
}
void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window) {
@@ -1768,8 +2107,8 @@ bool DisplayServerX11::window_can_draw(WindowID p_window) const {
bool DisplayServerX11::can_any_window_draw() const {
_THREAD_SAFE_METHOD_
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- if (window_get_mode(E->key()) != WINDOW_MODE_MINIMIZED) {
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
+ if (window_get_mode(E.key) != WINDOW_MODE_MINIMIZED) {
return true;
}
}
@@ -1841,12 +2180,12 @@ void DisplayServerX11::cursor_set_shape(CursorShape p_shape) {
if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
if (cursors[p_shape] != None) {
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- XDefineCursor(x11_display, E->get().x11_window, cursors[p_shape]);
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
+ XDefineCursor(x11_display, E.value.x11_window, cursors[p_shape]);
}
} else if (cursors[CURSOR_ARROW] != None) {
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- XDefineCursor(x11_display, E->get().x11_window, cursors[CURSOR_ARROW]);
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
+ XDefineCursor(x11_display, E.value.x11_window, cursors[CURSOR_ARROW]);
}
}
}
@@ -1944,8 +2283,8 @@ void DisplayServerX11::cursor_set_custom_image(const RES &p_cursor, CursorShape
if (p_shape == current_cursor) {
if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- XDefineCursor(x11_display, E->get().x11_window, cursors[p_shape]);
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
+ XDefineCursor(x11_display, E.value.x11_window, cursors[p_shape]);
}
}
}
@@ -2068,6 +2407,24 @@ String DisplayServerX11::keyboard_get_layout_name(int p_index) const {
return ret;
}
+Key DisplayServerX11::keyboard_get_keycode_from_physical(Key p_keycode) const {
+ Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK;
+ Key keycode_no_mod = p_keycode & KeyModifierMask::CODE_MASK;
+ unsigned int xkeycode = KeyMappingX11::get_xlibcode(keycode_no_mod);
+ KeySym xkeysym = XkbKeycodeToKeysym(x11_display, xkeycode, 0, 0);
+ if (xkeysym >= 'a' && xkeysym <= 'z') {
+ xkeysym -= ('a' - 'A');
+ }
+
+ Key key = KeyMappingX11::get_keycode(xkeysym);
+ // If not found, fallback to QWERTY.
+ // This should match the behavior of the event pump
+ if (key == Key::NONE) {
+ return p_keycode;
+ }
+ return (Key)(key | modifiers);
+}
+
DisplayServerX11::Property DisplayServerX11::_read_property(Display *p_display, Window p_window, Atom p_property) {
Atom actual_type = None;
int actual_format = 0;
@@ -2136,12 +2493,12 @@ void DisplayServerX11::_get_key_modifier_state(unsigned int p_x11_state, Ref<Inp
}
MouseButton DisplayServerX11::_get_mouse_button_state(MouseButton p_x11_button, int p_x11_type) {
- MouseButton mask = MouseButton(1 << (p_x11_button - 1));
+ MouseButton mask = mouse_button_to_mask(p_x11_button);
if (p_x11_type == ButtonPress) {
last_button_state |= mask;
} else {
- last_button_state &= MouseButton(~mask);
+ last_button_state &= ~mask;
}
return last_button_state;
@@ -2208,9 +2565,9 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
if (status == XLookupChars) {
bool keypress = xkeyevent->type == KeyPress;
Key keycode = KeyMappingX11::get_keycode(keysym_keycode);
- unsigned int physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
+ Key physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
- if (keycode >= 'a' && keycode <= 'z') {
+ if (keycode >= Key::A + 32 && keycode <= Key::Z + 32) {
keycode -= 'a' - 'A';
}
@@ -2219,11 +2576,11 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
for (int i = 0; i < tmp.length(); i++) {
Ref<InputEventKey> k;
k.instantiate();
- if (physical_keycode == 0 && keycode == 0 && tmp[i] == 0) {
+ if (physical_keycode == Key::NONE && keycode == Key::NONE && tmp[i] == 0) {
continue;
}
- if (keycode == 0) {
+ if (keycode == Key::NONE) {
keycode = (Key)physical_keycode;
}
@@ -2240,10 +2597,10 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
k->set_echo(false);
- if (k->get_keycode() == KEY_BACKTAB) {
+ if (k->get_keycode() == Key::BACKTAB) {
//make it consistent across platforms.
- k->set_keycode(KEY_TAB);
- k->set_physical_keycode(KEY_TAB);
+ k->set_keycode(Key::TAB);
+ k->set_physical_keycode(Key::TAB);
k->set_shift_pressed(true);
}
@@ -2272,7 +2629,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
// keysym, so it works in all platforms the same.
Key keycode = KeyMappingX11::get_keycode(keysym_keycode);
- unsigned int physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
+ Key physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
/* Phase 3, obtain a unicode character from the keysym */
@@ -2292,11 +2649,11 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
bool keypress = xkeyevent->type == KeyPress;
- if (physical_keycode == 0 && keycode == KEY_NONE && unicode == 0) {
+ if (physical_keycode == Key::NONE && keycode == Key::NONE && unicode == 0) {
return;
}
- if (keycode == KEY_NONE) {
+ if (keycode == Key::NONE) {
keycode = (Key)physical_keycode;
}
@@ -2359,7 +2716,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
k->set_pressed(keypress);
- if (keycode >= 'a' && keycode <= 'z') {
+ if (keycode >= Key::A + 32 && keycode <= Key::Z + 32) {
keycode -= int('a' - 'A');
}
@@ -2368,23 +2725,23 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
k->set_unicode(unicode);
k->set_echo(p_echo);
- if (k->get_keycode() == KEY_BACKTAB) {
+ if (k->get_keycode() == Key::BACKTAB) {
//make it consistent across platforms.
- k->set_keycode(KEY_TAB);
- k->set_physical_keycode(KEY_TAB);
+ k->set_keycode(Key::TAB);
+ k->set_physical_keycode(Key::TAB);
k->set_shift_pressed(true);
}
//don't set mod state if modifier keys are released by themselves
//else event.is_action() will not work correctly here
if (!k->is_pressed()) {
- if (k->get_keycode() == KEY_SHIFT) {
+ if (k->get_keycode() == Key::SHIFT) {
k->set_shift_pressed(false);
- } else if (k->get_keycode() == KEY_CTRL) {
+ } else if (k->get_keycode() == Key::CTRL) {
k->set_ctrl_pressed(false);
- } else if (k->get_keycode() == KEY_ALT) {
+ } else if (k->get_keycode() == Key::ALT) {
k->set_alt_pressed(false);
- } else if (k->get_keycode() == KEY_META) {
+ } else if (k->get_keycode() == Key::META) {
k->set_meta_pressed(false);
}
}
@@ -2399,7 +2756,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
Input::get_singleton()->parse_input_event(k);
}
-Atom DisplayServerX11::_process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property) const {
+Atom DisplayServerX11::_process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property, Atom p_selection) const {
if (p_target == XInternAtom(x11_display, "TARGETS", 0)) {
// Request to list all supported targets.
Atom data[9];
@@ -2434,14 +2791,20 @@ Atom DisplayServerX11::_process_selection_request_target(Atom p_target, Window p
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)) {
+ 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();
+ CharString clip;
+ static const char *target_type = "PRIMARY";
+ if (p_selection != None && String(XGetAtomName(x11_display, p_selection)) == target_type) {
+ clip = internal_clipboard_primary.utf8();
+ } else {
+ clip = internal_clipboard.utf8();
+ }
XChangeProperty(x11_display,
p_requestor,
p_property,
@@ -2479,7 +2842,7 @@ void DisplayServerX11::_handle_selection_request_event(XSelectionRequestEvent *p
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);
+ property = _process_selection_request_target(target, p_event->requestor, property, p_event->selection);
}
XChangeProperty(x11_display,
@@ -2497,7 +2860,7 @@ void DisplayServerX11::_handle_selection_request_event(XSelectionRequestEvent *p
}
} else {
// Request for target conversion.
- respond.xselection.property = _process_selection_request_target(p_event->target, p_event->requestor, p_event->property);
+ respond.xselection.property = _process_selection_request_target(p_event->target, p_event->requestor, p_event->property, p_event->selection);
}
respond.xselection.type = SelectionNotify;
@@ -2517,8 +2880,8 @@ void DisplayServerX11::_xim_destroy_callback(::XIM im, ::XPointer client_data,
DisplayServerX11 *ds = reinterpret_cast<DisplayServerX11 *>(client_data);
ds->xim = nullptr;
- for (Map<WindowID, WindowData>::Element *E = ds->windows.front(); E; E = E->next()) {
- E->get().xic = nullptr;
+ for (KeyValue<WindowID, WindowData> &E : ds->windows) {
+ E.value.xic = nullptr;
}
}
@@ -2526,9 +2889,9 @@ void DisplayServerX11::_window_changed(XEvent *event) {
WindowID window_id = MAIN_WINDOW_ID;
// Assign the event to the relevant window
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- if (event->xany.window == E->get().x11_window) {
- window_id = E->key();
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
+ if (event->xany.window == E.value.x11_window) {
+ window_id = E.key;
break;
}
}
@@ -2568,6 +2931,11 @@ void DisplayServerX11::_window_changed(XEvent *event) {
context_vulkan->window_resize(window_id, wd.size.width, wd.size.height);
}
#endif
+#if defined(GLES3_ENABLED)
+ if (gl_manager) {
+ gl_manager->window_resize(window_id, wd.size.width, wd.size.height);
+ }
+#endif
if (!wd.rect_changed_callback.is_null()) {
Rect2i r = new_rect;
@@ -2602,8 +2970,8 @@ void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) {
callable.call((const Variant **)&evp, 1, ret, ce);
} else {
//send to all windows
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- Callable callable = E->get().input_event_callback;
+ for (KeyValue<WindowID, WindowData> &E : windows) {
+ Callable callable = E.value.input_event_callback;
if (callable.is_null()) {
continue;
}
@@ -2668,27 +3036,34 @@ void DisplayServerX11::_poll_events() {
{
MutexLock mutex_lock(events_mutex);
- // 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.
- if (XFilterEvent(&ev, None)) {
- // Event has been filtered by the Input Manager,
- // it has to be ignored and a new one will be received.
- continue;
- }
+ _check_pending_events(polled_events);
+ }
+ }
+}
- // Handle selection request events directly in the event thread, because
- // communication through the x server takes several events sent back and forth
- // and we don't want to block other programs while processing only one each frame.
- if (ev.type == SelectionRequest) {
- _handle_selection_request_event(&(ev.xselectionrequest));
- continue;
- }
+void DisplayServerX11::_check_pending_events(LocalVector<XEvent> &r_events) {
+ // Flush to make sure to gather all pending events.
+ XFlush(x11_display);
- polled_events.push_back(ev);
- }
+ // 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.
+ if (XFilterEvent(&ev, None)) {
+ // Event has been filtered by the Input Manager,
+ // it has to be ignored and a new one will be received.
+ continue;
+ }
+
+ // Handle selection request events directly in the event thread, because
+ // communication through the x server takes several events sent back and forth
+ // and we don't want to block other programs while processing only one each frame.
+ if (ev.type == SelectionRequest) {
+ _handle_selection_request_event(&(ev.xselectionrequest));
+ continue;
}
+
+ r_events.push_back(ev);
}
}
@@ -2703,8 +3078,8 @@ void DisplayServerX11::process_events() {
if (app_focused) {
//verify that one of the windows has focus, else send focus out notification
bool focus_found = false;
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- if (E->get().focused) {
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
+ if (E.value.focused) {
focus_found = true;
break;
}
@@ -2741,6 +3116,9 @@ void DisplayServerX11::process_events() {
MutexLock mutex_lock(events_mutex);
events = polled_events;
polled_events.clear();
+
+ // Check for more pending events to avoid an extra frame delay.
+ _check_pending_events(events);
}
for (uint32_t event_index = 0; event_index < events.size(); ++event_index) {
@@ -2749,9 +3127,9 @@ void DisplayServerX11::process_events() {
WindowID window_id = MAIN_WINDOW_ID;
// Assign the event to the relevant window
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- if (event.xany.window == E->get().x11_window) {
- window_id = E->key();
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
+ if (event.xany.window == E.value.x11_window) {
+ window_id = E.key;
break;
}
}
@@ -2800,7 +3178,7 @@ void DisplayServerX11::process_events() {
if (pen_pressure_range != Vector2()) {
xi.pressure_supported = true;
xi.pressure = (*values - pen_pressure_range[0]) /
- (pen_pressure_range[1] - pen_pressure_range[0]);
+ (pen_pressure_range[1] - pen_pressure_range[0]);
}
}
@@ -2859,10 +3237,7 @@ void DisplayServerX11::process_events() {
xi.last_relative_time = raw_event->time;
} break;
#ifdef TOUCH_ENABLED
- case XI_TouchBegin: // Fall-through
- // Disabled hand-in-hand with the grabbing
- //XIAllowTouchEvents(x11_display, event_data->deviceid, event_data->detail, x11_window, XIAcceptTouch);
-
+ case XI_TouchBegin:
case XI_TouchEnd: {
bool is_begin = event_data->evtype == XI_TouchBegin;
@@ -2990,17 +3365,17 @@ void DisplayServerX11::process_events() {
if (mouse_mode_grab) {
// Show and update the cursor if confined and the window regained focus.
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
if (mouse_mode == MOUSE_MODE_CONFINED) {
- XUndefineCursor(x11_display, E->get().x11_window);
+ XUndefineCursor(x11_display, E.value.x11_window);
} else if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) { // Or re-hide it.
- XDefineCursor(x11_display, E->get().x11_window, null_cursor);
+ XDefineCursor(x11_display, E.value.x11_window, null_cursor);
}
XGrabPointer(
- x11_display, E->get().x11_window, True,
+ x11_display, E.value.x11_window, True,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
- GrabModeAsync, GrabModeAsync, E->get().x11_window, None, CurrentTime);
+ GrabModeAsync, GrabModeAsync, E.value.x11_window, None, CurrentTime);
}
}
#ifdef TOUCH_ENABLED
@@ -3036,11 +3411,11 @@ void DisplayServerX11::process_events() {
_send_window_event(wd, WINDOW_EVENT_FOCUS_OUT);
if (mouse_mode_grab) {
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
//dear X11, I try, I really try, but you never work, you do whathever you want.
if (mouse_mode == MOUSE_MODE_CAPTURED) {
// Show the cursor if we're in captured mode so it doesn't look weird.
- XUndefineCursor(x11_display, E->get().x11_window);
+ XUndefineCursor(x11_display, E.value.x11_window);
}
}
XUngrabPointer(x11_display, CurrentTime);
@@ -3052,12 +3427,12 @@ void DisplayServerX11::process_events() {
}*/
// Release every pointer to avoid sticky points
- for (Map<int, Vector2>::Element *E = xi.state.front(); E; E = E->next()) {
+ for (const KeyValue<int, Vector2> &E : xi.state) {
Ref<InputEventScreenTouch> st;
st.instantiate();
- st->set_index(E->key());
+ st->set_index(E.key);
st->set_window_id(window_id);
- st->set_position(E->get());
+ st->set_position(E.value);
Input::get_singleton()->parse_input_event(st);
}
xi.state.clear();
@@ -3094,10 +3469,10 @@ void DisplayServerX11::process_events() {
mb->set_window_id(window_id);
_get_key_modifier_state(event.xbutton.state, mb);
mb->set_button_index((MouseButton)event.xbutton.button);
- if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
- mb->set_button_index(MOUSE_BUTTON_MIDDLE);
- } else if (mb->get_button_index() == MOUSE_BUTTON_MIDDLE) {
- mb->set_button_index(MOUSE_BUTTON_RIGHT);
+ if (mb->get_button_index() == MouseButton::RIGHT) {
+ mb->set_button_index(MouseButton::MIDDLE);
+ } else if (mb->get_button_index() == MouseButton::MIDDLE) {
+ mb->set_button_index(MouseButton::RIGHT);
}
mb->set_button_mask(_get_mouse_button_state(mb->get_button_index(), event.xbutton.type));
mb->set_position(Vector2(event.xbutton.x, event.xbutton.y));
@@ -3123,11 +3498,11 @@ void DisplayServerX11::process_events() {
if (diff < 400 && Vector2(last_click_pos).distance_to(Vector2(event.xbutton.x, event.xbutton.y)) < 5) {
last_click_ms = 0;
last_click_pos = Point2i(-100, -100);
- last_click_button_index = -1;
+ last_click_button_index = MouseButton::NONE;
mb->set_double_click(true);
}
- } else if (mb->get_button_index() < 4 || mb->get_button_index() > 7) {
+ } else if (mb->get_button_index() < MouseButton::WHEEL_UP || mb->get_button_index() > MouseButton::WHEEL_RIGHT) {
last_click_button_index = mb->get_button_index();
}
@@ -3144,9 +3519,9 @@ void DisplayServerX11::process_events() {
// Note: This is needed for drag & drop to work between windows,
// because the engine expects events to keep being processed
// on the same window dragging started.
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- const WindowData &wd_other = E->get();
- WindowID window_id_other = E->key();
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
+ const WindowData &wd_other = E.value;
+ WindowID window_id_other = E.key;
if (wd_other.focused) {
if (window_id_other != window_id) {
int x, y;
@@ -3260,12 +3635,12 @@ void DisplayServerX11::process_events() {
if (xi.pressure_supported) {
mm->set_pressure(xi.pressure);
} else {
- mm->set_pressure((mouse_get_button_state() & MOUSE_BUTTON_MASK_LEFT) ? 1.0f : 0.0f);
+ mm->set_pressure(bool(mouse_get_button_state() & MouseButton::MASK_LEFT) ? 1.0f : 0.0f);
}
mm->set_tilt(xi.tilt);
_get_key_modifier_state(event.xmotion.state, mm);
- mm->set_button_mask(mouse_get_button_state());
+ mm->set_button_mask((MouseButton)mouse_get_button_state());
mm->set_position(pos);
mm->set_global_position(pos);
Input::get_singleton()->set_mouse_position(pos);
@@ -3287,8 +3662,8 @@ void DisplayServerX11::process_events() {
// Note: This is needed for drag & drop to work between windows,
// because the engine expects events to keep being processed
// on the same window dragging started.
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- const WindowData &wd_other = E->get();
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
+ const WindowData &wd_other = E.value;
if (wd_other.focused) {
int x, y;
Window child;
@@ -3296,7 +3671,7 @@ void DisplayServerX11::process_events() {
Point2i pos_focused(x, y);
- mm->set_window_id(E->key());
+ mm->set_window_id(E.key);
mm->set_position(pos_focused);
mm->set_global_position(pos_focused);
mm->set_speed(Input::get_singleton()->get_last_mouse_speed());
@@ -3310,11 +3685,18 @@ void DisplayServerX11::process_events() {
} break;
case KeyPress:
case KeyRelease: {
+#ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
+ if (event.type == KeyPress) {
+ DEBUG_LOG_X11("[%u] KeyPress window=%lu (%u), keycode=%u, time=%lu \n", frame, event.xkey.window, window_id, event.xkey.keycode, event.xkey.time);
+ } else {
+ DEBUG_LOG_X11("[%u] KeyRelease window=%lu (%u), keycode=%u, time=%lu \n", frame, event.xkey.window, window_id, event.xkey.keycode, event.xkey.time);
+ }
+#endif
last_timestamp = event.xkey.time;
// key event is a little complex, so
// it will be handled in its own function.
- _handle_key_event(window_id, (XKeyEvent *)&event, events, event_index);
+ _handle_key_event(window_id, &event.xkey, events, event_index);
} break;
case SelectionNotify:
@@ -3437,12 +3819,23 @@ void DisplayServerX11::process_events() {
}
void DisplayServerX11::release_rendering_thread() {
+#if defined(GLES3_ENABLED)
+// gl_manager->release_current();
+#endif
}
void DisplayServerX11::make_rendering_thread() {
+#if defined(GLES3_ENABLED)
+// gl_manager->make_current();
+#endif
}
void DisplayServerX11::swap_buffers() {
+#if defined(GLES3_ENABLED)
+ if (gl_manager) {
+ gl_manager->swap_buffers();
+ }
+#endif
}
void DisplayServerX11::_update_context(WindowData &wd) {
@@ -3487,8 +3880,8 @@ void DisplayServerX11::set_context(Context p_context) {
context = p_context;
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- _update_context(E->get());
+ for (KeyValue<WindowID, WindowData> &E : windows) {
+ _update_context(E.value);
}
}
@@ -3584,17 +3977,31 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) {
void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
_THREAD_SAFE_METHOD_
#if defined(VULKAN_ENABLED)
- context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+ if (context_vulkan) {
+ context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+ }
+#endif
+
+#if defined(GLES3_ENABLED)
+ if (gl_manager) {
+ gl_manager->set_use_vsync(p_vsync_mode == DisplayServer::VSYNC_ENABLED);
+ }
#endif
}
DisplayServer::VSyncMode DisplayServerX11::window_get_vsync_mode(WindowID p_window) const {
_THREAD_SAFE_METHOD_
#if defined(VULKAN_ENABLED)
- return context_vulkan->get_vsync_mode(p_window);
-#else
- return DisplayServer::VSYNC_ENABLED;
+ if (context_vulkan) {
+ return context_vulkan->get_vsync_mode(p_window);
+ }
+#endif
+#if defined(GLES3_ENABLED)
+ if (gl_manager) {
+ return gl_manager->is_using_vsync() ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED;
+ }
#endif
+ return DisplayServer::VSYNC_ENABLED;
}
Vector<String> DisplayServerX11::get_rendering_drivers_func() {
@@ -3603,8 +4010,8 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() {
#ifdef VULKAN_ENABLED
drivers.push_back("vulkan");
#endif
-#ifdef OPENGL_ENABLED
- drivers.push_back("opengl");
+#ifdef GLES3_ENABLED
+ drivers.push_back("opengl3");
#endif
return drivers;
@@ -3613,8 +4020,9 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() {
DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
if (r_error != OK) {
- OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan versions.\n"
- "Please update your drivers or if you have a very old or integrated GPU upgrade it.",
+ OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.\n"
+ "Please update your drivers or if you have a very old or integrated GPU, upgrade it.\n"
+ "If you have updated your graphics drivers recently, try rebooting.",
"Unable to initialize Video driver");
}
return ds;
@@ -3688,18 +4096,18 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
XSetWindowAttributes new_attr;
new_attr.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask |
- ButtonReleaseMask | EnterWindowMask |
- LeaveWindowMask | PointerMotionMask |
- Button1MotionMask |
- Button2MotionMask | Button3MotionMask |
- Button4MotionMask | Button5MotionMask |
- ButtonMotionMask | KeymapStateMask |
- ExposureMask | VisibilityChangeMask |
- StructureNotifyMask |
- SubstructureNotifyMask | SubstructureRedirectMask |
- FocusChangeMask | PropertyChangeMask |
- ColormapChangeMask | OwnerGrabButtonMask |
- im_event_mask;
+ ButtonReleaseMask | EnterWindowMask |
+ LeaveWindowMask | PointerMotionMask |
+ Button1MotionMask |
+ Button2MotionMask | Button3MotionMask |
+ Button4MotionMask | Button5MotionMask |
+ ButtonMotionMask | KeymapStateMask |
+ ExposureMask | VisibilityChangeMask |
+ StructureNotifyMask |
+ SubstructureNotifyMask | SubstructureRedirectMask |
+ FocusChangeMask | PropertyChangeMask |
+ ColormapChangeMask | OwnerGrabButtonMask |
+ im_event_mask;
XChangeWindowAttributes(x11_display, wd.x11_window, CWEventMask, &new_attr);
@@ -3788,6 +4196,12 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan window");
}
#endif
+#ifdef GLES3_ENABLED
+ if (gl_manager) {
+ Error err = gl_manager->window_create(id, wd.x11_window, x11_display, p_rect.size.width, p_rect.size.height);
+ ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL window");
+ }
+#endif
//set_class_hint(x11_display, wd.x11_window);
XFlush(x11_display);
@@ -3837,7 +4251,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
xmbstring = nullptr;
last_click_ms = 0;
- last_click_button_index = -1;
+ last_click_button_index = MouseButton::NONE;
last_click_pos = Point2i(-100, -100);
last_timestamp = 0;
@@ -3969,14 +4383,10 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
xdnd_selection = XInternAtom(x11_display, "XdndSelection", False);
//!!!!!!!!!!!!!!!!!!!!!!!!!!
- //TODO - do Vulkan and GLES2 support checks, driver selection and fallback
+ //TODO - do Vulkan and OpenGL support checks, driver selection and fallback
rendering_driver = p_rendering_driver;
-#ifndef _MSC_VER
-#warning Forcing vulkan rendering driver because OpenGL not implemented yet
-#endif
- rendering_driver = "vulkan";
-
+ bool driver_found = false;
#if defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") {
context_vulkan = memnew(VulkanContextX11);
@@ -3986,11 +4396,12 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
r_error = ERR_CANT_CREATE;
ERR_FAIL_MSG("Could not initialize Vulkan");
}
+ driver_found = true;
}
#endif
- // Init context and rendering device
-#if defined(OPENGL_ENABLED)
- if (rendering_driver == "opengl_es") {
+ // Initialize context and rendering device.
+#if defined(GLES3_ENABLED)
+ if (rendering_driver == "opengl3") {
if (getenv("DRI_PRIME") == nullptr) {
int use_prime = -1;
@@ -4032,28 +4443,37 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
}
- ContextGL_X11::ContextType opengl_api_type = ContextGL_X11::GLES_2_0_COMPATIBLE;
+ GLManager_X11::ContextType opengl_api_type = GLManager_X11::GLES_3_0_COMPATIBLE;
- context_gles2 = memnew(ContextGL_X11(x11_display, x11_window, current_videomode, opengl_api_type));
+ gl_manager = memnew(GLManager_X11(p_resolution, opengl_api_type));
- if (context_gles2->initialize() != OK) {
- memdelete(context_gles2);
- context_gles2 = nullptr;
- ERR_FAIL_V(ERR_UNAVAILABLE);
+ if (gl_manager->initialize() != OK) {
+ memdelete(gl_manager);
+ gl_manager = nullptr;
+ r_error = ERR_UNAVAILABLE;
+ return;
}
+ driver_found = true;
- context_gles2->set_use_vsync(current_videomode.use_vsync);
+ // gl_manager->set_use_vsync(current_videomode.use_vsync);
- if (RasterizerGLES2::is_viable() == OK) {
- RasterizerGLES2::register_config();
- RasterizerGLES2::make_current();
+ if (true) {
+ // if (RasterizerGLES3::is_viable() == OK) {
+ // RasterizerGLES3::register_config();
+ RasterizerGLES3::make_current();
} else {
- memdelete(context_gles2);
- context_gles2 = nullptr;
- ERR_FAIL_V(ERR_UNAVAILABLE);
+ memdelete(gl_manager);
+ gl_manager = nullptr;
+ r_error = ERR_UNAVAILABLE;
+ return;
}
}
#endif
+ if (!driver_found) {
+ r_error = ERR_UNAVAILABLE;
+ ERR_FAIL_MSG("Video driver not found");
+ }
+
Point2i window_position(
(screen_get_size(0).width - p_resolution.width) / 2,
(screen_get_size(0).height - p_resolution.height) / 2);
@@ -4069,7 +4489,6 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
show_window(main_window);
-//create RenderingDevice if used
#if defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") {
//temporary
@@ -4080,13 +4499,6 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
#endif
- /*
- 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));
- }
- */
-
{
//set all event master mask
XIEventMask all_master_event_mask;
@@ -4099,15 +4511,6 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
XISelectEvents(x11_display, DefaultRootWindow(x11_display), &all_master_event_mask, 1);
}
- // Disabled by now since grabbing also blocks mouse events
- // (they are received as extended events instead of standard events)
- /*XIClearMask(xi.touch_event_mask.mask, XI_TouchOwnership);
-
- // Grab touch devices to avoid OS gesture interference
- for (int i = 0; i < xi.touch_devices.size(); ++i) {
- XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask);
- }*/
-
cursor_size = XcursorGetDefaultSize(x11_display);
cursor_theme = XcursorGetTheme(x11_display);
@@ -4267,14 +4670,19 @@ DisplayServerX11::~DisplayServerX11() {
events_thread.wait_to_finish();
//destroy all windows
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ for (KeyValue<WindowID, WindowData> &E : windows) {
#ifdef VULKAN_ENABLED
if (rendering_driver == "vulkan") {
- context_vulkan->window_destroy(E->key());
+ context_vulkan->window_destroy(E.key);
+ }
+#endif
+#ifdef GLES3_ENABLED
+ if (rendering_driver == "opengl3") {
+ gl_manager->window_destroy(E.key);
}
#endif
- WindowData &wd = E->get();
+ WindowData &wd = E.value;
if (wd.xic) {
XDestroyIC(wd.xic);
wd.xic = nullptr;
@@ -4297,6 +4705,13 @@ DisplayServerX11::~DisplayServerX11() {
}
#endif
+#ifdef GLES3_ENABLED
+ if (gl_manager) {
+ memdelete(gl_manager);
+ gl_manager = nullptr;
+ }
+#endif
+
if (xrandr_handle) {
dlclose(xrandr_handle);
}
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 052c6d6b7b..3587d587d6 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -31,6 +31,8 @@
#ifndef DISPLAY_SERVER_X11_H
#define DISPLAY_SERVER_X11_H
+#include "drivers/gles3/rasterizer_platforms.h"
+
#ifdef X11_ENABLED
#include "servers/display_server.h"
@@ -46,8 +48,8 @@
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering_server.h"
-#if defined(OPENGL_ENABLED)
-#include "context_gl_x11.h"
+#if defined(GLES3_ENABLED)
+#include "gl_manager_x11.h"
#endif
#if defined(VULKAN_ENABLED)
@@ -99,12 +101,12 @@ class DisplayServerX11 : public DisplayServer {
Atom requested;
int xdnd_version;
-#if defined(OPENGL_ENABLED)
- ContextGL_X11 *context_gles2;
+#if defined(GLES3_ENABLED)
+ GLManager_X11 *gl_manager = nullptr;
#endif
#if defined(VULKAN_ENABLED)
- VulkanContextX11 *context_vulkan;
- RenderingDeviceVulkan *rendering_device_vulkan;
+ VulkanContextX11 *context_vulkan = nullptr;
+ RenderingDeviceVulkan *rendering_device_vulkan = nullptr;
#endif
#if defined(DBUS_ENABLED)
@@ -155,6 +157,7 @@ class DisplayServerX11 : public DisplayServer {
WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect);
String internal_clipboard;
+ String internal_clipboard_primary;
Window xdnd_source_window;
::Display *x11_display;
char *xmbstring;
@@ -170,8 +173,8 @@ class DisplayServerX11 : public DisplayServer {
bool last_mouse_pos_valid;
Point2i last_click_pos;
uint64_t last_click_ms;
- int last_click_button_index;
- MouseButton last_button_state = MOUSE_BUTTON_NONE;
+ MouseButton last_click_button_index = MouseButton::NONE;
+ MouseButton last_button_state = MouseButton::NONE;
bool app_focused = false;
uint64_t time_since_no_focus = 0;
@@ -196,6 +199,8 @@ class DisplayServerX11 : public DisplayServer {
bool _refresh_device_info();
+ Rect2i _screen_get_rect(int p_screen) const;
+
MouseButton _get_mouse_button_state(MouseButton p_x11_button, int p_x11_type);
void _get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state);
void _flush_mouse_motion();
@@ -205,7 +210,7 @@ class DisplayServerX11 : public DisplayServer {
void _handle_key_event(WindowID p_window, XKeyEvent *p_event, LocalVector<XEvent> &p_events, uint32_t &p_event_index, bool p_echo = false);
- Atom _process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property) const;
+ Atom _process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property, Atom p_selection) const;
void _handle_selection_request_event(XSelectionRequestEvent *p_event) const;
String _clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const;
@@ -267,6 +272,7 @@ class DisplayServerX11 : public DisplayServer {
static void _poll_events_thread(void *ud);
bool _wait_for_events() const;
void _poll_events();
+ void _check_pending_events(LocalVector<XEvent> &r_events);
static Bool _predicate_all_events(Display *display, XEvent *event, XPointer arg);
static Bool _predicate_clipboard_selection(Display *display, XEvent *event, XPointer arg);
@@ -290,6 +296,8 @@ public:
virtual void clipboard_set(const String &p_text) override;
virtual String clipboard_get() const override;
+ virtual void clipboard_set_primary(const String &p_text) override;
+ virtual String clipboard_get_primary() const override;
virtual int get_screen_count() const override;
virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
@@ -331,6 +339,7 @@ public:
virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override;
virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const override;
+ virtual void gl_window_make_current(DisplayServer::WindowID p_window_id) override;
virtual void window_set_transient(WindowID p_window, WindowID p_parent) override;
@@ -372,6 +381,7 @@ public:
virtual void keyboard_set_current_layout(int p_index) override;
virtual String keyboard_get_layout_language(int p_index) const override;
virtual String keyboard_get_layout_name(int p_index) const override;
+ virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override;
virtual void process_events() override;
diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp
index 5c6be2d7d4..965a38ef4e 100644
--- a/platform/linuxbsd/export/export.cpp
+++ b/platform/linuxbsd/export/export.cpp
@@ -53,7 +53,7 @@ void register_linuxbsd_exporter() {
platform->set_debug_32("linux_x11_32_debug");
platform->set_release_64("linux_x11_64_release");
platform->set_debug_64("linux_x11_64_debug");
- platform->set_os_name("X11");
+ platform->set_os_name("LinuxBSD");
platform->set_chmod_flags(0755);
platform->set_fixup_embedded_pck_func(&fixup_embedded_pck);
diff --git a/platform/linuxbsd/freedesktop_screensaver.cpp b/platform/linuxbsd/freedesktop_screensaver.cpp
index a6a3b27d76..3973d43d49 100644
--- a/platform/linuxbsd/freedesktop_screensaver.cpp
+++ b/platform/linuxbsd/freedesktop_screensaver.cpp
@@ -50,6 +50,7 @@ void FreeDesktopScreenSaver::inhibit() {
DBusConnection *bus = dbus_bus_get(DBUS_BUS_SESSION, &error);
if (dbus_error_is_set(&error)) {
+ dbus_error_free(&error);
unsupported = true;
return;
}
@@ -72,6 +73,7 @@ void FreeDesktopScreenSaver::inhibit() {
DBusMessage *reply = dbus_connection_send_with_reply_and_block(bus, message, 50, &error);
dbus_message_unref(message);
if (dbus_error_is_set(&error)) {
+ dbus_error_free(&error);
dbus_connection_unref(bus);
unsupported = false;
return;
@@ -96,6 +98,7 @@ void FreeDesktopScreenSaver::uninhibit() {
DBusConnection *bus = dbus_bus_get(DBUS_BUS_SESSION, &error);
if (dbus_error_is_set(&error)) {
+ dbus_error_free(&error);
unsupported = true;
return;
}
@@ -110,6 +113,7 @@ void FreeDesktopScreenSaver::uninhibit() {
DBusMessage *reply = dbus_connection_send_with_reply_and_block(bus, message, 50, &error);
if (dbus_error_is_set(&error)) {
+ dbus_error_free(&error);
dbus_connection_unref(bus);
unsupported = true;
return;
diff --git a/platform/linuxbsd/gl_manager_x11.cpp b/platform/linuxbsd/gl_manager_x11.cpp
new file mode 100644
index 0000000000..e069e92ee6
--- /dev/null
+++ b/platform/linuxbsd/gl_manager_x11.cpp
@@ -0,0 +1,384 @@
+/*************************************************************************/
+/* gl_manager_x11.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 "gl_manager_x11.h"
+
+#ifdef X11_ENABLED
+#if defined(GLES3_ENABLED)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define GLX_GLXEXT_PROTOTYPES
+#include <GL/glx.h>
+#include <GL/glxext.h>
+
+#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
+#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
+
+typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *);
+
+struct GLManager_X11_Private {
+ ::GLXContext glx_context;
+};
+
+GLManager_X11::GLDisplay::~GLDisplay() {
+ if (context) {
+ //release_current();
+ glXDestroyContext(x11_display, context->glx_context);
+ memdelete(context);
+ context = nullptr;
+ }
+}
+
+static bool ctxErrorOccurred = false;
+static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
+ ctxErrorOccurred = true;
+ return 0;
+}
+
+int GLManager_X11::_find_or_create_display(Display *p_x11_display) {
+ for (unsigned int n = 0; n < _displays.size(); n++) {
+ const GLDisplay &d = _displays[n];
+ if (d.x11_display == p_x11_display)
+ return n;
+ }
+
+ // create
+ GLDisplay d_temp;
+ d_temp.x11_display = p_x11_display;
+ _displays.push_back(d_temp);
+ int new_display_id = _displays.size() - 1;
+
+ // create context
+ GLDisplay &d = _displays[new_display_id];
+
+ d.context = memnew(GLManager_X11_Private);
+ ;
+ d.context->glx_context = 0;
+
+ //Error err = _create_context(d);
+ _create_context(d);
+ return new_display_id;
+}
+
+Error GLManager_X11::_create_context(GLDisplay &gl_display) {
+ // some aliases
+ ::Display *x11_display = gl_display.x11_display;
+
+ //const char *extensions = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display));
+
+ GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte *)"glXCreateContextAttribsARB");
+
+ ERR_FAIL_COND_V(!glXCreateContextAttribsARB, ERR_UNCONFIGURED);
+
+ static int visual_attribs[] = {
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ GLX_DOUBLEBUFFER, true,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DEPTH_SIZE, 24,
+ None
+ };
+
+ static int visual_attribs_layered[] = {
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ GLX_DOUBLEBUFFER, true,
+ GLX_RED_SIZE, 8,
+ GLX_GREEN_SIZE, 8,
+ GLX_BLUE_SIZE, 8,
+ GLX_ALPHA_SIZE, 8,
+ GLX_DEPTH_SIZE, 24,
+ None
+ };
+
+ int fbcount;
+ GLXFBConfig fbconfig = 0;
+ XVisualInfo *vi = nullptr;
+
+ gl_display.x_swa.event_mask = StructureNotifyMask;
+ gl_display.x_swa.border_pixel = 0;
+ gl_display.x_valuemask = CWBorderPixel | CWColormap | CWEventMask;
+
+ if (OS::get_singleton()->is_layered_allowed()) {
+ GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs_layered, &fbcount);
+ ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
+
+ for (int i = 0; i < fbcount; i++) {
+ vi = (XVisualInfo *)glXGetVisualFromFBConfig(x11_display, fbc[i]);
+ if (!vi)
+ continue;
+
+ XRenderPictFormat *pict_format = XRenderFindVisualFormat(x11_display, vi->visual);
+ if (!pict_format) {
+ XFree(vi);
+ vi = nullptr;
+ continue;
+ }
+
+ fbconfig = fbc[i];
+ if (pict_format->direct.alphaMask > 0) {
+ break;
+ }
+ }
+ XFree(fbc);
+
+ ERR_FAIL_COND_V(!fbconfig, ERR_UNCONFIGURED);
+
+ gl_display.x_swa.background_pixmap = None;
+ gl_display.x_swa.background_pixel = 0;
+ gl_display.x_swa.border_pixmap = None;
+ gl_display.x_valuemask |= CWBackPixel;
+
+ } else {
+ GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
+ ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
+
+ vi = glXGetVisualFromFBConfig(x11_display, fbc[0]);
+
+ fbconfig = fbc[0];
+ XFree(fbc);
+ }
+
+ int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&ctxErrorHandler);
+
+ switch (context_type) {
+ case GLES_3_0_COMPATIBLE: {
+ static int context_attribs[] = {
+ GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
+ GLX_CONTEXT_MINOR_VERSION_ARB, 3,
+ GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+ GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB /*|GLX_CONTEXT_DEBUG_BIT_ARB*/,
+ None
+ };
+
+ gl_display.context->glx_context = glXCreateContextAttribsARB(x11_display, fbconfig, nullptr, true, context_attribs);
+ ERR_FAIL_COND_V(ctxErrorOccurred || !gl_display.context->glx_context, ERR_UNCONFIGURED);
+ } break;
+ }
+
+ gl_display.x_swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
+
+ XSync(x11_display, False);
+ XSetErrorHandler(oldHandler);
+
+ // make our own copy of the vi data
+ // for later creating windows using this display
+ if (vi) {
+ gl_display.x_vi = *vi;
+ }
+
+ XFree(vi);
+
+ return OK;
+}
+
+Error GLManager_X11::window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height) {
+ // make sure vector is big enough...
+ // we can mirror the external vector, it is simpler
+ // to keep the IDs identical for fast lookup
+ if (p_window_id >= (int)_windows.size()) {
+ _windows.resize(p_window_id + 1);
+ }
+
+ GLWindow &win = _windows[p_window_id];
+ win.in_use = true;
+ win.window_id = p_window_id;
+ win.width = p_width;
+ win.height = p_height;
+ win.x11_window = p_window;
+ win.gldisplay_id = _find_or_create_display(p_display);
+
+ // the display could be invalid .. check NYI
+ GLDisplay &gl_display = _displays[win.gldisplay_id];
+ //const XVisualInfo &vi = gl_display.x_vi;
+ //XSetWindowAttributes &swa = gl_display.x_swa;
+ ::Display *x11_display = gl_display.x11_display;
+ ::Window &x11_window = win.x11_window;
+
+ if (!glXMakeCurrent(x11_display, x11_window, gl_display.context->glx_context)) {
+ ERR_PRINT("glXMakeCurrent failed");
+ }
+
+ _internal_set_current_window(&win);
+
+ return OK;
+}
+
+void GLManager_X11::_internal_set_current_window(GLWindow *p_win) {
+ _current_window = p_win;
+
+ // quick access to x info
+ _x_windisp.x11_window = _current_window->x11_window;
+ const GLDisplay &disp = get_current_display();
+ _x_windisp.x11_display = disp.x11_display;
+}
+
+void GLManager_X11::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {
+ get_window(p_window_id).width = p_width;
+ get_window(p_window_id).height = p_height;
+}
+
+void GLManager_X11::window_destroy(DisplayServer::WindowID p_window_id) {
+ GLWindow &win = get_window(p_window_id);
+ win.in_use = false;
+
+ if (_current_window == &win) {
+ _current_window = nullptr;
+ _x_windisp.x11_display = nullptr;
+ _x_windisp.x11_window = -1;
+ }
+}
+
+void GLManager_X11::release_current() {
+ if (!_current_window)
+ return;
+ glXMakeCurrent(_x_windisp.x11_display, None, nullptr);
+}
+
+void GLManager_X11::window_make_current(DisplayServer::WindowID p_window_id) {
+ if (p_window_id == -1)
+ return;
+
+ GLWindow &win = _windows[p_window_id];
+ if (!win.in_use)
+ return;
+
+ // noop
+ if (&win == _current_window)
+ return;
+
+ const GLDisplay &disp = get_display(win.gldisplay_id);
+
+ glXMakeCurrent(disp.x11_display, win.x11_window, disp.context->glx_context);
+
+ _internal_set_current_window(&win);
+}
+
+void GLManager_X11::make_current() {
+ if (!_current_window)
+ return;
+ if (!_current_window->in_use) {
+ WARN_PRINT("current window not in use!");
+ return;
+ }
+ const GLDisplay &disp = get_current_display();
+ glXMakeCurrent(_x_windisp.x11_display, _x_windisp.x11_window, disp.context->glx_context);
+}
+
+void GLManager_X11::swap_buffers() {
+ // NO NEED TO CALL SWAP BUFFERS for each window...
+ // see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glXSwapBuffers.xml
+
+ if (!_current_window)
+ return;
+ if (!_current_window->in_use) {
+ WARN_PRINT("current window not in use!");
+ return;
+ }
+
+ // print_line("\tswap_buffers");
+
+ // only for debugging without drawing anything
+ // glClearColor(Math::randf(), 0, 1, 1);
+ //glClear(GL_COLOR_BUFFER_BIT);
+
+ //const GLDisplay &disp = get_current_display();
+ glXSwapBuffers(_x_windisp.x11_display, _x_windisp.x11_window);
+}
+
+Error GLManager_X11::initialize() {
+ return OK;
+}
+
+void GLManager_X11::set_use_vsync(bool p_use) {
+ static bool setup = false;
+ static PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = nullptr;
+ static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalMESA = nullptr;
+ static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = nullptr;
+
+ // force vsync in the editor for now, as a safety measure
+ bool is_editor = Engine::get_singleton()->is_editor_hint();
+ if (is_editor) {
+ p_use = true;
+ }
+
+ // we need an active window to get a display to set the vsync
+ if (!_current_window)
+ return;
+ const GLDisplay &disp = get_current_display();
+
+ if (!setup) {
+ setup = true;
+ String extensions = glXQueryExtensionsString(disp.x11_display, DefaultScreen(disp.x11_display));
+ if (extensions.find("GLX_EXT_swap_control") != -1)
+ glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalEXT");
+ if (extensions.find("GLX_MESA_swap_control") != -1)
+ glXSwapIntervalMESA = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalMESA");
+ if (extensions.find("GLX_SGI_swap_control") != -1)
+ glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalSGI");
+ }
+ int val = p_use ? 1 : 0;
+ if (glXSwapIntervalMESA) {
+ glXSwapIntervalMESA(val);
+ } else if (glXSwapIntervalSGI) {
+ glXSwapIntervalSGI(val);
+ } else if (glXSwapIntervalEXT) {
+ GLXDrawable drawable = glXGetCurrentDrawable();
+ glXSwapIntervalEXT(disp.x11_display, drawable, val);
+ } else
+ return;
+ use_vsync = p_use;
+}
+
+bool GLManager_X11::is_using_vsync() const {
+ return use_vsync;
+}
+
+GLManager_X11::GLManager_X11(const Vector2i &p_size, ContextType p_context_type) {
+ context_type = p_context_type;
+
+ double_buffer = false;
+ direct_render = false;
+ glx_minor = glx_major = 0;
+ use_vsync = false;
+ _current_window = nullptr;
+}
+
+GLManager_X11::~GLManager_X11() {
+ release_current();
+}
+
+#endif
+#endif
diff --git a/platform/linuxbsd/context_gl_x11.h b/platform/linuxbsd/gl_manager_x11.h
index d089886f4d..fa2c8a9c84 100644
--- a/platform/linuxbsd/context_gl_x11.h
+++ b/platform/linuxbsd/gl_manager_x11.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* context_gl_x11.h */
+/* gl_manager_x11.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,53 +28,103 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef CONTEXT_GL_X11_H
-#define CONTEXT_GL_X11_H
+#ifndef GL_MANAGER_X11_H
+#define GL_MANAGER_X11_H
#ifdef X11_ENABLED
-#if defined(OPENGL_ENABLED)
+#include "drivers/gles3/rasterizer_platforms.h"
+
+#ifdef GLES3_ENABLED
#include "core/os/os.h"
+#include "core/templates/local_vector.h"
+#include "servers/display_server.h"
#include <X11/Xlib.h>
#include <X11/extensions/Xrender.h>
-struct ContextGL_X11_Private;
+struct GLManager_X11_Private;
-class ContextGL_X11 {
+class GLManager_X11 {
public:
enum ContextType {
- GLES_2_0_COMPATIBLE,
+ GLES_3_0_COMPATIBLE,
};
private:
- ContextGL_X11_Private *p;
- OS::VideoMode default_video_mode;
- ::Display *x11_display;
- ::Window &x11_window;
+ // any data specific to the window
+ struct GLWindow {
+ GLWindow() { in_use = false; }
+ bool in_use;
+
+ // the external ID .. should match the GL window number .. unused I think
+ DisplayServer::WindowID window_id;
+ int width;
+ int height;
+ ::Window x11_window;
+ int gldisplay_id;
+ };
+
+ struct GLDisplay {
+ GLDisplay() { context = nullptr; }
+ ~GLDisplay();
+ GLManager_X11_Private *context;
+ ::Display *x11_display;
+ XVisualInfo x_vi;
+ XSetWindowAttributes x_swa;
+ unsigned long x_valuemask;
+ };
+
+ // just for convenience, window and display struct
+ struct XWinDisp {
+ ::Window x11_window;
+ ::Display *x11_display;
+ } _x_windisp;
+
+ LocalVector<GLWindow> _windows;
+ LocalVector<GLDisplay> _displays;
+
+ GLWindow *_current_window;
+
+ void _internal_set_current_window(GLWindow *p_win);
+
+ GLWindow &get_window(unsigned int id) { return _windows[id]; }
+ const GLWindow &get_window(unsigned int id) const { return _windows[id]; }
+
+ const GLDisplay &get_current_display() const { return _displays[_current_window->gldisplay_id]; }
+ const GLDisplay &get_display(unsigned int id) { return _displays[id]; }
+
bool double_buffer;
bool direct_render;
int glx_minor, glx_major;
bool use_vsync;
ContextType context_type;
+private:
+ int _find_or_create_display(Display *p_x11_display);
+ Error _create_context(GLDisplay &gl_display);
+
public:
+ Error window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height);
+ void window_destroy(DisplayServer::WindowID p_window_id);
+ void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
+
void release_current();
void make_current();
void swap_buffers();
- int get_window_width();
- int get_window_height();
+
+ void window_make_current(DisplayServer::WindowID p_window_id);
Error initialize();
void set_use_vsync(bool p_use);
bool is_using_vsync() const;
- ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, const OS::VideoMode &p_default_video_mode, ContextType p_context_type);
- ~ContextGL_X11();
+ GLManager_X11(const Vector2i &p_size, ContextType p_context_type);
+ ~GLManager_X11();
};
-#endif
+#endif // GLES3_ENABLED
+#endif // X11_ENABLED
-#endif
-#endif
+#endif // GL_MANAGER_X11_H
diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp
index 8b6dbc4c20..55cc21cc6c 100644
--- a/platform/linuxbsd/joypad_linux.cpp
+++ b/platform/linuxbsd/joypad_linux.cpp
@@ -59,7 +59,7 @@ JoypadLinux::Joypad::~Joypad() {
}
void JoypadLinux::Joypad::reset() {
- dpad = 0;
+ dpad = HatMask::CENTER;
fd = -1;
Input::JoyAxisValue jx;
@@ -253,7 +253,7 @@ void JoypadLinux::close_joypad(int p_id) {
if (joy.fd != -1) {
close(joy.fd);
joy.fd = -1;
- attached_devices.remove(attached_devices.find(joy.devpath));
+ attached_devices.remove_at(attached_devices.find(joy.devpath));
input->joy_connection_changed(p_id, false, "");
};
}
@@ -484,12 +484,12 @@ void JoypadLinux::process_joypads() {
case ABS_HAT0X:
if (ev.value != 0) {
if (ev.value < 0) {
- joy->dpad = (HatMask)((joy->dpad | HatMask::HAT_MASK_LEFT) & ~HatMask::HAT_MASK_RIGHT);
+ joy->dpad = (HatMask)((joy->dpad | HatMask::LEFT) & ~HatMask::RIGHT);
} else {
- joy->dpad = (HatMask)((joy->dpad | HatMask::HAT_MASK_RIGHT) & ~HatMask::HAT_MASK_LEFT);
+ joy->dpad = (HatMask)((joy->dpad | HatMask::RIGHT) & ~HatMask::LEFT);
}
} else {
- joy->dpad &= ~(HatMask::HAT_MASK_LEFT | HatMask::HAT_MASK_RIGHT);
+ joy->dpad &= ~(HatMask::LEFT | HatMask::RIGHT);
}
input->joy_hat(i, (HatMask)joy->dpad);
@@ -498,12 +498,12 @@ void JoypadLinux::process_joypads() {
case ABS_HAT0Y:
if (ev.value != 0) {
if (ev.value < 0) {
- joy->dpad = (HatMask)((joy->dpad | HatMask::HAT_MASK_UP) & ~HatMask::HAT_MASK_DOWN);
+ joy->dpad = (HatMask)((joy->dpad | HatMask::UP) & ~HatMask::DOWN);
} else {
- joy->dpad = (HatMask)((joy->dpad | HatMask::HAT_MASK_DOWN) & ~HatMask::HAT_MASK_UP);
+ joy->dpad = (HatMask)((joy->dpad | HatMask::DOWN) & ~HatMask::UP);
}
} else {
- joy->dpad &= ~(HatMask::HAT_MASK_UP | HatMask::HAT_MASK_DOWN);
+ joy->dpad &= ~(HatMask::UP | HatMask::DOWN);
}
input->joy_hat(i, (HatMask)joy->dpad);
diff --git a/platform/linuxbsd/joypad_linux.h b/platform/linuxbsd/joypad_linux.h
index 177d7a51ce..12b9046d64 100644
--- a/platform/linuxbsd/joypad_linux.h
+++ b/platform/linuxbsd/joypad_linux.h
@@ -56,7 +56,7 @@ private:
Input::JoyAxisValue curr_axis[MAX_ABS];
int key_map[MAX_KEY];
int abs_map[MAX_ABS];
- int dpad = 0;
+ HatMask dpad = HatMask::CENTER;
int fd = -1;
String devpath;
diff --git a/platform/linuxbsd/key_mapping_x11.cpp b/platform/linuxbsd/key_mapping_x11.cpp
index a1ef28234d..16c2392859 100644
--- a/platform/linuxbsd/key_mapping_x11.cpp
+++ b/platform/linuxbsd/key_mapping_x11.cpp
@@ -40,266 +40,266 @@ struct _XTranslatePair {
static _XTranslatePair _xkeysym_to_keycode[] = {
// misc keys
- { XK_Escape, KEY_ESCAPE },
- { XK_Tab, KEY_TAB },
- { XK_ISO_Left_Tab, KEY_BACKTAB },
- { XK_BackSpace, KEY_BACKSPACE },
- { XK_Return, KEY_ENTER },
- { XK_Insert, KEY_INSERT },
- { XK_Delete, KEY_DELETE },
- { XK_Clear, KEY_DELETE },
- { XK_Pause, KEY_PAUSE },
- { XK_Print, KEY_PRINT },
- { XK_Home, KEY_HOME },
- { XK_End, KEY_END },
- { XK_Left, KEY_LEFT },
- { XK_Up, KEY_UP },
- { XK_Right, KEY_RIGHT },
- { XK_Down, KEY_DOWN },
- { XK_Prior, KEY_PAGEUP },
- { XK_Next, KEY_PAGEDOWN },
- { XK_Shift_L, KEY_SHIFT },
- { XK_Shift_R, KEY_SHIFT },
- { XK_Shift_Lock, KEY_SHIFT },
- { XK_Control_L, KEY_CTRL },
- { XK_Control_R, KEY_CTRL },
- { XK_Meta_L, KEY_META },
- { XK_Meta_R, KEY_META },
- { XK_Alt_L, KEY_ALT },
- { XK_Alt_R, KEY_ALT },
- { XK_Caps_Lock, KEY_CAPSLOCK },
- { XK_Num_Lock, KEY_NUMLOCK },
- { XK_Scroll_Lock, KEY_SCROLLLOCK },
- { XK_Super_L, KEY_SUPER_L },
- { XK_Super_R, KEY_SUPER_R },
- { XK_Menu, KEY_MENU },
- { XK_Hyper_L, KEY_HYPER_L },
- { XK_Hyper_R, KEY_HYPER_R },
- { XK_Help, KEY_HELP },
- { XK_KP_Space, KEY_SPACE },
- { XK_KP_Tab, KEY_TAB },
- { XK_KP_Enter, KEY_KP_ENTER },
- { XK_Home, KEY_HOME },
- { XK_Left, KEY_LEFT },
- { XK_Up, KEY_UP },
- { XK_Right, KEY_RIGHT },
- { XK_Down, KEY_DOWN },
- { XK_Prior, KEY_PAGEUP },
- { XK_Next, KEY_PAGEDOWN },
- { XK_End, KEY_END },
- { XK_Begin, KEY_CLEAR },
- { XK_Insert, KEY_INSERT },
- { XK_Delete, KEY_DELETE },
- //{ XK_KP_Equal, KEY_EQUAL },
- //{ XK_KP_Separator, KEY_COMMA },
- { XK_KP_Decimal, KEY_KP_PERIOD },
- { XK_KP_Delete, KEY_KP_PERIOD },
- { XK_KP_Multiply, KEY_KP_MULTIPLY },
- { XK_KP_Divide, KEY_KP_DIVIDE },
- { XK_KP_Subtract, KEY_KP_SUBTRACT },
- { XK_KP_Add, KEY_KP_ADD },
- { XK_KP_0, KEY_KP_0 },
- { XK_KP_1, KEY_KP_1 },
- { XK_KP_2, KEY_KP_2 },
- { XK_KP_3, KEY_KP_3 },
- { XK_KP_4, KEY_KP_4 },
- { XK_KP_5, KEY_KP_5 },
- { XK_KP_6, KEY_KP_6 },
- { XK_KP_7, KEY_KP_7 },
- { XK_KP_8, KEY_KP_8 },
- { XK_KP_9, KEY_KP_9 },
+ { XK_Escape, Key::ESCAPE },
+ { XK_Tab, Key::TAB },
+ { XK_ISO_Left_Tab, Key::BACKTAB },
+ { XK_BackSpace, Key::BACKSPACE },
+ { XK_Return, Key::ENTER },
+ { XK_Insert, Key::INSERT },
+ { XK_Delete, Key::KEY_DELETE },
+ { XK_Clear, Key::KEY_DELETE },
+ { XK_Pause, Key::PAUSE },
+ { XK_Print, Key::PRINT },
+ { XK_Home, Key::HOME },
+ { XK_End, Key::END },
+ { XK_Left, Key::LEFT },
+ { XK_Up, Key::UP },
+ { XK_Right, Key::RIGHT },
+ { XK_Down, Key::DOWN },
+ { XK_Prior, Key::PAGEUP },
+ { XK_Next, Key::PAGEDOWN },
+ { XK_Shift_L, Key::SHIFT },
+ { XK_Shift_R, Key::SHIFT },
+ { XK_Shift_Lock, Key::SHIFT },
+ { XK_Control_L, Key::CTRL },
+ { XK_Control_R, Key::CTRL },
+ { XK_Meta_L, Key::META },
+ { XK_Meta_R, Key::META },
+ { XK_Alt_L, Key::ALT },
+ { XK_Alt_R, Key::ALT },
+ { XK_Caps_Lock, Key::CAPSLOCK },
+ { XK_Num_Lock, Key::NUMLOCK },
+ { XK_Scroll_Lock, Key::SCROLLLOCK },
+ { XK_Super_L, Key::SUPER_L },
+ { XK_Super_R, Key::SUPER_R },
+ { XK_Menu, Key::MENU },
+ { XK_Hyper_L, Key::HYPER_L },
+ { XK_Hyper_R, Key::HYPER_R },
+ { XK_Help, Key::HELP },
+ { XK_KP_Space, Key::SPACE },
+ { XK_KP_Tab, Key::TAB },
+ { XK_KP_Enter, Key::KP_ENTER },
+ { XK_Home, Key::HOME },
+ { XK_Left, Key::LEFT },
+ { XK_Up, Key::UP },
+ { XK_Right, Key::RIGHT },
+ { XK_Down, Key::DOWN },
+ { XK_Prior, Key::PAGEUP },
+ { XK_Next, Key::PAGEDOWN },
+ { XK_End, Key::END },
+ { XK_Begin, Key::CLEAR },
+ { XK_Insert, Key::INSERT },
+ { XK_Delete, Key::KEY_DELETE },
+ //{ XK_KP_Equal, Key::EQUAL },
+ //{ XK_KP_Separator, Key::COMMA },
+ { XK_KP_Decimal, Key::KP_PERIOD },
+ { XK_KP_Delete, Key::KP_PERIOD },
+ { XK_KP_Multiply, Key::KP_MULTIPLY },
+ { XK_KP_Divide, Key::KP_DIVIDE },
+ { XK_KP_Subtract, Key::KP_SUBTRACT },
+ { XK_KP_Add, Key::KP_ADD },
+ { XK_KP_0, Key::KP_0 },
+ { XK_KP_1, Key::KP_1 },
+ { XK_KP_2, Key::KP_2 },
+ { XK_KP_3, Key::KP_3 },
+ { XK_KP_4, Key::KP_4 },
+ { XK_KP_5, Key::KP_5 },
+ { XK_KP_6, Key::KP_6 },
+ { XK_KP_7, Key::KP_7 },
+ { XK_KP_8, Key::KP_8 },
+ { XK_KP_9, Key::KP_9 },
// same but with numlock
- { XK_KP_Insert, KEY_KP_0 },
- { XK_KP_End, KEY_KP_1 },
- { XK_KP_Down, KEY_KP_2 },
- { XK_KP_Page_Down, KEY_KP_3 },
- { XK_KP_Left, KEY_KP_4 },
- { XK_KP_Begin, KEY_KP_5 },
- { XK_KP_Right, KEY_KP_6 },
- { XK_KP_Home, KEY_KP_7 },
- { XK_KP_Up, KEY_KP_8 },
- { XK_KP_Page_Up, KEY_KP_9 },
- { XK_F1, KEY_F1 },
- { XK_F2, KEY_F2 },
- { XK_F3, KEY_F3 },
- { XK_F4, KEY_F4 },
- { XK_F5, KEY_F5 },
- { XK_F6, KEY_F6 },
- { XK_F7, KEY_F7 },
- { XK_F8, KEY_F8 },
- { XK_F9, KEY_F9 },
- { XK_F10, KEY_F10 },
- { XK_F11, KEY_F11 },
- { XK_F12, KEY_F12 },
- { XK_F13, KEY_F13 },
- { XK_F14, KEY_F14 },
- { XK_F15, KEY_F15 },
- { XK_F16, KEY_F16 },
+ { XK_KP_Insert, Key::KP_0 },
+ { XK_KP_End, Key::KP_1 },
+ { XK_KP_Down, Key::KP_2 },
+ { XK_KP_Page_Down, Key::KP_3 },
+ { XK_KP_Left, Key::KP_4 },
+ { XK_KP_Begin, Key::KP_5 },
+ { XK_KP_Right, Key::KP_6 },
+ { XK_KP_Home, Key::KP_7 },
+ { XK_KP_Up, Key::KP_8 },
+ { XK_KP_Page_Up, Key::KP_9 },
+ { XK_F1, Key::F1 },
+ { XK_F2, Key::F2 },
+ { XK_F3, Key::F3 },
+ { XK_F4, Key::F4 },
+ { XK_F5, Key::F5 },
+ { XK_F6, Key::F6 },
+ { XK_F7, Key::F7 },
+ { XK_F8, Key::F8 },
+ { XK_F9, Key::F9 },
+ { XK_F10, Key::F10 },
+ { XK_F11, Key::F11 },
+ { XK_F12, Key::F12 },
+ { XK_F13, Key::F13 },
+ { XK_F14, Key::F14 },
+ { XK_F15, Key::F15 },
+ { XK_F16, Key::F16 },
// media keys
- { XF86XK_Back, KEY_BACK },
- { XF86XK_Forward, KEY_FORWARD },
- { XF86XK_Stop, KEY_STOP },
- { XF86XK_Refresh, KEY_REFRESH },
- { XF86XK_Favorites, KEY_FAVORITES },
- { XF86XK_AudioMedia, KEY_LAUNCHMEDIA },
- { XF86XK_OpenURL, KEY_OPENURL },
- { XF86XK_HomePage, KEY_HOMEPAGE },
- { XF86XK_Search, KEY_SEARCH },
- { XF86XK_AudioLowerVolume, KEY_VOLUMEDOWN },
- { XF86XK_AudioMute, KEY_VOLUMEMUTE },
- { XF86XK_AudioRaiseVolume, KEY_VOLUMEUP },
- { XF86XK_AudioPlay, KEY_MEDIAPLAY },
- { XF86XK_AudioStop, KEY_MEDIASTOP },
- { XF86XK_AudioPrev, KEY_MEDIAPREVIOUS },
- { XF86XK_AudioNext, KEY_MEDIANEXT },
- { XF86XK_AudioRecord, KEY_MEDIARECORD },
+ { XF86XK_Back, Key::BACK },
+ { XF86XK_Forward, Key::FORWARD },
+ { XF86XK_Stop, Key::STOP },
+ { XF86XK_Refresh, Key::REFRESH },
+ { XF86XK_Favorites, Key::FAVORITES },
+ { XF86XK_AudioMedia, Key::LAUNCHMEDIA },
+ { XF86XK_OpenURL, Key::OPENURL },
+ { XF86XK_HomePage, Key::HOMEPAGE },
+ { XF86XK_Search, Key::SEARCH },
+ { XF86XK_AudioLowerVolume, Key::VOLUMEDOWN },
+ { XF86XK_AudioMute, Key::VOLUMEMUTE },
+ { XF86XK_AudioRaiseVolume, Key::VOLUMEUP },
+ { XF86XK_AudioPlay, Key::MEDIAPLAY },
+ { XF86XK_AudioStop, Key::MEDIASTOP },
+ { XF86XK_AudioPrev, Key::MEDIAPREVIOUS },
+ { XF86XK_AudioNext, Key::MEDIANEXT },
+ { XF86XK_AudioRecord, Key::MEDIARECORD },
// launch keys
- { XF86XK_Mail, KEY_LAUNCHMAIL },
- { XF86XK_MyComputer, KEY_LAUNCH0 },
- { XF86XK_Calculator, KEY_LAUNCH1 },
- { XF86XK_Standby, KEY_STANDBY },
+ { XF86XK_Mail, Key::LAUNCHMAIL },
+ { XF86XK_MyComputer, Key::LAUNCH0 },
+ { XF86XK_Calculator, Key::LAUNCH1 },
+ { XF86XK_Standby, Key::STANDBY },
- { XF86XK_Launch0, KEY_LAUNCH2 },
- { XF86XK_Launch1, KEY_LAUNCH3 },
- { XF86XK_Launch2, KEY_LAUNCH4 },
- { XF86XK_Launch3, KEY_LAUNCH5 },
- { XF86XK_Launch4, KEY_LAUNCH6 },
- { XF86XK_Launch5, KEY_LAUNCH7 },
- { XF86XK_Launch6, KEY_LAUNCH8 },
- { XF86XK_Launch7, KEY_LAUNCH9 },
- { XF86XK_Launch8, KEY_LAUNCHA },
- { XF86XK_Launch9, KEY_LAUNCHB },
- { XF86XK_LaunchA, KEY_LAUNCHC },
- { XF86XK_LaunchB, KEY_LAUNCHD },
- { XF86XK_LaunchC, KEY_LAUNCHE },
- { XF86XK_LaunchD, KEY_LAUNCHF },
+ { XF86XK_Launch0, Key::LAUNCH2 },
+ { XF86XK_Launch1, Key::LAUNCH3 },
+ { XF86XK_Launch2, Key::LAUNCH4 },
+ { XF86XK_Launch3, Key::LAUNCH5 },
+ { XF86XK_Launch4, Key::LAUNCH6 },
+ { XF86XK_Launch5, Key::LAUNCH7 },
+ { XF86XK_Launch6, Key::LAUNCH8 },
+ { XF86XK_Launch7, Key::LAUNCH9 },
+ { XF86XK_Launch8, Key::LAUNCHA },
+ { XF86XK_Launch9, Key::LAUNCHB },
+ { XF86XK_LaunchA, Key::LAUNCHC },
+ { XF86XK_LaunchB, Key::LAUNCHD },
+ { XF86XK_LaunchC, Key::LAUNCHE },
+ { XF86XK_LaunchD, Key::LAUNCHF },
- { 0, KEY_NONE }
+ { 0, Key::NONE }
};
struct _TranslatePair {
- unsigned int keysym;
+ Key keysym;
unsigned int keycode;
};
static _TranslatePair _scancode_to_keycode[] = {
- { KEY_ESCAPE, 0x09 },
- { KEY_1, 0x0A },
- { KEY_2, 0x0B },
- { KEY_3, 0x0C },
- { KEY_4, 0x0D },
- { KEY_5, 0x0E },
- { KEY_6, 0x0F },
- { KEY_7, 0x10 },
- { KEY_8, 0x11 },
- { KEY_9, 0x12 },
- { KEY_0, 0x13 },
- { KEY_MINUS, 0x14 },
- { KEY_EQUAL, 0x15 },
- { KEY_BACKSPACE, 0x16 },
- { KEY_TAB, 0x17 },
- { KEY_Q, 0x18 },
- { KEY_W, 0x19 },
- { KEY_E, 0x1A },
- { KEY_R, 0x1B },
- { KEY_T, 0x1C },
- { KEY_Y, 0x1D },
- { KEY_U, 0x1E },
- { KEY_I, 0x1F },
- { KEY_O, 0x20 },
- { KEY_P, 0x21 },
- { KEY_BRACELEFT, 0x22 },
- { KEY_BRACERIGHT, 0x23 },
- { KEY_ENTER, 0x24 },
- { KEY_CTRL, 0x25 },
- { KEY_A, 0x26 },
- { KEY_S, 0x27 },
- { KEY_D, 0x28 },
- { KEY_F, 0x29 },
- { KEY_G, 0x2A },
- { KEY_H, 0x2B },
- { KEY_J, 0x2C },
- { KEY_K, 0x2D },
- { KEY_L, 0x2E },
- { KEY_SEMICOLON, 0x2F },
- { KEY_APOSTROPHE, 0x30 },
- { KEY_QUOTELEFT, 0x31 },
- { KEY_SHIFT, 0x32 },
- { KEY_BACKSLASH, 0x33 },
- { KEY_Z, 0x34 },
- { KEY_X, 0x35 },
- { KEY_C, 0x36 },
- { KEY_V, 0x37 },
- { KEY_B, 0x38 },
- { KEY_N, 0x39 },
- { KEY_M, 0x3A },
- { KEY_COMMA, 0x3B },
- { KEY_PERIOD, 0x3C },
- { KEY_SLASH, 0x3D },
- { KEY_SHIFT, 0x3E },
- { KEY_KP_MULTIPLY, 0x3F },
- { KEY_ALT, 0x40 },
- { KEY_SPACE, 0x41 },
- { KEY_CAPSLOCK, 0x42 },
- { KEY_F1, 0x43 },
- { KEY_F2, 0x44 },
- { KEY_F3, 0x45 },
- { KEY_F4, 0x46 },
- { KEY_F5, 0x47 },
- { KEY_F6, 0x48 },
- { KEY_F7, 0x49 },
- { KEY_F8, 0x4A },
- { KEY_F9, 0x4B },
- { KEY_F10, 0x4C },
- { KEY_NUMLOCK, 0x4D },
- { KEY_SCROLLLOCK, 0x4E },
- { KEY_KP_7, 0x4F },
- { KEY_KP_8, 0x50 },
- { KEY_KP_9, 0x51 },
- { KEY_KP_SUBTRACT, 0x52 },
- { KEY_KP_4, 0x53 },
- { KEY_KP_5, 0x54 },
- { KEY_KP_6, 0x55 },
- { KEY_KP_ADD, 0x56 },
- { KEY_KP_1, 0x57 },
- { KEY_KP_2, 0x58 },
- { KEY_KP_3, 0x59 },
- { KEY_KP_0, 0x5A },
- { KEY_KP_PERIOD, 0x5B },
- //{ KEY_???, 0x5E }, //NON US BACKSLASH
- { KEY_F11, 0x5F },
- { KEY_F12, 0x60 },
- { KEY_KP_ENTER, 0x68 },
- { KEY_CTRL, 0x69 },
- { KEY_KP_DIVIDE, 0x6A },
- { KEY_PRINT, 0x6B },
- { KEY_ALT, 0x6C },
- { KEY_ENTER, 0x6D },
- { KEY_HOME, 0x6E },
- { KEY_UP, 0x6F },
- { KEY_PAGEUP, 0x70 },
- { KEY_LEFT, 0x71 },
- { KEY_RIGHT, 0x72 },
- { KEY_END, 0x73 },
- { KEY_DOWN, 0x74 },
- { KEY_PAGEDOWN, 0x75 },
- { KEY_INSERT, 0x76 },
- { KEY_DELETE, 0x77 },
- { KEY_VOLUMEMUTE, 0x79 },
- { KEY_VOLUMEDOWN, 0x7A },
- { KEY_VOLUMEUP, 0x7B },
- { KEY_PAUSE, 0x7F },
- { KEY_SUPER_L, 0x85 },
- { KEY_SUPER_R, 0x86 },
- { KEY_MENU, 0x87 },
- { KEY_UNKNOWN, 0 }
+ { Key::ESCAPE, 0x09 },
+ { Key::KEY_1, 0x0A },
+ { Key::KEY_2, 0x0B },
+ { Key::KEY_3, 0x0C },
+ { Key::KEY_4, 0x0D },
+ { Key::KEY_5, 0x0E },
+ { Key::KEY_6, 0x0F },
+ { Key::KEY_7, 0x10 },
+ { Key::KEY_8, 0x11 },
+ { Key::KEY_9, 0x12 },
+ { Key::KEY_0, 0x13 },
+ { Key::MINUS, 0x14 },
+ { Key::EQUAL, 0x15 },
+ { Key::BACKSPACE, 0x16 },
+ { Key::TAB, 0x17 },
+ { Key::Q, 0x18 },
+ { Key::W, 0x19 },
+ { Key::E, 0x1A },
+ { Key::R, 0x1B },
+ { Key::T, 0x1C },
+ { Key::Y, 0x1D },
+ { Key::U, 0x1E },
+ { Key::I, 0x1F },
+ { Key::O, 0x20 },
+ { Key::P, 0x21 },
+ { Key::BRACELEFT, 0x22 },
+ { Key::BRACERIGHT, 0x23 },
+ { Key::ENTER, 0x24 },
+ { Key::CTRL, 0x25 },
+ { Key::A, 0x26 },
+ { Key::S, 0x27 },
+ { Key::D, 0x28 },
+ { Key::F, 0x29 },
+ { Key::G, 0x2A },
+ { Key::H, 0x2B },
+ { Key::J, 0x2C },
+ { Key::K, 0x2D },
+ { Key::L, 0x2E },
+ { Key::SEMICOLON, 0x2F },
+ { Key::APOSTROPHE, 0x30 },
+ { Key::QUOTELEFT, 0x31 },
+ { Key::SHIFT, 0x32 },
+ { Key::BACKSLASH, 0x33 },
+ { Key::Z, 0x34 },
+ { Key::X, 0x35 },
+ { Key::C, 0x36 },
+ { Key::V, 0x37 },
+ { Key::B, 0x38 },
+ { Key::N, 0x39 },
+ { Key::M, 0x3A },
+ { Key::COMMA, 0x3B },
+ { Key::PERIOD, 0x3C },
+ { Key::SLASH, 0x3D },
+ { Key::SHIFT, 0x3E },
+ { Key::KP_MULTIPLY, 0x3F },
+ { Key::ALT, 0x40 },
+ { Key::SPACE, 0x41 },
+ { Key::CAPSLOCK, 0x42 },
+ { Key::F1, 0x43 },
+ { Key::F2, 0x44 },
+ { Key::F3, 0x45 },
+ { Key::F4, 0x46 },
+ { Key::F5, 0x47 },
+ { Key::F6, 0x48 },
+ { Key::F7, 0x49 },
+ { Key::F8, 0x4A },
+ { Key::F9, 0x4B },
+ { Key::F10, 0x4C },
+ { Key::NUMLOCK, 0x4D },
+ { Key::SCROLLLOCK, 0x4E },
+ { Key::KP_7, 0x4F },
+ { Key::KP_8, 0x50 },
+ { Key::KP_9, 0x51 },
+ { Key::KP_SUBTRACT, 0x52 },
+ { Key::KP_4, 0x53 },
+ { Key::KP_5, 0x54 },
+ { Key::KP_6, 0x55 },
+ { Key::KP_ADD, 0x56 },
+ { Key::KP_1, 0x57 },
+ { Key::KP_2, 0x58 },
+ { Key::KP_3, 0x59 },
+ { Key::KP_0, 0x5A },
+ { Key::KP_PERIOD, 0x5B },
+ //{ Key::???, 0x5E }, //NON US BACKSLASH
+ { Key::F11, 0x5F },
+ { Key::F12, 0x60 },
+ { Key::KP_ENTER, 0x68 },
+ { Key::CTRL, 0x69 },
+ { Key::KP_DIVIDE, 0x6A },
+ { Key::PRINT, 0x6B },
+ { Key::ALT, 0x6C },
+ { Key::ENTER, 0x6D },
+ { Key::HOME, 0x6E },
+ { Key::UP, 0x6F },
+ { Key::PAGEUP, 0x70 },
+ { Key::LEFT, 0x71 },
+ { Key::RIGHT, 0x72 },
+ { Key::END, 0x73 },
+ { Key::DOWN, 0x74 },
+ { Key::PAGEDOWN, 0x75 },
+ { Key::INSERT, 0x76 },
+ { Key::KEY_DELETE, 0x77 },
+ { Key::VOLUMEMUTE, 0x79 },
+ { Key::VOLUMEDOWN, 0x7A },
+ { Key::VOLUMEUP, 0x7B },
+ { Key::PAUSE, 0x7F },
+ { Key::SUPER_L, 0x85 },
+ { Key::SUPER_R, 0x86 },
+ { Key::MENU, 0x87 },
+ { Key::UNKNOWN, 0 }
};
-unsigned int KeyMappingX11::get_scancode(unsigned int p_code) {
- unsigned int keycode = KEY_UNKNOWN;
- for (int i = 0; _scancode_to_keycode[i].keysym != KEY_UNKNOWN; i++) {
+Key KeyMappingX11::get_scancode(unsigned int p_code) {
+ Key keycode = Key::UNKNOWN;
+ for (int i = 0; _scancode_to_keycode[i].keysym != Key::UNKNOWN; i++) {
if (_scancode_to_keycode[i].keycode == p_code) {
keycode = _scancode_to_keycode[i].keysym;
break;
@@ -309,6 +309,18 @@ unsigned int KeyMappingX11::get_scancode(unsigned int p_code) {
return keycode;
}
+unsigned int KeyMappingX11::get_xlibcode(Key p_keysym) {
+ unsigned int code = 0;
+ for (int i = 0; _scancode_to_keycode[i].keysym != Key::UNKNOWN; i++) {
+ if (_scancode_to_keycode[i].keysym == p_keysym) {
+ code = _scancode_to_keycode[i].keycode;
+ break;
+ }
+ }
+
+ return code;
+}
+
Key KeyMappingX11::get_keycode(KeySym p_keysym) {
// kinda bruteforce.. could optimize.
@@ -323,13 +335,13 @@ Key KeyMappingX11::get_keycode(KeySym p_keysym) {
}
}
- return KEY_NONE;
+ return Key::NONE;
}
KeySym KeyMappingX11::get_keysym(Key p_code) {
// kinda bruteforce.. could optimize.
- if (p_code < 0x100) { // Latin 1, maps 1-1
+ if (p_code < Key::END_LATIN1) { // Latin 1, maps 1-1
return (KeySym)p_code;
}
@@ -340,7 +352,7 @@ KeySym KeyMappingX11::get_keysym(Key p_code) {
}
}
- return (KeySym)KEY_NONE;
+ return (KeySym)Key::NONE;
}
/***** UNICODE CONVERSION ******/
diff --git a/platform/linuxbsd/key_mapping_x11.h b/platform/linuxbsd/key_mapping_x11.h
index 598db1c45a..5f61197abe 100644
--- a/platform/linuxbsd/key_mapping_x11.h
+++ b/platform/linuxbsd/key_mapping_x11.h
@@ -45,10 +45,11 @@ class KeyMappingX11 {
public:
static Key get_keycode(KeySym p_keysym);
- static unsigned int get_scancode(unsigned int p_code);
+ static unsigned int get_xlibcode(Key p_keysym);
+ static Key get_scancode(unsigned int p_code);
static KeySym get_keysym(Key p_code);
static unsigned int get_unicode_from_keysym(KeySym p_keysym);
static KeySym get_keysym_from_unicode(unsigned int p_unicode);
};
-#endif
+#endif // KEY_MAPPING_X11_H
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index 2c9801f512..69474c6dec 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -463,7 +463,10 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) {
// 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());
+ String file_name = p_path.get_file();
+ if (file_name.length() == 0) {
+ file_name = p_path.get_base_dir().get_file();
+ }
if (file_name.length() > 240) {
file_name = file_name.substr(0, file_name.length() - 15);
}
diff --git a/platform/linuxbsd/platform_config.h b/platform/linuxbsd/platform_config.h
index 3195d08935..aa78b48bb0 100644
--- a/platform/linuxbsd/platform_config.h
+++ b/platform/linuxbsd/platform_config.h
@@ -43,3 +43,5 @@
#define PTHREAD_BSD_SET_NAME
#endif
#endif
+
+#define OPENGL_INCLUDE_H "thirdparty/glad/glad/glad.h"
diff --git a/platform/osx/SCsub b/platform/osx/SCsub
index 46c13d8550..8ba106d1c2 100644
--- a/platform/osx/SCsub
+++ b/platform/osx/SCsub
@@ -13,7 +13,7 @@ files = [
"dir_access_osx.mm",
"joypad_osx.cpp",
"vulkan_context_osx.mm",
- "context_gl_osx.mm",
+ "gl_manager_osx.mm",
]
prog = env.add_program("#bin/godot", files)
diff --git a/platform/osx/context_gl_osx.mm b/platform/osx/context_gl_osx.mm
deleted file mode 100644
index 88db1a296e..0000000000
--- a/platform/osx/context_gl_osx.mm
+++ /dev/null
@@ -1,161 +0,0 @@
-/*************************************************************************/
-/* context_gl_osx.mm */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 "context_gl_osx.h"
-
-#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED)
-
-void ContextGL_OSX::release_current() {
- [NSOpenGLContext clearCurrentContext];
-}
-
-void ContextGL_OSX::make_current() {
- [context makeCurrentContext];
-}
-
-void ContextGL_OSX::update() {
- [context update];
-}
-
-void ContextGL_OSX::set_opacity(GLint p_opacity) {
- [context setValues:&p_opacity forParameter:NSOpenGLCPSurfaceOpacity];
-}
-
-int ContextGL_OSX::get_window_width() {
- return OS::get_singleton()->get_video_mode().width;
-}
-
-int ContextGL_OSX::get_window_height() {
- return OS::get_singleton()->get_video_mode().height;
-}
-
-void ContextGL_OSX::swap_buffers() {
- [context flushBuffer];
-}
-
-void ContextGL_OSX::set_use_vsync(bool p_use) {
- CGLContextObj ctx = CGLGetCurrentContext();
- if (ctx) {
- GLint swapInterval = p_use ? 1 : 0;
- CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval);
- use_vsync = p_use;
- }
-}
-
-bool ContextGL_OSX::is_using_vsync() const {
- return use_vsync;
-}
-
-Error ContextGL_OSX::initialize() {
- framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
- ERR_FAIL_COND_V(!framework, ERR_CANT_CREATE);
-
- unsigned int attributeCount = 0;
-
- // OS X needs non-zero color size, so set reasonable values
- int colorBits = 32;
-
- // Fail if a robustness strategy was requested
-
-#define ADD_ATTR(x) \
- { attributes[attributeCount++] = x; }
-#define ADD_ATTR2(x, y) \
- { \
- ADD_ATTR(x); \
- ADD_ATTR(y); \
- }
-
- // Arbitrary array size here
- NSOpenGLPixelFormatAttribute attributes[40];
-
- ADD_ATTR(NSOpenGLPFADoubleBuffer);
- ADD_ATTR(NSOpenGLPFAClosestPolicy);
-
- if (!opengl_3_context) {
- ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersionLegacy);
- } else {
- //we now need OpenGL 3 or better, maybe even change this to 3_3Core ?
- ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
- }
-
- ADD_ATTR2(NSOpenGLPFAColorSize, colorBits);
-
- /*
- if (fbconfig->alphaBits > 0)
- ADD_ATTR2(NSOpenGLPFAAlphaSize, fbconfig->alphaBits);
-*/
-
- ADD_ATTR2(NSOpenGLPFADepthSize, 24);
-
- ADD_ATTR2(NSOpenGLPFAStencilSize, 8);
-
- /*
- if (fbconfig->stereo)
- ADD_ATTR(NSOpenGLPFAStereo);
-*/
-
- /*
- if (fbconfig->samples > 0) {
- ADD_ATTR2(NSOpenGLPFASampleBuffers, 1);
- ADD_ATTR2(NSOpenGLPFASamples, fbconfig->samples);
- }
-*/
-
- // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB
- // framebuffer, so there's no need (and no way) to request it
-
- ADD_ATTR(0);
-
-#undef ADD_ATTR
-#undef ADD_ATTR2
-
- pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
- ERR_FAIL_COND_V(pixelFormat == nil, ERR_CANT_CREATE);
-
- context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
-
- ERR_FAIL_COND_V(context == nil, ERR_CANT_CREATE);
-
- [context setView:window_view];
-
- [context makeCurrentContext];
-
- return OK;
-}
-
-ContextGL_OSX::ContextGL_OSX(id p_view, bool p_opengl_3_context) {
- opengl_3_context = p_opengl_3_context;
- window_view = p_view;
- use_vsync = false;
-}
-
-ContextGL_OSX::~ContextGL_OSX() {}
-
-#endif
diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm
index 31228b10b4..57bca7a5b9 100644
--- a/platform/osx/crash_handler_osx.mm
+++ b/platform/osx/crash_handler_osx.mm
@@ -134,8 +134,13 @@ static void handle_crash(int sig) {
args.push_back("-o");
args.push_back(_execpath);
+#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__)
args.push_back("-arch");
args.push_back("x86_64");
+#elif defined(__aarch64__)
+ args.push_back("-arch");
+ args.push_back("arm64");
+#endif
args.push_back("-l");
snprintf(str, 1024, "%p", load_addr);
args.push_back(str);
@@ -146,7 +151,7 @@ static void handle_crash(int sig) {
String out = "";
Error err = OS::get_singleton()->execute(String("atos"), args, &out, &ret);
if (err == OK && out.substr(0, 2) != "0x") {
- out.erase(out.length() - 1, 1);
+ out = out.substr(0, out.length() - 1);
output = out;
}
}
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index 6b25daf05d..f5c7731395 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -31,6 +31,7 @@ def get_opts():
BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False),
BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN)", False),
BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False),
+ BoolVariable("use_coverage", "Use instrumentation codes in the binary (e.g. for code coverage)", False),
]
@@ -57,13 +58,11 @@ def configure(env):
env.Prepend(CCFLAGS=["-O2"])
elif env["optimize"] == "size": # optimize for size
env.Prepend(CCFLAGS=["-Os"])
- env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
if env["debug_symbols"]:
env.Prepend(CCFLAGS=["-g2"])
elif env["target"] == "debug":
env.Prepend(CCFLAGS=["-g3"])
- env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
env.Prepend(LINKFLAGS=["-Xlinker", "-no_deduplicate"])
## Architecture
@@ -83,7 +82,7 @@ def configure(env):
env.Append(CCFLAGS=["-arch", "arm64", "-mmacosx-version-min=10.15"])
env.Append(LINKFLAGS=["-arch", "arm64", "-mmacosx-version-min=10.15"])
else:
- print("Building for macOS 10.12+, platform x86-64.")
+ print("Building for macOS 10.12+, platform x86_64.")
env.Append(CCFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"])
env.Append(LINKFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"])
@@ -96,7 +95,6 @@ def configure(env):
env["AR"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ar"
env["RANLIB"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ranlib"
env["AS"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-as"
- env.Append(CPPDEFINES=["__MACPORTS__"]) # hack to fix libvpx MM256_BROADCASTSI128_SI256 define
else:
env["CC"] = "clang"
env["CXX"] = "clang++"
@@ -124,7 +122,6 @@ def configure(env):
env["AR"] = basecmd + "ar"
env["RANLIB"] = basecmd + "ranlib"
env["AS"] = basecmd + "as"
- env.Append(CPPDEFINES=["__MACPORTS__"]) # hack to fix libvpx MM256_BROADCASTSI128_SI256 define
if env["use_ubsan"] or env["use_asan"] or env["use_tsan"]:
env.extra_suffix += "s"
@@ -146,6 +143,10 @@ def configure(env):
env.Append(CCFLAGS=["-fsanitize=thread"])
env.Append(LINKFLAGS=["-fsanitize=thread"])
+ if env["use_coverage"]:
+ env.Append(CCFLAGS=["-ftest-coverage", "-fprofile-arcs"])
+ env.Append(LINKFLAGS=["-ftest-coverage", "-fprofile-arcs"])
+
## Dependencies
if env["builtin_libtheora"]:
@@ -182,10 +183,13 @@ def configure(env):
)
env.Append(LIBS=["pthread", "z"])
+ if env["opengl3"]:
+ env.Append(CPPDEFINES=["GLES_ENABLED", "GLES3_ENABLED"])
+ env.Append(CCFLAGS=["-Wno-deprecated-declarations"]) # Disable deprecation warnings
+ env.Append(LINKFLAGS=["-framework", "OpenGL"])
+
if env["vulkan"]:
env.Append(CPPDEFINES=["VULKAN_ENABLED"])
env.Append(LINKFLAGS=["-framework", "Metal", "-framework", "QuartzCore", "-framework", "IOSurface"])
if not env["use_volk"]:
env.Append(LINKFLAGS=["-L$VULKAN_SDK_PATH/MoltenVK/MoltenVK.xcframework/macos-arm64_x86_64/", "-lMoltenVK"])
-
- # env.Append(CPPDEFINES=['GLES_ENABLED', 'OPENGL_ENABLED'])
diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h
index 06b14f1c14..3cc0b10c5b 100644
--- a/platform/osx/display_server_osx.h
+++ b/platform/osx/display_server_osx.h
@@ -36,9 +36,8 @@
#include "core/input/input.h"
#include "servers/display_server.h"
-#if defined(OPENGL_ENABLED)
-#include "context_gl_osx.h"
-//TODO - reimplement OpenGLES
+#if defined(GLES3_ENABLED)
+#include "gl_manager_osx.h"
#endif
#if defined(VULKAN_ENABLED)
@@ -64,12 +63,12 @@ public:
NSMenu *_get_dock_menu() const;
void _menu_callback(id p_sender);
-#if defined(OPENGL_ENABLED)
- ContextGL_OSX *context_gles2;
+#if defined(GLES3_ENABLED)
+ GLManager_OSX *gl_manager = nullptr;
#endif
#if defined(VULKAN_ENABLED)
- VulkanContextOSX *context_vulkan;
- RenderingDeviceVulkan *rendering_device_vulkan;
+ VulkanContextOSX *context_vulkan = nullptr;
+ RenderingDeviceVulkan *rendering_device_vulkan = nullptr;
#endif
const NSMenu *_get_menu_root(const String &p_menu_root) const;
@@ -85,8 +84,8 @@ public:
bool pressed = false;
bool echo = false;
bool raw = false;
- Key keycode = KEY_NONE;
- uint32_t physical_keycode = 0;
+ Key keycode = Key::NONE;
+ Key physical_keycode = Key::NONE;
uint32_t unicode = 0;
};
@@ -109,9 +108,6 @@ public:
Vector<Vector2> mpath;
-#if defined(OPENGL_ENABLED)
- ContextGL_OSX *context_gles2 = nullptr;
-#endif
Point2i mouse_pos;
Size2i min_size;
@@ -176,7 +172,7 @@ public:
MouseMode mouse_mode;
Point2i last_mouse_pos;
- MouseButton last_button_state = MOUSE_BUTTON_NONE;
+ MouseButton last_button_state = MouseButton::NONE;
bool window_focused;
bool drop_events;
@@ -287,6 +283,7 @@ public:
virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override;
virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override;
+ virtual void gl_window_make_current(DisplayServer::WindowID p_window_id) override;
virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override;
virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override;
@@ -305,6 +302,7 @@ public:
virtual void keyboard_set_current_layout(int p_index) override;
virtual String keyboard_get_layout_language(int p_index) const override;
virtual String keyboard_get_layout_name(int p_index) const override;
+ virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override;
virtual void process_events() override;
virtual void force_process_and_drop_events() override;
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index f037d75fbd..fec5c98a99 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -45,8 +45,8 @@
#include <IOKit/hid/IOHIDKeys.h>
#include <IOKit/hid/IOHIDLib.h>
-#if defined(OPENGL_ENABLED)
-//TODO - reimplement OpenGLES
+#if defined(GLES3_ENABLED)
+#include "drivers/gles3/rasterizer_gles3.h"
#import <AppKit/NSOpenGLView.h>
#endif
@@ -166,9 +166,9 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
[pwd.window_object makeKeyAndOrderFront:nil]; // Move focus back to main window if there is no parent or other windows left.
}
-#if defined(OPENGL_ENABLED)
- if (DS_OSX->rendering_driver == "opengl_es") {
- //TODO - reimplement OpenGLES
+#if defined(GLES3_ENABLED)
+ if (DS_OSX->rendering_driver == "opengl3") {
+ DS_OSX->gl_manager->window_destroy(window_id);
}
#endif
#ifdef VULKAN_ENABLED
@@ -271,9 +271,9 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
layer.contentsScale = scale;
}
-#if defined(OPENGL_ENABLED)
- if (DS_OSX->rendering_driver == "opengl_es") {
- //TODO - reimplement OpenGLES
+#if defined(GLES3_ENABLED)
+ if (DS_OSX->rendering_driver == "opengl3") {
+ DS_OSX->gl_manager->window_resize(window_id, wd.size.width, wd.size.height);
}
#endif
#if defined(VULKAN_ENABLED)
@@ -289,14 +289,6 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
Callable::CallError ce;
wd.rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce);
}
-
- if (OS_OSX::get_singleton()->get_main_loop()) {
- Main::force_redraw();
- //Event retrieval blocks until resize is over. Call Main::iteration() directly.
- if (!Main::is_iterating()) { //avoid cyclic loop
- Main::iteration();
- }
- }
}
- (void)windowDidMove:(NSNotification *)notification {
@@ -377,7 +369,12 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
/* GodotContentView */
/*************************************************************************/
+#if defined(GLES3_ENABLED)
+@interface GodotContentView : NSOpenGLView <NSTextInputClient> {
+#else
@interface GodotContentView : NSView <NSTextInputClient> {
+#endif
+
DisplayServerOSX::WindowID window_id;
NSTrackingArea *trackingArea;
NSMutableAttributedString *markedText;
@@ -405,12 +402,6 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
}
- (CALayer *)makeBackingLayer {
-#if defined(OPENGL_ENABLED)
- if (DS_OSX->rendering_driver == "opengl_es") {
- CALayer *layer = [[NSOpenGLLayer class] layer];
- return layer;
- }
-#endif
#if defined(VULKAN_ENABLED)
if (DS_OSX->rendering_driver == "vulkan") {
CALayer *layer = [[CAMetalLayer class] layer];
@@ -421,10 +412,9 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
}
- (void)updateLayer {
-#if defined(OPENGL_ENABLED)
- if (DS_OSX->rendering_driver == "opengl_es") {
- [super updateLayer];
- //TODO - reimplement OpenGLES
+#if defined(GLES3_ENABLED)
+ if (DS_OSX->rendering_driver == "opengl3") {
+ DS_OSX->gl_manager->window_update(window_id);
}
#endif
#if defined(VULKAN_ENABLED)
@@ -589,8 +579,8 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
ke.pressed = true;
ke.echo = false;
ke.raw = false; // IME input event
- ke.keycode = KEY_NONE;
- ke.physical_keycode = 0;
+ ke.keycode = Key::NONE;
+ ke.physical_keycode = Key::NONE;
ke.unicode = codepoint;
_push_to_key_event_buffer(ke);
@@ -690,7 +680,7 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, M
mb->set_position(pos);
mb->set_global_position(pos);
mb->set_button_mask(DS_OSX->last_button_state);
- if (index == MOUSE_BUTTON_LEFT && pressed) {
+ if (index == MouseButton::LEFT && pressed) {
mb->set_double_click([event clickCount] == 2);
}
@@ -703,10 +693,10 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, M
if (([event modifierFlags] & NSEventModifierFlagControl)) {
wd.mouse_down_control = true;
- _mouseDownEvent(window_id, event, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MASK_RIGHT, true);
+ _mouseDownEvent(window_id, event, MouseButton::RIGHT, MouseButton::MASK_RIGHT, true);
} else {
wd.mouse_down_control = false;
- _mouseDownEvent(window_id, event, MOUSE_BUTTON_LEFT, MOUSE_BUTTON_MASK_LEFT, true);
+ _mouseDownEvent(window_id, event, MouseButton::LEFT, MouseButton::MASK_LEFT, true);
}
}
@@ -719,9 +709,9 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, M
DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
if (wd.mouse_down_control) {
- _mouseDownEvent(window_id, event, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MASK_RIGHT, false);
+ _mouseDownEvent(window_id, event, MouseButton::RIGHT, MouseButton::MASK_RIGHT, false);
} else {
- _mouseDownEvent(window_id, event, MOUSE_BUTTON_LEFT, MOUSE_BUTTON_MASK_LEFT, false);
+ _mouseDownEvent(window_id, event, MouseButton::LEFT, MouseButton::MASK_LEFT, false);
}
}
@@ -807,7 +797,7 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, M
}
- (void)rightMouseDown:(NSEvent *)event {
- _mouseDownEvent(window_id, event, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MASK_RIGHT, true);
+ _mouseDownEvent(window_id, event, MouseButton::RIGHT, MouseButton::MASK_RIGHT, true);
}
- (void)rightMouseDragged:(NSEvent *)event {
@@ -815,16 +805,16 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, M
}
- (void)rightMouseUp:(NSEvent *)event {
- _mouseDownEvent(window_id, event, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MASK_RIGHT, false);
+ _mouseDownEvent(window_id, event, MouseButton::RIGHT, MouseButton::MASK_RIGHT, false);
}
- (void)otherMouseDown:(NSEvent *)event {
if ((int)[event buttonNumber] == 2) {
- _mouseDownEvent(window_id, event, MOUSE_BUTTON_MIDDLE, MOUSE_BUTTON_MASK_MIDDLE, true);
+ _mouseDownEvent(window_id, event, MouseButton::MIDDLE, MouseButton::MASK_MIDDLE, true);
} else if ((int)[event buttonNumber] == 3) {
- _mouseDownEvent(window_id, event, MOUSE_BUTTON_XBUTTON1, MOUSE_BUTTON_MASK_XBUTTON1, true);
+ _mouseDownEvent(window_id, event, MouseButton::MB_XBUTTON1, MouseButton::MASK_XBUTTON1, true);
} else if ((int)[event buttonNumber] == 4) {
- _mouseDownEvent(window_id, event, MOUSE_BUTTON_XBUTTON2, MOUSE_BUTTON_MASK_XBUTTON2, true);
+ _mouseDownEvent(window_id, event, MouseButton::MB_XBUTTON2, MouseButton::MASK_XBUTTON2, true);
} else {
return;
}
@@ -836,11 +826,11 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, M
- (void)otherMouseUp:(NSEvent *)event {
if ((int)[event buttonNumber] == 2) {
- _mouseDownEvent(window_id, event, MOUSE_BUTTON_MIDDLE, MOUSE_BUTTON_MASK_MIDDLE, false);
+ _mouseDownEvent(window_id, event, MouseButton::MIDDLE, MouseButton::MASK_MIDDLE, false);
} else if ((int)[event buttonNumber] == 3) {
- _mouseDownEvent(window_id, event, MOUSE_BUTTON_XBUTTON1, MOUSE_BUTTON_MASK_XBUTTON1, false);
+ _mouseDownEvent(window_id, event, MouseButton::MB_XBUTTON1, MouseButton::MASK_XBUTTON1, false);
} else if ((int)[event buttonNumber] == 4) {
- _mouseDownEvent(window_id, event, MOUSE_BUTTON_XBUTTON2, MOUSE_BUTTON_MASK_XBUTTON2, false);
+ _mouseDownEvent(window_id, event, MouseButton::MB_XBUTTON2, MouseButton::MASK_XBUTTON2, false);
} else {
return;
}
@@ -930,146 +920,155 @@ static bool isNumpadKey(unsigned int key) {
return false;
}
+// Keyboard symbol translation table
+static const Key _osx_to_godot_table[128] = {
+ /* 00 */ Key::A,
+ /* 01 */ Key::S,
+ /* 02 */ Key::D,
+ /* 03 */ Key::F,
+ /* 04 */ Key::H,
+ /* 05 */ Key::G,
+ /* 06 */ Key::Z,
+ /* 07 */ Key::X,
+ /* 08 */ Key::C,
+ /* 09 */ Key::V,
+ /* 0a */ Key::SECTION, /* ISO Section */
+ /* 0b */ Key::B,
+ /* 0c */ Key::Q,
+ /* 0d */ Key::W,
+ /* 0e */ Key::E,
+ /* 0f */ Key::R,
+ /* 10 */ Key::Y,
+ /* 11 */ Key::T,
+ /* 12 */ Key::KEY_1,
+ /* 13 */ Key::KEY_2,
+ /* 14 */ Key::KEY_3,
+ /* 15 */ Key::KEY_4,
+ /* 16 */ Key::KEY_6,
+ /* 17 */ Key::KEY_5,
+ /* 18 */ Key::EQUAL,
+ /* 19 */ Key::KEY_9,
+ /* 1a */ Key::KEY_7,
+ /* 1b */ Key::MINUS,
+ /* 1c */ Key::KEY_8,
+ /* 1d */ Key::KEY_0,
+ /* 1e */ Key::BRACERIGHT,
+ /* 1f */ Key::O,
+ /* 20 */ Key::U,
+ /* 21 */ Key::BRACELEFT,
+ /* 22 */ Key::I,
+ /* 23 */ Key::P,
+ /* 24 */ Key::ENTER,
+ /* 25 */ Key::L,
+ /* 26 */ Key::J,
+ /* 27 */ Key::APOSTROPHE,
+ /* 28 */ Key::K,
+ /* 29 */ Key::SEMICOLON,
+ /* 2a */ Key::BACKSLASH,
+ /* 2b */ Key::COMMA,
+ /* 2c */ Key::SLASH,
+ /* 2d */ Key::N,
+ /* 2e */ Key::M,
+ /* 2f */ Key::PERIOD,
+ /* 30 */ Key::TAB,
+ /* 31 */ Key::SPACE,
+ /* 32 */ Key::QUOTELEFT,
+ /* 33 */ Key::BACKSPACE,
+ /* 34 */ Key::UNKNOWN,
+ /* 35 */ Key::ESCAPE,
+ /* 36 */ Key::META,
+ /* 37 */ Key::META,
+ /* 38 */ Key::SHIFT,
+ /* 39 */ Key::CAPSLOCK,
+ /* 3a */ Key::ALT,
+ /* 3b */ Key::CTRL,
+ /* 3c */ Key::SHIFT,
+ /* 3d */ Key::ALT,
+ /* 3e */ Key::CTRL,
+ /* 3f */ Key::UNKNOWN, /* Function */
+ /* 40 */ Key::UNKNOWN, /* F17 */
+ /* 41 */ Key::KP_PERIOD,
+ /* 42 */ Key::UNKNOWN,
+ /* 43 */ Key::KP_MULTIPLY,
+ /* 44 */ Key::UNKNOWN,
+ /* 45 */ Key::KP_ADD,
+ /* 46 */ Key::UNKNOWN,
+ /* 47 */ Key::NUMLOCK, /* Really KeypadClear... */
+ /* 48 */ Key::VOLUMEUP, /* VolumeUp */
+ /* 49 */ Key::VOLUMEDOWN, /* VolumeDown */
+ /* 4a */ Key::VOLUMEMUTE, /* Mute */
+ /* 4b */ Key::KP_DIVIDE,
+ /* 4c */ Key::KP_ENTER,
+ /* 4d */ Key::UNKNOWN,
+ /* 4e */ Key::KP_SUBTRACT,
+ /* 4f */ Key::UNKNOWN, /* F18 */
+ /* 50 */ Key::UNKNOWN, /* F19 */
+ /* 51 */ Key::EQUAL, /* KeypadEqual */
+ /* 52 */ Key::KP_0,
+ /* 53 */ Key::KP_1,
+ /* 54 */ Key::KP_2,
+ /* 55 */ Key::KP_3,
+ /* 56 */ Key::KP_4,
+ /* 57 */ Key::KP_5,
+ /* 58 */ Key::KP_6,
+ /* 59 */ Key::KP_7,
+ /* 5a */ Key::UNKNOWN, /* F20 */
+ /* 5b */ Key::KP_8,
+ /* 5c */ Key::KP_9,
+ /* 5d */ Key::YEN, /* JIS Yen */
+ /* 5e */ Key::UNDERSCORE, /* JIS Underscore */
+ /* 5f */ Key::COMMA, /* JIS KeypadComma */
+ /* 60 */ Key::F5,
+ /* 61 */ Key::F6,
+ /* 62 */ Key::F7,
+ /* 63 */ Key::F3,
+ /* 64 */ Key::F8,
+ /* 65 */ Key::F9,
+ /* 66 */ Key::UNKNOWN, /* JIS Eisu */
+ /* 67 */ Key::F11,
+ /* 68 */ Key::UNKNOWN, /* JIS Kana */
+ /* 69 */ Key::F13,
+ /* 6a */ Key::F16,
+ /* 6b */ Key::F14,
+ /* 6c */ Key::UNKNOWN,
+ /* 6d */ Key::F10,
+ /* 6e */ Key::MENU,
+ /* 6f */ Key::F12,
+ /* 70 */ Key::UNKNOWN,
+ /* 71 */ Key::F15,
+ /* 72 */ Key::INSERT, /* Really Help... */
+ /* 73 */ Key::HOME,
+ /* 74 */ Key::PAGEUP,
+ /* 75 */ Key::KEY_DELETE,
+ /* 76 */ Key::F4,
+ /* 77 */ Key::END,
+ /* 78 */ Key::F2,
+ /* 79 */ Key::PAGEDOWN,
+ /* 7a */ Key::F1,
+ /* 7b */ Key::LEFT,
+ /* 7c */ Key::RIGHT,
+ /* 7d */ Key::DOWN,
+ /* 7e */ Key::UP,
+ /* 7f */ Key::UNKNOWN,
+};
+
// Translates a OS X keycode to a Godot keycode
-//
static Key translateKey(unsigned int key) {
- // Keyboard symbol translation table
- static const Key table[128] = {
- /* 00 */ KEY_A,
- /* 01 */ KEY_S,
- /* 02 */ KEY_D,
- /* 03 */ KEY_F,
- /* 04 */ KEY_H,
- /* 05 */ KEY_G,
- /* 06 */ KEY_Z,
- /* 07 */ KEY_X,
- /* 08 */ KEY_C,
- /* 09 */ KEY_V,
- /* 0a */ KEY_SECTION, /* ISO Section */
- /* 0b */ KEY_B,
- /* 0c */ KEY_Q,
- /* 0d */ KEY_W,
- /* 0e */ KEY_E,
- /* 0f */ KEY_R,
- /* 10 */ KEY_Y,
- /* 11 */ KEY_T,
- /* 12 */ KEY_1,
- /* 13 */ KEY_2,
- /* 14 */ KEY_3,
- /* 15 */ KEY_4,
- /* 16 */ KEY_6,
- /* 17 */ KEY_5,
- /* 18 */ KEY_EQUAL,
- /* 19 */ KEY_9,
- /* 1a */ KEY_7,
- /* 1b */ KEY_MINUS,
- /* 1c */ KEY_8,
- /* 1d */ KEY_0,
- /* 1e */ KEY_BRACERIGHT,
- /* 1f */ KEY_O,
- /* 20 */ KEY_U,
- /* 21 */ KEY_BRACELEFT,
- /* 22 */ KEY_I,
- /* 23 */ KEY_P,
- /* 24 */ KEY_ENTER,
- /* 25 */ KEY_L,
- /* 26 */ KEY_J,
- /* 27 */ KEY_APOSTROPHE,
- /* 28 */ KEY_K,
- /* 29 */ KEY_SEMICOLON,
- /* 2a */ KEY_BACKSLASH,
- /* 2b */ KEY_COMMA,
- /* 2c */ KEY_SLASH,
- /* 2d */ KEY_N,
- /* 2e */ KEY_M,
- /* 2f */ KEY_PERIOD,
- /* 30 */ KEY_TAB,
- /* 31 */ KEY_SPACE,
- /* 32 */ KEY_QUOTELEFT,
- /* 33 */ KEY_BACKSPACE,
- /* 34 */ KEY_UNKNOWN,
- /* 35 */ KEY_ESCAPE,
- /* 36 */ KEY_META,
- /* 37 */ KEY_META,
- /* 38 */ KEY_SHIFT,
- /* 39 */ KEY_CAPSLOCK,
- /* 3a */ KEY_ALT,
- /* 3b */ KEY_CTRL,
- /* 3c */ KEY_SHIFT,
- /* 3d */ KEY_ALT,
- /* 3e */ KEY_CTRL,
- /* 3f */ KEY_UNKNOWN, /* Function */
- /* 40 */ KEY_UNKNOWN, /* F17 */
- /* 41 */ KEY_KP_PERIOD,
- /* 42 */ KEY_UNKNOWN,
- /* 43 */ KEY_KP_MULTIPLY,
- /* 44 */ KEY_UNKNOWN,
- /* 45 */ KEY_KP_ADD,
- /* 46 */ KEY_UNKNOWN,
- /* 47 */ KEY_NUMLOCK, /* Really KeypadClear... */
- /* 48 */ KEY_VOLUMEUP, /* VolumeUp */
- /* 49 */ KEY_VOLUMEDOWN, /* VolumeDown */
- /* 4a */ KEY_VOLUMEMUTE, /* Mute */
- /* 4b */ KEY_KP_DIVIDE,
- /* 4c */ KEY_KP_ENTER,
- /* 4d */ KEY_UNKNOWN,
- /* 4e */ KEY_KP_SUBTRACT,
- /* 4f */ KEY_UNKNOWN, /* F18 */
- /* 50 */ KEY_UNKNOWN, /* F19 */
- /* 51 */ KEY_EQUAL, /* KeypadEqual */
- /* 52 */ KEY_KP_0,
- /* 53 */ KEY_KP_1,
- /* 54 */ KEY_KP_2,
- /* 55 */ KEY_KP_3,
- /* 56 */ KEY_KP_4,
- /* 57 */ KEY_KP_5,
- /* 58 */ KEY_KP_6,
- /* 59 */ KEY_KP_7,
- /* 5a */ KEY_UNKNOWN, /* F20 */
- /* 5b */ KEY_KP_8,
- /* 5c */ KEY_KP_9,
- /* 5d */ KEY_YEN, /* JIS Yen */
- /* 5e */ KEY_UNDERSCORE, /* JIS Underscore */
- /* 5f */ KEY_COMMA, /* JIS KeypadComma */
- /* 60 */ KEY_F5,
- /* 61 */ KEY_F6,
- /* 62 */ KEY_F7,
- /* 63 */ KEY_F3,
- /* 64 */ KEY_F8,
- /* 65 */ KEY_F9,
- /* 66 */ KEY_UNKNOWN, /* JIS Eisu */
- /* 67 */ KEY_F11,
- /* 68 */ KEY_UNKNOWN, /* JIS Kana */
- /* 69 */ KEY_F13,
- /* 6a */ KEY_F16,
- /* 6b */ KEY_F14,
- /* 6c */ KEY_UNKNOWN,
- /* 6d */ KEY_F10,
- /* 6e */ KEY_MENU,
- /* 6f */ KEY_F12,
- /* 70 */ KEY_UNKNOWN,
- /* 71 */ KEY_F15,
- /* 72 */ KEY_INSERT, /* Really Help... */
- /* 73 */ KEY_HOME,
- /* 74 */ KEY_PAGEUP,
- /* 75 */ KEY_DELETE,
- /* 76 */ KEY_F4,
- /* 77 */ KEY_END,
- /* 78 */ KEY_F2,
- /* 79 */ KEY_PAGEDOWN,
- /* 7a */ KEY_F1,
- /* 7b */ KEY_LEFT,
- /* 7c */ KEY_RIGHT,
- /* 7d */ KEY_DOWN,
- /* 7e */ KEY_UP,
- /* 7f */ KEY_UNKNOWN,
- };
-
if (key >= 128) {
- return KEY_UNKNOWN;
+ return Key::UNKNOWN;
}
- return table[key];
+ return _osx_to_godot_table[key];
+}
+
+// Translates a Godot keycode back to a OSX keycode
+static unsigned int unmapKey(Key key) {
+ for (int i = 0; i <= 126; i++) {
+ if (_osx_to_godot_table[i] == key) {
+ return i;
+ }
+ }
+ return 127;
}
struct _KeyCodeMap {
@@ -1078,61 +1077,61 @@ struct _KeyCodeMap {
};
static const _KeyCodeMap _keycodes[55] = {
- { '`', KEY_QUOTELEFT },
- { '~', KEY_ASCIITILDE },
- { '0', KEY_0 },
- { '1', KEY_1 },
- { '2', KEY_2 },
- { '3', KEY_3 },
- { '4', KEY_4 },
- { '5', KEY_5 },
- { '6', KEY_6 },
- { '7', KEY_7 },
- { '8', KEY_8 },
- { '9', KEY_9 },
- { '-', KEY_MINUS },
- { '_', KEY_UNDERSCORE },
- { '=', KEY_EQUAL },
- { '+', KEY_PLUS },
- { 'q', KEY_Q },
- { 'w', KEY_W },
- { 'e', KEY_E },
- { 'r', KEY_R },
- { 't', KEY_T },
- { 'y', KEY_Y },
- { 'u', KEY_U },
- { 'i', KEY_I },
- { 'o', KEY_O },
- { 'p', KEY_P },
- { '[', KEY_BRACELEFT },
- { ']', KEY_BRACERIGHT },
- { '{', KEY_BRACELEFT },
- { '}', KEY_BRACERIGHT },
- { 'a', KEY_A },
- { 's', KEY_S },
- { 'd', KEY_D },
- { 'f', KEY_F },
- { 'g', KEY_G },
- { 'h', KEY_H },
- { 'j', KEY_J },
- { 'k', KEY_K },
- { 'l', KEY_L },
- { ';', KEY_SEMICOLON },
- { ':', KEY_COLON },
- { '\'', KEY_APOSTROPHE },
- { '\"', KEY_QUOTEDBL },
- { '\\', KEY_BACKSLASH },
- { '#', KEY_NUMBERSIGN },
- { 'z', KEY_Z },
- { 'x', KEY_X },
- { 'c', KEY_C },
- { 'v', KEY_V },
- { 'b', KEY_B },
- { 'n', KEY_N },
- { 'm', KEY_M },
- { ',', KEY_COMMA },
- { '.', KEY_PERIOD },
- { '/', KEY_SLASH }
+ { '`', Key::QUOTELEFT },
+ { '~', Key::ASCIITILDE },
+ { '0', Key::KEY_0 },
+ { '1', Key::KEY_1 },
+ { '2', Key::KEY_2 },
+ { '3', Key::KEY_3 },
+ { '4', Key::KEY_4 },
+ { '5', Key::KEY_5 },
+ { '6', Key::KEY_6 },
+ { '7', Key::KEY_7 },
+ { '8', Key::KEY_8 },
+ { '9', Key::KEY_9 },
+ { '-', Key::MINUS },
+ { '_', Key::UNDERSCORE },
+ { '=', Key::EQUAL },
+ { '+', Key::PLUS },
+ { 'q', Key::Q },
+ { 'w', Key::W },
+ { 'e', Key::E },
+ { 'r', Key::R },
+ { 't', Key::T },
+ { 'y', Key::Y },
+ { 'u', Key::U },
+ { 'i', Key::I },
+ { 'o', Key::O },
+ { 'p', Key::P },
+ { '[', Key::BRACELEFT },
+ { ']', Key::BRACERIGHT },
+ { '{', Key::BRACELEFT },
+ { '}', Key::BRACERIGHT },
+ { 'a', Key::A },
+ { 's', Key::S },
+ { 'd', Key::D },
+ { 'f', Key::F },
+ { 'g', Key::G },
+ { 'h', Key::H },
+ { 'j', Key::J },
+ { 'k', Key::K },
+ { 'l', Key::L },
+ { ';', Key::SEMICOLON },
+ { ':', Key::COLON },
+ { '\'', Key::APOSTROPHE },
+ { '\"', Key::QUOTEDBL },
+ { '\\', Key::BACKSLASH },
+ { '#', Key::NUMBERSIGN },
+ { 'z', Key::Z },
+ { 'x', Key::X },
+ { 'c', Key::C },
+ { 'v', Key::V },
+ { 'b', Key::B },
+ { 'n', Key::N },
+ { 'm', Key::M },
+ { ',', Key::COMMA },
+ { '.', Key::PERIOD },
+ { '/', Key::SLASH }
};
static Key remapKey(unsigned int key, unsigned int state) {
@@ -1346,7 +1345,7 @@ inline void sendScrollEvent(DisplayServer::WindowID window_id, MouseButton butto
ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
- MouseButton mask = MouseButton(1 << (button - 1));
+ MouseButton mask = mouse_button_to_mask(button);
Ref<InputEventMouseButton> sc;
sc.instantiate();
@@ -1419,10 +1418,10 @@ inline void sendPanEvent(DisplayServer::WindowID window_id, double dx, double dy
sendPanEvent(window_id, deltaX, deltaY, [event modifierFlags]);
} else {
if (fabs(deltaX)) {
- sendScrollEvent(window_id, 0 > deltaX ? MOUSE_BUTTON_WHEEL_RIGHT : MOUSE_BUTTON_WHEEL_LEFT, fabs(deltaX * 0.3), [event modifierFlags]);
+ sendScrollEvent(window_id, 0 > deltaX ? MouseButton::WHEEL_RIGHT : MouseButton::WHEEL_LEFT, fabs(deltaX * 0.3), [event modifierFlags]);
}
if (fabs(deltaY)) {
- sendScrollEvent(window_id, 0 < deltaY ? MOUSE_BUTTON_WHEEL_UP : MOUSE_BUTTON_WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]);
+ sendScrollEvent(window_id, 0 < deltaY ? MouseButton::WHEEL_UP : MouseButton::WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]);
}
}
}
@@ -1921,6 +1920,7 @@ void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) {
return;
}
+ WindowData &wd = windows[MAIN_WINDOW_ID];
if (p_mode == MOUSE_MODE_CAPTURED) {
// Apple Docs state that the display parameter is not used.
// "This parameter is not used. By default, you may pass kCGDirectMainDisplay."
@@ -1929,7 +1929,7 @@ void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) {
CGDisplayHideCursor(kCGDirectMainDisplay);
}
CGAssociateMouseAndMouseCursorPosition(false);
- WindowData &wd = windows[MAIN_WINDOW_ID];
+ [wd.window_object setMovable:NO];
const NSRect contentRect = [wd.window_view frame];
NSRect pointInWindowRect = NSMakeRect(contentRect.size.width / 2, contentRect.size.height / 2, 0, 0);
NSPoint pointOnScreen = [[wd.window_view window] convertRectToScreen:pointInWindowRect].origin;
@@ -1939,17 +1939,21 @@ void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) {
if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
CGDisplayHideCursor(kCGDirectMainDisplay);
}
+ [wd.window_object setMovable:YES];
CGAssociateMouseAndMouseCursorPosition(true);
} else if (p_mode == MOUSE_MODE_CONFINED) {
CGDisplayShowCursor(kCGDirectMainDisplay);
+ [wd.window_object setMovable:NO];
CGAssociateMouseAndMouseCursorPosition(false);
} else if (p_mode == MOUSE_MODE_CONFINED_HIDDEN) {
if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
CGDisplayHideCursor(kCGDirectMainDisplay);
}
+ [wd.window_object setMovable:NO];
CGAssociateMouseAndMouseCursorPosition(false);
} else { // MOUSE_MODE_VISIBLE
CGDisplayShowCursor(kCGDirectMainDisplay);
+ [wd.window_object setMovable:YES];
CGAssociateMouseAndMouseCursorPosition(true);
}
@@ -2577,8 +2581,8 @@ void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled
//TODO - implement transparency for Vulkan
}
#endif
-#if defined(OPENGL_ENABLED)
- if (rendering_driver == "opengl_es") {
+#if defined(GLES3_ENABLED)
+ if (rendering_driver == "opengl3") {
//TODO - reimplement OpenGLES
}
#endif
@@ -2596,15 +2600,15 @@ void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled
//TODO - implement transparency for Vulkan
}
#endif
-#if defined(OPENGL_ENABLED)
- if (rendering_driver == "opengl_es") {
+#if defined(GLES3_ENABLED)
+ if (rendering_driver == "opengl3") {
//TODO - reimplement OpenGLES
}
#endif
wd.layered_window = false;
}
-#if defined(OPENGL_ENABLED)
- if (rendering_driver == "opengl_es") {
+#if defined(GLES3_ENABLED)
+ if (rendering_driver == "opengl3") {
//TODO - reimplement OpenGLES
}
#endif
@@ -3005,7 +3009,7 @@ void DisplayServerOSX::cursor_set_custom_image(const RES &p_cursor, CursorShape
ERR_FAIL_COND(!image.is_valid());
NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
- initWithBitmapDataPlanes:NULL
+ initWithBitmapDataPlanes:nullptr
pixelsWide:int(texture_size.width)
pixelsHigh:int(texture_size.height)
bitsPerSample:8
@@ -3200,6 +3204,17 @@ String DisplayServerOSX::keyboard_get_layout_name(int p_index) const {
return kbd_layouts[p_index].name;
}
+Key DisplayServerOSX::keyboard_get_keycode_from_physical(Key p_keycode) const {
+ if (p_keycode == Key::PAUSE) {
+ return p_keycode;
+ }
+
+ Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK;
+ Key keycode_no_mod = p_keycode & KeyModifierMask::CODE_MASK;
+ unsigned int osx_keycode = unmapKey((Key)keycode_no_mod);
+ return (Key)(remapKey(osx_keycode, 0) | modifiers);
+}
+
void DisplayServerOSX::_push_input(const Ref<InputEvent> &p_event) {
Ref<InputEvent> ev = p_event;
Input::get_singleton()->parse_input_event(ev);
@@ -3253,8 +3268,8 @@ void DisplayServerOSX::_send_event(NSEvent *p_event) {
_get_key_modifier_state([p_event modifierFlags], k);
k->set_window_id(DisplayServerOSX::INVALID_WINDOW_ID);
k->set_pressed(true);
- k->set_keycode(KEY_PERIOD);
- k->set_physical_keycode(KEY_PERIOD);
+ k->set_keycode(Key::PERIOD);
+ k->set_physical_keycode(Key::PERIOD);
k->set_echo([p_event isARepeat]);
Input::get_singleton()->parse_input_event(k);
@@ -3281,20 +3296,20 @@ void DisplayServerOSX::_process_key_events() {
_push_input(k);
} else {
// IME input
- if ((i == 0 && ke.keycode == 0) || (i > 0 && key_event_buffer[i - 1].keycode == 0)) {
+ if ((i == 0 && ke.keycode == Key::NONE) || (i > 0 && key_event_buffer[i - 1].keycode == Key::NONE)) {
k.instantiate();
k->set_window_id(ke.window_id);
_get_key_modifier_state(ke.osx_state, k);
k->set_pressed(ke.pressed);
k->set_echo(ke.echo);
- k->set_keycode(KEY_NONE);
- k->set_physical_keycode(KEY_NONE);
+ k->set_keycode(Key::NONE);
+ k->set_physical_keycode(Key::NONE);
k->set_unicode(ke.unicode);
_push_input(k);
}
- if (ke.keycode != 0) {
+ if (ke.keycode != Key::NONE) {
k.instantiate();
k->set_window_id(ke.window_id);
@@ -3304,7 +3319,7 @@ void DisplayServerOSX::_process_key_events() {
k->set_keycode(ke.keycode);
k->set_physical_keycode((Key)ke.physical_keycode);
- if (i + 1 < key_event_pos && key_event_buffer[i + 1].keycode == 0) {
+ if (i + 1 < key_event_pos && key_event_buffer[i + 1].keycode == Key::NONE) {
k->set_unicode(key_event_buffer[i + 1].unicode);
}
@@ -3398,7 +3413,7 @@ void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) {
img = img->duplicate();
img->convert(Image::FORMAT_RGBA8);
NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
- initWithBitmapDataPlanes:NULL
+ initWithBitmapDataPlanes:nullptr
pixelsWide:img->get_width()
pixelsHigh:img->get_height()
bitsPerSample:8
@@ -3435,18 +3450,31 @@ void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) {
void DisplayServerOSX::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
_THREAD_SAFE_METHOD_
+#if defined(GLES3_ENABLED)
+ if (rendering_driver == "opengl3") {
+ gl_manager->swap_buffers();
+ }
+#endif
#if defined(VULKAN_ENABLED)
- context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+ if (rendering_driver == "vulkan") {
+ context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+ }
#endif
}
DisplayServer::VSyncMode DisplayServerOSX::window_get_vsync_mode(WindowID p_window) const {
_THREAD_SAFE_METHOD_
+#if defined(GLES3_ENABLED)
+ if (rendering_driver == "opengl3") {
+ return (gl_manager->is_using_vsync() ? DisplayServer::VSyncMode::VSYNC_ENABLED : DisplayServer::VSyncMode::VSYNC_DISABLED);
+ }
+#endif
#if defined(VULKAN_ENABLED)
- return context_vulkan->get_vsync_mode(p_window);
-#else
- return DisplayServer::VSYNC_ENABLED;
+ if (rendering_driver == "vulkan") {
+ return context_vulkan->get_vsync_mode(p_window);
+ }
#endif
+ return DisplayServer::VSYNC_ENABLED;
}
Vector<String> DisplayServerOSX::get_rendering_drivers_func() {
@@ -3455,13 +3483,19 @@ Vector<String> DisplayServerOSX::get_rendering_drivers_func() {
#if defined(VULKAN_ENABLED)
drivers.push_back("vulkan");
#endif
-#if defined(OPENGL_ENABLED)
- drivers.push_back("opengl_es");
+#if defined(GLES3_ENABLED)
+ drivers.push_back("opengl3");
#endif
return drivers;
}
+void DisplayServerOSX::gl_window_make_current(DisplayServer::WindowID p_window_id) {
+#if defined(GLES3_ENABLED)
+ gl_manager->window_make_current(p_window_id);
+#endif
+}
+
Point2i DisplayServerOSX::ime_get_selection() const {
return im_selection;
}
@@ -3502,7 +3536,7 @@ ObjectID DisplayServerOSX::window_get_attached_instance_id(WindowID p_window) co
DisplayServer *DisplayServerOSX::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
DisplayServer *ds = memnew(DisplayServerOSX(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
if (r_error != OK) {
- OS::get_singleton()->alert("Your video card driver does not support any of the supported Metal versions.", "Unable to initialize Video driver");
+ OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.", "Unable to initialize Video driver");
}
return ds;
}
@@ -3559,9 +3593,12 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, V
}
}
#endif
-#if defined(OPENGL_ENABLED)
- if (rendering_driver == "opengl_es") {
- //TODO - reimplement OpenGLES
+#if defined(GLES3_ENABLED)
+ if (rendering_driver == "opengl3") {
+ if (gl_manager) {
+ Error err = gl_manager->window_create(window_id_counter, wd.window_view, p_rect.size.width, p_rect.size.height);
+ ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL context");
+ }
}
#endif
id = window_id_counter++;
@@ -3580,9 +3617,9 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, V
layer.contentsScale = scale;
}
-#if defined(OPENGL_ENABLED)
- if (rendering_driver == "opengl_es") {
- //TODO - reimplement OpenGLES
+#if defined(GLES3_ENABLED)
+ if (rendering_driver == "opengl3") {
+ gl_manager->window_resize(id, wd.size.width, wd.size.height);
}
#endif
#if defined(VULKAN_ENABLED)
@@ -3634,15 +3671,15 @@ void DisplayServerOSX::_dispatch_input_event(const Ref<InputEvent> &p_event) {
}
void DisplayServerOSX::release_rendering_thread() {
- //TODO - reimplement OpenGLES
}
void DisplayServerOSX::make_rendering_thread() {
- //TODO - reimplement OpenGLES
}
void DisplayServerOSX::swap_buffers() {
- //TODO - reimplement OpenGLES
+#if defined(GLES3_ENABLED)
+ gl_manager->swap_buffers();
+#endif
}
void DisplayServerOSX::console_set_visible(bool p_enabled) {
@@ -3730,17 +3767,20 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
[main_menu setSubmenu:apple_menu forItem:menu_item];
//!!!!!!!!!!!!!!!!!!!!!!!!!!
- //TODO - do Vulkan and GLES2 support checks, driver selection and fallback
+ //TODO - do Vulkan and OpenGL support checks, driver selection and fallback
rendering_driver = p_rendering_driver;
-#ifndef _MSC_VER
-#warning Forcing vulkan rendering driver because OpenGL not implemented yet
-#endif
- rendering_driver = "vulkan";
-
-#if defined(OPENGL_ENABLED)
- if (rendering_driver == "opengl_es") {
- //TODO - reimplement OpenGLES
+#if defined(GLES3_ENABLED)
+ if (rendering_driver == "opengl3") {
+ GLManager_OSX::ContextType opengl_api_type = GLManager_OSX::GLES_3_0_COMPATIBLE;
+ gl_manager = memnew(GLManager_OSX(opengl_api_type));
+ if (gl_manager->initialize() != OK) {
+ memdelete(gl_manager);
+ gl_manager = nullptr;
+ r_error = ERR_UNAVAILABLE;
+ ERR_FAIL_MSG("Could not initialize OpenGL");
+ return;
+ }
}
#endif
#if defined(VULKAN_ENABLED)
@@ -3767,9 +3807,9 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
}
show_window(MAIN_WINDOW_ID);
-#if defined(OPENGL_ENABLED)
- if (rendering_driver == "opengl_es") {
- //TODO - reimplement OpenGLES
+#if defined(GLES3_ENABLED)
+ if (rendering_driver == "opengl3") {
+ RasterizerGLES3::make_current();
}
#endif
#if defined(VULKAN_ENABLED)
@@ -3800,21 +3840,22 @@ DisplayServerOSX::~DisplayServerOSX() {
}
//destroy drivers
-#if defined(OPENGL_ENABLED)
- if (rendering_driver == "opengl_es") {
- //TODO - reimplement OpenGLES
+#if defined(GLES3_ENABLED)
+ if (gl_manager) {
+ memdelete(gl_manager);
+ gl_manager = nullptr;
}
#endif
#if defined(VULKAN_ENABLED)
- if (rendering_driver == "vulkan") {
- if (rendering_device_vulkan) {
- rendering_device_vulkan->finalize();
- memdelete(rendering_device_vulkan);
- }
+ if (rendering_device_vulkan) {
+ rendering_device_vulkan->finalize();
+ memdelete(rendering_device_vulkan);
+ rendering_device_vulkan = nullptr;
+ }
- if (context_vulkan) {
- memdelete(context_vulkan);
- }
+ if (context_vulkan) {
+ memdelete(context_vulkan);
+ context_vulkan = nullptr;
}
#endif
diff --git a/platform/osx/export/export_plugin.cpp b/platform/osx/export/export_plugin.cpp
index 54a3104482..a88f7bb332 100644
--- a/platform/osx/export/export_plugin.cpp
+++ b/platform/osx/export/export_plugin.cpp
@@ -95,6 +95,7 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_pictures", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_music", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_movies", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::ARRAY, "codesign/entitlements/app_sandbox/helper_executables", PROPERTY_HINT_ARRAY_TYPE, itos(Variant::STRING) + "/" + itos(PROPERTY_HINT_GLOBAL_FILE) + ":"), Array()));
r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
@@ -324,11 +325,11 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset
}
/**
- If we're running the OSX version of the Godot editor we'll:
- - export our application bundle to a temporary folder
- - attempt to code sign it
- - and then wrap it up in a DMG
-**/
+ * If we're running the OSX version of the Godot editor we'll:
+ * - export our application bundle to a temporary folder
+ * - attempt to code sign it
+ * - and then wrap it up in a DMG
+ */
Error EditorExportPlatformOSX::_notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
#ifdef OSX_ENABLED
@@ -535,6 +536,8 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
err = ERR_CANT_CREATE;
}
+ Array helpers = p_preset->get("codesign/entitlements/app_sandbox/helper_executables");
+
// Create our folder structure.
if (err == OK) {
print_line("Creating " + tmp_app_path_name + "/Contents/MacOS");
@@ -546,6 +549,11 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks");
}
+ if ((err == OK) && helpers.size() > 0) {
+ print_line("Creating " + tmp_app_path_name + "/Contents/Helpers");
+ err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Helpers");
+ }
+
if (err == OK) {
print_line("Creating " + tmp_app_path_name + "/Contents/Resources");
err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Resources");
@@ -553,7 +561,6 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
// Now process our template.
bool found_binary = false;
- int total_size = 0;
Vector<String> dylibs_found;
while (ret == UNZ_OK && err == OK) {
@@ -641,7 +648,6 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
}
print_line("ADDING: " + file + " size: " + itos(data.size()));
- total_size += data.size();
// Write it into our application bundle.
file = tmp_app_path_name.plus_file(file);
@@ -688,6 +694,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
bool sign_enabled = p_preset->get("codesign/enable");
String ent_path = p_preset->get("codesign/entitlements/custom_file");
+ String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + "_helper.entitlements");
if (sign_enabled && (ent_path == "")) {
ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + ".entitlements");
@@ -819,10 +826,43 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
} else {
err = ERR_CANT_CREATE;
}
+
+ if ((err == OK) && helpers.size() > 0) {
+ ent_f = FileAccess::open(hlp_ent_path, FileAccess::WRITE);
+ if (ent_f) {
+ ent_f->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ ent_f->store_line("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
+ ent_f->store_line("<plist version=\"1.0\">");
+ ent_f->store_line("<dict>");
+ ent_f->store_line("<key>com.apple.security.app-sandbox</key>");
+ ent_f->store_line("<true/>");
+ ent_f->store_line("<key>com.apple.security.inherit</key>");
+ ent_f->store_line("<true/>");
+ ent_f->store_line("</dict>");
+ ent_f->store_line("</plist>");
+
+ ent_f->close();
+ memdelete(ent_f);
+ } else {
+ err = ERR_CANT_CREATE;
+ }
+ }
+ }
+
+ if ((err == OK) && helpers.size() > 0) {
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ for (int i = 0; i < helpers.size(); i++) {
+ String hlp_path = helpers[i];
+ err = da->copy(hlp_path, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file());
+ if (err == OK && sign_enabled) {
+ err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), hlp_ent_path);
+ }
+ FileAccess::set_unix_permissions(tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), 0755);
+ }
}
if (err == OK) {
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
for (int i = 0; i < shared_objects.size(); i++) {
String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path);
if (da->dir_exists(src_path)) {
@@ -842,7 +882,6 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(), ent_path);
}
}
- memdelete(da);
}
if (sign_enabled) {
@@ -903,6 +942,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
err = _notarize(p_preset, p_path);
}
+ // Clean up temporary entitlements files.
+ DirAccess::remove_file_or_error(hlp_ent_path);
+
// Clean up temporary .app dir.
tmp_app_dir->change_dir(tmp_app_path_name);
tmp_app_dir->erase_contents_recursive();
@@ -916,7 +958,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) {
String dir = p_root_path.plus_file(p_folder);
- DirAccess *da = DirAccess::open(dir);
+ DirAccessRef da = DirAccess::open(dir);
da->list_dir_begin();
String f;
while ((f = da->get_next()) != "") {
@@ -967,7 +1009,7 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String
} else if (da->current_is_dir()) {
_zip_folder_recursive(p_zip, p_root_path, p_folder.plus_file(f), p_pkg_name);
} else {
- bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name));
+ bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name)) || p_folder.ends_with("Helpers");
OS::Time time = OS::get_singleton()->get_time();
OS::Date date = OS::get_singleton()->get_date();
@@ -1006,13 +1048,25 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String
0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
0);
- Vector<uint8_t> array = FileAccess::get_file_as_array(dir.plus_file(f));
- zipWriteInFileInZip(p_zip, array.ptr(), array.size());
+ FileAccessRef fa = FileAccess::open(dir.plus_file(f), FileAccess::READ);
+ if (!fa) {
+ ERR_FAIL_MSG("Can't open file to read from path '" + String(dir.plus_file(f)) + "'.");
+ }
+ const int bufsize = 16384;
+ uint8_t buf[bufsize];
+
+ while (true) {
+ uint64_t got = fa->get_buffer(buf, bufsize);
+ if (got == 0) {
+ break;
+ }
+ zipWriteInFileInZip(p_zip, buf, got);
+ }
+
zipCloseFileInZip(p_zip);
}
}
da->list_dir_end();
- memdelete(da);
}
bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
diff --git a/platform/osx/export/export_plugin.h b/platform/osx/export/export_plugin.h
index cd85ce2aad..ca5086622e 100644
--- a/platform/osx/export/export_plugin.h
+++ b/platform/osx/export/export_plugin.h
@@ -115,7 +115,7 @@ public:
virtual void get_platform_features(List<String> *r_features) override {
r_features->push_back("pc");
r_features->push_back("s3tc");
- r_features->push_back("macOS");
+ r_features->push_back("macos");
}
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override {
diff --git a/platform/osx/context_gl_osx.h b/platform/osx/gl_manager_osx.h
index ac45559217..f86bc805c1 100644
--- a/platform/osx/context_gl_osx.h
+++ b/platform/osx/gl_manager_osx.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* context_gl_osx.h */
+/* gl_manager_osx.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,47 +28,79 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef CONTEXT_GL_OSX_H
-#define CONTEXT_GL_OSX_H
+#ifndef GL_MANAGER_OSX_H
+#define GL_MANAGER_OSX_H
-#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED)
+#if defined(OSX_ENABLED) && defined(GLES3_ENABLED)
#include "core/error/error_list.h"
#include "core/os/os.h"
+#include "core/templates/local_vector.h"
+#include "servers/display_server.h"
#include <AppKit/AppKit.h>
#include <ApplicationServices/ApplicationServices.h>
#include <CoreVideo/CoreVideo.h>
-class ContextGL_OSX {
- bool opengl_3_context;
- bool use_vsync;
+class GLManager_OSX {
+public:
+ enum ContextType {
+ GLES_3_0_COMPATIBLE,
+ };
+
+private:
+ struct GLWindow {
+ GLWindow() { in_use = false; }
+ bool in_use;
+
+ DisplayServer::WindowID window_id;
+ int width;
+ int height;
+
+ id window_view;
+ NSOpenGLContext *context;
+ };
+
+ LocalVector<GLWindow> _windows;
+
+ NSOpenGLContext *_shared_context = nullptr;
+ GLWindow *_current_window;
+
+ Error _create_context(GLWindow &win);
+ void _internal_set_current_window(GLWindow *p_win);
- void *framework;
- id window_view;
- NSOpenGLPixelFormat *pixelFormat;
- NSOpenGLContext *context;
+ GLWindow &get_window(unsigned int id) { return _windows[id]; }
+ const GLWindow &get_window(unsigned int id) const { return _windows[id]; }
+
+ bool use_vsync;
+ ContextType context_type;
public:
- void release_current();
+ Error window_create(DisplayServer::WindowID p_window_id, id p_view, int p_width, int p_height);
+ void window_destroy(DisplayServer::WindowID p_window_id);
+ void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
+
+ // get directly from the cached GLWindow
+ int window_get_width(DisplayServer::WindowID p_window_id = 0);
+ int window_get_height(DisplayServer::WindowID p_window_id = 0);
+ void release_current();
void make_current();
- void update();
+ void swap_buffers();
- void set_opacity(GLint p_opacity);
+ void window_make_current(DisplayServer::WindowID p_window_id);
- int get_window_width();
- int get_window_height();
- void swap_buffers();
+ void window_update(DisplayServer::WindowID p_window_id);
Error initialize();
void set_use_vsync(bool p_use);
bool is_using_vsync() const;
- ContextGL_OSX(id p_view, bool p_opengl_3_context);
- ~ContextGL_OSX();
+ GLManager_OSX(ContextType p_context_type);
+ ~GLManager_OSX();
};
-#endif
-#endif
+#endif // defined(OSX_ENABLED) && defined(GLES3_ENABLED)
+
+#endif // GL_MANAGER_OSX_H
diff --git a/platform/osx/gl_manager_osx.mm b/platform/osx/gl_manager_osx.mm
new file mode 100644
index 0000000000..60e0706fc0
--- /dev/null
+++ b/platform/osx/gl_manager_osx.mm
@@ -0,0 +1,233 @@
+/*************************************************************************/
+/* gl_manager_osx.mm */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 "gl_manager_osx.h"
+
+#ifdef OSX_ENABLED
+#ifdef GLES3_ENABLED
+
+#include <stdio.h>
+#include <stdlib.h>
+
+Error GLManager_OSX::_create_context(GLWindow &win) {
+ NSOpenGLPixelFormatAttribute attributes[] = {
+ NSOpenGLPFADoubleBuffer,
+ NSOpenGLPFAClosestPolicy,
+ NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
+ NSOpenGLPFAColorSize, 32,
+ NSOpenGLPFADepthSize, 24,
+ NSOpenGLPFAStencilSize, 8,
+ 0
+ };
+
+ NSOpenGLPixelFormat *pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
+ ERR_FAIL_COND_V(pixel_format == nil, ERR_CANT_CREATE);
+
+ win.context = [[NSOpenGLContext alloc] initWithFormat:pixel_format shareContext:_shared_context];
+ ERR_FAIL_COND_V(win.context == nil, ERR_CANT_CREATE);
+ if (_shared_context == nullptr) {
+ _shared_context = win.context;
+ }
+
+ [win.context setView:win.window_view];
+ [win.context makeCurrentContext];
+
+ return OK;
+}
+
+Error GLManager_OSX::window_create(DisplayServer::WindowID p_window_id, id p_view, int p_width, int p_height) {
+ if (p_window_id >= (int)_windows.size()) {
+ _windows.resize(p_window_id + 1);
+ }
+
+ GLWindow &win = _windows[p_window_id];
+ win.in_use = true;
+ win.window_id = p_window_id;
+ win.width = p_width;
+ win.height = p_height;
+ win.window_view = p_view;
+
+ if (_create_context(win) != OK) {
+ _windows.remove_at(_windows.size() - 1);
+ return FAILED;
+ }
+
+ window_make_current(_windows.size() - 1);
+
+ return OK;
+}
+
+void GLManager_OSX::_internal_set_current_window(GLWindow *p_win) {
+ _current_window = p_win;
+}
+
+void GLManager_OSX::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {
+ if (p_window_id == -1) {
+ return;
+ }
+
+ GLWindow &win = _windows[p_window_id];
+ if (!win.in_use) {
+ return;
+ }
+
+ win.width = p_width;
+ win.height = p_height;
+
+ GLint dim[2];
+ dim[0] = p_width;
+ dim[1] = p_height;
+ CGLSetParameter((CGLContextObj)[win.context CGLContextObj], kCGLCPSurfaceBackingSize, &dim[0]);
+ CGLEnable((CGLContextObj)[win.context CGLContextObj], kCGLCESurfaceBackingSize);
+ if (OS::get_singleton()->is_hidpi_allowed()) {
+ [win.window_view setWantsBestResolutionOpenGLSurface:YES];
+ } else {
+ [win.window_view setWantsBestResolutionOpenGLSurface:NO];
+ }
+
+ [win.context update];
+}
+
+int GLManager_OSX::window_get_width(DisplayServer::WindowID p_window_id) {
+ return get_window(p_window_id).width;
+}
+
+int GLManager_OSX::window_get_height(DisplayServer::WindowID p_window_id) {
+ return get_window(p_window_id).height;
+}
+
+void GLManager_OSX::window_destroy(DisplayServer::WindowID p_window_id) {
+ GLWindow &win = get_window(p_window_id);
+ win.in_use = false;
+
+ if (_current_window == &win) {
+ _current_window = nullptr;
+ }
+}
+
+void GLManager_OSX::release_current() {
+ if (!_current_window) {
+ return;
+ }
+
+ [NSOpenGLContext clearCurrentContext];
+}
+
+void GLManager_OSX::window_make_current(DisplayServer::WindowID p_window_id) {
+ if (p_window_id == -1) {
+ return;
+ }
+
+ GLWindow &win = _windows[p_window_id];
+ if (!win.in_use) {
+ return;
+ }
+
+ if (&win == _current_window) {
+ return;
+ }
+
+ [win.context makeCurrentContext];
+
+ _internal_set_current_window(&win);
+}
+
+void GLManager_OSX::make_current() {
+ if (!_current_window) {
+ return;
+ }
+ if (!_current_window->in_use) {
+ WARN_PRINT("current window not in use!");
+ return;
+ }
+ [_current_window->context makeCurrentContext];
+}
+
+void GLManager_OSX::swap_buffers() {
+ // NO NEED TO CALL SWAP BUFFERS for each window...
+ // see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glXSwapBuffers.xml
+
+ if (!_current_window) {
+ return;
+ }
+ if (!_current_window->in_use) {
+ WARN_PRINT("current window not in use!");
+ return;
+ }
+ [_current_window->context flushBuffer];
+}
+
+void GLManager_OSX::window_update(DisplayServer::WindowID p_window_id) {
+ if (p_window_id == -1) {
+ return;
+ }
+
+ GLWindow &win = _windows[p_window_id];
+ if (!win.in_use) {
+ return;
+ }
+
+ if (&win == _current_window) {
+ return;
+ }
+
+ [win.context update];
+}
+
+Error GLManager_OSX::initialize() {
+ return OK;
+}
+
+void GLManager_OSX::set_use_vsync(bool p_use) {
+ use_vsync = p_use;
+ CGLContextObj ctx = CGLGetCurrentContext();
+ if (ctx) {
+ GLint swapInterval = p_use ? 1 : 0;
+ CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval);
+ use_vsync = p_use;
+ }
+}
+
+bool GLManager_OSX::is_using_vsync() const {
+ return use_vsync;
+}
+
+GLManager_OSX::GLManager_OSX(ContextType p_context_type) {
+ context_type = p_context_type;
+ use_vsync = false;
+ _current_window = nullptr;
+}
+
+GLManager_OSX::~GLManager_OSX() {
+ release_current();
+}
+
+#endif // GLES3_ENABLED
+#endif // OSX
diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp
index e67d2b0e91..48d165d30b 100644
--- a/platform/osx/joypad_osx.cpp
+++ b/platform/osx/joypad_osx.cpp
@@ -58,6 +58,7 @@ void joypad::free() {
if (ff_device) {
FFDeviceReleaseEffect(ff_device, ff_object);
FFReleaseDevice(ff_device);
+ ff_device = nullptr;
memfree(ff_axes);
memfree(ff_directions);
}
@@ -243,7 +244,7 @@ void JoypadOSX::_device_added(IOReturn p_res, IOHIDDeviceRef p_device) {
if (is_joypad(p_device)) {
configure_joypad(p_device, &new_joypad);
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
- if (IOHIDDeviceGetService != nullptr) {
+ if (IOHIDDeviceGetService) {
#endif
const io_service_t ioservice = IOHIDDeviceGetService(p_device);
if ((ioservice) && (FFIsForceFeedback(ioservice) == FF_OK) && new_joypad.config_force_feedback(ioservice)) {
@@ -263,7 +264,7 @@ void JoypadOSX::_device_removed(IOReturn p_res, IOHIDDeviceRef p_device) {
input->joy_connection_changed(device_list[device].id, false, "");
device_list.write[device].free();
- device_list.remove(device);
+ device_list.remove_at(device);
}
static String _hex_str(uint8_t p_byte) {
@@ -336,10 +337,10 @@ bool JoypadOSX::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) {
}
// Xbox controller hat values start at 1 rather than 0.
p_joy->offset_hat = vendor == 0x45e &&
- (product_id == 0x0b05 ||
- product_id == 0x02e0 ||
- product_id == 0x02fd ||
- product_id == 0x0b13);
+ (product_id == 0x0b05 ||
+ product_id == 0x02e0 ||
+ product_id == 0x02fd ||
+ product_id == 0x0b13);
return true;
}
@@ -348,6 +349,7 @@ bool JoypadOSX::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) {
{ \
if (ret != FF_OK) { \
FFReleaseDevice(ff_device); \
+ ff_device = nullptr; \
return false; \
} \
}
@@ -367,6 +369,7 @@ bool joypad::config_force_feedback(io_service_t p_service) {
return true;
}
FFReleaseDevice(ff_device);
+ ff_device = nullptr;
return false;
}
#undef FF_ERR
@@ -397,10 +400,10 @@ bool joypad::check_ff_features() {
return false;
}
-static int process_hat_value(int p_min, int p_max, int p_value, bool p_offset_hat) {
+static HatMask process_hat_value(int p_min, int p_max, int p_value, bool p_offset_hat) {
int range = (p_max - p_min + 1);
int value = p_value - p_min;
- int hat_value = HatMask::HAT_MASK_CENTER;
+ HatMask hat_value = HatMask::CENTER;
if (range == 4) {
value *= 2;
}
@@ -410,31 +413,31 @@ static int process_hat_value(int p_min, int p_max, int p_value, bool p_offset_ha
switch (value) {
case 0:
- hat_value = (HatMask)HatMask::HAT_MASK_UP;
+ hat_value = HatMask::UP;
break;
case 1:
- hat_value = (HatMask)(HatMask::HAT_MASK_UP | HatMask::HAT_MASK_RIGHT);
+ hat_value = (HatMask::UP | HatMask::RIGHT);
break;
case 2:
- hat_value = (HatMask)HatMask::HAT_MASK_RIGHT;
+ hat_value = HatMask::RIGHT;
break;
case 3:
- hat_value = (HatMask)(HatMask::HAT_MASK_DOWN | HatMask::HAT_MASK_RIGHT);
+ hat_value = (HatMask::DOWN | HatMask::RIGHT);
break;
case 4:
- hat_value = (HatMask)HatMask::HAT_MASK_DOWN;
+ hat_value = HatMask::DOWN;
break;
case 5:
- hat_value = (HatMask)(HatMask::HAT_MASK_DOWN | HatMask::HAT_MASK_LEFT);
+ hat_value = (HatMask::DOWN | HatMask::LEFT);
break;
case 6:
- hat_value = (HatMask)HatMask::HAT_MASK_LEFT;
+ hat_value = HatMask::LEFT;
break;
case 7:
- hat_value = (HatMask)(HatMask::HAT_MASK_UP | HatMask::HAT_MASK_LEFT);
+ hat_value = (HatMask::UP | HatMask::LEFT);
break;
default:
- hat_value = (HatMask)HatMask::HAT_MASK_CENTER;
+ hat_value = HatMask::CENTER;
break;
}
return hat_value;
@@ -480,8 +483,8 @@ void JoypadOSX::process_joypads() {
for (int j = 0; j < joy.hat_elements.size(); j++) {
rec_element &elem = joy.hat_elements.write[j];
int value = joy.get_hid_element_state(&elem);
- int hat_value = process_hat_value(elem.min, elem.max, value, joy.offset_hat);
- input->joy_hat(joy.id, (HatMask)hat_value);
+ HatMask hat_value = process_hat_value(elem.min, elem.max, value, joy.offset_hat);
+ input->joy_hat(joy.id, hat_value);
}
if (joy.ffservice) {
@@ -601,7 +604,7 @@ JoypadOSX::JoypadOSX(Input *in) {
if (array) {
hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
- if (hid_manager != nullptr) {
+ if (hid_manager) {
config_hid_manager(array);
}
CFRelease(array);
diff --git a/platform/osx/joypad_osx.h b/platform/osx/joypad_osx.h
index c060c3d523..2ba7f0d950 100644
--- a/platform/osx/joypad_osx.h
+++ b/platform/osx/joypad_osx.h
@@ -68,8 +68,8 @@ struct joypad {
io_service_t ffservice = 0; /* Interface for force feedback, 0 = no ff */
FFCONSTANTFORCE ff_constant_force;
- FFDeviceObjectReference ff_device;
- FFEffectObjectReference ff_object;
+ FFDeviceObjectReference ff_device = nullptr;
+ FFEffectObjectReference ff_object = nullptr;
uint64_t ff_timestamp = 0;
LONG *ff_directions = nullptr;
FFEFFECT ff_effect;
@@ -106,7 +106,6 @@ private:
int get_joy_ref(IOHIDDeviceRef p_device) const;
void poll_joypads() const;
- void setup_joypad_objects();
void config_hid_manager(CFArrayRef p_matching_array) const;
void joypad_vibration_start(int p_id, float p_magnitude, float p_duration, uint64_t p_timestamp);
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index df41ccd892..7e02f4e154 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -57,6 +57,8 @@ class OS_OSX : public OS_Unix {
MainLoop *main_loop;
+ static void pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context);
+
public:
String open_with_filename;
@@ -82,6 +84,7 @@ public:
virtual String get_data_path() const override;
virtual String get_cache_path() const override;
virtual String get_bundle_resource_dir() const override;
+ virtual String get_bundle_icon_path() const override;
virtual String get_godot_dir_name() const override;
virtual String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const override;
@@ -91,6 +94,8 @@ public:
String get_locale() const override;
virtual String get_executable_path() const override;
+ virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override;
+ virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override;
virtual String get_unique_id() const override; //++
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index c6e35fee83..45a81be80a 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -178,7 +178,7 @@
class OSXTerminalLogger : public StdLogger {
public:
- virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR) {
+ virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type = ERR_ERROR) {
if (!should_log(true)) {
return;
}
@@ -314,17 +314,27 @@ String OS_OSX::get_name() const {
return "macOS";
}
+_FORCE_INLINE_ String _get_framework_executable(const String p_path) {
+ // Append framework executable name, or return as is if p_path is not a framework.
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (da->dir_exists(p_path) && da->file_exists(p_path.plus_file(p_path.get_file().get_basename()))) {
+ return p_path.plus_file(p_path.get_file().get_basename());
+ } else {
+ return p_path;
+ }
+}
+
Error OS_OSX::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
- String path = p_path;
+ String path = _get_framework_executable(p_path);
if (!FileAccess::exists(path)) {
- //this code exists so gdnative can load .dylib files from within the executable path
- path = get_executable_path().get_base_dir().plus_file(p_path.get_file());
+ // This code exists so gdnative can load .dylib files from within the executable path.
+ path = _get_framework_executable(get_executable_path().get_base_dir().plus_file(p_path.get_file()));
}
if (!FileAccess::exists(path)) {
- //this code exists so gdnative can load .dylib files from a standard macOS location
- path = get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(p_path.get_file());
+ // This code exists so gdnative can load .dylib files from a standard macOS location.
+ path = _get_framework_executable(get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(p_path.get_file()));
}
p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
@@ -379,14 +389,26 @@ String OS_OSX::get_cache_path() const {
}
String OS_OSX::get_bundle_resource_dir() const {
+ String ret;
+
NSBundle *main = [NSBundle mainBundle];
- NSString *resourcePath = [main resourcePath];
+ if (main) {
+ NSString *resourcePath = [main resourcePath];
+ ret.parse_utf8([resourcePath UTF8String]);
+ }
+ return ret;
+}
- char *utfs = strdup([resourcePath UTF8String]);
+String OS_OSX::get_bundle_icon_path() const {
String ret;
- ret.parse_utf8(utfs);
- free(utfs);
+ NSBundle *main = [NSBundle mainBundle];
+ if (main) {
+ NSString *iconPath = [[main infoDictionary] objectForKey:@"CFBundleIconFile"];
+ if (iconPath) {
+ ret.parse_utf8([iconPath UTF8String]);
+ }
+ }
return ret;
}
@@ -469,14 +491,89 @@ String OS_OSX::get_executable_path() const {
}
}
+Error OS_OSX::create_instance(const List<String> &p_arguments, ProcessID *r_child_id) {
+ // If executable is bundled, always execute editor instances as an app bundle to ensure app window is registered and activated correctly.
+ NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
+ if (nsappname != nil) {
+ String path;
+ path.parse_utf8([[[NSBundle mainBundle] bundlePath] UTF8String]);
+ return create_process(path, p_arguments, r_child_id);
+ } else {
+ return create_process(get_executable_path(), p_arguments, r_child_id);
+ }
+}
+
+Error OS_OSX::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) {
+ if (@available(macOS 10.15, *)) {
+ // Use NSWorkspace if path is an .app bundle.
+ NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())];
+ NSBundle *bundle = [NSBundle bundleWithURL:url];
+ if (bundle) {
+ NSMutableArray *arguments = [[NSMutableArray alloc] init];
+ for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) {
+ [arguments addObject:[NSString stringWithUTF8String:E->get().utf8().get_data()]];
+ }
+ NSWorkspaceOpenConfiguration *configuration = [[NSWorkspaceOpenConfiguration alloc] init];
+ [configuration setArguments:arguments];
+ [configuration setCreatesNewApplicationInstance:YES];
+ __block dispatch_semaphore_t lock = dispatch_semaphore_create(0);
+ __block Error err = ERR_TIMEOUT;
+ __block pid_t pid = 0;
+ [[NSWorkspace sharedWorkspace] openApplicationAtURL:url
+ configuration:configuration
+ completionHandler:^(NSRunningApplication *app, NSError *error) {
+ if (error) {
+ err = ERR_CANT_FORK;
+ NSLog(@"Failed to execute: %@", error.localizedDescription);
+ } else {
+ pid = [app processIdentifier];
+ err = OK;
+ }
+ dispatch_semaphore_signal(lock);
+ }];
+ dispatch_semaphore_wait(lock, dispatch_time(DISPATCH_TIME_NOW, 20000000000)); // 20 sec timeout, wait for app to launch.
+ dispatch_release(lock);
+
+ if (err == OK) {
+ if (r_child_id) {
+ *r_child_id = (ProcessID)pid;
+ }
+ }
+
+ return err;
+ } else {
+ return OS_Unix::create_process(p_path, p_arguments, r_child_id);
+ }
+ } else {
+ return OS_Unix::create_process(p_path, p_arguments, r_child_id);
+ }
+}
+
+void OS_OSX::pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context) {
+ // Prevent main loop from sleeping and redraw window during resize / modal popups.
+
+ if (get_singleton()->get_main_loop()) {
+ Main::force_redraw();
+ if (!Main::is_iterating()) { // Avoid cyclic loop.
+ Main::iteration();
+ }
+ }
+
+ CFRunLoopWakeUp(CFRunLoopGetCurrent()); // Prevent main loop from sleeping.
+}
+
void OS_OSX::run() {
force_quit = false;
- if (!main_loop)
+ if (!main_loop) {
return;
+ }
main_loop->initialize();
+ CFRunLoopObserverRef pre_wait_observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, true, 0, &pre_wait_observer_cb, nullptr);
+ CFRunLoopAddObserver(CFRunLoopGetCurrent(), pre_wait_observer, kCFRunLoopCommonModes);
+
bool quit = false;
while (!force_quit && !quit) {
@try {
@@ -492,6 +589,10 @@ void OS_OSX::run() {
ERR_PRINT("NSException: " + String([exception reason].UTF8String));
}
};
+
+ CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), pre_wait_observer, kCFRunLoopCommonModes);
+ CFRelease(pre_wait_observer);
+
main_loop->finalize();
}
diff --git a/platform/osx/platform_config.h b/platform/osx/platform_config.h
index 2d0fd872dc..7bfa466b97 100644
--- a/platform/osx/platform_config.h
+++ b/platform/osx/platform_config.h
@@ -30,4 +30,5 @@
#include <alloca.h>
+#define OPENGL_INCLUDE_H "thirdparty/glad/glad/glad.h"
#define PTHREAD_RENAME_SELF
diff --git a/platform/uwp/SCsub b/platform/uwp/SCsub
index 71c402358f..8726d32d61 100644
--- a/platform/uwp/SCsub
+++ b/platform/uwp/SCsub
@@ -7,7 +7,7 @@ files = [
"#platform/windows/windows_terminal_logger.cpp",
"joypad_uwp.cpp",
"context_egl_uwp.cpp",
- "app.cpp",
+ "app_uwp.cpp",
"os_uwp.cpp",
]
diff --git a/platform/uwp/app.cpp b/platform/uwp/app_uwp.cpp
index 1da17ffc5d..9e6ad7a63e 100644
--- a/platform/uwp/app.cpp
+++ b/platform/uwp/app_uwp.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* app.cpp */
+/* app_uwp.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -32,7 +32,7 @@
// This file demonstrates how to initialize EGL in a Windows Store app, using ICoreWindow.
//
-#include "app.h"
+#include "app_uwp.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
@@ -121,8 +121,7 @@ void App::SetWindow(CoreWindow ^ p_window) {
window->PointerWheelChanged +=
ref new TypedEventHandler<CoreWindow ^, PointerEventArgs ^>(this, &App::OnPointerWheelChanged);
- mouseChangedNotifier = SignalNotifier::AttachToEvent(L"os_mouse_mode_changed", ref new SignalHandler(
- this, &App::OnMouseModeChanged));
+ mouseChangedNotifier = SignalNotifier::AttachToEvent(L"os_mouse_mode_changed", ref new SignalHandler(this, &App::OnMouseModeChanged));
mouseChangedNotifier->Enable();
diff --git a/platform/uwp/app.h b/platform/uwp/app_uwp.h
index 0b02527dae..8d4a0b90c3 100644
--- a/platform/uwp/app.h
+++ b/platform/uwp/app_uwp.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* app.h */
+/* app_uwp.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#pragma once
+#ifndef APP_UWP_H
+#define APP_UWP_H
#include <string>
@@ -111,3 +112,4 @@ namespace GodotUWP
}
/* clang-format on */
+#endif // APP_UWP_H
diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py
index 28922a4f59..9c91378b22 100644
--- a/platform/uwp/detect.py
+++ b/platform/uwp/detect.py
@@ -64,14 +64,12 @@ def configure(env):
env.Append(CCFLAGS=["/MD"])
env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
env.AppendUnique(CPPDEFINES=["WINDOWS_SUBSYSTEM_CONSOLE"])
- env.Append(CPPDEFINES=["DEBUG_ENABLED"])
if env["optimize"] != "none":
env.Append(CCFLAGS=["/O2", "/Zi"])
elif env["target"] == "debug":
env.Append(CCFLAGS=["/Zi"])
env.Append(CCFLAGS=["/MDd"])
- env.Append(CPPDEFINES=["DEBUG_ENABLED"])
env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
env.AppendUnique(CPPDEFINES=["WINDOWS_SUBSYSTEM_CONSOLE"])
env.Append(LINKFLAGS=["/DEBUG"])
diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp
index 5bd00b1549..192814efe4 100644
--- a/platform/uwp/export/export_plugin.cpp
+++ b/platform/uwp/export/export_plugin.cpp
@@ -376,7 +376,7 @@ Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_p
Vector<String> cl = ((String)p_preset->get("command_line/extra_args")).strip_edges().split(" ");
for (int i = 0; i < cl.size(); i++) {
if (cl[i].strip_edges().length() == 0) {
- cl.remove(i);
+ cl.remove_at(i);
i--;
}
}
@@ -485,7 +485,7 @@ Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_p
void EditorExportPlatformUWP::get_platform_features(List<String> *r_features) {
r_features->push_back("pc");
- r_features->push_back("UWP");
+ r_features->push_back("uwp");
}
void EditorExportPlatformUWP::resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) {
diff --git a/platform/uwp/export/export_plugin.h b/platform/uwp/export/export_plugin.h
index f295789254..acdd85e888 100644
--- a/platform/uwp/export/export_plugin.h
+++ b/platform/uwp/export/export_plugin.h
@@ -367,15 +367,15 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
static bool _should_compress_asset(const String &p_path, const Vector<uint8_t> &p_data) {
/* TODO: This was copied verbatim from Android export. It should be
- * refactored to the parent class and also be used for .zip export.
- */
+ * refactored to the parent class and also be used for .zip export.
+ */
/*
- * By not compressing files with little or not benefit in doing so,
- * a performance gain is expected at runtime. Moreover, if the APK is
- * zip-aligned, assets stored as they are can be efficiently read by
- * Android by memory-mapping them.
- */
+ * By not compressing files with little or not benefit in doing so,
+ * a performance gain is expected at runtime. Moreover, if the APK is
+ * zip-aligned, assets stored as they are can be efficiently read by
+ * Android by memory-mapping them.
+ */
// -- Unconditional uncompress to mimic AAPT plus some other
diff --git a/platform/uwp/joypad_uwp.cpp b/platform/uwp/joypad_uwp.cpp
index b419fb4fae..f8eb4fc96d 100644
--- a/platform/uwp/joypad_uwp.cpp
+++ b/platform/uwp/joypad_uwp.cpp
@@ -58,12 +58,12 @@ void JoypadUWP::process_controllers() {
button_mask *= 2;
}
- input->joy_axis(joy.id, JOY_AXIS_LEFT_X, axis_correct(reading.LeftThumbstickX));
- input->joy_axis(joy.id, JOY_AXIS_LEFT_Y, axis_correct(reading.LeftThumbstickY, true));
- input->joy_axis(joy.id, JOY_AXIS_RIGHT_X, axis_correct(reading.RightThumbstickX));
- input->joy_axis(joy.id, JOY_AXIS_RIGHT_Y, axis_correct(reading.RightThumbstickY, true));
- input->joy_axis(joy.id, JOY_AXIS_TRIGGER_LEFT, axis_correct(reading.LeftTrigger, false, true));
- input->joy_axis(joy.id, JOY_AXIS_TRIGGER_RIGHT, axis_correct(reading.RightTrigger, false, true));
+ input->joy_axis(joy.id, JoyAxis::LEFT_X, axis_correct(reading.LeftThumbstickX));
+ input->joy_axis(joy.id, JoyAxis::LEFT_Y, axis_correct(reading.LeftThumbstickY, true));
+ input->joy_axis(joy.id, JoyAxis::RIGHT_X, axis_correct(reading.RightThumbstickX));
+ input->joy_axis(joy.id, JoyAxis::RIGHT_Y, axis_correct(reading.RightThumbstickY, true));
+ input->joy_axis(joy.id, JoyAxis::TRIGGER_LEFT, axis_correct(reading.LeftTrigger, false, true));
+ input->joy_axis(joy.id, JoyAxis::TRIGGER_RIGHT, axis_correct(reading.RightTrigger, false, true));
uint64_t timestamp = input->get_joy_vibration_timestamp(joy.id);
if (timestamp > joy.ff_timestamp) {
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 6ac5b55156..1114f5359a 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -28,14 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-// Must include Winsock before windows.h (included by os_uwp.h)
-#include "drivers/unix/net_socket_posix.h"
-
#include "os_uwp.h"
#include "core/config/project_settings.h"
#include "core/io/marshalls.h"
#include "drivers/unix/ip_unix.h"
+#include "drivers/unix/net_socket_posix.h"
#include "drivers/windows/dir_access_windows.h"
#include "drivers/windows/file_access_windows.h"
#include "drivers/windows/mutex_windows.h"
@@ -163,7 +161,7 @@ Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
outside = true;
// FIXME: Hardcoded for now, add Vulkan support.
- p_video_driver = VIDEO_DRIVER_GLES2;
+ p_video_driver = VIDEO_DRIVER_OPENGL;
ContextEGL_UWP::Driver opengl_api_type = ContextEGL_UWP::GLES_2_0;
bool gl_initialization_error = false;
@@ -177,9 +175,9 @@ Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
}
if (opengl_api_type == ContextEGL_UWP::GLES_2_0) {
- if (RasterizerGLES2::is_viable() == OK) {
- RasterizerGLES2::register_config();
- RasterizerGLES2::make_current();
+ if (RasterizerGLES3::is_viable() == OK) {
+ RasterizerGLES3::register_config();
+ RasterizerGLES3::make_current();
} else {
gl_initialization_error = true;
}
@@ -321,7 +319,7 @@ void OS_UWP::finalize() {
rendering_server->finish();
memdelete(rendering_server);
-#ifdef OPENGL_ENABLED
+#ifdef GLES3_ENABLED
if (gl_context)
memdelete(gl_context);
#endif
@@ -443,12 +441,13 @@ String OS_UWP::get_name() const {
return "UWP";
}
-OS::Date OS_UWP::get_date(bool utc) const {
+OS::Date OS_UWP::get_date(bool p_utc) const {
SYSTEMTIME systemtime;
- if (utc)
+ if (utc) {
GetSystemTime(&systemtime);
- else
+ } else {
GetLocalTime(&systemtime);
+ }
Date date;
date.day = systemtime.wDay;
@@ -459,7 +458,7 @@ OS::Date OS_UWP::get_date(bool utc) const {
return date;
}
-OS::Time OS_UWP::get_time(bool utc) const {
+OS::Time OS_UWP::get_time(bool p_utc) const {
SYSTEMTIME systemtime;
if (utc)
GetSystemTime(&systemtime);
diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h
index c9b2600c8e..0b4d6b73b6 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -45,6 +45,7 @@
#include <fcntl.h>
#include <io.h>
#include <stdio.h>
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
class OS_UWP : public OS {
@@ -58,7 +59,7 @@ public:
bool alt = false, shift = false, control = false;
MessageType type = KEY_EVENT_MESSAGE;
bool pressed = false;
- Key keycode = KEY_NONE;
+ Key keycode = Key::NONE;
unsigned int physical_keycode = 0;
unsigned int unicode = 0;
bool echo = false;
@@ -106,7 +107,7 @@ private:
bool control_mem;
bool meta_mem;
bool force_quit;
- MouseButton last_button_state = MOUSE_BUTTON_NONE;
+ MouseButton last_button_state = MouseButton::NONE;
CursorShape cursor_shape;
@@ -116,11 +117,6 @@ private:
Windows::System::Display::DisplayRequest ^ display_request;
- void _post_dpad(DWORD p_dpad, int p_device, bool p_pressed);
-
- void _drag_event(int idx, UINT uMsg, WPARAM wParam, LPARAM lParam);
- void _touch_event(int idx, UINT uMsg, WPARAM wParam, LPARAM lParam);
-
ref class ManagedType {
public:
property bool alert_close_handle;
@@ -189,8 +185,8 @@ public:
virtual String get_name() const;
- virtual Date get_date(bool utc) const;
- virtual Time get_time(bool utc) const;
+ virtual Date get_date(bool p_utc) const;
+ virtual Time get_time(bool p_utc) const;
virtual TimeZoneInfo get_time_zone_info() const;
virtual uint64_t get_unix_time() const;
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index 47d8e14680..76234c3065 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -15,7 +15,7 @@ common_win = [
"joypad_windows.cpp",
"windows_terminal_logger.cpp",
"vulkan_context_win.cpp",
- "context_gl_windows.cpp",
+ "gl_manager_windows.cpp",
]
res_file = "godot_res.rc"
diff --git a/platform/windows/context_gl_windows.cpp b/platform/windows/context_gl_windows.cpp
deleted file mode 100644
index 74b12cbb3b..0000000000
--- a/platform/windows/context_gl_windows.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-/*************************************************************************/
-/* context_gl_windows.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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. */
-/*************************************************************************/
-
-#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED)
-
-// Author: Juan Linietsky <reduzio@gmail.com>, (C) 2008
-
-#include "context_gl_windows.h"
-
-#include <dwmapi.h>
-
-#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
-#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
-#define WGL_CONTEXT_FLAGS_ARB 0x2094
-#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
-#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
-#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
-
-#if defined(__GNUC__)
-// Workaround GCC warning from -Wcast-function-type.
-#define wglGetProcAddress (void *)wglGetProcAddress
-#endif
-
-typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *);
-
-void ContextGL_Windows::release_current() {
- wglMakeCurrent(hDC, nullptr);
-}
-
-void ContextGL_Windows::make_current() {
- wglMakeCurrent(hDC, hRC);
-}
-
-int ContextGL_Windows::get_window_width() {
- return OS::get_singleton()->get_video_mode().width;
-}
-
-int ContextGL_Windows::get_window_height() {
- return OS::get_singleton()->get_video_mode().height;
-}
-
-void ContextGL_Windows::swap_buffers() {
- SwapBuffers(hDC);
-}
-
-void ContextGL_Windows::set_use_vsync(bool p_use) {
- if (wglSwapIntervalEXT) {
- int swap_interval = p_use ? 1 : 0;
- wglSwapIntervalEXT(swap_interval);
- }
-
- use_vsync = p_use;
-}
-
-bool ContextGL_Windows::is_using_vsync() const {
- return use_vsync;
-}
-
-#define _WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
-
-Error ContextGL_Windows::initialize() {
- static PIXELFORMATDESCRIPTOR pfd = {
- sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
- 1,
- PFD_DRAW_TO_WINDOW | // Format Must Support Window
- PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
- PFD_DOUBLEBUFFER,
- (BYTE)PFD_TYPE_RGBA,
- (BYTE)(OS::get_singleton()->is_layered_allowed() ? 32 : 24),
- (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Color Bits Ignored
- (BYTE)(OS::get_singleton()->is_layered_allowed() ? 8 : 0), // Alpha Buffer
- (BYTE)0, // Shift Bit Ignored
- (BYTE)0, // No Accumulation Buffer
- (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Accumulation Bits Ignored
- (BYTE)24, // 24Bit Z-Buffer (Depth Buffer)
- (BYTE)0, // No Stencil Buffer
- (BYTE)0, // No Auxiliary Buffer
- (BYTE)PFD_MAIN_PLANE, // Main Drawing Layer
- (BYTE)0, // Reserved
- 0, 0, 0 // Layer Masks Ignored
- };
-
- hDC = GetDC(hWnd);
- if (!hDC) {
- return ERR_CANT_CREATE; // Return FALSE
- }
-
- pixel_format = ChoosePixelFormat(hDC, &pfd);
- if (!pixel_format) // Did Windows Find A Matching Pixel Format?
- {
- return ERR_CANT_CREATE; // Return FALSE
- }
-
- BOOL ret = SetPixelFormat(hDC, pixel_format, &pfd);
- if (!ret) // Are We Able To Set The Pixel Format?
- {
- return ERR_CANT_CREATE; // Return FALSE
- }
-
- hRC = wglCreateContext(hDC);
- if (!hRC) // Are We Able To Get A Rendering Context?
- {
- return ERR_CANT_CREATE; // Return FALSE
- }
-
- wglMakeCurrent(hDC, hRC);
-
- if (opengl_3_context) {
- int attribs[] = {
- WGL_CONTEXT_MAJOR_VERSION_ARB, 3, //we want a 3.3 context
- WGL_CONTEXT_MINOR_VERSION_ARB, 3,
- //and it shall be forward compatible so that we can only use up to date functionality
- WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
- WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB /*| _WGL_CONTEXT_DEBUG_BIT_ARB*/,
- 0
- }; //zero indicates the end of the array
-
- PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr; //pointer to the method
- wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
-
- if (wglCreateContextAttribsARB == nullptr) //OpenGL 3.0 is not supported
- {
- wglDeleteContext(hRC);
- return ERR_CANT_CREATE;
- }
-
- HGLRC new_hRC = wglCreateContextAttribsARB(hDC, 0, attribs);
- if (!new_hRC) {
- wglDeleteContext(hRC);
- return ERR_CANT_CREATE; // Return false
- }
- wglMakeCurrent(hDC, nullptr);
- wglDeleteContext(hRC);
- hRC = new_hRC;
-
- if (!wglMakeCurrent(hDC, hRC)) // Try To Activate The Rendering Context
- {
- return ERR_CANT_CREATE; // Return FALSE
- }
- }
-
- wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
- wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)wglGetProcAddress("wglGetSwapIntervalEXT");
- //glWrapperInit(wrapper_get_proc_address);
-
- return OK;
-}
-
-ContextGL_Windows::ContextGL_Windows(HWND hwnd, bool p_opengl_3_context) {
- opengl_3_context = p_opengl_3_context;
- hWnd = hwnd;
- use_vsync = false;
- pixel_format = 0;
-}
-
-ContextGL_Windows::~ContextGL_Windows() {
-}
-
-#endif
diff --git a/platform/windows/crash_handler_windows.h b/platform/windows/crash_handler_windows.h
index e1ec8e6787..5cdc6d3e05 100644
--- a/platform/windows/crash_handler_windows.h
+++ b/platform/windows/crash_handler_windows.h
@@ -31,6 +31,7 @@
#ifndef CRASH_HANDLER_WINDOWS_H
#define CRASH_HANDLER_WINDOWS_H
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
// Crash handler exception only enabled with MSVC
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 3961480d23..aaaa50e729 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -203,11 +203,11 @@ def configure_msvc(env, manual_msvc_config):
elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["/O1"])
env.Append(LINKFLAGS=["/OPT:REF"])
- env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED"])
elif env["target"] == "debug":
env.AppendUnique(CCFLAGS=["/Zi", "/FS", "/Od", "/EHsc"])
- env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED"])
+ # Allow big objects. Only needed for debug, see MinGW branch for rationale.
+ env.AppendUnique(CCFLAGS=["/bigobj"])
env.Append(LINKFLAGS=["/DEBUG"])
if env["debug_symbols"]:
@@ -228,9 +228,9 @@ def configure_msvc(env, manual_msvc_config):
env.AppendUnique(CCFLAGS=["/MD"])
env.AppendUnique(CCFLAGS=["/Gd", "/GR", "/nologo"])
- # Force to use Unicode encoding
- env.AppendUnique(CCFLAGS=["/utf-8"])
+ env.AppendUnique(CCFLAGS=["/utf-8"]) # Force to use Unicode encoding.
env.AppendUnique(CXXFLAGS=["/TP"]) # assume all sources are C++
+
if manual_msvc_config: # should be automatic if SCons found it
if os.getenv("WindowsSdkDir") is not None:
env.Prepend(CPPPATH=[os.getenv("WindowsSdkDir") + "/Include"])
@@ -281,7 +281,7 @@ def configure_msvc(env, manual_msvc_config):
if not env["use_volk"]:
LIBS += ["vulkan"]
- # env.AppendUnique(CPPDEFINES = ['OPENGL_ENABLED'])
+ env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"])
LIBS += ["opengl32"]
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS])
@@ -351,7 +351,6 @@ def configure_mingw(env):
elif env["target"] == "release_debug":
env.Append(CCFLAGS=["-O2"])
- env.Append(CPPDEFINES=["DEBUG_ENABLED"])
if env["debug_symbols"]:
env.Prepend(CCFLAGS=["-g2"])
if env["optimize"] == "speed": # optimize for speed (default)
@@ -361,7 +360,10 @@ def configure_mingw(env):
elif env["target"] == "debug":
env.Append(CCFLAGS=["-g3"])
- env.Append(CPPDEFINES=["DEBUG_ENABLED"])
+ # Allow big objects. It's supposed not to have drawbacks but seems to break
+ # GCC LTO, so enabling for debug builds only (which are not built with LTO
+ # and are the only ones with too big objects).
+ env.Append(CCFLAGS=["-Wa,-mbig-obj"])
if env["windows_subsystem"] == "gui":
env.Append(LINKFLAGS=["-Wl,--subsystem,windows"])
@@ -457,8 +459,7 @@ def configure_mingw(env):
if not env["use_volk"]:
env.Append(LIBS=["vulkan"])
- ## TODO !!! Re-enable when OpenGLES Rendering Device is implemented !!!
- # env.Append(CPPDEFINES=['OPENGL_ENABLED'])
+ env.Append(CPPDEFINES=["GLES3_ENABLED"])
env.Append(LIBS=["opengl32"])
env.Append(CPPDEFINES=["MINGW_ENABLED", ("MINGW_HAS_SECURE_API", 1)])
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index cf51caa6d5..9fe15366f4 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -38,7 +38,15 @@
#include <avrt.h>
-#ifdef DEBUG_ENABLED
+#if defined(GLES3_ENABLED)
+#include "drivers/gles3/rasterizer_gles3.h"
+#endif
+
+#if defined(__GNUC__)
+// Workaround GCC warning from -Wcast-function-type.
+#define GetProcAddress (void *)GetProcAddress
+#endif
+
static String format_error_message(DWORD id) {
LPWSTR messageBuffer = nullptr;
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
@@ -50,7 +58,6 @@ static String format_error_message(DWORD id) {
return msg;
}
-#endif // DEBUG_ENABLED
bool DisplayServerWindows::has_feature(Feature p_feature) const {
switch (p_feature) {
@@ -80,7 +87,7 @@ String DisplayServerWindows::get_name() const {
}
void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
- if (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED || p_mode == MOUSE_MODE_CONFINED_HIDDEN) {
+ if (windows.has(MAIN_WINDOW_ID) && (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED || p_mode == MOUSE_MODE_CONFINED_HIDDEN)) {
// Mouse is grabbed (captured or confined).
WindowData &wd = windows[MAIN_WINDOW_ID];
@@ -118,8 +125,10 @@ void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
void DisplayServerWindows::mouse_set_mode(MouseMode p_mode) {
_THREAD_SAFE_METHOD_
- if (mouse_mode == p_mode)
+ if (mouse_mode == p_mode) {
+ // Already in the same mode; do nothing.
return;
+ }
mouse_mode = p_mode;
@@ -134,7 +143,7 @@ void DisplayServerWindows::mouse_warp_to_position(const Point2i &p_to) {
_THREAD_SAFE_METHOD_
if (!windows.has(last_focused_window)) {
- return; //no window focused?
+ return; // No focused window?
}
if (mouse_mode == MOUSE_MODE_CAPTURED) {
@@ -154,7 +163,6 @@ Point2i DisplayServerWindows::mouse_get_position() const {
POINT p;
GetCursorPos(&p);
return Point2i(p.x, p.y);
- //return Point2(old_x, old_y);
}
MouseButton DisplayServerWindows::mouse_get_button_state() const {
@@ -165,12 +173,12 @@ void DisplayServerWindows::clipboard_set(const String &p_text) {
_THREAD_SAFE_METHOD_
if (!windows.has(last_focused_window)) {
- return; //no window focused?
+ return; // No focused window?
}
- // Convert LF line endings to CRLF in clipboard content
- // Otherwise, line endings won't be visible when pasted in other software
- String text = p_text.replace("\r\n", "\n").replace("\n", "\r\n"); // avoid \r\r\n
+ // Convert LF line endings to CRLF in clipboard content.
+ // Otherwise, line endings won't be visible when pasted in other software.
+ String text = p_text.replace("\r\n", "\n").replace("\n", "\r\n"); // Avoid \r\r\n.
if (!OpenClipboard(windows[last_focused_window].hWnd)) {
ERR_FAIL_MSG("Unable to open clipboard.");
@@ -187,7 +195,7 @@ void DisplayServerWindows::clipboard_set(const String &p_text) {
SetClipboardData(CF_UNICODETEXT, mem);
- // set the CF_TEXT version (not needed?)
+ // Set the CF_TEXT version (not needed?).
CharString utf8 = text.utf8();
mem = GlobalAlloc(GMEM_MOVEABLE, utf8.length() + 1);
ERR_FAIL_COND_MSG(mem == nullptr, "Unable to allocate memory for clipboard contents.");
@@ -206,7 +214,7 @@ String DisplayServerWindows::clipboard_get() const {
_THREAD_SAFE_METHOD_
if (!windows.has(last_focused_window)) {
- return String(); //no window focused?
+ return String(); // No focused window?
}
String ret;
@@ -453,8 +461,8 @@ Vector<DisplayServer::WindowID> DisplayServerWindows::get_window_list() const {
_THREAD_SAFE_METHOD_
Vector<DisplayServer::WindowID> ret;
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- ret.push_back(E->key());
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
+ ret.push_back(E.key);
}
return ret;
}
@@ -464,9 +472,9 @@ DisplayServer::WindowID DisplayServerWindows::get_window_at_screen_position(cons
p.x = p_position.x;
p.y = p_position.y;
HWND hwnd = WindowFromPoint(p);
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- if (E->get().hWnd == hwnd) {
- return E->key();
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
+ if (E.value.hWnd == hwnd) {
+ return E.key;
}
}
@@ -498,16 +506,18 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
}
void DisplayServerWindows::show_window(WindowID p_id) {
+ ERR_FAIL_COND(!windows.has(p_id));
+
WindowData &wd = windows[p_id];
if (p_id != MAIN_WINDOW_ID) {
_update_window_style(p_id);
}
- ShowWindow(wd.hWnd, wd.no_focus ? SW_SHOWNOACTIVATE : SW_SHOW); // Show The Window
+ ShowWindow(wd.hWnd, wd.no_focus ? SW_SHOWNOACTIVATE : SW_SHOW); // Show the window.
if (!wd.no_focus) {
- SetForegroundWindow(wd.hWnd); // Slightly Higher Priority
- SetFocus(wd.hWnd); // Sets Keyboard Focus To
+ SetForegroundWindow(wd.hWnd); // Slightly higher priority.
+ SetFocus(wd.hWnd); // Set keyboard focus.
}
}
@@ -532,6 +542,11 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
context_vulkan->window_destroy(p_window);
}
#endif
+#ifdef GLES3_ENABLED
+ if (rendering_driver == "opengl3") {
+ gl_manager->window_destroy(p_window);
+ }
+#endif
if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[p_window].wtctx) {
wintab_WTClose(windows[p_window].wtctx);
@@ -541,6 +556,12 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
windows.erase(p_window);
}
+void DisplayServerWindows::gl_window_make_current(DisplayServer::WindowID p_window_id) {
+#if defined(GLES3_ENABLED)
+ gl_manager->window_make_current(p_window_id);
+#endif
+}
+
void DisplayServerWindows::window_attach_instance_id(ObjectID p_instance, WindowID p_window) {
_THREAD_SAFE_METHOD_
@@ -606,6 +627,8 @@ void DisplayServerWindows::window_set_mouse_passthrough(const Vector<Vector2> &p
}
void DisplayServerWindows::_update_window_mouse_passthrough(WindowID p_window) {
+ ERR_FAIL_COND(!windows.has(p_window));
+
if (windows[p_window].mpath.size() == 0) {
SetWindowRgn(windows[p_window].hWnd, nullptr, TRUE);
} else {
@@ -664,16 +687,11 @@ Point2i DisplayServerWindows::window_get_position(WindowID p_window) const {
ClientToScreen(wd.hWnd, &point);
return Point2i(point.x, point.y);
-
-#if 0
- //do not use this method, as it includes windows decorations
- RECT r;
- GetWindowRect(wd.hWnd, &r);
- return Point2(r.left, r.top);
-#endif
}
void DisplayServerWindows::_update_real_mouse_position(WindowID p_window) {
+ ERR_FAIL_COND(!windows.has(p_window));
+
POINT mouse_pos;
if (GetCursorPos(&mouse_pos) && ScreenToClient(windows[p_window].hWnd, &mouse_pos)) {
if (mouse_pos.x > 0 && mouse_pos.y > 0 && mouse_pos.x <= windows[p_window].width && mouse_pos.y <= windows[p_window].height) {
@@ -691,14 +709,9 @@ void DisplayServerWindows::window_set_position(const Point2i &p_position, Window
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
- if (wd.fullscreen)
+ if (wd.fullscreen) {
return;
-#if 0
- //wrong needs to account properly for decorations
- RECT r;
- GetWindowRect(wd.hWnd, &r);
- MoveWindow(wd.hWnd, p_position.x, p_position.y, r.right - r.left, r.bottom - r.top, TRUE);
-#else
+ }
RECT rc;
rc.left = p_position.x;
@@ -711,8 +724,8 @@ void DisplayServerWindows::window_set_position(const Point2i &p_position, Window
AdjustWindowRectEx(&rc, style, false, exStyle);
MoveWindow(wd.hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
-#endif
- // Don't let the mouse leave the window when moved
+
+ // Don't let the mouse leave the window when moved.
if (mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) {
RECT rect;
GetClientRect(wd.hWnd, &rect);
@@ -729,16 +742,15 @@ void DisplayServerWindows::window_set_transient(WindowID p_window, WindowID p_pa
_THREAD_SAFE_METHOD_
ERR_FAIL_COND(p_window == p_parent);
-
ERR_FAIL_COND(!windows.has(p_window));
+
WindowData &wd_window = windows[p_window];
ERR_FAIL_COND(wd_window.transient_parent == p_parent);
-
ERR_FAIL_COND_MSG(wd_window.always_on_top, "Windows with the 'on top' can't become transient.");
if (p_parent == INVALID_WINDOW_ID) {
- //remove transient
+ // Remove transient.
ERR_FAIL_COND(wd_window.transient_parent == INVALID_WINDOW_ID);
ERR_FAIL_COND(!windows.has(wd_window.transient_parent));
@@ -820,6 +832,11 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo
context_vulkan->window_resize(p_window, w, h);
}
#endif
+#if defined(GLES3_ENABLED)
+ if (rendering_driver == "opengl3") {
+ gl_manager->window_resize(p_window, w, h);
+ }
+#endif
if (wd.fullscreen) {
return;
@@ -838,7 +855,7 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo
MoveWindow(wd.hWnd, rect.left, rect.top, w, h, TRUE);
- // Don't let the mouse leave the window when resizing to a smaller resolution
+ // Don't let the mouse leave the window when resizing to a smaller resolution.
if (mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) {
RECT crect;
GetClientRect(wd.hWnd, &crect);
@@ -860,7 +877,7 @@ Size2i DisplayServerWindows::window_get_size(WindowID p_window) const {
}
RECT r;
- if (GetClientRect(wd.hWnd, &r)) { // Retrieves area inside of window border.
+ if (GetClientRect(wd.hWnd, &r)) { // Retrieves area inside of window border, including decoration.
return Size2(r.right - r.left, r.bottom - r.top);
}
return Size2();
@@ -873,13 +890,17 @@ Size2i DisplayServerWindows::window_get_real_size(WindowID p_window) const {
const WindowData &wd = windows[p_window];
RECT r;
- if (GetWindowRect(wd.hWnd, &r)) { // Includes area of the window border
+ if (GetWindowRect(wd.hWnd, &r)) { // Retrieves area inside of window border, including decoration.
return Size2(r.right - r.left, r.bottom - r.top);
}
return Size2();
}
void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscreen, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex) {
+ // Windows docs for window styles:
+ // https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles
+ // https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles
+
r_style = 0;
r_style_ex = WS_EX_WINDOWEDGE;
if (p_main_window) {
@@ -887,10 +908,7 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre
}
if (p_fullscreen || p_borderless) {
- r_style |= WS_POPUP;
- //if (p_borderless) {
- // r_style_ex |= WS_EX_TOOLWINDOW;
- //}
+ r_style |= WS_POPUP; // p_borderless was WS_EX_TOOLWINDOW in the past.
} else {
if (p_resizable) {
if (p_maximized) {
@@ -960,6 +978,11 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window)
_update_window_style(p_window, false);
MoveWindow(wd.hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
+
+ if (restore_mouse_trails > 1) {
+ SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, 0, 0);
+ restore_mouse_trails = 0;
+ }
} else if (p_mode == WINDOW_MODE_WINDOWED) {
ShowWindow(wd.hWnd, SW_RESTORE);
wd.maximized = false;
@@ -999,6 +1022,13 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window)
_update_window_style(false);
MoveWindow(wd.hWnd, pos.x, pos.y, size.width, size.height, TRUE);
+
+ // If the user has mouse trails enabled in windows, then sometimes the cursor disappears in fullscreen mode.
+ // Save number of trails so we can restore when exiting, then turn off mouse trails
+ SystemParametersInfoA(SPI_GETMOUSETRAILS, 0, &restore_mouse_trails, 0);
+ if (restore_mouse_trails > 1) {
+ SystemParametersInfoA(SPI_SETMOUSETRAILS, 0, 0, 0);
+ }
}
}
@@ -1026,7 +1056,7 @@ bool DisplayServerWindows::window_is_maximize_allowed(WindowID p_window) const {
// FIXME: Implement this, or confirm that it should always be true.
- return true; //no idea
+ return true;
}
void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) {
@@ -1124,8 +1154,8 @@ bool DisplayServerWindows::window_can_draw(WindowID p_window) const {
bool DisplayServerWindows::can_any_window_draw() const {
_THREAD_SAFE_METHOD_
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- if (!E->get().minimized) {
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
+ if (!E.value.minimized) {
return true;
}
}
@@ -1171,8 +1201,9 @@ void DisplayServerWindows::window_set_ime_position(const Point2i &p_pos, WindowI
void DisplayServerWindows::console_set_visible(bool p_enabled) {
_THREAD_SAFE_METHOD_
- if (console_visible == p_enabled)
+ if (console_visible == p_enabled) {
return;
+ }
ShowWindow(GetConsoleWindow(), p_enabled ? SW_SHOW : SW_HIDE);
console_visible = p_enabled;
}
@@ -1186,8 +1217,9 @@ void DisplayServerWindows::cursor_set_shape(CursorShape p_shape) {
ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
- if (cursor_shape == p_shape)
+ if (cursor_shape == p_shape) {
return;
+ }
if (mouse_mode != MOUSE_MODE_VISIBLE && mouse_mode != MOUSE_MODE_CONFINED) {
cursor_shape = p_shape;
@@ -1197,11 +1229,11 @@ void DisplayServerWindows::cursor_set_shape(CursorShape p_shape) {
static const LPCTSTR win_cursors[CURSOR_MAX] = {
IDC_ARROW,
IDC_IBEAM,
- IDC_HAND, //finger
+ IDC_HAND, // Finger.
IDC_CROSS,
IDC_WAIT,
IDC_APPSTARTING,
- IDC_ARROW,
+ IDC_SIZEALL,
IDC_ARROW,
IDC_NO,
IDC_SIZENS,
@@ -1228,49 +1260,49 @@ DisplayServer::CursorShape DisplayServerWindows::cursor_get_shape() const {
}
void DisplayServerWindows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap) {
- // Get the system display DC
+ // Get the system display DC.
HDC hDC = GetDC(nullptr);
- // Create helper DC
+ // Create helper DC.
HDC hMainDC = CreateCompatibleDC(hDC);
HDC hAndMaskDC = CreateCompatibleDC(hDC);
HDC hXorMaskDC = CreateCompatibleDC(hDC);
- // Get the dimensions of the source bitmap
+ // Get the dimensions of the source bitmap.
BITMAP bm;
GetObject(hSourceBitmap, sizeof(BITMAP), &bm);
- // Create the mask bitmaps
- hAndMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // color
- hXorMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // color
+ // Create the mask bitmaps.
+ hAndMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // Color.
+ hXorMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // Color.
- // Release the system display DC
+ // Release the system display DC.
ReleaseDC(nullptr, hDC);
- // Select the bitmaps to helper DC
+ // Select the bitmaps to helper DC.
HBITMAP hOldMainBitmap = (HBITMAP)SelectObject(hMainDC, hSourceBitmap);
HBITMAP hOldAndMaskBitmap = (HBITMAP)SelectObject(hAndMaskDC, hAndMaskBitmap);
HBITMAP hOldXorMaskBitmap = (HBITMAP)SelectObject(hXorMaskDC, hXorMaskBitmap);
// Assign the monochrome AND mask bitmap pixels so that the pixels of the source bitmap
- // with 'clrTransparent' will be white pixels of the monochrome bitmap
+ // with 'clrTransparent' will be white pixels of the monochrome bitmap.
SetBkColor(hMainDC, clrTransparent);
BitBlt(hAndMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCCOPY);
// Assign the color XOR mask bitmap pixels so that the pixels of the source bitmap
// with 'clrTransparent' will be black and rest the pixels same as corresponding
- // pixels of the source bitmap
+ // pixels of the source bitmap.
SetBkColor(hXorMaskDC, RGB(0, 0, 0));
SetTextColor(hXorMaskDC, RGB(255, 255, 255));
BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hAndMaskDC, 0, 0, SRCCOPY);
BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCAND);
- // Deselect bitmaps from the helper DC
+ // Deselect bitmaps from the helper DC.
SelectObject(hMainDC, hOldMainBitmap);
SelectObject(hAndMaskDC, hOldAndMaskBitmap);
SelectObject(hXorMaskDC, hOldXorMaskBitmap);
- // Delete the helper DC
+ // Delete the helper DC.
DeleteDC(hXorMaskDC);
DeleteDC(hAndMaskDC);
DeleteDC(hMainDC);
@@ -1327,7 +1359,7 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh
UINT image_size = texture_size.width * texture_size.height;
- // Create the BITMAP with alpha channel
+ // Create the BITMAP with alpha channel.
COLORREF *buffer = (COLORREF *)memalloc(sizeof(COLORREF) * image_size);
for (UINT index = 0; index < image_size; index++) {
@@ -1342,11 +1374,11 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh
*(buffer + index) = image->get_pixel(column_index, row_index).to_argb32();
}
- // Using 4 channels, so 4 * 8 bits
+ // Using 4 channels, so 4 * 8 bits.
HBITMAP bitmap = CreateBitmap(texture_size.width, texture_size.height, 1, 4 * 8, buffer);
COLORREF clrTransparent = -1;
- // Create the AND and XOR masks for the bitmap
+ // Create the AND and XOR masks for the bitmap.
HBITMAP hAndMask = nullptr;
HBITMAP hXorMask = nullptr;
@@ -1358,7 +1390,7 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh
return;
}
- // Finally, create the icon
+ // Finally, create the icon.
ICONINFO iconinfo;
iconinfo.fIcon = FALSE;
iconinfo.xHotspot = p_hotspot.x;
@@ -1366,8 +1398,9 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh
iconinfo.hbmMask = hAndMask;
iconinfo.hbmColor = hXorMask;
- if (cursors[p_shape])
+ if (cursors[p_shape]) {
DestroyIcon(cursors[p_shape]);
+ }
cursors[p_shape] = CreateIconIndirect(&iconinfo);
@@ -1393,7 +1426,7 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh
memfree(buffer);
DeleteObject(bitmap);
} else {
- // Reset to default system cursor
+ // Reset to default system cursor.
if (cursors[p_shape]) {
DestroyIcon(cursors[p_shape]);
cursors[p_shape] = nullptr;
@@ -1466,6 +1499,42 @@ String DisplayServerWindows::keyboard_get_layout_language(int p_index) const {
return String::utf16((const char16_t *)buf).substr(0, 2);
}
+Key DisplayServerWindows::keyboard_get_keycode_from_physical(Key p_keycode) const {
+ Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK;
+ Key keycode_no_mod = (Key)(p_keycode & KeyModifierMask::CODE_MASK);
+
+ if (keycode_no_mod == Key::PRINT ||
+ keycode_no_mod == Key::KP_ADD ||
+ keycode_no_mod == Key::KP_5 ||
+ (keycode_no_mod >= Key::KEY_0 && keycode_no_mod <= Key::KEY_9)) {
+ return p_keycode;
+ }
+
+ unsigned int scancode = KeyMappingWindows::get_scancode(keycode_no_mod);
+ if (scancode == 0) {
+ return p_keycode;
+ }
+
+ HKL current_layout = GetKeyboardLayout(0);
+ UINT vk = MapVirtualKeyEx(scancode, MAPVK_VSC_TO_VK, current_layout);
+ if (vk == 0) {
+ return p_keycode;
+ }
+
+ UINT char_code = MapVirtualKeyEx(vk, MAPVK_VK_TO_CHAR, current_layout) & 0x7FFF;
+ // Unlike a similar Linux/BSD check which matches full Latin-1 range,
+ // we limit these to ASCII to fix some layouts, including Arabic ones
+ if (char_code >= 32 && char_code <= 127) {
+ // Godot uses 'braces' instead of 'brackets'
+ if (char_code == (unsigned int)Key::BRACKETLEFT || char_code == (unsigned int)Key::BRACKETRIGHT) {
+ char_code += 32;
+ }
+ return (Key)(char_code | (unsigned int)modifiers);
+ }
+
+ return (Key)(KeyMappingWindows::get_keysym(vk) | modifiers);
+}
+
String _get_full_layout_name_from_registry(HKL p_layout) {
String id = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\" + String::num_int64((int64_t)p_layout, 16, false).lpad(8, "0");
String ret;
@@ -1547,6 +1616,9 @@ void DisplayServerWindows::make_rendering_thread() {
}
void DisplayServerWindows::swap_buffers() {
+#if defined(GLES3_ENABLED)
+ gl_manager->swap_buffers();
+#endif
}
void DisplayServerWindows::set_native_icon(const String &p_filename) {
@@ -1575,9 +1647,9 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) {
icon_dir = (ICONDIR *)memrealloc(icon_dir, 3 * sizeof(WORD) + icon_dir->idCount * sizeof(ICONDIRENTRY));
f->get_buffer((uint8_t *)&icon_dir->idEntries[0], icon_dir->idCount * sizeof(ICONDIRENTRY));
- int small_icon_index = -1; // Select 16x16 with largest color count
+ int small_icon_index = -1; // Select 16x16 with largest color count.
int small_icon_cc = 0;
- int big_icon_index = -1; // Select largest
+ int big_icon_index = -1; // Select largest.
int big_icon_width = 16;
int big_icon_cc = 0;
@@ -1607,7 +1679,7 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) {
small_icon_cc = big_icon_cc;
}
- // Read the big icon
+ // Read the big icon.
DWORD bytecount_big = icon_dir->idEntries[big_icon_index].dwBytesInRes;
Vector<uint8_t> data_big;
data_big.resize(bytecount_big);
@@ -1617,7 +1689,7 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) {
HICON icon_big = CreateIconFromResource((PBYTE)&data_big.write[0], bytecount_big, TRUE, 0x00030000);
ERR_FAIL_COND_MSG(!icon_big, "Could not create " + itos(big_icon_width) + "x" + itos(big_icon_width) + " @" + itos(big_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + ".");
- // Read the small icon
+ // Read the small icon.
DWORD bytecount_small = icon_dir->idEntries[small_icon_index].dwBytesInRes;
Vector<uint8_t> data_small;
data_small.resize(bytecount_small);
@@ -1627,7 +1699,7 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) {
HICON icon_small = CreateIconFromResource((PBYTE)&data_small.write[0], bytecount_small, TRUE, 0x00030000);
ERR_FAIL_COND_MSG(!icon_small, "Could not create 16x16 @" + itos(small_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + ".");
- // Online tradition says to be sure last error is cleared and set the small icon first
+ // Online tradition says to be sure last error is cleared and set the small icon first.
int err = 0;
SetLastError(err);
@@ -1648,12 +1720,13 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
ERR_FAIL_COND(!p_icon.is_valid());
Ref<Image> icon = p_icon->duplicate();
- if (icon->get_format() != Image::FORMAT_RGBA8)
+ if (icon->get_format() != Image::FORMAT_RGBA8) {
icon->convert(Image::FORMAT_RGBA8);
+ }
int w = icon->get_width();
int h = icon->get_height();
- /* Create temporary bitmap buffer */
+ // Create temporary bitmap buffer.
int icon_len = 40 + h * w * 4;
Vector<BYTE> v;
v.resize(icon_len);
@@ -1687,27 +1760,28 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
HICON hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
- /* Set the icon for the window */
+ // Set the icon for the window.
SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hicon);
- /* Set the icon in the task manager (should we do this?) */
+ // Set the icon in the task manager (should we do this?).
SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, (LPARAM)hicon);
}
void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
_THREAD_SAFE_METHOD_
#if defined(VULKAN_ENABLED)
- context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+ // TODO disabling for now
+ //context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
#endif
}
DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_window) const {
_THREAD_SAFE_METHOD_
#if defined(VULKAN_ENABLED)
- return context_vulkan->get_vsync_mode(p_window);
-#else
- return DisplayServer::VSYNC_ENABLED;
+ //TODO disabling for now
+ //return context_vulkan->get_vsync_mode(p_window);
#endif
+ return DisplayServer::VSYNC_ENABLED;
}
void DisplayServerWindows::set_context(Context p_context) {
@@ -1718,13 +1792,13 @@ void DisplayServerWindows::set_context(Context p_context) {
// Keeping the name suggested by Microsoft, but this macro really answers:
// Is this mouse event emulated from touch or pen input?
#define IsPenEvent(dw) (((dw)&SIGNATURE_MASK) == MI_WP_SIGNATURE)
-// This one tells whether the event comes from touchscreen (and not from pen)
+// This one tells whether the event comes from touchscreen (and not from pen).
#define IsTouchEvent(dw) (IsPenEvent(dw) && ((dw)&0x80))
void DisplayServerWindows::_touch_event(WindowID p_window, bool p_pressed, float p_x, float p_y, int idx) {
- // Defensive
- if (touch_state.has(idx) == p_pressed)
+ if (touch_state.has(idx) == p_pressed) {
return;
+ }
if (p_pressed) {
touch_state.insert(idx, Vector2(p_x, p_y));
@@ -1744,12 +1818,13 @@ void DisplayServerWindows::_touch_event(WindowID p_window, bool p_pressed, float
void DisplayServerWindows::_drag_event(WindowID p_window, float p_x, float p_y, int idx) {
Map<int, Vector2>::Element *curr = touch_state.find(idx);
- // Defensive
- if (!curr)
+ if (!curr) {
return;
+ }
- if (curr->get() == Vector2(p_x, p_y))
+ if (curr->get() == Vector2(p_x, p_y)) {
return;
+ }
Ref<InputEventScreenDrag> event;
event.instantiate();
@@ -1791,7 +1866,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event)
Ref<InputEventFromWindow> event_from_window = p_event;
if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) {
- //send to a window
+ // Send to a single window.
if (!windows.has(event_from_window->get_window_id())) {
in_dispatch_input_event = false;
ERR_FAIL_MSG("DisplayServerWindows: Invalid window id in input event.");
@@ -1803,9 +1878,9 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event)
}
callable.call((const Variant **)&evp, 1, ret, ce);
} else {
- //send to all windows
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- Callable callable = E->get().input_event_callback;
+ // Send to all windows.
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
+ const Callable callable = E.value.input_event_callback;
if (callable.is_null()) {
continue;
}
@@ -1816,6 +1891,9 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event)
in_dispatch_input_event = false;
}
+// Our default window procedure to handle processing of window-related system messages/events.
+// Also known as DefProc or DefWindowProc.
+// See: https://docs.microsoft.com/en-us/windows/win32/winmsg/window-procedures
LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (drop_events) {
if (user_proc) {
@@ -1828,27 +1906,28 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
WindowID window_id = INVALID_WINDOW_ID;
bool window_created = false;
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- if (E->get().hWnd == hWnd) {
- window_id = E->key();
+ // Check whether window exists.
+ for (const KeyValue<WindowID, WindowData> &E : windows) {
+ if (E.value.hWnd == hWnd) {
+ window_id = E.key;
window_created = true;
break;
}
}
+ // Window doesn't exist or creation in progress, don't handle messages yet.
if (!window_created) {
- // Window creation in progress.
window_id = window_id_counter;
ERR_FAIL_COND_V(!windows.has(window_id), 0);
}
- switch (uMsg) // Check For Windows Messages
- {
+ // Process window messages.
+ switch (uMsg) {
case WM_SETFOCUS: {
windows[window_id].window_has_focus = true;
last_focused_window = window_id;
- // Restore mouse mode
+ // Restore mouse mode.
_set_mouse_mode_impl(mouse_mode);
if (!app_focused) {
@@ -1857,18 +1936,17 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
app_focused = true;
}
- break;
- }
+ } break;
case WM_KILLFOCUS: {
windows[window_id].window_has_focus = false;
last_focused_window = window_id;
- // Release capture unconditionally because it can be set due to dragging, in addition to captured mode
+ // Release capture unconditionally because it can be set due to dragging, in addition to captured mode.
ReleaseCapture();
- // Release every touch to avoid sticky points
- for (Map<int, Vector2>::Element *E = touch_state.front(); E; E = E->next()) {
- _touch_event(window_id, false, E->get().x, E->get().y, E->key());
+ // Release every touch to avoid sticky points.
+ for (const KeyValue<int, Vector2> &E : touch_state) {
+ _touch_event(window_id, false, E.value.x, E.value.y, E.key);
}
touch_state.clear();
@@ -1884,10 +1962,8 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
app_focused = false;
}
-
- break;
- }
- case WM_ACTIVATE: { // Watch For Window Activate Message
+ } break;
+ case WM_ACTIVATE: { // Watch for window activate message.
if (!windows[window_id].window_focused) {
_process_activate_event(window_id, wParam, lParam);
} else {
@@ -1897,8 +1973,8 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
// Run a timer to prevent event catching warning if the focused window is closing.
windows[window_id].focus_timer_id = SetTimer(windows[window_id].hWnd, 2, USER_TIMER_MINIMUM, (TIMERPROC) nullptr);
}
- return 0; // Return To The Message Loop
- }
+ return 0; // Return to the message loop.
+ } break;
case WM_GETMINMAXINFO: {
if (windows[window_id].resizable && !windows[window_id].fullscreen) {
// Size of window decorations.
@@ -1914,37 +1990,31 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
min_max_info->ptMaxTrackSize.y = windows[window_id].max_size.y + decor.y;
}
return 0;
- } else {
- break;
}
- }
- case WM_PAINT:
-
+ } break;
+ case WM_PAINT: {
Main::force_redraw();
- break;
-
- case WM_SYSCOMMAND: // Intercept System Commands
+ } break;
+ case WM_SYSCOMMAND: // Intercept system commands.
{
- switch (wParam) // Check System Calls
+ switch (wParam) // Check system calls.
{
- case SC_SCREENSAVE: // Screensaver Trying To Start?
- case SC_MONITORPOWER: // Monitor Trying To Enter Powersave?
- return 0; // Prevent From Happening
+ case SC_SCREENSAVE: // Screensaver trying to start?
+ case SC_MONITORPOWER: // Monitor trying to enter powersave?
+ return 0; // Prevent from happening.
case SC_KEYMENU:
if ((lParam >> 16) <= 0)
return 0;
}
- break; // Exit
- }
-
- case WM_CLOSE: // Did We Receive A Close Message?
+ } break;
+ case WM_CLOSE: // Did we receive a close message?
{
if (windows[window_id].focus_timer_id != 0U) {
KillTimer(windows[window_id].hWnd, windows[window_id].focus_timer_id);
}
_send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST);
- return 0; // Jump Back
+ return 0; // Jump back.
}
case WM_MOUSELEAVE: {
old_invalid = true;
@@ -1986,7 +2056,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
Point2i c(windows[window_id].width / 2, windows[window_id].height / 2);
- // centering just so it works as before
+ // Centering just so it works as before.
POINT pos = { (int)c.x, (int)c.y };
ClientToScreen(windows[window_id].hWnd, &pos);
SetCursorPos(pos.x, pos.y);
@@ -2009,7 +2079,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
(double(raw->data.mouse.lLastX) - 65536.0 / (nScreenWidth)) * nScreenWidth / 65536.0 + nScreenLeft,
(double(raw->data.mouse.lLastY) - 65536.0 / (nScreenHeight)) * nScreenHeight / 65536.0 + nScreenTop);
- POINT coords; //client coords
+ POINT coords; // Client coords.
coords.x = abs_pos.x;
coords.y = abs_pos.y;
@@ -2018,14 +2088,11 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_relative(Vector2(coords.x - old_x, coords.y - old_y));
old_x = coords.x;
old_y = coords.y;
-
- /*Input.mi.dx = (int)((((double)(pos.x)-nScreenLeft) * 65536) / nScreenWidth + 65536 / (nScreenWidth));
- Input.mi.dy = (int)((((double)(pos.y)-nScreenTop) * 65536) / nScreenHeight + 65536 / (nScreenHeight));
- */
}
- if (windows[window_id].window_has_focus && mm->get_relative() != Vector2())
+ if (windows[window_id].window_has_focus && mm->get_relative() != Vector2()) {
Input::get_singleton()->parse_input_event(mm);
+ }
}
delete[] lpb;
} break;
@@ -2170,7 +2237,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
if (Input::get_singleton()->is_emulating_mouse_from_touch()) {
- // Universal translation enabled; ignore OS translation
+ // Universal translation enabled; ignore OS translation.
LPARAM extra = GetMessageExtraInfo();
if (IsTouchEvent(extra)) {
break;
@@ -2178,7 +2245,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
if (outside) {
- //mouse enter
+ // Mouse enter.
if (mouse_mode != MOUSE_MODE_CAPTURED) {
_send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
@@ -2189,7 +2256,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
cursor_set_shape(c);
outside = false;
- //Once-Off notification, must call again....
+ // Once-off notification, must call again.
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
@@ -2222,7 +2289,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_button_mask(last_button_state);
- POINT coords; //client coords
+ POINT coords; // Client coords.
coords.x = GET_X_LPARAM(lParam);
coords.y = GET_Y_LPARAM(lParam);
@@ -2264,7 +2331,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
Input::get_singleton()->parse_input_event(mm);
}
- return 0; //Pointer event handled return 0 to avoid duplicate WM_MOUSEMOVE event
+ return 0; // Pointer event handled return 0 to avoid duplicate WM_MOUSEMOVE event.
} break;
case WM_MOUSEMOVE: {
if (windows[window_id].block_mm) {
@@ -2276,7 +2343,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
if (Input::get_singleton()->is_emulating_mouse_from_touch()) {
- // Universal translation enabled; ignore OS translation
+ // Universal translation enabled; ignore OS translation.
LPARAM extra = GetMessageExtraInfo();
if (IsTouchEvent(extra)) {
break;
@@ -2284,7 +2351,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
if (outside) {
- //mouse enter
+ // Mouse enter.
if (mouse_mode != MOUSE_MODE_CAPTURED) {
_send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
@@ -2295,7 +2362,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
cursor_set_shape(c);
outside = false;
- //Once-Off notification, must call again....
+ // Once-off notification, must call again.
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
@@ -2373,7 +2440,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
if (Input::get_singleton()->is_emulating_mouse_from_touch()) {
- // Universal translation enabled; ignore OS translations for left button
+ // Universal translation enabled; ignore OS translations for left button.
LPARAM extra = GetMessageExtraInfo();
if (IsTouchEvent(extra)) {
break;
@@ -2399,41 +2466,41 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
switch (uMsg) {
case WM_LBUTTONDOWN: {
mb->set_pressed(true);
- mb->set_button_index(MOUSE_BUTTON_LEFT);
+ mb->set_button_index(MouseButton::LEFT);
} break;
case WM_LBUTTONUP: {
mb->set_pressed(false);
- mb->set_button_index(MOUSE_BUTTON_LEFT);
+ mb->set_button_index(MouseButton::LEFT);
} break;
case WM_MBUTTONDOWN: {
mb->set_pressed(true);
- mb->set_button_index(MOUSE_BUTTON_MIDDLE);
+ mb->set_button_index(MouseButton::MIDDLE);
} break;
case WM_MBUTTONUP: {
mb->set_pressed(false);
- mb->set_button_index(MOUSE_BUTTON_MIDDLE);
+ mb->set_button_index(MouseButton::MIDDLE);
} break;
case WM_RBUTTONDOWN: {
mb->set_pressed(true);
- mb->set_button_index(MOUSE_BUTTON_RIGHT);
+ mb->set_button_index(MouseButton::RIGHT);
} break;
case WM_RBUTTONUP: {
mb->set_pressed(false);
- mb->set_button_index(MOUSE_BUTTON_RIGHT);
+ mb->set_button_index(MouseButton::RIGHT);
} break;
case WM_LBUTTONDBLCLK: {
mb->set_pressed(true);
- mb->set_button_index(MOUSE_BUTTON_LEFT);
+ mb->set_button_index(MouseButton::LEFT);
mb->set_double_click(true);
} break;
case WM_RBUTTONDBLCLK: {
mb->set_pressed(true);
- mb->set_button_index(MOUSE_BUTTON_RIGHT);
+ mb->set_button_index(MouseButton::RIGHT);
mb->set_double_click(true);
} break;
case WM_MBUTTONDBLCLK: {
mb->set_pressed(true);
- mb->set_button_index(MOUSE_BUTTON_MIDDLE);
+ mb->set_button_index(MouseButton::MIDDLE);
mb->set_double_click(true);
} break;
case WM_MOUSEWHEEL: {
@@ -2444,9 +2511,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
if (motion > 0) {
- mb->set_button_index(MOUSE_BUTTON_WHEEL_UP);
+ mb->set_button_index(MouseButton::WHEEL_UP);
} else {
- mb->set_button_index(MOUSE_BUTTON_WHEEL_DOWN);
+ mb->set_button_index(MouseButton::WHEEL_DOWN);
}
mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA));
} break;
@@ -2458,34 +2525,34 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
if (motion < 0) {
- mb->set_button_index(MOUSE_BUTTON_WHEEL_LEFT);
+ mb->set_button_index(MouseButton::WHEEL_LEFT);
} else {
- mb->set_button_index(MOUSE_BUTTON_WHEEL_RIGHT);
+ mb->set_button_index(MouseButton::WHEEL_RIGHT);
}
mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA));
} break;
case WM_XBUTTONDOWN: {
mb->set_pressed(true);
if (HIWORD(wParam) == XBUTTON1) {
- mb->set_button_index(MOUSE_BUTTON_XBUTTON1);
+ mb->set_button_index(MouseButton::MB_XBUTTON1);
} else {
- mb->set_button_index(MOUSE_BUTTON_XBUTTON2);
+ mb->set_button_index(MouseButton::MB_XBUTTON2);
}
} break;
case WM_XBUTTONUP: {
mb->set_pressed(false);
if (HIWORD(wParam) == XBUTTON1) {
- mb->set_button_index(MOUSE_BUTTON_XBUTTON1);
+ mb->set_button_index(MouseButton::MB_XBUTTON1);
} else {
- mb->set_button_index(MOUSE_BUTTON_XBUTTON2);
+ mb->set_button_index(MouseButton::MB_XBUTTON2);
}
} break;
case WM_XBUTTONDBLCLK: {
mb->set_pressed(true);
if (HIWORD(wParam) == XBUTTON1) {
- mb->set_button_index(MOUSE_BUTTON_XBUTTON1);
+ mb->set_button_index(MouseButton::MB_XBUTTON1);
} else {
- mb->set_button_index(MOUSE_BUTTON_XBUTTON2);
+ mb->set_button_index(MouseButton::MB_XBUTTON2);
}
mb->set_double_click(true);
} break;
@@ -2497,11 +2564,11 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mb->set_ctrl_pressed((wParam & MK_CONTROL) != 0);
mb->set_shift_pressed((wParam & MK_SHIFT) != 0);
mb->set_alt_pressed(alt_mem);
- //mb->is_alt_pressed()=(wParam&MK_MENU)!=0;
+ // mb->is_alt_pressed()=(wParam&MK_MENU)!=0;
if (mb->is_pressed()) {
- last_button_state |= MouseButton(1 << (mb->get_button_index() - 1));
+ last_button_state |= mouse_button_to_mask(mb->get_button_index());
} else {
- last_button_state &= (MouseButton) ~(1 << (mb->get_button_index() - 1));
+ last_button_state &= ~mouse_button_to_mask(mb->get_button_index());
}
mb->set_button_mask(last_button_state);
@@ -2524,7 +2591,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
}
} else {
- // for reasons unknown to mankind, wheel comes in screen coordinates
+ // For reasons unknown to mankind, wheel comes in screen coordinates.
POINT coords;
coords.x = mb->get_position().x;
coords.y = mb->get_position().y;
@@ -2537,18 +2604,17 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mb->set_global_position(mb->get_position());
Input::get_singleton()->parse_input_event(mb);
- if (mb->is_pressed() && mb->get_button_index() > 3 && mb->get_button_index() < 8) {
- //send release for mouse wheel
+ if (mb->is_pressed() && mb->get_button_index() >= MouseButton::WHEEL_UP && mb->get_button_index() <= MouseButton::WHEEL_RIGHT) {
+ // Send release for mouse wheel.
Ref<InputEventMouseButton> mbd = mb->duplicate();
mbd->set_window_id(window_id);
- last_button_state &= (MouseButton) ~(1 << (mbd->get_button_index() - 1));
+ last_button_state &= ~mouse_button_to_mask(mbd->get_button_index());
mbd->set_button_mask(last_button_state);
mbd->set_pressed(false);
Input::get_singleton()->parse_input_event(mbd);
}
} break;
-
case WM_MOVE: {
if (!IsIconic(windows[window_id].hWnd)) {
int x = int16_t(LOWORD(lParam));
@@ -2564,7 +2630,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
}
} break;
-
case WM_SIZE: {
// Ignore window size change when a SIZE_MINIMIZED event is triggered.
if (wParam != SIZE_MINIMIZED) {
@@ -2642,7 +2707,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
#endif
} break;
-
case WM_ENTERSIZEMOVE: {
Input::get_singleton()->release_pressed_events();
windows[window_id].move_timer_id = SetTimer(windows[window_id].hWnd, 1, USER_TIMER_MINIMUM, (TIMERPROC) nullptr);
@@ -2662,7 +2726,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
windows[window_id].focus_timer_id = 0U;
}
} break;
-
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYUP:
@@ -2714,7 +2777,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
case WM_INPUTLANGCHANGEREQUEST: {
// FIXME: Do something?
} break;
-
case WM_TOUCH: {
BOOL bHandled = FALSE;
UINT cInputs = LOWORD(wParam);
@@ -2728,7 +2790,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
TOUCH_COORD_TO_PIXEL(ti.y),
};
ScreenToClient(hWnd, &touch_pos);
- //do something with each touch input entry
+ // Do something with each touch input entry.
if (ti.dwFlags & TOUCHEVENTF_MOVE) {
_drag_event(window_id, touch_pos.x, touch_pos.y, ti.dwID);
} else if (ti.dwFlags & (TOUCHEVENTF_UP | TOUCHEVENTF_DOWN)) {
@@ -2737,11 +2799,11 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
bHandled = TRUE;
} else {
- /* handle the error here */
+ // TODO: Handle the error here.
}
memdelete_arr(pInputs);
} else {
- /* handle the error here, probably out of memory */
+ // TODO: Handle the error here, probably out of memory.
}
if (bHandled) {
CloseTouchInputHandle((HTOUCHINPUT)lParam);
@@ -2749,14 +2811,13 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
};
} break;
-
case WM_DEVICECHANGE: {
joypad->probe_joypads();
} break;
case WM_SETCURSOR: {
if (LOWORD(lParam) == HTCLIENT) {
if (windows[window_id].window_has_focus && (mouse_mode == MOUSE_MODE_HIDDEN || mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN)) {
- //Hide the cursor
+ // Hide the cursor.
if (hCursor == nullptr) {
hCursor = SetCursor(nullptr);
} else {
@@ -2771,7 +2832,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
}
}
-
} break;
case WM_DROPFILES: {
HDROP hDropInfo = (HDROP)wParam;
@@ -2795,9 +2855,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
Callable::CallError ce;
windows[window_id].drop_files_callback.call((const Variant **)&vp, 1, ret, ce);
}
-
} break;
-
default: {
if (user_proc) {
return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam);
@@ -2823,7 +2881,7 @@ void DisplayServerWindows::_process_activate_event(WindowID p_window_id, WPARAM
alt_mem = false;
control_mem = false;
shift_mem = false;
- } else { // WM_INACTIVE
+ } else { // WM_INACTIVE.
Input::get_singleton()->release_pressed_events();
_send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_OUT);
windows[p_window_id].window_focused = false;
@@ -2840,7 +2898,7 @@ void DisplayServerWindows::_process_key_events() {
KeyEvent &ke = key_event_buffer[i];
switch (ke.uMsg) {
case WM_CHAR: {
- // extended keys should only be processed as WM_KEYDOWN message.
+ // 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;
@@ -2881,9 +2939,9 @@ void DisplayServerWindows::_process_key_events() {
k->set_unicode(0);
Input::get_singleton()->parse_input_event(k);
+ } else {
+ // Do nothing.
}
-
- //do nothing
} break;
case WM_KEYUP:
case WM_KEYDOWN: {
@@ -2899,8 +2957,8 @@ void DisplayServerWindows::_process_key_events() {
k->set_pressed(ke.uMsg == WM_KEYDOWN);
if ((ke.lParam & (1 << 24)) && (ke.wParam == VK_RETURN)) {
- // Special case for Numpad Enter key
- k->set_keycode(KEY_KP_ENTER);
+ // Special case for Numpad Enter key.
+ k->set_keycode(Key::KP_ENTER);
} else {
k->set_keycode((Key)KeyMappingWindows::get_keysym(ke.wParam));
}
@@ -2948,8 +3006,8 @@ void DisplayServerWindows::_process_key_events() {
}
void DisplayServerWindows::_update_tablet_ctx(const String &p_old_driver, const String &p_new_driver) {
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- WindowData &wd = E->get();
+ for (KeyValue<WindowID, WindowData> &E : windows) {
+ WindowData &wd = E.value;
wd.block_mm = false;
if ((p_old_driver == "wintab") && wintab_available && wd.wtctx) {
wintab_WTEnable(wd.wtctx, false);
@@ -3045,8 +3103,8 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
if (p_mode != WINDOW_MODE_FULLSCREEN) {
wd.pre_fs_valid = true;
}
-#ifdef VULKAN_ENABLED
+#ifdef VULKAN_ENABLED
if (rendering_driver == "vulkan") {
if (context_vulkan->window_create(id, p_vsync_mode, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) == -1) {
memdelete(context_vulkan);
@@ -3057,6 +3115,13 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
}
#endif
+#ifdef GLES3_ENABLED
+ if (rendering_driver == "opengl3") {
+ Error err = gl_manager->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top);
+ ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Failed to create an OpenGL window.");
+ }
+#endif
+
RegisterTouchWindow(wd.hWnd, 0);
TRACKMOUSEEVENT tme;
@@ -3101,7 +3166,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
wd.last_pressure_update = 0;
wd.last_tilt = Vector2();
- // IME
+ // IME.
wd.im_himc = ImmGetContext(wd.hWnd);
ImmReleaseContext(wd.hWnd, wd.im_himc);
@@ -3116,7 +3181,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
return id;
}
-// WinTab API
+// WinTab API.
bool DisplayServerWindows::wintab_available = false;
WTOpenPtr DisplayServerWindows::wintab_WTOpen = nullptr;
WTClosePtr DisplayServerWindows::wintab_WTClose = nullptr;
@@ -3124,7 +3189,7 @@ WTInfoPtr DisplayServerWindows::wintab_WTInfo = nullptr;
WTPacketPtr DisplayServerWindows::wintab_WTPacket = nullptr;
WTEnablePtr DisplayServerWindows::wintab_WTEnable = nullptr;
-// Windows Ink API
+// Windows Ink API.
bool DisplayServerWindows::winink_available = false;
GetPointerTypePtr DisplayServerWindows::win8p_GetPointerType = nullptr;
GetPointerPenInfoPtr DisplayServerWindows::win8p_GetPointerPenInfo = nullptr;
@@ -3187,7 +3252,9 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
outside = true;
- //Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink.
+ rendering_driver = p_rendering_driver;
+
+ // Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink.
HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll");
if (wintab_lib) {
wintab_WTOpen = (WTOpenPtr)GetProcAddress(wintab_lib, "WTOpenW");
@@ -3203,7 +3270,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
tablet_drivers.push_back("wintab");
}
- //Note: Windows Ink API for pen input, available on Windows 8+ only.
+ // Note: Windows Ink API for pen input, available on Windows 8+ only.
HMODULE user32_lib = LoadLibraryW(L"user32.dll");
if (user32_lib) {
win8p_GetPointerType = (GetPointerTypePtr)GetProcAddress(user32_lib, "GetPointerType");
@@ -3236,7 +3303,6 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
wc.lpfnWndProc = (WNDPROC)::WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
- //wc.hInstance = hInstance;
wc.hInstance = hInstance ? hInstance : GetModuleHandle(nullptr);
wc.hIcon = LoadIcon(nullptr, IDI_WINLOGO);
wc.hCursor = nullptr; //LoadCursor(nullptr, IDC_ARROW);
@@ -3260,12 +3326,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
Rid[0].hwndTarget = 0;
if (RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])) == FALSE) {
- //registration failed.
+ // Registration failed.
use_raw_input = false;
}
- rendering_driver = "vulkan";
-
#if defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") {
context_vulkan = memnew(VulkanContextWindows);
@@ -3277,28 +3341,26 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
}
}
#endif
-#if defined(OPENGL_ENABLED)
- if (rendering_driver_index == VIDEO_DRIVER_GLES2) {
- context_gles2 = memnew(ContextGL_Windows(hWnd, false));
-
- if (context_gles2->initialize() != OK) {
- memdelete(context_gles2);
- context_gles2 = nullptr;
- ERR_FAIL_V(ERR_UNAVAILABLE);
- }
+ // Init context and rendering device
+#if defined(GLES3_ENABLED)
- context_gles2->set_use_vsync(video_mode.use_vsync);
+ if (rendering_driver == "opengl3") {
+ GLManager_Windows::ContextType opengl_api_type = GLManager_Windows::GLES_3_0_COMPATIBLE;
- if (RasterizerGLES2::is_viable() == OK) {
- RasterizerGLES2::register_config();
- RasterizerGLES2::make_current();
- } else {
- memdelete(context_gles2);
- context_gles2 = nullptr;
- ERR_FAIL_V(ERR_UNAVAILABLE);
+ gl_manager = memnew(GLManager_Windows(opengl_api_type));
+
+ if (gl_manager->initialize() != OK) {
+ memdelete(gl_manager);
+ gl_manager = nullptr;
+ r_error = ERR_UNAVAILABLE;
+ return;
}
+
+ // gl_manager->set_use_vsync(current_videomode.use_vsync);
+ RasterizerGLES3::make_current();
}
#endif
+
Point2i window_position(
(screen_get_size(0).width - p_resolution.width) / 2,
(screen_get_size(0).height - p_resolution.height) / 2);
@@ -3327,7 +3389,6 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
//set_ime_active(false);
if (!OS::get_singleton()->is_in_low_processor_usage_mode()) {
- //SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
DWORD index = 0;
HANDLE handle = AvSetMmThreadCharacteristics("Games", &index);
@@ -3335,7 +3396,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
AvSetMmThreadPriority(handle, AVRT_PRIORITY_CRITICAL);
// This is needed to make sure that background work does not starve the main thread.
- // This is only setting priority of this thread, not the whole process.
+ // This is only setting the priority of this thread, not the whole process.
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
}
@@ -3357,8 +3418,8 @@ Vector<String> DisplayServerWindows::get_rendering_drivers_func() {
#ifdef VULKAN_ENABLED
drivers.push_back("vulkan");
#endif
-#ifdef OPENGL_ENABLED
- drivers.push_back("opengl");
+#ifdef GLES3_ENABLED
+ drivers.push_back("opengl3");
#endif
return drivers;
@@ -3367,7 +3428,7 @@ Vector<String> DisplayServerWindows::get_rendering_drivers_func() {
DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
if (r_error != OK) {
- OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan versions.\n"
+ OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.\n"
"Please update your drivers or if you have a very old or integrated GPU upgrade it.",
"Unable to initialize Video driver");
}
@@ -3388,6 +3449,10 @@ DisplayServerWindows::~DisplayServerWindows() {
SetWindowLongPtr(windows[MAIN_WINDOW_ID].hWnd, GWLP_WNDPROC, (LONG_PTR)user_proc);
};
+#ifdef GLES3_ENABLED
+ // destroy windows .. NYI?
+#endif
+
if (windows.has(MAIN_WINDOW_ID)) {
#ifdef VULKAN_ENABLED
if (rendering_driver == "vulkan") {
@@ -3412,4 +3477,14 @@ DisplayServerWindows::~DisplayServerWindows() {
memdelete(context_vulkan);
}
#endif
+
+ if (restore_mouse_trails > 1) {
+ SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, 0, 0);
+ }
+#ifdef GLES3_ENABLED
+ if (gl_manager) {
+ memdelete(gl_manager);
+ gl_manager = nullptr;
+ }
+#endif
}
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 06014fbabe..a59f8ebb44 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -51,18 +51,19 @@
#include "drivers/xaudio2/audio_driver_xaudio2.h"
#endif
-#if defined(OPENGL_ENABLED)
-#include "context_gl_windows.h"
-#endif
-
#if defined(VULKAN_ENABLED)
#include "drivers/vulkan/rendering_device_vulkan.h"
#include "platform/windows/vulkan_context_win.h"
#endif
+#if defined(GLES3_ENABLED)
+#include "gl_manager_windows.h"
+#endif
+
#include <fcntl.h>
#include <io.h>
#include <stdio.h>
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
@@ -303,8 +304,8 @@ class DisplayServerWindows : public DisplayServer {
int old_x, old_y;
Point2i center;
-#if defined(OPENGL_ENABLED)
- ContextGL_Windows *context_gles2;
+#if defined(GLES3_ENABLED)
+ GLManager_Windows *gl_manager;
#endif
#if defined(VULKAN_ENABLED)
@@ -403,12 +404,13 @@ class DisplayServerWindows : public DisplayServer {
void _get_window_style(bool p_main_window, bool p_fullscreen, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex);
MouseMode mouse_mode;
+ int restore_mouse_trails = 0;
bool alt_mem = false;
bool gr_mem = false;
bool shift_mem = false;
bool control_mem = false;
bool meta_mem = false;
- MouseButton last_button_state = MOUSE_BUTTON_NONE;
+ MouseButton last_button_state = MouseButton::NONE;
bool use_raw_input = false;
bool drop_events = false;
bool in_dispatch_input_event = false;
@@ -460,7 +462,7 @@ public:
virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual void screen_set_orientation(ScreenOrientation p_orientation, int p_screen = SCREEN_OF_MAIN_WINDOW) override;
- ScreenOrientation screen_get_orientation(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual ScreenOrientation screen_get_orientation(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual void screen_set_keep_on(bool p_enable) override; //disable screensaver
virtual bool screen_is_kept_on() const override;
@@ -475,6 +477,7 @@ public:
virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override;
virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override;
+ virtual void gl_window_make_current(DisplayServer::WindowID p_window_id);
virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
@@ -542,6 +545,7 @@ public:
virtual void keyboard_set_current_layout(int p_index) override;
virtual String keyboard_get_layout_language(int p_index) const override;
virtual String keyboard_get_layout_name(int p_index) const override;
+ virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override;
virtual int tablet_get_driver_count() const override;
virtual String tablet_get_driver_name(int p_driver) const override;
diff --git a/platform/windows/gl_manager_windows.cpp b/platform/windows/gl_manager_windows.cpp
new file mode 100644
index 0000000000..fe98f8b0ba
--- /dev/null
+++ b/platform/windows/gl_manager_windows.cpp
@@ -0,0 +1,346 @@
+/*************************************************************************/
+/* gl_manager_windows.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 "gl_manager_windows.h"
+
+#ifdef WINDOWS_ENABLED
+#ifdef GLES3_ENABLED
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <dwmapi.h>
+
+#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
+#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
+#define WGL_CONTEXT_FLAGS_ARB 0x2094
+#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
+#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
+#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
+
+#define _WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
+
+#if defined(__GNUC__)
+// Workaround GCC warning from -Wcast-function-type.
+#define wglGetProcAddress (void *)wglGetProcAddress
+#endif
+
+typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *);
+
+int GLManager_Windows::_find_or_create_display(GLWindow &win) {
+ // find display NYI, only 1 supported so far
+ if (_displays.size())
+ return 0;
+
+ // for (unsigned int n = 0; n < _displays.size(); n++) {
+ // const GLDisplay &d = _displays[n];
+ // if (d.x11_display == p_x11_display)
+ // return n;
+ // }
+
+ // create
+ GLDisplay d_temp = {};
+ _displays.push_back(d_temp);
+ int new_display_id = _displays.size() - 1;
+
+ // create context
+ GLDisplay &d = _displays[new_display_id];
+ Error err = _create_context(win, d);
+
+ if (err != OK) {
+ // not good
+ // delete the _display?
+ _displays.remove_at(new_display_id);
+ return -1;
+ }
+
+ return new_display_id;
+}
+
+Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
+ static PIXELFORMATDESCRIPTOR pfd = {
+ sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
+ 1,
+ PFD_DRAW_TO_WINDOW | // Format Must Support Window
+ PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
+ PFD_DOUBLEBUFFER,
+ (BYTE)PFD_TYPE_RGBA,
+ (BYTE)(OS::get_singleton()->is_layered_allowed() ? 32 : 24),
+ (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Color Bits Ignored
+ (BYTE)(OS::get_singleton()->is_layered_allowed() ? 8 : 0), // Alpha Buffer
+ (BYTE)0, // Shift Bit Ignored
+ (BYTE)0, // No Accumulation Buffer
+ (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Accumulation Bits Ignored
+ (BYTE)24, // 24Bit Z-Buffer (Depth Buffer)
+ (BYTE)0, // No Stencil Buffer
+ (BYTE)0, // No Auxiliary Buffer
+ (BYTE)PFD_MAIN_PLANE, // Main Drawing Layer
+ (BYTE)0, // Reserved
+ 0, 0, 0 // Layer Masks Ignored
+ };
+
+ // alias
+ HDC hDC = win.hDC;
+
+ int pixel_format = ChoosePixelFormat(hDC, &pfd);
+ if (!pixel_format) // Did Windows Find A Matching Pixel Format?
+ {
+ return ERR_CANT_CREATE; // Return FALSE
+ }
+
+ BOOL ret = SetPixelFormat(hDC, pixel_format, &pfd);
+ if (!ret) // Are We Able To Set The Pixel Format?
+ {
+ return ERR_CANT_CREATE; // Return FALSE
+ }
+
+ gl_display.hRC = wglCreateContext(hDC);
+ if (!gl_display.hRC) // Are We Able To Get A Rendering Context?
+ {
+ return ERR_CANT_CREATE; // Return FALSE
+ }
+
+ wglMakeCurrent(hDC, gl_display.hRC);
+
+ int attribs[] = {
+ WGL_CONTEXT_MAJOR_VERSION_ARB, 3, //we want a 3.3 context
+ WGL_CONTEXT_MINOR_VERSION_ARB, 3,
+ //and it shall be forward compatible so that we can only use up to date functionality
+ WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
+ WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB /*| _WGL_CONTEXT_DEBUG_BIT_ARB*/,
+ 0
+ }; //zero indicates the end of the array
+
+ PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr; //pointer to the method
+ wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
+
+ if (wglCreateContextAttribsARB == nullptr) //OpenGL 3.0 is not supported
+ {
+ wglDeleteContext(gl_display.hRC);
+ gl_display.hRC = 0;
+ return ERR_CANT_CREATE;
+ }
+
+ HGLRC new_hRC = wglCreateContextAttribsARB(hDC, 0, attribs);
+ if (!new_hRC) {
+ wglDeleteContext(gl_display.hRC);
+ gl_display.hRC = 0;
+ return ERR_CANT_CREATE; // Return false
+ }
+ wglMakeCurrent(hDC, nullptr);
+ wglDeleteContext(gl_display.hRC);
+ gl_display.hRC = new_hRC;
+
+ if (!wglMakeCurrent(hDC, gl_display.hRC)) // Try To Activate The Rendering Context
+ {
+ wglDeleteContext(gl_display.hRC);
+ gl_display.hRC = 0;
+ return ERR_CANT_CREATE; // Return FALSE
+ }
+
+ return OK;
+}
+
+Error GLManager_Windows::window_create(DisplayServer::WindowID p_window_id, HWND p_hwnd, HINSTANCE p_hinstance, int p_width, int p_height) {
+ HDC hdc = GetDC(p_hwnd);
+ if (!hdc) {
+ return ERR_CANT_CREATE; // Return FALSE
+ }
+
+ // make sure vector is big enough...
+ // we can mirror the external vector, it is simpler
+ // to keep the IDs identical for fast lookup
+ if (p_window_id >= (int)_windows.size()) {
+ _windows.resize(p_window_id + 1);
+ }
+
+ GLWindow &win = _windows[p_window_id];
+ win.in_use = true;
+ win.window_id = p_window_id;
+ win.width = p_width;
+ win.height = p_height;
+ win.hwnd = p_hwnd;
+ win.hDC = hdc;
+
+ win.gldisplay_id = _find_or_create_display(win);
+
+ if (win.gldisplay_id == -1) {
+ // release DC?
+ _windows.remove_at(_windows.size() - 1);
+ return FAILED;
+ }
+
+ // make current
+ window_make_current(_windows.size() - 1);
+
+ return OK;
+}
+
+void GLManager_Windows::_internal_set_current_window(GLWindow *p_win) {
+ _current_window = p_win;
+}
+
+void GLManager_Windows::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {
+ get_window(p_window_id).width = p_width;
+ get_window(p_window_id).height = p_height;
+}
+
+int GLManager_Windows::window_get_width(DisplayServer::WindowID p_window_id) {
+ return get_window(p_window_id).width;
+}
+
+int GLManager_Windows::window_get_height(DisplayServer::WindowID p_window_id) {
+ return get_window(p_window_id).height;
+}
+
+void GLManager_Windows::window_destroy(DisplayServer::WindowID p_window_id) {
+ GLWindow &win = get_window(p_window_id);
+ win.in_use = false;
+
+ if (_current_window == &win) {
+ _current_window = nullptr;
+ }
+}
+
+void GLManager_Windows::release_current() {
+ if (!_current_window)
+ return;
+
+ wglMakeCurrent(_current_window->hDC, nullptr);
+}
+
+void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id) {
+ if (p_window_id == -1)
+ return;
+
+ GLWindow &win = _windows[p_window_id];
+ if (!win.in_use)
+ return;
+
+ // noop
+ if (&win == _current_window)
+ return;
+
+ const GLDisplay &disp = get_display(win.gldisplay_id);
+ wglMakeCurrent(win.hDC, disp.hRC);
+
+ _internal_set_current_window(&win);
+}
+
+void GLManager_Windows::make_current() {
+ if (!_current_window)
+ return;
+ if (!_current_window->in_use) {
+ WARN_PRINT("current window not in use!");
+ return;
+ }
+ const GLDisplay &disp = get_current_display();
+ wglMakeCurrent(_current_window->hDC, disp.hRC);
+}
+
+void GLManager_Windows::swap_buffers() {
+ // NO NEED TO CALL SWAP BUFFERS for each window...
+ // see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glXSwapBuffers.xml
+
+ if (!_current_window)
+ return;
+ if (!_current_window->in_use) {
+ WARN_PRINT("current window not in use!");
+ return;
+ }
+
+ // print_line("\tswap_buffers");
+
+ // only for debugging without drawing anything
+ // glClearColor(Math::randf(), 0, 1, 1);
+ //glClear(GL_COLOR_BUFFER_BIT);
+
+ // const GLDisplay &disp = get_current_display();
+ SwapBuffers(_current_window->hDC);
+}
+
+Error GLManager_Windows::initialize() {
+ wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
+ wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)wglGetProcAddress("wglGetSwapIntervalEXT");
+ //glWrapperInit(wrapper_get_proc_address);
+
+ return OK;
+}
+
+void GLManager_Windows::set_use_vsync(bool p_use) {
+ /*
+ static bool setup = false;
+ static PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = nullptr;
+ static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalMESA = nullptr;
+ static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = nullptr;
+
+ if (!setup) {
+ setup = true;
+ String extensions = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display));
+ if (extensions.find("GLX_EXT_swap_control") != -1)
+ glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalEXT");
+ if (extensions.find("GLX_MESA_swap_control") != -1)
+ glXSwapIntervalMESA = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalMESA");
+ if (extensions.find("GLX_SGI_swap_control") != -1)
+ glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalSGI");
+ }
+ int val = p_use ? 1 : 0;
+ if (glXSwapIntervalMESA) {
+ glXSwapIntervalMESA(val);
+ } else if (glXSwapIntervalSGI) {
+ glXSwapIntervalSGI(val);
+ } else if (glXSwapIntervalEXT) {
+ GLXDrawable drawable = glXGetCurrentDrawable();
+ glXSwapIntervalEXT(x11_display, drawable, val);
+ } else
+ return;
+ use_vsync = p_use;
+ */
+}
+
+bool GLManager_Windows::is_using_vsync() const {
+ return use_vsync;
+}
+
+GLManager_Windows::GLManager_Windows(ContextType p_context_type) {
+ context_type = p_context_type;
+
+ direct_render = false;
+ glx_minor = glx_major = 0;
+ use_vsync = false;
+ _current_window = nullptr;
+}
+
+GLManager_Windows::~GLManager_Windows() {
+ release_current();
+}
+
+#endif // GLES3_ENABLED
+#endif // WINDOWS
diff --git a/platform/windows/context_gl_windows.h b/platform/windows/gl_manager_windows.h
index c8e8a0891d..9733a57420 100644
--- a/platform/windows/context_gl_windows.h
+++ b/platform/windows/gl_manager_windows.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* context_gl_windows.h */
+/* gl_manager_windows.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,49 +28,100 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED)
+#ifndef GL_MANAGER_WINDOWS_H
+#define GL_MANAGER_WINDOWS_H
-// Author: Juan Linietsky <reduzio@gmail.com>, (C) 2008
-
-#ifndef CONTEXT_GL_WIN_H
-#define CONTEXT_GL_WIN_H
+#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED)
#include "core/error/error_list.h"
#include "core/os/os.h"
+#include "core/templates/local_vector.h"
+#include "servers/display_server.h"
#include <windows.h>
typedef bool(APIENTRY *PFNWGLSWAPINTERVALEXTPROC)(int interval);
typedef int(APIENTRY *PFNWGLGETSWAPINTERVALEXTPROC)(void);
-class ContextGL_Windows {
- HDC hDC;
- HGLRC hRC;
- unsigned int pixel_format;
- HWND hWnd;
- bool opengl_3_context;
- bool use_vsync;
+class GLManager_Windows {
+public:
+ enum ContextType {
+ GLES_3_0_COMPATIBLE,
+ };
+
+private:
+ // any data specific to the window
+ struct GLWindow {
+ GLWindow() { in_use = false; }
+ bool in_use;
+
+ // the external ID .. should match the GL window number .. unused I think
+ DisplayServer::WindowID window_id;
+ int width;
+ int height;
+
+ // windows specific
+ HDC hDC;
+ HWND hwnd;
+
+ int gldisplay_id;
+ };
+
+ struct GLDisplay {
+ // windows specific
+ HGLRC hRC;
+ };
+
+ LocalVector<GLWindow> _windows;
+ LocalVector<GLDisplay> _displays;
+
+ GLWindow *_current_window;
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT;
+ // funcs
+ void _internal_set_current_window(GLWindow *p_win);
+
+ GLWindow &get_window(unsigned int id) { return _windows[id]; }
+ const GLWindow &get_window(unsigned int id) const { return _windows[id]; }
+
+ const GLDisplay &get_current_display() const { return _displays[_current_window->gldisplay_id]; }
+ const GLDisplay &get_display(unsigned int id) { return _displays[id]; }
+
+ bool direct_render;
+ int glx_minor, glx_major;
+ bool use_vsync;
+ ContextType context_type;
+
+private:
+ int _find_or_create_display(GLWindow &win);
+ Error _create_context(GLWindow &win, GLDisplay &gl_display);
+
public:
- void release_current();
+ Error window_create(DisplayServer::WindowID p_window_id, HWND p_hwnd, HINSTANCE p_hinstance, int p_width, int p_height);
+ void window_destroy(DisplayServer::WindowID p_window_id);
+ void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
- void make_current();
+ // get directly from the cached GLWindow
+ int window_get_width(DisplayServer::WindowID p_window_id = 0);
+ int window_get_height(DisplayServer::WindowID p_window_id = 0);
- int get_window_width();
- int get_window_height();
+ void release_current();
+ void make_current();
void swap_buffers();
+ void window_make_current(DisplayServer::WindowID p_window_id);
+
Error initialize();
void set_use_vsync(bool p_use);
bool is_using_vsync() const;
- ContextGL_Windows(HWND hwnd, bool p_opengl_3_context);
- ~ContextGL_Windows();
+ GLManager_Windows(ContextType p_context_type);
+ ~GLManager_Windows();
};
-#endif
-#endif
+#endif // defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED)
+
+#endif // GL_MANAGER_WINDOWS_H
diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp
index 94da63e49d..1d3761ee83 100644
--- a/platform/windows/joypad_windows.cpp
+++ b/platform/windows/joypad_windows.cpp
@@ -334,12 +334,12 @@ void JoypadWindows::process_joypads() {
button_mask = button_mask * 2;
}
- input->joy_axis(joy.id, JOY_AXIS_LEFT_X, axis_correct(joy.state.Gamepad.sThumbLX, true));
- input->joy_axis(joy.id, JOY_AXIS_LEFT_Y, axis_correct(joy.state.Gamepad.sThumbLY, true, false, true));
- input->joy_axis(joy.id, JOY_AXIS_RIGHT_X, axis_correct(joy.state.Gamepad.sThumbRX, true));
- input->joy_axis(joy.id, JOY_AXIS_RIGHT_Y, axis_correct(joy.state.Gamepad.sThumbRY, true, false, true));
- input->joy_axis(joy.id, JOY_AXIS_TRIGGER_LEFT, axis_correct(joy.state.Gamepad.bLeftTrigger, true, true));
- input->joy_axis(joy.id, JOY_AXIS_TRIGGER_RIGHT, axis_correct(joy.state.Gamepad.bRightTrigger, true, true));
+ input->joy_axis(joy.id, JoyAxis::LEFT_X, axis_correct(joy.state.Gamepad.sThumbLX, true));
+ input->joy_axis(joy.id, JoyAxis::LEFT_Y, axis_correct(joy.state.Gamepad.sThumbLY, true, false, true));
+ input->joy_axis(joy.id, JoyAxis::RIGHT_X, axis_correct(joy.state.Gamepad.sThumbRX, true));
+ input->joy_axis(joy.id, JoyAxis::RIGHT_Y, axis_correct(joy.state.Gamepad.sThumbRY, true, false, true));
+ input->joy_axis(joy.id, JoyAxis::TRIGGER_LEFT, axis_correct(joy.state.Gamepad.bLeftTrigger, true, true));
+ input->joy_axis(joy.id, JoyAxis::TRIGGER_RIGHT, axis_correct(joy.state.Gamepad.bRightTrigger, true, true));
joy.last_packet = joy.state.dwPacketNumber;
}
uint64_t timestamp = input->get_joy_vibration_timestamp(joy.id);
@@ -417,31 +417,31 @@ void JoypadWindows::post_hat(int p_device, DWORD p_dpad) {
// BOOL POVCentered = (LOWORD(dwPOV) == 0xFFFF);"
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee416628(v%3Dvs.85)#remarks
if (LOWORD(p_dpad) == 0xFFFF) {
- dpad_val = (HatMask)HatMask::HAT_MASK_CENTER;
+ dpad_val = (HatMask)HatMask::CENTER;
}
if (p_dpad == 0) {
- dpad_val = (HatMask)HatMask::HAT_MASK_UP;
+ dpad_val = (HatMask)HatMask::UP;
} else if (p_dpad == 4500) {
- dpad_val = (HatMask)(HatMask::HAT_MASK_UP | HatMask::HAT_MASK_RIGHT);
+ dpad_val = (HatMask)(HatMask::UP | HatMask::RIGHT);
} else if (p_dpad == 9000) {
- dpad_val = (HatMask)HatMask::HAT_MASK_RIGHT;
+ dpad_val = (HatMask)HatMask::RIGHT;
} else if (p_dpad == 13500) {
- dpad_val = (HatMask)(HatMask::HAT_MASK_RIGHT | HatMask::HAT_MASK_DOWN);
+ dpad_val = (HatMask)(HatMask::RIGHT | HatMask::DOWN);
} else if (p_dpad == 18000) {
- dpad_val = (HatMask)HatMask::HAT_MASK_DOWN;
+ dpad_val = (HatMask)HatMask::DOWN;
} else if (p_dpad == 22500) {
- dpad_val = (HatMask)(HatMask::HAT_MASK_DOWN | HatMask::HAT_MASK_LEFT);
+ dpad_val = (HatMask)(HatMask::DOWN | HatMask::LEFT);
} else if (p_dpad == 27000) {
- dpad_val = (HatMask)HatMask::HAT_MASK_LEFT;
+ dpad_val = (HatMask)HatMask::LEFT;
} else if (p_dpad == 31500) {
- dpad_val = (HatMask)(HatMask::HAT_MASK_LEFT | HatMask::HAT_MASK_UP);
+ dpad_val = (HatMask)(HatMask::LEFT | HatMask::UP);
}
input->joy_hat(p_device, dpad_val);
};
diff --git a/platform/windows/key_mapping_windows.cpp b/platform/windows/key_mapping_windows.cpp
index db99d6c122..65ee5dd46b 100644
--- a/platform/windows/key_mapping_windows.cpp
+++ b/platform/windows/key_mapping_windows.cpp
@@ -33,200 +33,200 @@
#include <stdio.h>
struct _WinTranslatePair {
- unsigned int keysym;
+ Key keysym;
unsigned int keycode;
};
static _WinTranslatePair _vk_to_keycode[] = {
- { KEY_BACKSPACE, VK_BACK }, // (0x08) // backspace
- { KEY_TAB, VK_TAB }, //(0x09)
+ { Key::BACKSPACE, VK_BACK }, // (0x08) // backspace
+ { Key::TAB, VK_TAB }, //(0x09)
//VK_CLEAR (0x0C)
- { KEY_ENTER, VK_RETURN }, //(0x0D)
+ { Key::ENTER, VK_RETURN }, //(0x0D)
- { KEY_SHIFT, VK_SHIFT }, //(0x10)
+ { Key::SHIFT, VK_SHIFT }, //(0x10)
- { KEY_CTRL, VK_CONTROL }, //(0x11)
+ { Key::CTRL, VK_CONTROL }, //(0x11)
- { KEY_ALT, VK_MENU }, //(0x12)
+ { Key::ALT, VK_MENU }, //(0x12)
- { KEY_PAUSE, VK_PAUSE }, //(0x13)
+ { Key::PAUSE, VK_PAUSE }, //(0x13)
- { KEY_CAPSLOCK, VK_CAPITAL }, //(0x14)
+ { Key::CAPSLOCK, VK_CAPITAL }, //(0x14)
- { KEY_ESCAPE, VK_ESCAPE }, //(0x1B)
+ { Key::ESCAPE, VK_ESCAPE }, //(0x1B)
- { KEY_SPACE, VK_SPACE }, //(0x20)
+ { Key::SPACE, VK_SPACE }, //(0x20)
- { KEY_PAGEUP, VK_PRIOR }, //(0x21)
+ { Key::PAGEUP, VK_PRIOR }, //(0x21)
- { KEY_PAGEDOWN, VK_NEXT }, //(0x22)
+ { Key::PAGEDOWN, VK_NEXT }, //(0x22)
- { KEY_END, VK_END }, //(0x23)
+ { Key::END, VK_END }, //(0x23)
- { KEY_HOME, VK_HOME }, //(0x24)
+ { Key::HOME, VK_HOME }, //(0x24)
- { KEY_LEFT, VK_LEFT }, //(0x25)
+ { Key::LEFT, VK_LEFT }, //(0x25)
- { KEY_UP, VK_UP }, //(0x26)
+ { Key::UP, VK_UP }, //(0x26)
- { KEY_RIGHT, VK_RIGHT }, //(0x27)
+ { Key::RIGHT, VK_RIGHT }, //(0x27)
- { KEY_DOWN, VK_DOWN }, // (0x28)
+ { Key::DOWN, VK_DOWN }, // (0x28)
//VK_SELECT (0x29)
- { KEY_PRINT, VK_PRINT }, // (0x2A)
+ { Key::PRINT, VK_PRINT }, // (0x2A)
//VK_EXECUTE (0x2B)
- { KEY_PRINT, VK_SNAPSHOT }, // (0x2C)
-
- { KEY_INSERT, VK_INSERT }, // (0x2D)
-
- { KEY_DELETE, VK_DELETE }, // (0x2E)
-
- { KEY_HELP, VK_HELP }, // (0x2F)
-
- { KEY_0, (0x30) }, ////0 key
- { KEY_1, (0x31) }, ////1 key
- { KEY_2, (0x32) }, ////2 key
- { KEY_3, (0x33) }, ////3 key
- { KEY_4, (0x34) }, ////4 key
- { KEY_5, (0x35) }, ////5 key
- { KEY_6, (0x36) }, ////6 key
- { KEY_7, (0x37) }, ////7 key
- { KEY_8, (0x38) }, ////8 key
- { KEY_9, (0x39) }, ////9 key
- { KEY_A, (0x41) }, ////A key
- { KEY_B, (0x42) }, ////B key
- { KEY_C, (0x43) }, ////C key
- { KEY_D, (0x44) }, ////D key
- { KEY_E, (0x45) }, ////E key
- { KEY_F, (0x46) }, ////F key
- { KEY_G, (0x47) }, ////G key
- { KEY_H, (0x48) }, ////H key
- { KEY_I, (0x49) }, ////I key
- { KEY_J, (0x4A) }, ////J key
- { KEY_K, (0x4B) }, ////K key
- { KEY_L, (0x4C) }, ////L key
- { KEY_M, (0x4D) }, ////M key
- { KEY_N, (0x4E) }, ////N key
- { KEY_O, (0x4F) }, ////O key
- { KEY_P, (0x50) }, ////P key
- { KEY_Q, (0x51) }, ////Q key
- { KEY_R, (0x52) }, ////R key
- { KEY_S, (0x53) }, ////S key
- { KEY_T, (0x54) }, ////T key
- { KEY_U, (0x55) }, ////U key
- { KEY_V, (0x56) }, ////V key
- { KEY_W, (0x57) }, ////W key
- { KEY_X, (0x58) }, ////X key
- { KEY_Y, (0x59) }, ////Y key
- { KEY_Z, (0x5A) }, ////Z key
-
- { KEY_MASK_META, VK_LWIN }, //(0x5B)
- { KEY_MASK_META, VK_RWIN }, //(0x5C)
- { KEY_MENU, VK_APPS }, //(0x5D)
- { KEY_STANDBY, VK_SLEEP }, //(0x5F)
- { KEY_KP_0, VK_NUMPAD0 }, //(0x60)
- { KEY_KP_1, VK_NUMPAD1 }, //(0x61)
- { KEY_KP_2, VK_NUMPAD2 }, //(0x62)
- { KEY_KP_3, VK_NUMPAD3 }, //(0x63)
- { KEY_KP_4, VK_NUMPAD4 }, //(0x64)
- { KEY_KP_5, VK_NUMPAD5 }, //(0x65)
- { KEY_KP_6, VK_NUMPAD6 }, //(0x66)
- { KEY_KP_7, VK_NUMPAD7 }, //(0x67)
- { KEY_KP_8, VK_NUMPAD8 }, //(0x68)
- { KEY_KP_9, VK_NUMPAD9 }, //(0x69)
- { KEY_KP_MULTIPLY, VK_MULTIPLY }, // (0x6A)
- { KEY_KP_ADD, VK_ADD }, // (0x6B)
+ { Key::PRINT, VK_SNAPSHOT }, // (0x2C)
+
+ { Key::INSERT, VK_INSERT }, // (0x2D)
+
+ { Key::KEY_DELETE, VK_DELETE }, // (0x2E)
+
+ { Key::HELP, VK_HELP }, // (0x2F)
+
+ { Key::KEY_0, (0x30) }, ////0 key
+ { Key::KEY_1, (0x31) }, ////1 key
+ { Key::KEY_2, (0x32) }, ////2 key
+ { Key::KEY_3, (0x33) }, ////3 key
+ { Key::KEY_4, (0x34) }, ////4 key
+ { Key::KEY_5, (0x35) }, ////5 key
+ { Key::KEY_6, (0x36) }, ////6 key
+ { Key::KEY_7, (0x37) }, ////7 key
+ { Key::KEY_8, (0x38) }, ////8 key
+ { Key::KEY_9, (0x39) }, ////9 key
+ { Key::A, (0x41) }, ////A key
+ { Key::B, (0x42) }, ////B key
+ { Key::C, (0x43) }, ////C key
+ { Key::D, (0x44) }, ////D key
+ { Key::E, (0x45) }, ////E key
+ { Key::F, (0x46) }, ////F key
+ { Key::G, (0x47) }, ////G key
+ { Key::H, (0x48) }, ////H key
+ { Key::I, (0x49) }, ////I key
+ { Key::J, (0x4A) }, ////J key
+ { Key::K, (0x4B) }, ////K key
+ { Key::L, (0x4C) }, ////L key
+ { Key::M, (0x4D) }, ////M key
+ { Key::N, (0x4E) }, ////N key
+ { Key::O, (0x4F) }, ////O key
+ { Key::P, (0x50) }, ////P key
+ { Key::Q, (0x51) }, ////Q key
+ { Key::R, (0x52) }, ////R key
+ { Key::S, (0x53) }, ////S key
+ { Key::T, (0x54) }, ////T key
+ { Key::U, (0x55) }, ////U key
+ { Key::V, (0x56) }, ////V key
+ { Key::W, (0x57) }, ////W key
+ { Key::X, (0x58) }, ////X key
+ { Key::Y, (0x59) }, ////Y key
+ { Key::Z, (0x5A) }, ////Z key
+
+ { (Key)KeyModifierMask::META, VK_LWIN }, //(0x5B)
+ { (Key)KeyModifierMask::META, VK_RWIN }, //(0x5C)
+ { Key::MENU, VK_APPS }, //(0x5D)
+ { Key::STANDBY, VK_SLEEP }, //(0x5F)
+ { Key::KP_0, VK_NUMPAD0 }, //(0x60)
+ { Key::KP_1, VK_NUMPAD1 }, //(0x61)
+ { Key::KP_2, VK_NUMPAD2 }, //(0x62)
+ { Key::KP_3, VK_NUMPAD3 }, //(0x63)
+ { Key::KP_4, VK_NUMPAD4 }, //(0x64)
+ { Key::KP_5, VK_NUMPAD5 }, //(0x65)
+ { Key::KP_6, VK_NUMPAD6 }, //(0x66)
+ { Key::KP_7, VK_NUMPAD7 }, //(0x67)
+ { Key::KP_8, VK_NUMPAD8 }, //(0x68)
+ { Key::KP_9, VK_NUMPAD9 }, //(0x69)
+ { Key::KP_MULTIPLY, VK_MULTIPLY }, // (0x6A)
+ { Key::KP_ADD, VK_ADD }, // (0x6B)
//VK_SEPARATOR (0x6C)
- { KEY_KP_SUBTRACT, VK_SUBTRACT }, // (0x6D)
- { KEY_KP_PERIOD, VK_DECIMAL }, // (0x6E)
- { KEY_KP_DIVIDE, VK_DIVIDE }, // (0x6F)
- { KEY_F1, VK_F1 }, // (0x70)
- { KEY_F2, VK_F2 }, // (0x71)
- { KEY_F3, VK_F3 }, // (0x72)
- { KEY_F4, VK_F4 }, // (0x73)
- { KEY_F5, VK_F5 }, // (0x74)
- { KEY_F6, VK_F6 }, // (0x75)
- { KEY_F7, VK_F7 }, // (0x76)
- { KEY_F8, VK_F8 }, // (0x77)
- { KEY_F9, VK_F9 }, // (0x78)
- { KEY_F10, VK_F10 }, // (0x79)
- { KEY_F11, VK_F11 }, // (0x7A)
- { KEY_F12, VK_F12 }, // (0x7B)
- { KEY_F13, VK_F13 }, // (0x7C)
- { KEY_F14, VK_F14 }, // (0x7D)
- { KEY_F15, VK_F15 }, // (0x7E)
- { KEY_F16, VK_F16 }, // (0x7F)
- { KEY_NUMLOCK, VK_NUMLOCK }, // (0x90)
- { KEY_SCROLLLOCK, VK_SCROLL }, // (0x91)
- { KEY_SHIFT, VK_LSHIFT }, // (0xA0)
- { KEY_SHIFT, VK_RSHIFT }, // (0xA1)
- { KEY_CTRL, VK_LCONTROL }, // (0xA2)
- { KEY_CTRL, VK_RCONTROL }, // (0xA3)
- { KEY_MENU, VK_LMENU }, // (0xA4)
- { KEY_MENU, VK_RMENU }, // (0xA5)
+ { Key::KP_SUBTRACT, VK_SUBTRACT }, // (0x6D)
+ { Key::KP_PERIOD, VK_DECIMAL }, // (0x6E)
+ { Key::KP_DIVIDE, VK_DIVIDE }, // (0x6F)
+ { Key::F1, VK_F1 }, // (0x70)
+ { Key::F2, VK_F2 }, // (0x71)
+ { Key::F3, VK_F3 }, // (0x72)
+ { Key::F4, VK_F4 }, // (0x73)
+ { Key::F5, VK_F5 }, // (0x74)
+ { Key::F6, VK_F6 }, // (0x75)
+ { Key::F7, VK_F7 }, // (0x76)
+ { Key::F8, VK_F8 }, // (0x77)
+ { Key::F9, VK_F9 }, // (0x78)
+ { Key::F10, VK_F10 }, // (0x79)
+ { Key::F11, VK_F11 }, // (0x7A)
+ { Key::F12, VK_F12 }, // (0x7B)
+ { Key::F13, VK_F13 }, // (0x7C)
+ { Key::F14, VK_F14 }, // (0x7D)
+ { Key::F15, VK_F15 }, // (0x7E)
+ { Key::F16, VK_F16 }, // (0x7F)
+ { Key::NUMLOCK, VK_NUMLOCK }, // (0x90)
+ { Key::SCROLLLOCK, VK_SCROLL }, // (0x91)
+ { Key::SHIFT, VK_LSHIFT }, // (0xA0)
+ { Key::SHIFT, VK_RSHIFT }, // (0xA1)
+ { Key::CTRL, VK_LCONTROL }, // (0xA2)
+ { Key::CTRL, VK_RCONTROL }, // (0xA3)
+ { Key::MENU, VK_LMENU }, // (0xA4)
+ { Key::MENU, VK_RMENU }, // (0xA5)
- { KEY_BACK, VK_BROWSER_BACK }, // (0xA6)
+ { Key::BACK, VK_BROWSER_BACK }, // (0xA6)
- { KEY_FORWARD, VK_BROWSER_FORWARD }, // (0xA7)
+ { Key::FORWARD, VK_BROWSER_FORWARD }, // (0xA7)
- { KEY_REFRESH, VK_BROWSER_REFRESH }, // (0xA8)
+ { Key::REFRESH, VK_BROWSER_REFRESH }, // (0xA8)
- { KEY_STOP, VK_BROWSER_STOP }, // (0xA9)
+ { Key::STOP, VK_BROWSER_STOP }, // (0xA9)
- { KEY_SEARCH, VK_BROWSER_SEARCH }, // (0xAA)
+ { Key::SEARCH, VK_BROWSER_SEARCH }, // (0xAA)
- { KEY_FAVORITES, VK_BROWSER_FAVORITES }, // (0xAB)
+ { Key::FAVORITES, VK_BROWSER_FAVORITES }, // (0xAB)
- { KEY_HOMEPAGE, VK_BROWSER_HOME }, // (0xAC)
+ { Key::HOMEPAGE, VK_BROWSER_HOME }, // (0xAC)
- { KEY_VOLUMEMUTE, VK_VOLUME_MUTE }, // (0xAD)
+ { Key::VOLUMEMUTE, VK_VOLUME_MUTE }, // (0xAD)
- { KEY_VOLUMEDOWN, VK_VOLUME_DOWN }, // (0xAE)
+ { Key::VOLUMEDOWN, VK_VOLUME_DOWN }, // (0xAE)
- { KEY_VOLUMEUP, VK_VOLUME_UP }, // (0xAF)
+ { Key::VOLUMEUP, VK_VOLUME_UP }, // (0xAF)
- { KEY_MEDIANEXT, VK_MEDIA_NEXT_TRACK }, // (0xB0)
+ { Key::MEDIANEXT, VK_MEDIA_NEXT_TRACK }, // (0xB0)
- { KEY_MEDIAPREVIOUS, VK_MEDIA_PREV_TRACK }, // (0xB1)
+ { Key::MEDIAPREVIOUS, VK_MEDIA_PREV_TRACK }, // (0xB1)
- { KEY_MEDIASTOP, VK_MEDIA_STOP }, // (0xB2)
+ { Key::MEDIASTOP, VK_MEDIA_STOP }, // (0xB2)
//VK_MEDIA_PLAY_PAUSE (0xB3)
- { KEY_LAUNCHMAIL, VK_LAUNCH_MAIL }, // (0xB4)
+ { Key::LAUNCHMAIL, VK_LAUNCH_MAIL }, // (0xB4)
- { KEY_LAUNCHMEDIA, VK_LAUNCH_MEDIA_SELECT }, // (0xB5)
+ { Key::LAUNCHMEDIA, VK_LAUNCH_MEDIA_SELECT }, // (0xB5)
- { KEY_LAUNCH0, VK_LAUNCH_APP1 }, // (0xB6)
+ { Key::LAUNCH0, VK_LAUNCH_APP1 }, // (0xB6)
- { KEY_LAUNCH1, VK_LAUNCH_APP2 }, // (0xB7)
+ { Key::LAUNCH1, VK_LAUNCH_APP2 }, // (0xB7)
- { KEY_SEMICOLON, VK_OEM_1 }, // (0xBA)
+ { Key::SEMICOLON, VK_OEM_1 }, // (0xBA)
- { KEY_EQUAL, VK_OEM_PLUS }, // (0xBB) // Windows 2000/XP: For any country/region, the '+' key
- { KEY_COMMA, VK_OEM_COMMA }, // (0xBC) // Windows 2000/XP: For any country/region, the ',' key
- { KEY_MINUS, VK_OEM_MINUS }, // (0xBD) // Windows 2000/XP: For any country/region, the '-' key
- { KEY_PERIOD, VK_OEM_PERIOD }, // (0xBE) // Windows 2000/XP: For any country/region, the '.' key
- { KEY_SLASH, VK_OEM_2 }, // (0xBF) //Windows 2000/XP: For the US standard keyboard, the '/?' key
+ { Key::EQUAL, VK_OEM_PLUS }, // (0xBB) // Windows 2000/XP: For any country/region, the '+' key
+ { Key::COMMA, VK_OEM_COMMA }, // (0xBC) // Windows 2000/XP: For any country/region, the ',' key
+ { Key::MINUS, VK_OEM_MINUS }, // (0xBD) // Windows 2000/XP: For any country/region, the '-' key
+ { Key::PERIOD, VK_OEM_PERIOD }, // (0xBE) // Windows 2000/XP: For any country/region, the '.' key
+ { Key::SLASH, VK_OEM_2 }, // (0xBF) //Windows 2000/XP: For the US standard keyboard, the '/?' key
- { KEY_QUOTELEFT, VK_OEM_3 }, // (0xC0)
- { KEY_BRACELEFT, VK_OEM_4 }, // (0xDB)
- { KEY_BACKSLASH, VK_OEM_5 }, // (0xDC)
- { KEY_BRACERIGHT, VK_OEM_6 }, // (0xDD)
- { KEY_APOSTROPHE, VK_OEM_7 }, // (0xDE)
+ { Key::QUOTELEFT, VK_OEM_3 }, // (0xC0)
+ { Key::BRACELEFT, VK_OEM_4 }, // (0xDB)
+ { Key::BACKSLASH, VK_OEM_5 }, // (0xDC)
+ { Key::BRACERIGHT, VK_OEM_6 }, // (0xDD)
+ { Key::APOSTROPHE, VK_OEM_7 }, // (0xDE)
/*
{VK_OEM_8 (0xDF)
{VK_OEM_102 (0xE2) // Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard
*/
- //{ KEY_PLAY, VK_PLAY},// (0xFA)
+ //{ Key::PLAY, VK_PLAY},// (0xFA)
- { KEY_UNKNOWN, 0 }
+ { Key::UNKNOWN, 0 }
};
/*
@@ -237,104 +237,104 @@ VK_OEM_CLEAR (0xFE)
*/
static _WinTranslatePair _scancode_to_keycode[] = {
- { KEY_ESCAPE, 0x01 },
- { KEY_1, 0x02 },
- { KEY_2, 0x03 },
- { KEY_3, 0x04 },
- { KEY_4, 0x05 },
- { KEY_5, 0x06 },
- { KEY_6, 0x07 },
- { KEY_7, 0x08 },
- { KEY_8, 0x09 },
- { KEY_9, 0x0A },
- { KEY_0, 0x0B },
- { KEY_MINUS, 0x0C },
- { KEY_EQUAL, 0x0D },
- { KEY_BACKSPACE, 0x0E },
- { KEY_TAB, 0x0F },
- { KEY_Q, 0x10 },
- { KEY_W, 0x11 },
- { KEY_E, 0x12 },
- { KEY_R, 0x13 },
- { KEY_T, 0x14 },
- { KEY_Y, 0x15 },
- { KEY_U, 0x16 },
- { KEY_I, 0x17 },
- { KEY_O, 0x18 },
- { KEY_P, 0x19 },
- { KEY_BRACELEFT, 0x1A },
- { KEY_BRACERIGHT, 0x1B },
- { KEY_ENTER, 0x1C },
- { KEY_CTRL, 0x1D },
- { KEY_A, 0x1E },
- { KEY_S, 0x1F },
- { KEY_D, 0x20 },
- { KEY_F, 0x21 },
- { KEY_G, 0x22 },
- { KEY_H, 0x23 },
- { KEY_J, 0x24 },
- { KEY_K, 0x25 },
- { KEY_L, 0x26 },
- { KEY_SEMICOLON, 0x27 },
- { KEY_APOSTROPHE, 0x28 },
- { KEY_QUOTELEFT, 0x29 },
- { KEY_SHIFT, 0x2A },
- { KEY_BACKSLASH, 0x2B },
- { KEY_Z, 0x2C },
- { KEY_X, 0x2D },
- { KEY_C, 0x2E },
- { KEY_V, 0x2F },
- { KEY_B, 0x30 },
- { KEY_N, 0x31 },
- { KEY_M, 0x32 },
- { KEY_COMMA, 0x33 },
- { KEY_PERIOD, 0x34 },
- { KEY_SLASH, 0x35 },
- { KEY_SHIFT, 0x36 },
- { KEY_PRINT, 0x37 },
- { KEY_ALT, 0x38 },
- { KEY_SPACE, 0x39 },
- { KEY_CAPSLOCK, 0x3A },
- { KEY_F1, 0x3B },
- { KEY_F2, 0x3C },
- { KEY_F3, 0x3D },
- { KEY_F4, 0x3E },
- { KEY_F5, 0x3F },
- { KEY_F6, 0x40 },
- { KEY_F7, 0x41 },
- { KEY_F8, 0x42 },
- { KEY_F9, 0x43 },
- { KEY_F10, 0x44 },
- { KEY_NUMLOCK, 0x45 },
- { KEY_SCROLLLOCK, 0x46 },
- { KEY_HOME, 0x47 },
- { KEY_UP, 0x48 },
- { KEY_PAGEUP, 0x49 },
- { KEY_KP_SUBTRACT, 0x4A },
- { KEY_LEFT, 0x4B },
- { KEY_KP_5, 0x4C },
- { KEY_RIGHT, 0x4D },
- { KEY_KP_ADD, 0x4E },
- { KEY_END, 0x4F },
- { KEY_DOWN, 0x50 },
- { KEY_PAGEDOWN, 0x51 },
- { KEY_INSERT, 0x52 },
- { KEY_DELETE, 0x53 },
- //{ KEY_???, 0x56 }, //NON US BACKSLASH
- { KEY_F11, 0x57 },
- { KEY_F12, 0x58 },
- { KEY_META, 0x5B },
- { KEY_META, 0x5C },
- { KEY_MENU, 0x5D },
- { KEY_F13, 0x64 },
- { KEY_F14, 0x65 },
- { KEY_F15, 0x66 },
- { KEY_F16, 0x67 },
- { KEY_UNKNOWN, 0 }
+ { Key::ESCAPE, 0x01 },
+ { Key::KEY_1, 0x02 },
+ { Key::KEY_2, 0x03 },
+ { Key::KEY_3, 0x04 },
+ { Key::KEY_4, 0x05 },
+ { Key::KEY_5, 0x06 },
+ { Key::KEY_6, 0x07 },
+ { Key::KEY_7, 0x08 },
+ { Key::KEY_8, 0x09 },
+ { Key::KEY_9, 0x0A },
+ { Key::KEY_0, 0x0B },
+ { Key::MINUS, 0x0C },
+ { Key::EQUAL, 0x0D },
+ { Key::BACKSPACE, 0x0E },
+ { Key::TAB, 0x0F },
+ { Key::Q, 0x10 },
+ { Key::W, 0x11 },
+ { Key::E, 0x12 },
+ { Key::R, 0x13 },
+ { Key::T, 0x14 },
+ { Key::Y, 0x15 },
+ { Key::U, 0x16 },
+ { Key::I, 0x17 },
+ { Key::O, 0x18 },
+ { Key::P, 0x19 },
+ { Key::BRACELEFT, 0x1A },
+ { Key::BRACERIGHT, 0x1B },
+ { Key::ENTER, 0x1C },
+ { Key::CTRL, 0x1D },
+ { Key::A, 0x1E },
+ { Key::S, 0x1F },
+ { Key::D, 0x20 },
+ { Key::F, 0x21 },
+ { Key::G, 0x22 },
+ { Key::H, 0x23 },
+ { Key::J, 0x24 },
+ { Key::K, 0x25 },
+ { Key::L, 0x26 },
+ { Key::SEMICOLON, 0x27 },
+ { Key::APOSTROPHE, 0x28 },
+ { Key::QUOTELEFT, 0x29 },
+ { Key::SHIFT, 0x2A },
+ { Key::BACKSLASH, 0x2B },
+ { Key::Z, 0x2C },
+ { Key::X, 0x2D },
+ { Key::C, 0x2E },
+ { Key::V, 0x2F },
+ { Key::B, 0x30 },
+ { Key::N, 0x31 },
+ { Key::M, 0x32 },
+ { Key::COMMA, 0x33 },
+ { Key::PERIOD, 0x34 },
+ { Key::SLASH, 0x35 },
+ { Key::SHIFT, 0x36 },
+ { Key::PRINT, 0x37 },
+ { Key::ALT, 0x38 },
+ { Key::SPACE, 0x39 },
+ { Key::CAPSLOCK, 0x3A },
+ { Key::F1, 0x3B },
+ { Key::F2, 0x3C },
+ { Key::F3, 0x3D },
+ { Key::F4, 0x3E },
+ { Key::F5, 0x3F },
+ { Key::F6, 0x40 },
+ { Key::F7, 0x41 },
+ { Key::F8, 0x42 },
+ { Key::F9, 0x43 },
+ { Key::F10, 0x44 },
+ { Key::NUMLOCK, 0x45 },
+ { Key::SCROLLLOCK, 0x46 },
+ { Key::HOME, 0x47 },
+ { Key::UP, 0x48 },
+ { Key::PAGEUP, 0x49 },
+ { Key::KP_SUBTRACT, 0x4A },
+ { Key::LEFT, 0x4B },
+ { Key::KP_5, 0x4C },
+ { Key::RIGHT, 0x4D },
+ { Key::KP_ADD, 0x4E },
+ { Key::END, 0x4F },
+ { Key::DOWN, 0x50 },
+ { Key::PAGEDOWN, 0x51 },
+ { Key::INSERT, 0x52 },
+ { Key::KEY_DELETE, 0x53 },
+ //{ Key::???, 0x56 }, //NON US BACKSLASH
+ { Key::F11, 0x57 },
+ { Key::F12, 0x58 },
+ { Key::META, 0x5B },
+ { Key::META, 0x5C },
+ { Key::MENU, 0x5D },
+ { Key::F13, 0x64 },
+ { Key::F14, 0x65 },
+ { Key::F15, 0x66 },
+ { Key::F16, 0x67 },
+ { Key::UNKNOWN, 0 }
};
-unsigned int KeyMappingWindows::get_keysym(unsigned int p_code) {
- for (int i = 0; _vk_to_keycode[i].keysym != KEY_UNKNOWN; i++) {
+Key KeyMappingWindows::get_keysym(unsigned int p_code) {
+ for (int i = 0; _vk_to_keycode[i].keysym != Key::UNKNOWN; i++) {
if (_vk_to_keycode[i].keycode == p_code) {
//printf("outcode: %x\n",_vk_to_keycode[i].keysym);
@@ -342,12 +342,22 @@ unsigned int KeyMappingWindows::get_keysym(unsigned int p_code) {
}
}
- return KEY_UNKNOWN;
+ return Key::UNKNOWN;
}
-unsigned int KeyMappingWindows::get_scansym(unsigned int p_code, bool p_extended) {
- unsigned int keycode = KEY_UNKNOWN;
- for (int i = 0; _scancode_to_keycode[i].keysym != KEY_UNKNOWN; i++) {
+unsigned int KeyMappingWindows::get_scancode(Key p_keycode) {
+ for (int i = 0; _scancode_to_keycode[i].keysym != Key::UNKNOWN; i++) {
+ if (_scancode_to_keycode[i].keysym == p_keycode) {
+ return _scancode_to_keycode[i].keycode;
+ }
+ }
+
+ return 0;
+}
+
+Key KeyMappingWindows::get_scansym(unsigned int p_code, bool p_extended) {
+ Key keycode = Key::UNKNOWN;
+ for (int i = 0; _scancode_to_keycode[i].keysym != Key::UNKNOWN; i++) {
if (_scancode_to_keycode[i].keycode == p_code) {
keycode = _scancode_to_keycode[i].keysym;
break;
@@ -356,55 +366,55 @@ unsigned int KeyMappingWindows::get_scansym(unsigned int p_code, bool p_extended
if (p_extended) {
switch (keycode) {
- case KEY_ENTER: {
- keycode = KEY_KP_ENTER;
+ case Key::ENTER: {
+ keycode = Key::KP_ENTER;
} break;
- case KEY_SLASH: {
- keycode = KEY_KP_DIVIDE;
+ case Key::SLASH: {
+ keycode = Key::KP_DIVIDE;
} break;
- case KEY_CAPSLOCK: {
- keycode = KEY_KP_ADD;
+ case Key::CAPSLOCK: {
+ keycode = Key::KP_ADD;
} break;
default:
break;
}
} else {
switch (keycode) {
- case KEY_NUMLOCK: {
- keycode = KEY_PAUSE;
+ case Key::NUMLOCK: {
+ keycode = Key::PAUSE;
} break;
- case KEY_HOME: {
- keycode = KEY_KP_7;
+ case Key::HOME: {
+ keycode = Key::KP_7;
} break;
- case KEY_UP: {
- keycode = KEY_KP_8;
+ case Key::UP: {
+ keycode = Key::KP_8;
} break;
- case KEY_PAGEUP: {
- keycode = KEY_KP_9;
+ case Key::PAGEUP: {
+ keycode = Key::KP_9;
} break;
- case KEY_LEFT: {
- keycode = KEY_KP_4;
+ case Key::LEFT: {
+ keycode = Key::KP_4;
} break;
- case KEY_RIGHT: {
- keycode = KEY_KP_6;
+ case Key::RIGHT: {
+ keycode = Key::KP_6;
} break;
- case KEY_END: {
- keycode = KEY_KP_1;
+ case Key::END: {
+ keycode = Key::KP_1;
} break;
- case KEY_DOWN: {
- keycode = KEY_KP_2;
+ case Key::DOWN: {
+ keycode = Key::KP_2;
} break;
- case KEY_PAGEDOWN: {
- keycode = KEY_KP_3;
+ case Key::PAGEDOWN: {
+ keycode = Key::KP_3;
} break;
- case KEY_INSERT: {
- keycode = KEY_KP_0;
+ case Key::INSERT: {
+ keycode = Key::KP_0;
} break;
- case KEY_DELETE: {
- keycode = KEY_KP_PERIOD;
+ case Key::KEY_DELETE: {
+ keycode = Key::KP_PERIOD;
} break;
- case KEY_PRINT: {
- keycode = KEY_KP_MULTIPLY;
+ case Key::PRINT: {
+ keycode = Key::KP_MULTIPLY;
} break;
default:
break;
@@ -416,13 +426,13 @@ unsigned int KeyMappingWindows::get_scansym(unsigned int p_code, bool p_extended
bool KeyMappingWindows::is_extended_key(unsigned int p_code) {
return p_code == VK_INSERT ||
- p_code == VK_DELETE ||
- p_code == VK_HOME ||
- p_code == VK_END ||
- p_code == VK_PRIOR ||
- p_code == VK_NEXT ||
- p_code == VK_LEFT ||
- p_code == VK_UP ||
- p_code == VK_RIGHT ||
- p_code == VK_DOWN;
+ p_code == VK_DELETE ||
+ p_code == VK_HOME ||
+ p_code == VK_END ||
+ p_code == VK_PRIOR ||
+ p_code == VK_NEXT ||
+ p_code == VK_LEFT ||
+ p_code == VK_UP ||
+ p_code == VK_RIGHT ||
+ p_code == VK_DOWN;
}
diff --git a/platform/windows/key_mapping_windows.h b/platform/windows/key_mapping_windows.h
index fb07227014..0454be7310 100644
--- a/platform/windows/key_mapping_windows.h
+++ b/platform/windows/key_mapping_windows.h
@@ -33,16 +33,17 @@
#include "core/os/keyboard.h"
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
-
#include <winuser.h>
class KeyMappingWindows {
KeyMappingWindows() {}
public:
- static unsigned int get_keysym(unsigned int p_code);
- static unsigned int get_scansym(unsigned int p_code, bool p_extended);
+ static Key get_keysym(unsigned int p_code);
+ static unsigned int get_scancode(Key p_keycode);
+ static Key get_scansym(unsigned int p_code, bool p_extended);
static bool is_extended_key(unsigned int p_code);
};
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 2a0a509d43..d8d4e92d9d 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -28,15 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-// Must include Winsock before windows.h (included by os_windows.h)
-#include "drivers/unix/net_socket_posix.h"
-
#include "os_windows.h"
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
#include "core/io/marshalls.h"
#include "core/version_generated.gen.h"
+#include "drivers/unix/net_socket_posix.h"
#include "drivers/windows/dir_access_windows.h"
#include "drivers/windows/file_access_windows.h"
#include "joypad_windows.h"
@@ -75,7 +73,6 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
#define GetProcAddress (void *)GetProcAddress
#endif
-#ifdef DEBUG_ENABLED
static String format_error_message(DWORD id) {
LPWSTR messageBuffer = nullptr;
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
@@ -87,7 +84,6 @@ static String format_error_message(DWORD id) {
return msg;
}
-#endif // DEBUG_ENABLED
void RedirectIOToConsole() {
int hConHandle;
@@ -294,12 +290,13 @@ String OS_Windows::get_name() const {
return "Windows";
}
-OS::Date OS_Windows::get_date(bool utc) const {
+OS::Date OS_Windows::get_date(bool p_utc) const {
SYSTEMTIME systemtime;
- if (utc)
+ if (p_utc) {
GetSystemTime(&systemtime);
- else
+ } else {
GetLocalTime(&systemtime);
+ }
Date date;
date.day = systemtime.wDay;
@@ -310,12 +307,13 @@ OS::Date OS_Windows::get_date(bool utc) const {
return date;
}
-OS::Time OS_Windows::get_time(bool utc) const {
+OS::Time OS_Windows::get_time(bool p_utc) const {
SYSTEMTIME systemtime;
- if (utc)
+ if (p_utc) {
GetSystemTime(&systemtime);
- else
+ } else {
GetLocalTime(&systemtime);
+ }
Time time;
time.hour = systemtime.wHour;
@@ -449,7 +447,7 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
ZeroMemory(&pi.pi, sizeof(pi.pi));
LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si;
- int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi);
+ int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi);
ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command);
WaitForSingleObject(pi.pi.hProcess, INFINITE);
@@ -477,7 +475,7 @@ Error OS_Windows::create_process(const String &p_path, const List<String> &p_arg
ZeroMemory(&pi.pi, sizeof(pi.pi));
LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si;
- int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi);
+ int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi);
ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command);
ProcessID pid = pi.pi.dwProcessId;
@@ -557,8 +555,27 @@ String OS_Windows::get_stdin_string(bool p_block) {
}
Error OS_Windows::shell_open(String p_uri) {
- ShellExecuteW(nullptr, nullptr, (LPCWSTR)(p_uri.utf16().get_data()), nullptr, nullptr, SW_SHOWNORMAL);
- return OK;
+ INT_PTR ret = (INT_PTR)ShellExecuteW(nullptr, nullptr, (LPCWSTR)(p_uri.utf16().get_data()), nullptr, nullptr, SW_SHOWNORMAL);
+ if (ret > 32) {
+ return OK;
+ } else {
+ switch (ret) {
+ case ERROR_FILE_NOT_FOUND:
+ case SE_ERR_DLLNOTFOUND:
+ return ERR_FILE_NOT_FOUND;
+ case ERROR_PATH_NOT_FOUND:
+ return ERR_FILE_BAD_PATH;
+ case ERROR_BAD_FORMAT:
+ return ERR_FILE_CORRUPT;
+ case SE_ERR_ACCESSDENIED:
+ return ERR_UNAUTHORIZED;
+ case 0:
+ case SE_ERR_OOM:
+ return ERR_OUT_OF_MEMORY;
+ default:
+ return FAILED;
+ }
+ }
}
String OS_Windows::get_locale() const {
@@ -662,18 +679,27 @@ String OS_Windows::get_data_path() const {
}
String OS_Windows::get_cache_path() const {
- // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well.
- if (has_environment("XDG_CACHE_HOME")) {
- if (get_environment("XDG_CACHE_HOME").is_absolute_path()) {
- return get_environment("XDG_CACHE_HOME").replace("\\", "/");
- } else {
- WARN_PRINT_ONCE("`XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `%TEMP%` or `get_config_path()` per the XDG Base Directory specification.");
+ static String cache_path_cache;
+ if (cache_path_cache.is_empty()) {
+ // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well.
+ if (has_environment("XDG_CACHE_HOME")) {
+ if (get_environment("XDG_CACHE_HOME").is_absolute_path()) {
+ cache_path_cache = get_environment("XDG_CACHE_HOME").replace("\\", "/");
+ } else {
+ WARN_PRINT_ONCE("`XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `%LOCALAPPDATA%\\cache`, `%TEMP%` or `get_config_path()` per the XDG Base Directory specification.");
+ }
+ }
+ if (cache_path_cache.is_empty() && has_environment("LOCALAPPDATA")) {
+ cache_path_cache = get_environment("LOCALAPPDATA").replace("\\", "/");
+ }
+ if (cache_path_cache.is_empty() && has_environment("TEMP")) {
+ cache_path_cache = get_environment("TEMP").replace("\\", "/");
+ }
+ if (cache_path_cache.is_empty()) {
+ cache_path_cache = get_config_path();
}
}
- if (has_environment("TEMP")) {
- return get_environment("TEMP").replace("\\", "/");
- }
- return get_config_path();
+ return cache_path_cache;
}
// Get properly capitalized engine name for system paths
@@ -734,7 +760,7 @@ String OS_Windows::get_user_data_dir() const {
}
}
- return ProjectSettings::get_singleton()->get_resource_path();
+ return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file("[unnamed project]");
}
String OS_Windows::get_unique_id() const {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index c4a2eda8f4..1342d95575 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -46,10 +46,6 @@
#include "drivers/xaudio2/audio_driver_xaudio2.h"
#endif
-#if defined(OPENGL_ENABLED)
-#include "context_gl_windows.h"
-#endif
-
#if defined(VULKAN_ENABLED)
#include "drivers/vulkan/rendering_device_vulkan.h"
#include "platform/windows/vulkan_context_win.h"
@@ -57,7 +53,9 @@
#include <fcntl.h>
#include <io.h>
+#include <shellapi.h>
#include <stdio.h>
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
@@ -120,8 +118,8 @@ public:
virtual void initialize_joypads() override {}
- virtual Date get_date(bool utc) const override;
- virtual Time get_time(bool utc) const override;
+ virtual Date get_date(bool p_utc) const override;
+ virtual Time get_time(bool p_utc) const override;
virtual TimeZoneInfo get_time_zone_info() const override;
virtual double get_unix_time() const override;
diff --git a/platform/windows/platform_config.h b/platform/windows/platform_config.h
index 481f583f6f..dace0f86af 100644
--- a/platform/windows/platform_config.h
+++ b/platform/windows/platform_config.h
@@ -29,3 +29,5 @@
/*************************************************************************/
#include <malloc.h>
+
+#define OPENGL_INCLUDE_H "thirdparty/glad/glad/glad.h"
diff --git a/platform/windows/vulkan_context_win.h b/platform/windows/vulkan_context_win.h
index 39dd2641fd..61e66b8ae0 100644
--- a/platform/windows/vulkan_context_win.h
+++ b/platform/windows/vulkan_context_win.h
@@ -32,6 +32,8 @@
#define VULKAN_DEVICE_WIN_H
#include "drivers/vulkan/vulkan_context.h"
+
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
class VulkanContextWindows : public VulkanContext {
diff --git a/platform/windows/windows_terminal_logger.cpp b/platform/windows/windows_terminal_logger.cpp
index 8cab7ca521..e54a61fdfd 100644
--- a/platform/windows/windows_terminal_logger.cpp
+++ b/platform/windows/windows_terminal_logger.cpp
@@ -33,6 +33,7 @@
#ifdef WINDOWS_ENABLED
#include <stdio.h>
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
void WindowsTerminalLogger::logv(const char *p_format, va_list p_list, bool p_err) {