summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/ProjectSettings.xml4
-rw-r--r--editor/editor_node.cpp17
-rw-r--r--editor/editor_node.h1
-rw-r--r--modules/fbx/data/fbx_mesh_data.cpp28
-rw-r--r--modules/fbx/data/import_state.h1
-rw-r--r--modules/fbx/editor_scene_importer_fbx.cpp10
-rw-r--r--modules/fbx/editor_scene_importer_fbx.h4
-rw-r--r--modules/webxr/doc_classes/WebXRInterface.xml140
-rw-r--r--modules/webxr/webxr_interface.cpp2
-rw-r--r--platform/windows/display_server_windows.cpp67
-rw-r--r--platform/windows/display_server_windows.h15
-rw-r--r--scene/gui/text_edit.cpp3
12 files changed, 143 insertions, 149 deletions
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index ec380ddc54..a82cf9a2a9 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -1058,6 +1058,8 @@
<member name="rendering/environment/default_environment" type="String" setter="" getter="" default="&quot;&quot;">
[Environment] that will be used as a fallback environment in case a scene does not specify its own environment. The default environment is loaded in at scene load time regardless of whether you have set an environment or not. If you do not rely on the fallback environment, it is best to delete [code]default_env.tres[/code], or to specify a different default environment here.
</member>
+ <member name="rendering/forward_renderer/threaded_render_minimum_instances" type="int" setter="" getter="" default="500">
+ </member>
<member name="rendering/gpu_lightmapper/performance/max_rays_per_pass" type="int" setter="" getter="" default="32">
</member>
<member name="rendering/gpu_lightmapper/performance/max_rays_per_probe_pass" type="int" setter="" getter="" default="64">
@@ -1287,6 +1289,8 @@
</member>
<member name="rendering/sdfgi/probe_ray_count" type="int" setter="" getter="" default="2">
</member>
+ <member name="rendering/spatial_indexer/threaded_cull_minimum_instances" type="int" setter="" getter="" default="1000">
+ </member>
<member name="rendering/spatial_indexer/update_iterations_per_frame" type="int" setter="" getter="" default="10">
</member>
<member name="rendering/threads/thread_model" type="int" setter="" getter="" default="1">
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 1cdff65545..6f03518029 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -2123,7 +2123,10 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
if (scene->get_filename() == "") {
current_option = -1;
- _menu_option_confirm(FILE_SAVE_BEFORE_RUN, false);
+ _menu_option(FILE_SAVE_AS_SCENE);
+ // Set the option to save and run so when the dialog is accepted, the scene runs.
+ current_option = FILE_SAVE_AND_RUN;
+ file->set_title(TTR("Save scene before running..."));
return;
}
@@ -2382,18 +2385,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case FILE_SAVE_ALL_SCENES: {
_save_all_scenes();
} break;
- case FILE_SAVE_BEFORE_RUN: {
- if (!p_confirmed) {
- confirmation->get_cancel_button()->set_text(TTR("No"));
- confirmation->get_ok_button()->set_text(TTR("Yes"));
- confirmation->set_text(TTR("This scene has never been saved. Save before running?"));
- confirmation->popup_centered();
- break;
- }
-
- _menu_option(FILE_SAVE_AS_SCENE);
- _menu_option_confirm(FILE_SAVE_AND_RUN, false);
- } break;
case FILE_EXPORT_PROJECT: {
project_export->popup_export();
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 6e05fc7703..1da162dc9c 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -126,7 +126,6 @@ private:
FILE_SAVE_SCENE,
FILE_SAVE_AS_SCENE,
FILE_SAVE_ALL_SCENES,
- FILE_SAVE_BEFORE_RUN,
FILE_SAVE_AND_RUN,
FILE_SHOW_IN_FILESYSTEM,
FILE_IMPORT_SUBSCENE,
diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp
index d84a7ab17c..963a815896 100644
--- a/modules/fbx/data/fbx_mesh_data.cpp
+++ b/modules/fbx/data/fbx_mesh_data.cpp
@@ -135,26 +135,6 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
&collect_all,
HashMap<int, Vector3>());
- // List<int> keys;
- // normals.get_key_list(&keys);
- //
- // const std::vector<Assimp::FBX::MeshGeometry::Edge>& edges = mesh_geometry->get_edge_map();
- // for (int index = 0; index < keys.size(); index++) {
- // const int key = keys[index];
- // const int v1 = edges[key].vertex_0;
- // const int v2 = edges[key].vertex_1;
- // const Vector3& n1 = normals.get(v1);
- // const Vector3& n2 = normals.get(v2);
- // print_verbose("[" + itos(v1) + "] n1: " + n1 + "\n[" + itos(v2) + "] n2: " + n2);
- // //print_verbose("[" + itos(key) + "] n1: " + n1 + ", n2: " + n2) ;
- // //print_verbose("vindex: " + itos(edges[key].vertex_0) + ", vindex2: " + itos(edges[key].vertex_1));
- // //Vector3 ver1 = vertices[edges[key].vertex_0];
- // //Vector3 ver2 = vertices[edges[key].vertex_1];
- // /*real_t angle1 = Math::rad2deg(n1.angle_to(n2));
- // real_t angle2 = Math::rad2deg(n2.angle_to(n1));
- // print_verbose("angle of normals: " + rtos(angle1) + " angle 2" + rtos(angle2));*/
- // }
-
HashMap<int, Vector2> uvs_0;
HashMap<int, HashMap<int, Vector2>> uvs_0_raw = extract_per_vertex_data(
vertices.size(),
@@ -371,6 +351,9 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
normals_ptr[vertex]);
}
+ if (state.is_blender_fbx) {
+ morph_st->generate_normals();
+ }
morph_st->generate_tangents();
surface->morphs.push_back(morph_st->commit_to_arrays());
}
@@ -393,6 +376,9 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) {
SurfaceData *surface = surfaces.getptr(*surface_id);
+ if (state.is_blender_fbx) {
+ surface->surface_tool->generate_normals();
+ }
// you can't generate them without a valid uv map.
if (uvs_0_raw.size() > 0) {
surface->surface_tool->generate_tangents();
@@ -785,7 +771,7 @@ void FBXMeshData::add_vertex(
const Vector3 &p_morph_normal) {
ERR_FAIL_INDEX_MSG(p_vertex, (Vertex)p_vertices_position.size(), "FBX file is corrupted, the position of the vertex can't be retrieved.");
- if (p_normals.has(p_vertex)) {
+ if (p_normals.has(p_vertex) && !state.is_blender_fbx) {
p_surface_tool->set_normal(p_normals[p_vertex] + p_morph_normal);
}
diff --git a/modules/fbx/data/import_state.h b/modules/fbx/data/import_state.h
index 1d664a5212..83bc43faff 100644
--- a/modules/fbx/data/import_state.h
+++ b/modules/fbx/data/import_state.h
@@ -64,6 +64,7 @@ struct FBXSkeleton;
struct ImportState {
bool enable_material_import = true;
bool enable_animation_import = true;
+ bool is_blender_fbx = false;
Map<StringName, Ref<Texture>> cached_image_searches;
Map<uint64_t, Ref<Material>> cached_materials;
diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp
index 5918f4dbed..6576147b2b 100644
--- a/modules/fbx/editor_scene_importer_fbx.cpp
+++ b/modules/fbx/editor_scene_importer_fbx.cpp
@@ -180,10 +180,12 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
}
if (is_blender_fbx) {
- WARN_PRINT("Blender FBX files will not work properly with keyframes or skeletons until we make fixes. Please stand by.");
+ WARN_PRINT("We don't officially support Blender FBX animations yet, due to issues with upstream Blender,\n"
+ "so please wait for us to work around remaining issues. We will continue to import the file but it may be broken.\n"
+ "For minimal breakage, please export FBX from Blender with -Z forward, and Y up.");
}
- Node3D *spatial = _generate_scene(p_path, &doc, p_flags, p_bake_fps, 8);
+ Node3D *spatial = _generate_scene(p_path, &doc, p_flags, p_bake_fps, 8, is_blender_fbx);
// todo: move to document shutdown (will need to be validated after moving; this code has been validated already)
for (FBXDocParser::TokenPtr token : tokens) {
if (token) {
@@ -327,8 +329,10 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
const FBXDocParser::Document *p_document,
const uint32_t p_flags,
int p_bake_fps,
- const int32_t p_max_bone_weights) {
+ const int32_t p_max_bone_weights,
+ bool p_is_blender_fbx) {
ImportState state;
+ state.is_blender_fbx = p_is_blender_fbx;
state.path = p_path;
state.animation_player = NULL;
diff --git a/modules/fbx/editor_scene_importer_fbx.h b/modules/fbx/editor_scene_importer_fbx.h
index 25c7c1a907..39f8648b0f 100644
--- a/modules/fbx/editor_scene_importer_fbx.h
+++ b/modules/fbx/editor_scene_importer_fbx.h
@@ -114,7 +114,9 @@ private:
Node3D *_generate_scene(const String &p_path, const FBXDocParser::Document *p_document,
const uint32_t p_flags,
- int p_bake_fps, const int32_t p_max_bone_weights);
+ int p_bake_fps,
+ const int32_t p_max_bone_weights,
+ bool p_is_blender_fbx);
template <class T>
T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, float p_time, AssetImportAnimation::Interpolation p_interp);
diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml
index f178dc1bd5..bddffd910e 100644
--- a/modules/webxr/doc_classes/WebXRInterface.xml
+++ b/modules/webxr/doc_classes/WebXRInterface.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebXRInterface" inherits="XRInterface" version="3.2">
+<class name="WebXRInterface" inherits="XRInterface" version="4.0">
<brief_description>
AR/VR interface using WebXR.
</brief_description>
@@ -66,7 +66,7 @@
func _webxr_session_started():
# This tells Godot to start rendering to the headset.
- get_viewport().arvr = true
+ get_viewport().xr = true
# This will be the reference space type you ultimately got, out of the
# types that you requested above. This is useful if you want the game to
# work a little differently in 'bounded-floor' versus 'local-floor'.
@@ -75,7 +75,7 @@
func _webxr_session_ended():
# If the user exits immersive mode, then we tell Godot to render to the web
# page again.
- get_viewport().arvr = false
+ get_viewport().xr = false
func _webxr_session_failed(message):
OS.alert("Failed to initialize: " + message)
@@ -90,18 +90,7 @@
<link title="How to make a VR game for WebXR with Godot">https://www.snopekgames.com/blog/2020/how-make-vr-game-webxr-godot</link>
</tutorials>
<methods>
- <method name="is_session_supported">
- <return type="void">
- </return>
- <argument index="0" name="session_mode" type="String">
- </argument>
- <description>
- Checks if the given [code]session_mode[/code] is supported by the user's browser.
- Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRSessionMode]WebXR's XRSessionMode[/url], including: [code]"immersive-vr"[/code], [code]"immersive-ar"[/code], and [code]"inline"[/code].
- This method returns nothing, instead it emits the [signal session_supported] signal with the result.
- </description>
- </method>
- <method name="get_controller">
+ <method name="get_controller" qualifiers="const">
<return type="XRPositionalTracker">
</return>
<argument index="0" name="controller_id" type="int">
@@ -118,18 +107,23 @@
- [signal squeezestart]
</description>
</method>
+ <method name="is_session_supported">
+ <return type="void">
+ </return>
+ <argument index="0" name="session_mode" type="String">
+ </argument>
+ <description>
+ Checks if the given [code]session_mode[/code] is supported by the user's browser.
+ Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRSessionMode]WebXR's XRSessionMode[/url], including: [code]"immersive-vr"[/code], [code]"immersive-ar"[/code], and [code]"inline"[/code].
+ This method returns nothing, instead it emits the [signal session_supported] signal with the result.
+ </description>
+ </method>
</methods>
<members>
- <member name="session_mode" type="String" setter="set_session_mode" getter="get_session_mode">
- The session mode used by [method XRInterface.initialize] when setting up the WebXR session.
- This doesn't have any effect on the interface when already initialized.
- Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRSessionMode]WebXR's XRSessionMode[/url], including: [code]"immersive-vr"[/code], [code]"immersive-ar"[/code], and [code]"inline"[/code].
- </member>
- <member name="required_features" type="String" setter="set_required_features" getter="get_required_features">
- A comma-seperated list of required features used by [method XRInterface.initialize] when setting up the WebXR session.
- If a user's browser or device doesn't support one of the given features, initialization will fail and [signal session_failed] will be emitted.
- This doesn't have any effect on the interface when already initialized.
- Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url]. If you want to use a particular reference space type, it must be listed in either [member required_features] or [member optional_features].
+ <member name="bounds_geometry" type="PackedVector3Array" setter="" getter="get_bounds_geometry">
+ The vertices of a polygon which defines the boundaries of the user's play area.
+ This will only be available if [member reference_space_type] is [code]"bounded-floor"[/code] and only on certain browsers and devices that support it.
+ The [signal reference_space_reset] signal may indicate when this changes.
</member>
<member name="optional_features" type="String" setter="set_optional_features" getter="get_optional_features">
A comma-seperated list of optional features used by [method XRInterface.initialize] when setting up the WebXR session.
@@ -137,54 +131,54 @@
This doesn't have any effect on the interface when already initialized.
Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url]. If you want to use a particular reference space type, it must be listed in either [member required_features] or [member optional_features].
</member>
+ <member name="reference_space_type" type="String" setter="" getter="get_reference_space_type">
+ The reference space type (from the list of requested types set in the [member requested_reference_space_types] property), that was ultimately used by [method XRInterface.initialize] when setting up the WebXR session.
+ Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url]. If you want to use a particular reference space type, it must be listed in either [member required_features] or [member optional_features].
+ </member>
<member name="requested_reference_space_types" type="String" setter="set_requested_reference_space_types" getter="get_requested_reference_space_types">
A comma-seperated list of reference space types used by [method XRInterface.initialize] when setting up the WebXR session.
The reference space types are requested in order, and the first on supported by the users device or browser will be used. The [member reference_space_type] property contains the reference space type that was ultimately used.
This doesn't have any effect on the interface when already initialized.
Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url]. If you want to use a particular reference space type, it must be listed in either [member required_features] or [member optional_features].
</member>
- <member name="reference_space_type" type="String" setter="" getter="get_reference_space_type">
- The reference space type (from the list of requested types set in the [member requested_reference_space_types] property), that was ultimately used by [method XRInterface.initialize] when setting up the WebXR session.
+ <member name="required_features" type="String" setter="set_required_features" getter="get_required_features">
+ A comma-seperated list of required features used by [method XRInterface.initialize] when setting up the WebXR session.
+ If a user's browser or device doesn't support one of the given features, initialization will fail and [signal session_failed] will be emitted.
+ This doesn't have any effect on the interface when already initialized.
Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpaceType]WebXR's XRReferenceSpaceType[/url]. If you want to use a particular reference space type, it must be listed in either [member required_features] or [member optional_features].
</member>
+ <member name="session_mode" type="String" setter="set_session_mode" getter="get_session_mode">
+ The session mode used by [method XRInterface.initialize] when setting up the WebXR session.
+ This doesn't have any effect on the interface when already initialized.
+ Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRSessionMode]WebXR's XRSessionMode[/url], including: [code]"immersive-vr"[/code], [code]"immersive-ar"[/code], and [code]"inline"[/code].
+ </member>
<member name="visibility_state" type="String" setter="" getter="get_visibility_state">
Indicates if the WebXR session's imagery is visible to the user.
Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRVisibilityState]WebXR's XRVisibilityState[/url], including [code]"hidden"[/code], [code]"visible"[/code], and [code]"visible-blurred"[/code].
</member>
- <member name="bounds_geometry" type="PackedVector3Array" setter="" getter="get_bounds_geometry">
- The vertices of a polygon which defines the boundaries of the user's play area.
- This will only be available if [member reference_space_type] is [code]"bounded-floor"[/code] and only on certain browsers and devices that support it.
- The [signal reference_space_reset] signal may indicate when this changes.
- </member>
</members>
<signals>
- <signal name="session_supported">
- <argument index="0" name="session_mode" type="String">
- </argument>
- <argument index="1" name="supported" type="bool">
- </argument>
- <description>
- Emitted by [method is_session_supported] to indicate if the given [code]session_mode[/code] is supported or not.
- </description>
- </signal>
- <signal name="session_started">
+ <signal name="reference_space_reset">
<description>
- Emitted by [method XRInterface.initialize] if the session is successfully started.
- At this point, it's safe to do [code]get_viewport().arvr = true[/code] to instruct Godot to start rendering to the AR/VR device.
+ Emitted to indicate that the reference space has been reset or reconfigured.
+ When (or whether) this is emitted depends on the user's browser or device, but may include when the user has changed the dimensions of their play space (which you may be able to access via [member bounds_geometry]) or pressed/held a button to recenter their position.
+ See [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpace/reset_event]WebXR's XRReferenceSpace reset event[/url] for more information.
</description>
</signal>
- <signal name="session_failed">
- <argument index="0" name="message" type="String">
+ <signal name="select">
+ <argument index="0" name="controller_id" type="int">
</argument>
<description>
- Emitted by [method XRInterface.initialize] if the session fails to start.
- [code]message[/code] may optionally contain an error message from WebXR, or an empty string if no message is available.
+ Emitted after one of the "controllers" has finished its "primary action".
+ Use [method get_controller] to get more information about the controller.
</description>
</signal>
- <signal name="session_ended">
+ <signal name="selectend">
+ <argument index="0" name="controller_id" type="int">
+ </argument>
<description>
- Emitted when the user ends the WebXR session (which can be done using UI from the browser or device).
- At this point, you should do [code]get_viewport().arvr = false[/code] to instruct Godot to resume rendering to the screen.
+ Emitted when one of the "controllers" has finished its "primary action".
+ Use [method get_controller] to get more information about the controller.
</description>
</signal>
<signal name="selectstart">
@@ -195,28 +189,33 @@
Use [method get_controller] to get more information about the controller.
</description>
</signal>
- <signal name="select">
- <argument index="0" name="controller_id" type="int">
- </argument>
+ <signal name="session_ended">
<description>
- Emitted after one of the "controllers" has finished its "primary action".
- Use [method get_controller] to get more information about the controller.
+ Emitted when the user ends the WebXR session (which can be done using UI from the browser or device).
+ At this point, you should do [code]get_viewport().xr = false[/code] to instruct Godot to resume rendering to the screen.
</description>
</signal>
- <signal name="selectend">
- <argument index="0" name="controller_id" type="int">
+ <signal name="session_failed">
+ <argument index="0" name="message" type="String">
</argument>
<description>
- Emitted when one of the "controllers" has finished its "primary action".
- Use [method get_controller] to get more information about the controller.
+ Emitted by [method XRInterface.initialize] if the session fails to start.
+ [code]message[/code] may optionally contain an error message from WebXR, or an empty string if no message is available.
</description>
</signal>
- <signal name="squeezestart">
- <argument index="0" name="controller_id" type="int">
+ <signal name="session_started">
+ <description>
+ Emitted by [method XRInterface.initialize] if the session is successfully started.
+ At this point, it's safe to do [code]get_viewport().xr = true[/code] to instruct Godot to start rendering to the AR/VR device.
+ </description>
+ </signal>
+ <signal name="session_supported">
+ <argument index="0" name="session_mode" type="String">
+ </argument>
+ <argument index="1" name="supported" type="bool">
</argument>
<description>
- Emitted when one of the "controllers" has started its "primary squeeze action".
- Use [method get_controller] to get more information about the controller.
+ Emitted by [method is_session_supported] to indicate if the given [code]session_mode[/code] is supported or not.
</description>
</signal>
<signal name="squeeze">
@@ -235,16 +234,17 @@
Use [method get_controller] to get more information about the controller.
</description>
</signal>
- <signal name="visibility_state_changed">
+ <signal name="squeezestart">
+ <argument index="0" name="controller_id" type="int">
+ </argument>
<description>
- Emitted when [member visibility_state] has changed.
+ Emitted when one of the "controllers" has started its "primary squeeze action".
+ Use [method get_controller] to get more information about the controller.
</description>
</signal>
- <signal name="reference_space_reset">
+ <signal name="visibility_state_changed">
<description>
- Emitted to indicate that the reference space has been reset or reconfigured.
- When (or whether) this is emitted depends on the user's browser or device, but may include when the user has changed the dimensions of their play space (which you may be able to access via [member bounds_geometry]) or pressed/held a button to recenter their position.
- See [url=https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpace/reset_event]WebXR's XRReferenceSpace reset event[/url] for more information.
+ Emitted when [member visibility_state] has changed.
</description>
</signal>
</signals>
diff --git a/modules/webxr/webxr_interface.cpp b/modules/webxr/webxr_interface.cpp
index 2c28ce070f..3e8e75bf0e 100644
--- a/modules/webxr/webxr_interface.cpp
+++ b/modules/webxr/webxr_interface.cpp
@@ -42,7 +42,7 @@ void WebXRInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_reference_space_type"), &WebXRInterface::get_reference_space_type);
ClassDB::bind_method(D_METHOD("set_requested_reference_space_types", "requested_reference_space_types"), &WebXRInterface::set_requested_reference_space_types);
ClassDB::bind_method(D_METHOD("get_requested_reference_space_types"), &WebXRInterface::get_requested_reference_space_types);
- ClassDB::bind_method(D_METHOD("get_controller"), &WebXRInterface::get_controller);
+ ClassDB::bind_method(D_METHOD("get_controller", "controller_id"), &WebXRInterface::get_controller);
ClassDB::bind_method(D_METHOD("get_visibility_state"), &WebXRInterface::get_visibility_state);
ClassDB::bind_method(D_METHOD("get_bounds_geometry"), &WebXRInterface::get_bounds_geometry);
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 98ca724655..14e7d395d3 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -1877,11 +1877,15 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
break;
}
case WM_ACTIVATE: { // Watch For Window Activate Message
- saved_wparam = wParam;
- saved_lparam = lParam;
+ if (!windows[window_id].window_focused) {
+ _process_activate_event(window_id, wParam, lParam);
+ } else {
+ windows[window_id].saved_wparam = wParam;
+ windows[window_id].saved_lparam = lParam;
- // Run a timer to prevent event catching warning if the window is closing.
- focus_timer_id = SetTimer(windows[window_id].hWnd, 2, USER_TIMER_MINIMUM, (TIMERPROC) nullptr);
+ // 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
}
case WM_GETMINMAXINFO: {
@@ -1922,8 +1926,8 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
case WM_CLOSE: // Did We Receive A Close Message?
{
- if (focus_timer_id != 0U) {
- KillTimer(windows[window_id].hWnd, focus_timer_id);
+ 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);
@@ -2607,39 +2611,21 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
case WM_ENTERSIZEMOVE: {
Input::get_singleton()->release_pressed_events();
- move_timer_id = SetTimer(windows[window_id].hWnd, 1, USER_TIMER_MINIMUM, (TIMERPROC) nullptr);
+ windows[window_id].move_timer_id = SetTimer(windows[window_id].hWnd, 1, USER_TIMER_MINIMUM, (TIMERPROC) nullptr);
} break;
case WM_EXITSIZEMOVE: {
- KillTimer(windows[window_id].hWnd, move_timer_id);
+ KillTimer(windows[window_id].hWnd, windows[window_id].move_timer_id);
} break;
case WM_TIMER: {
- if (wParam == move_timer_id) {
+ if (wParam == windows[window_id].move_timer_id) {
_process_key_events();
if (!Main::is_iterating()) {
Main::iteration();
}
- } else if (wParam == focus_timer_id) {
- windows[window_id].minimized = HIWORD(saved_wparam) != 0;
-
- if (LOWORD(saved_wparam) == WA_ACTIVE || LOWORD(saved_wparam) == WA_CLICKACTIVE) {
- _send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_IN);
- windows[window_id].window_focused = true;
- alt_mem = false;
- control_mem = false;
- shift_mem = false;
- } else { // WM_INACTIVE
- Input::get_singleton()->release_pressed_events();
- _send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_OUT);
- windows[window_id].window_focused = false;
- alt_mem = false;
- };
-
- if ((OS::get_singleton()->get_current_tablet_driver() == "wintab") && wintab_available && windows[window_id].wtctx) {
- wintab_WTEnable(windows[window_id].wtctx, GET_WM_ACTIVATE_STATE(saved_wparam, saved_lparam));
- }
-
- KillTimer(windows[window_id].hWnd, focus_timer_id);
- focus_timer_id = 0U;
+ } else if (wParam == windows[window_id].focus_timer_id) {
+ _process_activate_event(window_id, windows[window_id].saved_wparam, windows[window_id].saved_lparam);
+ KillTimer(windows[window_id].hWnd, wParam);
+ windows[window_id].focus_timer_id = 0U;
}
} break;
@@ -2796,6 +2782,25 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
+void DisplayServerWindows::_process_activate_event(WindowID p_window_id, WPARAM wParam, LPARAM lParam) {
+ if (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) {
+ _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_IN);
+ windows[p_window_id].window_focused = true;
+ alt_mem = false;
+ control_mem = false;
+ shift_mem = false;
+ } 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;
+ alt_mem = false;
+ }
+
+ if ((OS::get_singleton()->get_current_tablet_driver() == "wintab") && wintab_available && windows[p_window_id].wtctx) {
+ wintab_WTEnable(windows[p_window_id].wtctx, GET_WM_ACTIVATE_STATE(wParam, lParam));
+ }
+}
+
void DisplayServerWindows::_process_key_events() {
for (int i = 0; i < key_event_pos; i++) {
KeyEvent &ke = key_event_buffer[i];
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 722854c538..4a3f91eb21 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -339,6 +339,14 @@ private:
bool no_focus = false;
bool window_has_focus = false;
+ // Used to transfer data between events using timer.
+ WPARAM saved_wparam;
+ LPARAM saved_lparam;
+
+ // Timers.
+ uint32_t move_timer_id = 0U;
+ uint32_t focus_timer_id = 0U;
+
HANDLE wtctx;
LOGCONTEXTW wtlc;
int min_pressure;
@@ -387,9 +395,6 @@ private:
WindowID last_focused_window = INVALID_WINDOW_ID;
- uint32_t move_timer_id = 0U;
- uint32_t focus_timer_id = 0U;
-
HCURSOR hCursor;
WNDPROC user_proc = nullptr;
@@ -409,9 +414,6 @@ private:
bool in_dispatch_input_event = false;
bool console_visible = false;
- WPARAM saved_wparam;
- LPARAM saved_lparam;
-
WNDCLASSEXW wc;
HCURSOR cursors[CURSOR_MAX] = { nullptr };
@@ -428,6 +430,7 @@ private:
void _set_mouse_mode_impl(MouseMode p_mode);
+ void _process_activate_event(WindowID p_window_id, WPARAM wParam, LPARAM lParam);
void _process_key_events();
static void _dispatch_input_events(const Ref<InputEvent> &p_event);
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 75b875ff0b..7557d36298 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1285,8 +1285,7 @@ void TextEdit::_notification(int p_what) {
if (draw_tabs && ((glyphs[j].flags & TextServer::GRAPHEME_IS_TAB) == TextServer::GRAPHEME_IS_TAB)) {
int yofs = (text_height - cache.tab_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index);
cache.tab_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), current_color);
- }
- if (draw_spaces && ((glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE)) {
+ } else if (draw_spaces && ((glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE)) {
int yofs = (text_height - cache.space_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index);
int xofs = (glyphs[j].advance * glyphs[j].repeat - cache.space_icon->get_width()) / 2;
cache.space_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x + xofs, ofs_y + yofs), current_color);