summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SConstruct4
-rw-r--r--core/config/project_settings.cpp8
-rw-r--r--core/core_bind.h3
-rw-r--r--core/doc_data.h1
-rw-r--r--core/extension/extension_api_dump.cpp7
-rw-r--r--core/input/input_event.cpp2
-rw-r--r--core/io/dir_access.cpp2
-rw-r--r--core/io/resource.cpp2
-rw-r--r--core/math/bvh_structs.inc4
-rw-r--r--core/math/convex_hull.h6
-rw-r--r--core/math/math_fieldwise.cpp43
-rw-r--r--core/object/ref_counted.cpp3
-rw-r--r--core/object/ref_counted.h2
-rw-r--r--core/os/os.cpp4
-rw-r--r--core/os/os.h2
-rw-r--r--core/os/pool_allocator.cpp8
-rw-r--r--core/register_core_types.cpp1
-rw-r--r--core/string/ustring.h4
-rw-r--r--core/templates/pooled_list.h5
-rw-r--r--core/variant/array.h2
-rw-r--r--core/variant/callable.cpp15
-rw-r--r--core/variant/callable.h1
-rw-r--r--core/variant/variant_call.cpp9
-rw-r--r--core/variant/variant_construct.cpp1
-rw-r--r--core/variant/variant_construct.h76
-rw-r--r--doc/classes/Array.xml54
-rw-r--r--doc/classes/Callable.xml7
-rw-r--r--doc/classes/DirAccess.xml5
-rw-r--r--doc/classes/DisplayServer.xml6
-rw-r--r--doc/classes/EditorImportPlugin.xml6
-rw-r--r--doc/classes/EditorScenePostImport.xml2
-rw-r--r--doc/classes/EditorScript.xml2
-rw-r--r--doc/classes/EditorTranslationParserPlugin.xml2
-rw-r--r--doc/classes/NavigationPathQueryParameters2D.xml1
-rw-r--r--doc/classes/NavigationPathQueryParameters3D.xml1
-rw-r--r--doc/classes/NavigationRegion2D.xml1
-rw-r--r--doc/classes/NavigationRegion3D.xml1
-rw-r--r--doc/classes/PackedScene.xml4
-rw-r--r--doc/classes/PhysicsServer2D.xml14
-rw-r--r--doc/classes/PhysicsServer2DExtension.xml12
-rw-r--r--doc/classes/PhysicsServer3D.xml14
-rw-r--r--doc/classes/PhysicsServer3DExtension.xml12
-rw-r--r--doc/classes/ProjectSettings.xml18
-rw-r--r--doc/classes/QuadMesh.xml1
-rw-r--r--doc/classes/RefCounted.xml6
-rw-r--r--doc/classes/ScriptEditorBase.xml9
-rw-r--r--doc/classes/Tree.xml3
-rw-r--r--doc/classes/TreeItem.xml15
-rw-r--r--doc/classes/Window.xml8
-rw-r--r--drivers/unix/os_unix.cpp5
-rw-r--r--drivers/unix/os_unix.h1
-rw-r--r--editor/connections_dialog.cpp6
-rw-r--r--editor/connections_dialog.h1
-rw-r--r--editor/debugger/editor_debugger_tree.h4
-rw-r--r--editor/editor_feature_profile.cpp2
-rw-r--r--editor/editor_inspector.cpp5
-rw-r--r--editor/editor_node.cpp112
-rw-r--r--editor/editor_node.h6
-rw-r--r--editor/editor_quick_open.h2
-rw-r--r--editor/editor_settings_dialog.cpp1
-rw-r--r--editor/editor_themes.cpp374
-rw-r--r--editor/editor_themes.h11
-rw-r--r--editor/export/editor_export_platform.cpp2
-rw-r--r--editor/filesystem_dock.cpp17
-rw-r--r--editor/icons/MemberAnnotation.svg2
-rw-r--r--editor/icons/MethodOverride.svg1
-rw-r--r--editor/icons/MethodOverrideAndSlot.svg1
-rw-r--r--editor/import/dynamic_font_import_settings.cpp1
-rw-r--r--editor/import/resource_importer_scene.h11
-rw-r--r--editor/plugins/font_config_plugin.cpp10
-rw-r--r--editor/plugins/script_editor_plugin.cpp76
-rw-r--r--editor/plugins/script_editor_plugin.h4
-rw-r--r--editor/plugins/script_text_editor.cpp114
-rw-r--r--editor/plugins/theme_editor_plugin.cpp32
-rw-r--r--editor/project_converter_3_to_4.cpp43
-rw-r--r--editor/scene_create_dialog.cpp2
-rw-r--r--editor/scene_tree_dock.cpp58
-rw-r--r--editor/scene_tree_dock.h7
-rw-r--r--editor/scene_tree_editor.cpp15
-rw-r--r--main/main.cpp25
-rw-r--r--methods.py5
-rw-r--r--misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj1
-rwxr-xr-xmisc/scripts/header_guards.sh17
-rw-r--r--modules/csg/csg.h1
-rw-r--r--modules/denoise/SCsub2
-rw-r--r--modules/gdscript/gdscript.cpp2
-rw-r--r--modules/gdscript/gdscript_cache.cpp14
-rw-r--r--modules/gdscript/gdscript_cache.h2
-rw-r--r--modules/gdscript/gdscript_parser.cpp2
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp1
-rw-r--r--modules/gltf/register_types.h5
-rw-r--r--modules/mono/csharp_script.cpp8
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/EventHandlerSuffixSuppressor.cs53
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs10
-rw-r--r--modules/mono/utils/macos_utils.h4
-rw-r--r--modules/openxr/SCsub61
-rw-r--r--modules/openxr/config.py4
-rw-r--r--modules/openxr/extensions/openxr_android_extension.cpp20
-rw-r--r--modules/openxr/extensions/openxr_android_extension.h7
-rw-r--r--modules/openxr/extensions/openxr_extension_wrapper.h1
-rw-r--r--modules/openxr/extensions/openxr_vulkan_extension.cpp67
-rw-r--r--modules/openxr/extensions/openxr_vulkan_extension.h36
-rw-r--r--modules/openxr/openxr_api.cpp105
-rw-r--r--modules/openxr/openxr_api.h58
-rw-r--r--modules/openxr/util.h110
-rw-r--r--modules/raycast/SCsub3
-rw-r--r--modules/raycast/lightmap_raycaster_embree.cpp (renamed from modules/raycast/lightmap_raycaster.cpp)6
-rw-r--r--modules/raycast/lightmap_raycaster_embree.h (renamed from modules/raycast/lightmap_raycaster.h)9
-rw-r--r--modules/raycast/register_types.cpp4
-rw-r--r--modules/raycast/register_types.h5
-rw-r--r--modules/raycast/static_raycaster_embree.cpp (renamed from modules/raycast/static_raycaster.cpp)6
-rw-r--r--modules/raycast/static_raycaster_embree.h (renamed from modules/raycast/static_raycaster.h)9
-rw-r--r--modules/text_server_adv/gdextension_build/SConstruct29
-rw-r--r--modules/text_server_adv/text_server_adv.cpp60
-rw-r--r--modules/text_server_adv/text_server_adv.h3
-rw-r--r--modules/text_server_fb/gdextension_build/SConstruct20
-rw-r--r--modules/text_server_fb/text_server_fb.cpp46
-rw-r--r--modules/text_server_fb/text_server_fb.h1
-rw-r--r--modules/tga/image_loader_tga.cpp25
-rw-r--r--modules/tga/image_loader_tga.h2
-rw-r--r--platform/android/detect.py8
-rw-r--r--platform/android/java_godot_io_wrapper.h3
-rw-r--r--platform/android/java_godot_wrapper.h3
-rw-r--r--platform/ios/detect.py9
-rw-r--r--platform/ios/os_ios.h6
-rw-r--r--platform/linuxbsd/detect_prime_x11.h8
-rw-r--r--platform/macos/detect.py4
-rw-r--r--platform/macos/display_server_macos.h6
-rw-r--r--platform/macos/display_server_macos.mm67
-rw-r--r--platform/macos/export/codesign.h6
-rw-r--r--platform/macos/export/lipo.h4
-rw-r--r--platform/macos/export/macho.h4
-rw-r--r--platform/macos/export/plist.h4
-rw-r--r--platform/macos/godot_button_view.h3
-rw-r--r--platform/macos/godot_button_view.mm23
-rw-r--r--platform/macos/godot_window.h2
-rw-r--r--platform/macos/godot_window.mm13
-rw-r--r--platform/macos/godot_window_delegate.h2
-rw-r--r--platform/macos/godot_window_delegate.mm56
-rw-r--r--platform/windows/detect.py1
-rw-r--r--platform/windows/display_server_windows.cpp30
-rw-r--r--scene/2d/navigation_region_2d.cpp34
-rw-r--r--scene/2d/navigation_region_2d.h4
-rw-r--r--scene/2d/physics_body_2d.cpp4
-rw-r--r--scene/3d/navigation_region_3d.cpp33
-rw-r--r--scene/3d/navigation_region_3d.h4
-rw-r--r--scene/3d/physics_body_3d.cpp4
-rw-r--r--scene/animation/easing_equations.h6
-rw-r--r--scene/gui/code_edit.cpp35
-rw-r--r--scene/gui/color_picker.cpp7
-rw-r--r--scene/gui/item_list.cpp16
-rw-r--r--scene/gui/rich_text_label.cpp5
-rw-r--r--scene/gui/text_edit.cpp19
-rw-r--r--scene/gui/tree.cpp78
-rw-r--r--scene/gui/tree.h10
-rw-r--r--scene/main/window.cpp4
-rw-r--r--scene/resources/font.cpp12
-rw-r--r--scene/resources/particle_process_material.h6
-rw-r--r--scene/resources/primitive_meshes.h1
-rw-r--r--scene/resources/sky_material.h6
-rw-r--r--scene/resources/texture.h9
-rw-r--r--scene/resources/visual_shader.h7
-rw-r--r--servers/display_server.cpp1
-rw-r--r--servers/display_server.h1
-rw-r--r--servers/extensions/physics_server_2d_extension.cpp3
-rw-r--r--servers/extensions/physics_server_2d_extension.h5
-rw-r--r--servers/extensions/physics_server_3d_extension.cpp3
-rw-r--r--servers/extensions/physics_server_3d_extension.h5
-rw-r--r--servers/physics_2d/godot_physics_server_2d.cpp20
-rw-r--r--servers/physics_2d/godot_physics_server_2d.h6
-rw-r--r--servers/physics_3d/godot_physics_server_3d.cpp14
-rw-r--r--servers/physics_3d/godot_physics_server_3d.h5
-rw-r--r--servers/physics_3d/joints/godot_cone_twist_joint_3d.h6
-rw-r--r--servers/physics_3d/joints/godot_generic_6dof_joint_3d.h6
-rw-r--r--servers/physics_3d/joints/godot_hinge_joint_3d.h6
-rw-r--r--servers/physics_3d/joints/godot_jacobian_entry_3d.h6
-rw-r--r--servers/physics_3d/joints/godot_pin_joint_3d.h6
-rw-r--r--servers/physics_3d/joints/godot_slider_joint_3d.h6
-rw-r--r--servers/physics_server_2d.cpp3
-rw-r--r--servers/physics_server_2d.h5
-rw-r--r--servers/physics_server_2d_wrap_mt.h5
-rw-r--r--servers/physics_server_3d.cpp3
-rw-r--r--servers/physics_server_3d.h5
-rw-r--r--servers/physics_server_3d_wrap_mt.h5
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp3
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/SCsub2
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/SCsub2
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/SCsub2
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/SCsub2
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp2
-rw-r--r--servers/rendering_server.cpp10
-rw-r--r--servers/text/text_server_extension.cpp4
-rw-r--r--servers/text/text_server_extension.h4
-rw-r--r--servers/text_server.h2
-rw-r--r--tests/core/math/test_vector2.h83
-rw-r--r--tests/core/math/test_vector2i.h16
-rw-r--r--tests/core/math/test_vector3.h73
-rw-r--r--tests/core/math/test_vector3i.h8
-rw-r--r--tests/core/math/test_vector4.h8
-rw-r--r--tests/core/math/test_vector4i.h8
203 files changed, 2253 insertions, 869 deletions
diff --git a/SConstruct b/SConstruct
index 200e8e5984..b64e0bddd8 100644
--- a/SConstruct
+++ b/SConstruct
@@ -386,6 +386,9 @@ if env_base["target"] == "debug":
# DEV_ENABLED enables *engine developer* code which should only be compiled for those
# working on the engine itself.
env_base.Append(CPPDEFINES=["DEV_ENABLED"])
+else:
+ # Disable assert() for production targets (only used in thirdparty code).
+ env_base.Append(CPPDEFINES=["NDEBUG"])
# SCons speed optimization controlled by the `fast_unsafe` option, which provide
# more than 10 s speed up for incremental rebuilds.
@@ -669,7 +672,6 @@ if selected_platform in platform_list:
print(" Use `tools=no target=release` to build a release export template.")
Exit(255)
suffix += ".opt"
- env.Append(CPPDEFINES=["NDEBUG"])
elif env["target"] == "release_debug":
if env["tools"]:
suffix += ".opt.tools"
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 15f807017f..a1b22e7f7d 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1207,10 +1207,16 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_BASIC("display/window/size/viewport_height", 648);
custom_prop_info["display/window/size/viewport_height"] = PropertyInfo(Variant::INT, "display/window/size/viewport_height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"); // 8K resolution
+ GLOBAL_DEF_BASIC("display/window/size/mode", 0);
+ custom_prop_info["display/window/size/mode"] = PropertyInfo(Variant::INT, "display/window/size/mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen");
+
GLOBAL_DEF_BASIC("display/window/size/resizable", true);
GLOBAL_DEF_BASIC("display/window/size/borderless", false);
- GLOBAL_DEF_BASIC("display/window/size/fullscreen", false);
GLOBAL_DEF("display/window/size/always_on_top", false);
+ GLOBAL_DEF("display/window/size/transparent", false);
+ GLOBAL_DEF("display/window/size/extend_to_title", false);
+ GLOBAL_DEF("display/window/size/no_focus", false);
+
GLOBAL_DEF("display/window/size/window_width_override", 0);
custom_prop_info["display/window/size/window_width_override"] = PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"); // 8K resolution
GLOBAL_DEF("display/window/size/window_height_override", 0);
diff --git a/core/core_bind.h b/core/core_bind.h
index 3ca2da0acf..ba22971d78 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -32,9 +32,6 @@
#define CORE_BIND_H
#include "core/debugger/engine_profiler.h"
-#include "core/io/compression.h"
-#include "core/io/dir_access.h"
-#include "core/io/file_access.h"
#include "core/io/image.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
diff --git a/core/doc_data.h b/core/doc_data.h
index 3b7bf149b4..bb356f027e 100644
--- a/core/doc_data.h
+++ b/core/doc_data.h
@@ -32,7 +32,6 @@
#define DOC_DATA_H
#include "core/io/xml_parser.h"
-#include "core/templates/rb_map.h"
#include "core/variant/variant.h"
struct ScriptMemberInfo {
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index bda1a5cdc1..e6e0fff266 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -46,6 +46,9 @@ static String get_type_name(const PropertyInfo &p_info) {
return p_info.hint_string + "*";
}
}
+ if (p_info.type == Variant::ARRAY && (p_info.hint == PROPERTY_HINT_ARRAY_TYPE)) {
+ return String("typedarray::") + p_info.hint_string;
+ }
if (p_info.type == Variant::INT && (p_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM))) {
return String("enum::") + String(p_info.class_name);
}
@@ -215,7 +218,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
String name = t == Variant::VARIANT_MAX ? String("Variant") : Variant::get_type_name(t);
Dictionary d2;
d2["name"] = name;
- uint32_t size;
+ uint32_t size = 0;
switch (i) {
case 0:
size = type_size_array[j].size_32_bits_real_float;
@@ -330,7 +333,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
last_type = t;
}
Dictionary d3;
- uint32_t offset;
+ uint32_t offset = 0;
switch (i) {
case 0:
offset = member_offset_array[idx].offset_32_bits_real_float;
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 596b704732..712fc68c93 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -1325,7 +1325,7 @@ bool InputEventAction::is_match(const Ref<InputEvent> &p_event, bool p_exact_mat
return false;
}
- return p_event->is_action(action);
+ return p_event->is_action(action, p_exact_match);
}
bool InputEventAction::is_action(const StringName &p_action) const {
diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp
index f86dfe8057..79e7fa16e3 100644
--- a/core/io/dir_access.cpp
+++ b/core/io/dir_access.cpp
@@ -492,6 +492,7 @@ PackedStringArray DirAccess::get_files() {
PackedStringArray DirAccess::get_files_at(const String &p_path) {
Ref<DirAccess> da = DirAccess::open(p_path);
+ ERR_FAIL_COND_V_MSG(da.is_null(), PackedStringArray(), vformat("Couldn't open directory at path \"%s\".", p_path));
return da->get_files();
}
@@ -501,6 +502,7 @@ PackedStringArray DirAccess::get_directories() {
PackedStringArray DirAccess::get_directories_at(const String &p_path) {
Ref<DirAccess> da = DirAccess::open(p_path);
+ ERR_FAIL_COND_V_MSG(da.is_null(), PackedStringArray(), vformat("Couldn't open directory at path \"%s\".", p_path));
return da->get_directories();
}
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index 553698f8a6..ab30fb1ca3 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -489,7 +489,7 @@ bool ResourceCache::has(const String &p_path) {
Resource **res = resources.getptr(p_path);
- if (res && (*res)->reference_get_count() == 0) {
+ if (res && (*res)->get_reference_count() == 0) {
// This resource is in the process of being deleted, ignore its existence.
(*res)->path_cache = String();
resources.erase(p_path);
diff --git a/core/math/bvh_structs.inc b/core/math/bvh_structs.inc
index 58c8f0479a..06f6e5d05d 100644
--- a/core/math/bvh_structs.inc
+++ b/core/math/bvh_structs.inc
@@ -100,7 +100,11 @@ public:
num_items++;
return id;
}
+#ifdef DEV_ENABLED
return -1;
+#else
+ ERR_FAIL_V_MSG(0, "BVH request_item error.");
+#endif
}
};
diff --git a/core/math/convex_hull.h b/core/math/convex_hull.h
index bd86fe0eba..cc41a794bd 100644
--- a/core/math/convex_hull.h
+++ b/core/math/convex_hull.h
@@ -28,6 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef CONVEX_HULL_H
+#define CONVEX_HULL_H
+
/*
Copyright (c) 2011 Ole Kniemeyer, MAXON, www.maxon.net
This software is provided 'as-is', without any express or implied warranty.
@@ -40,9 +43,6 @@ subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution.
*/
-#ifndef CONVEX_HULL_H
-#define CONVEX_HULL_H
-
#include "core/math/geometry_3d.h"
#include "core/math/vector3.h"
#include "core/templates/local_vector.h"
diff --git a/core/math/math_fieldwise.cpp b/core/math/math_fieldwise.cpp
index f36b228543..726a2aeb97 100644
--- a/core/math/math_fieldwise.cpp
+++ b/core/math/math_fieldwise.cpp
@@ -56,6 +56,15 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
+ case Variant::VECTOR2I: {
+ SETUP_TYPE(Vector2i)
+
+ /**/ TRY_TRANSFER_FIELD("x", x)
+ else TRY_TRANSFER_FIELD("y", y)
+
+ return target;
+ }
+
case Variant::RECT2: {
SETUP_TYPE(Rect2)
@@ -67,6 +76,17 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
+ case Variant::RECT2I: {
+ SETUP_TYPE(Rect2i)
+
+ /**/ TRY_TRANSFER_FIELD("x", position.x)
+ else TRY_TRANSFER_FIELD("y", position.y)
+ else TRY_TRANSFER_FIELD("w", size.x)
+ else TRY_TRANSFER_FIELD("h", size.y)
+
+ return target;
+ }
+
case Variant::VECTOR3: {
SETUP_TYPE(Vector3)
@@ -192,6 +212,29 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
+ case Variant::PROJECTION: {
+ SETUP_TYPE(Projection)
+
+ /**/ TRY_TRANSFER_FIELD("xx", matrix[0].x)
+ else TRY_TRANSFER_FIELD("xy", matrix[0].y)
+ else TRY_TRANSFER_FIELD("xz", matrix[0].z)
+ else TRY_TRANSFER_FIELD("xw", matrix[0].w)
+ else TRY_TRANSFER_FIELD("yx", matrix[1].x)
+ else TRY_TRANSFER_FIELD("yy", matrix[1].y)
+ else TRY_TRANSFER_FIELD("yz", matrix[1].z)
+ else TRY_TRANSFER_FIELD("yw", matrix[1].w)
+ else TRY_TRANSFER_FIELD("zx", matrix[2].x)
+ else TRY_TRANSFER_FIELD("zy", matrix[2].y)
+ else TRY_TRANSFER_FIELD("zz", matrix[2].z)
+ else TRY_TRANSFER_FIELD("zw", matrix[2].w)
+ else TRY_TRANSFER_FIELD("xo", matrix[3].x)
+ else TRY_TRANSFER_FIELD("yo", matrix[3].y)
+ else TRY_TRANSFER_FIELD("zo", matrix[3].z)
+ else TRY_TRANSFER_FIELD("wo", matrix[3].w)
+
+ return target;
+ }
+
default: {
ERR_FAIL_V(p_target);
}
diff --git a/core/object/ref_counted.cpp b/core/object/ref_counted.cpp
index cac2400744..50467d795d 100644
--- a/core/object/ref_counted.cpp
+++ b/core/object/ref_counted.cpp
@@ -48,9 +48,10 @@ void RefCounted::_bind_methods() {
ClassDB::bind_method(D_METHOD("init_ref"), &RefCounted::init_ref);
ClassDB::bind_method(D_METHOD("reference"), &RefCounted::reference);
ClassDB::bind_method(D_METHOD("unreference"), &RefCounted::unreference);
+ ClassDB::bind_method(D_METHOD("get_reference_count"), &RefCounted::get_reference_count);
}
-int RefCounted::reference_get_count() const {
+int RefCounted::get_reference_count() const {
return refcount.get();
}
diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h
index bd06a84bd8..71790fb825 100644
--- a/core/object/ref_counted.h
+++ b/core/object/ref_counted.h
@@ -47,7 +47,7 @@ public:
bool init_ref();
bool reference(); // returns false if refcount is at zero and didn't get increased
bool unreference();
- int reference_get_count() const;
+ int get_reference_count() const;
RefCounted();
~RefCounted() {}
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 526b31ae7e..ee8da21751 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -54,10 +54,6 @@ double OS::get_unix_time() const {
return 0;
}
-void OS::debug_break() {
- // something
-}
-
void OS::_set_logger(CompositeLogger *p_logger) {
if (_logger) {
memdelete(_logger);
diff --git a/core/os/os.h b/core/os/os.h
index 0f79ff1a23..aa45a3b8a8 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -287,8 +287,6 @@ public:
virtual Error move_to_trash(const String &p_path) { return FAILED; }
- virtual void debug_break();
-
virtual int get_exit_code() const;
// `set_exit_code` should only be used from `SceneTree` (or from a similar
// level, e.g. from the `Main::start` if leaving without creating a `SceneTree`).
diff --git a/core/os/pool_allocator.cpp b/core/os/pool_allocator.cpp
index f622e2c7c5..e7f2cff7c5 100644
--- a/core/os/pool_allocator.cpp
+++ b/core/os/pool_allocator.cpp
@@ -35,8 +35,6 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
-#include <assert.h>
-
#define COMPACT_CHUNK(m_entry, m_to_pos) \
do { \
void *_dst = &((unsigned char *)pool)[m_to_pos]; \
@@ -169,11 +167,6 @@ bool PoolAllocator::find_entry_index(EntryIndicesPos *p_map_pos, const Entry *p_
PoolAllocator::ID PoolAllocator::alloc(int p_size) {
ERR_FAIL_COND_V(p_size < 1, POOL_ALLOCATOR_INVALID_ID);
-#ifdef DEBUG_ENABLED
- if (p_size > free_mem) {
- OS::get_singleton()->debug_break();
- }
-#endif
ERR_FAIL_COND_V(p_size > free_mem, POOL_ALLOCATOR_INVALID_ID);
mt_lock();
@@ -482,7 +475,6 @@ void *PoolAllocator::get(ID p_mem) {
ERR_FAIL_COND_V(!e, nullptr);
}
if (e->lock == 0) {
- //assert(0);
mt_unlock();
ERR_PRINT("e->lock == 0");
return nullptr;
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index bad53ab4e6..2e144a4c9a 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -44,6 +44,7 @@
#include "core/input/input_map.h"
#include "core/input/shortcut.h"
#include "core/io/config_file.h"
+#include "core/io/dir_access.h"
#include "core/io/dtls_server.h"
#include "core/io/http_client.h"
#include "core/io/image_loader.h"
diff --git a/core/string/ustring.h b/core/string/ustring.h
index b8ae3c2392..4b6568a502 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-// Note: _GODOT suffix added to avoid conflict with ICU header with the same guard.
-
#ifndef USTRING_GODOT_H
#define USTRING_GODOT_H
+// Note: _GODOT suffix added to header guard to avoid conflict with ICU header.
+
#include "core/string/char_utils.h"
#include "core/templates/cowdata.h"
#include "core/templates/vector.h"
diff --git a/core/templates/pooled_list.h b/core/templates/pooled_list.h
index f13156b292..08f53572e7 100644
--- a/core/templates/pooled_list.h
+++ b/core/templates/pooled_list.h
@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#pragma once
+#ifndef POOLED_LIST_H
+#define POOLED_LIST_H
// Simple template to provide a pool with O(1) allocate and free.
// The freelist could alternatively be a linked list placed within the unused elements
@@ -206,3 +207,5 @@ private:
LocalVector<U, U> _active_map;
LocalVector<U, U> _active_list;
};
+
+#endif // POOLED_LIST_H
diff --git a/core/variant/array.h b/core/variant/array.h
index c007376734..3d9a794969 100644
--- a/core/variant/array.h
+++ b/core/variant/array.h
@@ -47,7 +47,6 @@ class Array {
void _unref() const;
protected:
- Array(const Array &p_base, uint32_t p_type, const StringName &p_class_name, const Variant &p_script);
bool _assign(const Array &p_array);
public:
@@ -131,6 +130,7 @@ public:
void set_read_only(bool p_enable);
bool is_read_only() const;
+ Array(const Array &p_base, uint32_t p_type, const StringName &p_class_name, const Variant &p_script);
Array(const Array &p_from);
Array();
~Array();
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index 28efb43fc5..b35e2f004b 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -63,6 +63,21 @@ void Callable::callp(const Variant **p_arguments, int p_argcount, Variant &r_ret
}
}
+Variant Callable::callv(const Array &p_arguments) const {
+ int argcount = p_arguments.size();
+ const Variant **argptrs = nullptr;
+ if (argcount) {
+ argptrs = (const Variant **)alloca(sizeof(Variant *) * argcount);
+ for (int i = 0; i < argcount; i++) {
+ argptrs[i] = &p_arguments[i];
+ }
+ }
+ CallError ce;
+ Variant ret;
+ callp(argptrs, argcount, ret, ce);
+ return ret;
+}
+
Error Callable::rpcp(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const {
if (is_null()) {
r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
diff --git a/core/variant/callable.h b/core/variant/callable.h
index 1f1c983eb3..0305dc55c3 100644
--- a/core/variant/callable.h
+++ b/core/variant/callable.h
@@ -71,6 +71,7 @@ public:
void callp(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const;
void call_deferredp(const Variant **p_arguments, int p_argcount) const;
+ Variant callv(const Array &p_arguments) const;
Error rpcp(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const;
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index f09885b325..1831f7b72a 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1859,6 +1859,7 @@ static void _register_variant_builtin_methods() {
/* Callable */
+ bind_method(Callable, callv, sarray("arguments"), varray());
bind_method(Callable, is_null, sarray(), varray());
bind_method(Callable, is_custom, sarray(), varray());
bind_method(Callable, is_standard, sarray(), varray());
@@ -2065,6 +2066,14 @@ static void _register_variant_builtin_methods() {
bind_method(Array, all, sarray("method"), varray());
bind_method(Array, max, sarray(), varray());
bind_method(Array, min, sarray(), varray());
+ bind_method(Array, typed_assign, sarray("array"), varray());
+ bind_method(Array, set_typed, sarray("type", "class_name", "script"), varray());
+ bind_method(Array, is_typed, sarray(), varray());
+ bind_method(Array, get_typed_builtin, sarray(), varray());
+ bind_method(Array, get_typed_class_name, sarray(), varray());
+ bind_method(Array, get_typed_script, sarray(), varray());
+ bind_method(Array, set_read_only, sarray("enable"), varray());
+ bind_method(Array, is_read_only, sarray(), varray());
/* Byte Array */
bind_method(PackedByteArray, size, sarray(), varray());
diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp
index d048f45737..3b88dc11ca 100644
--- a/core/variant/variant_construct.cpp
+++ b/core/variant/variant_construct.cpp
@@ -200,6 +200,7 @@ void Variant::_register_variant_constructors() {
add_constructor<VariantConstructNoArgs<Array>>(sarray());
add_constructor<VariantConstructor<Array, Array>>(sarray("from"));
+ add_constructor<VariantConstructorTypedArray>(sarray("base", "type", "class_name", "script"));
add_constructor<VariantConstructorToArray<PackedByteArray>>(sarray("from"));
add_constructor<VariantConstructorToArray<PackedInt32Array>>(sarray("from"));
add_constructor<VariantConstructorToArray<PackedInt64Array>>(sarray("from"));
diff --git a/core/variant/variant_construct.h b/core/variant/variant_construct.h
index 58a0f34c1e..34d228f4d2 100644
--- a/core/variant/variant_construct.h
+++ b/core/variant/variant_construct.h
@@ -336,6 +336,82 @@ public:
}
};
+class VariantConstructorTypedArray {
+public:
+ static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
+ if (p_args[0]->get_type() != Variant::ARRAY) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::ARRAY;
+ return;
+ }
+
+ if (p_args[1]->get_type() != Variant::INT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = Variant::INT;
+ return;
+ }
+
+ if (p_args[2]->get_type() != Variant::STRING_NAME) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 2;
+ r_error.expected = Variant::STRING_NAME;
+ return;
+ }
+
+ const Array &base_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]);
+ const uint32_t type = p_args[1]->operator uint32_t();
+ const StringName &class_name = *VariantGetInternalPtr<StringName>::get_ptr(p_args[2]);
+ r_ret = Array(base_arr, type, class_name, *p_args[3]);
+ }
+
+ static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
+ const Array &base_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]);
+ const uint32_t type = p_args[1]->operator uint32_t();
+ const StringName &class_name = *VariantGetInternalPtr<StringName>::get_ptr(p_args[2]);
+ *r_ret = Array(base_arr, type, class_name, *p_args[3]);
+ }
+
+ static void ptr_construct(void *base, const void **p_args) {
+ const Array &base_arr = PtrToArg<Array>::convert(p_args[0]);
+ const uint32_t type = PtrToArg<uint32_t>::convert(p_args[1]);
+ const StringName &class_name = PtrToArg<StringName>::convert(p_args[2]);
+ const Variant &script = PtrToArg<Variant>::convert(p_args[3]);
+ Array dst_arr = Array(base_arr, type, class_name, script);
+
+ PtrConstruct<Array>::construct(dst_arr, base);
+ }
+
+ static int get_argument_count() {
+ return 4;
+ }
+
+ static Variant::Type get_argument_type(int p_arg) {
+ switch (p_arg) {
+ case 0: {
+ return Variant::ARRAY;
+ } break;
+ case 1: {
+ return Variant::INT;
+ } break;
+ case 2: {
+ return Variant::STRING_NAME;
+ } break;
+ case 3: {
+ return Variant::NIL;
+ } break;
+ default: {
+ return Variant::NIL;
+ } break;
+ }
+ }
+
+ static Variant::Type get_base_type() {
+ return Variant::ARRAY;
+ }
+};
+
template <class T>
class VariantConstructorToArray {
public:
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index f6d926031d..d8c4b8fdb5 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -53,6 +53,15 @@
</constructor>
<constructor name="Array">
<return type="Array" />
+ <param index="0" name="base" type="Array" />
+ <param index="1" name="type" type="int" />
+ <param index="2" name="class_name" type="StringName" />
+ <param index="3" name="script" type="Variant" />
+ <description>
+ </description>
+ </constructor>
+ <constructor name="Array">
+ <return type="Array" />
<param index="0" name="from" type="Array" />
<description>
Constructs an [Array] as a copy of the given [Array].
@@ -303,6 +312,21 @@
[b]Note:[/b] Calling this function is not the same as writing [code]array[0][/code]. If the array is empty, accessing by index will pause project execution when running from the editor.
</description>
</method>
+ <method name="get_typed_builtin" qualifiers="const">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="get_typed_class_name" qualifiers="const">
+ <return type="StringName" />
+ <description>
+ </description>
+ </method>
+ <method name="get_typed_script" qualifiers="const">
+ <return type="Variant" />
+ <description>
+ </description>
+ </method>
<method name="has" qualifiers="const">
<return type="bool" />
<param index="0" name="value" type="Variant" />
@@ -366,6 +390,16 @@
Returns [code]true[/code] if the array is empty.
</description>
</method>
+ <method name="is_read_only" qualifiers="const">
+ <return type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="is_typed" qualifiers="const">
+ <return type="bool" />
+ <description>
+ </description>
+ </method>
<method name="map" qualifiers="const">
<return type="Array" />
<param index="0" name="method" type="Callable" />
@@ -479,6 +513,20 @@
Searches the array in reverse order. Optionally, a start search index can be passed. If negative, the start index is considered relative to the end of the array.
</description>
</method>
+ <method name="set_read_only">
+ <return type="void" />
+ <param index="0" name="enable" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="set_typed">
+ <return type="void" />
+ <param index="0" name="type" type="int" />
+ <param index="1" name="class_name" type="StringName" />
+ <param index="2" name="script" type="Variant" />
+ <description>
+ </description>
+ </method>
<method name="shuffle">
<return type="void" />
<description>
@@ -556,6 +604,12 @@
[/codeblocks]
</description>
</method>
+ <method name="typed_assign">
+ <return type="bool" />
+ <param index="0" name="array" type="Array" />
+ <description>
+ </description>
+ </method>
</methods>
<operators>
<operator name="operator !=">
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index 1fcaf6d866..dd48ee6790 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -81,6 +81,13 @@
[/codeblock]
</description>
</method>
+ <method name="callv" qualifiers="const">
+ <return type="Variant" />
+ <param index="0" name="arguments" type="Array" />
+ <description>
+ Calls the method represented by this [Callable]. Contrary to [method call], this method does not take a variable number of arguments but expects all arguments to be passed via a single [Array].
+ </description>
+ </method>
<method name="get_method" qualifiers="const">
<return type="StringName" />
<description>
diff --git a/doc/classes/DirAccess.xml b/doc/classes/DirAccess.xml
index cb7bf56f11..af498a6519 100644
--- a/doc/classes/DirAccess.xml
+++ b/doc/classes/DirAccess.xml
@@ -9,11 +9,10 @@
Most of the methods have a static alternative that can be used without creating a [DirAccess]. Static methods only support absolute paths (including [code]res://[/code] and [code]user://[/code]).
[codeblock]
# Standard
- var dir = Directory.new()
- dir.open("user://levels")
+ var dir = DirAccess.open("user://levels")
dir.make_dir("world1")
# Static
- Directory.make_dir_absolute("user://levels/world1")
+ DirAccess.make_dir_absolute("user://levels/world1")
[/codeblock]
[b]Note:[/b] Many resources types are imported (e.g. textures or sound files), and their source asset will not be included in the exported game, as only the imported version is used. Use [ResourceLoader] to access imported resources.
Here is an example on how to iterate through the files of a directory:
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index a1dee7ecc7..6d3f3a7362 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -1324,6 +1324,7 @@
<param index="0" name="window_id" type="int" />
<param index="1" name="parent_window_id" type="int" />
<description>
+ Sets window transient parent. Transient window is will be destroyed with its transient parent and displayed on top of non-exclusive full-screen parent window. Transient windows can't enter full-screen mode.
</description>
</method>
<method name="window_set_vsync_mode">
@@ -1518,7 +1519,8 @@
Window is floating above other regular windows. This flag is ignored for full-screen windows.
</constant>
<constant name="WINDOW_FLAG_TRANSPARENT" value="3" enum="WindowFlags">
- Window is will be destroyed with its transient parent and displayed on top of non-exclusive full-screen parent window. Transient windows can't enter full-screen mode.
+ Window background can be transparent.
+ [b]Note:[/b] This flag has no effect if [member ProjectSettings.display/window/per_pixel_transparency/allowed] is set to [code]false[/code].
</constant>
<constant name="WINDOW_FLAG_NO_FOCUS" value="4" enum="WindowFlags">
Window can't be focused. No-focus window will ignore all input, except mouse clicks.
@@ -1546,6 +1548,8 @@
</constant>
<constant name="WINDOW_EVENT_DPI_CHANGE" value="6" enum="WindowEvent">
</constant>
+ <constant name="WINDOW_EVENT_TITLEBAR_CHANGE" value="7" enum="WindowEvent">
+ </constant>
<constant name="VSYNC_DISABLED" value="0" enum="VSyncMode">
No vertical synchronization, which means the engine will display frames as fast as possible (tearing may be visible).
</constant>
diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml
index 348347c4ef..c395815117 100644
--- a/doc/classes/EditorImportPlugin.xml
+++ b/doc/classes/EditorImportPlugin.xml
@@ -9,7 +9,7 @@
Below is an example EditorImportPlugin that imports a [Mesh] from a file with the extension ".special" or ".spec":
[codeblocks]
[gdscript]
- tool
+ @tool
extends EditorImportPlugin
func _get_importer_name():
@@ -44,7 +44,7 @@
# Fill the Mesh with data read in "file", left as an exercise to the reader.
var filename = save_path + "." + _get_save_extension()
- return ResourceSaver.save(filename, mesh)
+ return ResourceSaver.save(mesh, filename)
[/gdscript]
[csharp]
using Godot;
@@ -103,7 +103,7 @@
var mesh = new ArrayMesh();
// Fill the Mesh with data read in "file", left as an exercise to the reader.
String filename = savePath + "." + GetSaveExtension();
- return (int)ResourceSaver.Save(filename, mesh);
+ return (int)ResourceSaver.Save(mesh, filename);
}
}
[/csharp]
diff --git a/doc/classes/EditorScenePostImport.xml b/doc/classes/EditorScenePostImport.xml
index 395b094bf2..2bf2accf17 100644
--- a/doc/classes/EditorScenePostImport.xml
+++ b/doc/classes/EditorScenePostImport.xml
@@ -8,7 +8,7 @@
The [method _post_import] callback receives the imported scene's root node and returns the modified version of the scene. Usage example:
[codeblocks]
[gdscript]
- tool # Needed so it runs in editor.
+ @tool # Needed so it runs in editor.
extends EditorScenePostImport
# This sample changes all node names.
# Called right after the scene is imported and gets the root node.
diff --git a/doc/classes/EditorScript.xml b/doc/classes/EditorScript.xml
index 2ff8a7ba2a..dfc04c9cde 100644
--- a/doc/classes/EditorScript.xml
+++ b/doc/classes/EditorScript.xml
@@ -9,7 +9,7 @@
[b]Example script:[/b]
[codeblocks]
[gdscript]
- tool
+ @tool
extends EditorScript
func _run():
diff --git a/doc/classes/EditorTranslationParserPlugin.xml b/doc/classes/EditorTranslationParserPlugin.xml
index 08986781cd..df10c645ef 100644
--- a/doc/classes/EditorTranslationParserPlugin.xml
+++ b/doc/classes/EditorTranslationParserPlugin.xml
@@ -11,7 +11,7 @@
Below shows an example of a custom parser that extracts strings from a CSV file to write into a POT.
[codeblocks]
[gdscript]
- tool
+ @tool
extends EditorTranslationParserPlugin
func _parse_file(path, msgids, msgids_context_plural):
diff --git a/doc/classes/NavigationPathQueryParameters2D.xml b/doc/classes/NavigationPathQueryParameters2D.xml
index 70455017c4..364f495a72 100644
--- a/doc/classes/NavigationPathQueryParameters2D.xml
+++ b/doc/classes/NavigationPathQueryParameters2D.xml
@@ -16,6 +16,7 @@
The navigation layers the query will use (as a bitmask).
</member>
<member name="path_postprocessing" type="int" setter="set_path_postprocessing" getter="get_path_postprocessing" enum="NavigationPathQueryParameters2D.PathPostProcessing" default="0">
+ The path postprocessing applied to the raw path corridor found by the [member pathfinding_algorithm].
</member>
<member name="pathfinding_algorithm" type="int" setter="set_pathfinding_algorithm" getter="get_pathfinding_algorithm" enum="NavigationPathQueryParameters2D.PathfindingAlgorithm" default="0">
The pathfinding algorithm used in the path query.
diff --git a/doc/classes/NavigationPathQueryParameters3D.xml b/doc/classes/NavigationPathQueryParameters3D.xml
index 4dd54601f5..59c907c5b5 100644
--- a/doc/classes/NavigationPathQueryParameters3D.xml
+++ b/doc/classes/NavigationPathQueryParameters3D.xml
@@ -16,6 +16,7 @@
The navigation layers the query will use (as a bitmask).
</member>
<member name="path_postprocessing" type="int" setter="set_path_postprocessing" getter="get_path_postprocessing" enum="NavigationPathQueryParameters3D.PathPostProcessing" default="0">
+ The path postprocessing applied to the raw path corridor found by the [member pathfinding_algorithm].
</member>
<member name="pathfinding_algorithm" type="int" setter="set_pathfinding_algorithm" getter="get_pathfinding_algorithm" enum="NavigationPathQueryParameters3D.PathfindingAlgorithm" default="0">
The pathfinding algorithm used in the path query.
diff --git a/doc/classes/NavigationRegion2D.xml b/doc/classes/NavigationRegion2D.xml
index 89f7dcb4af..0f28081201 100644
--- a/doc/classes/NavigationRegion2D.xml
+++ b/doc/classes/NavigationRegion2D.xml
@@ -10,6 +10,7 @@
The pathfinding cost of entering this region from another region can be controlled with the [member enter_cost] value.
[b]Note:[/b] This value is not added to the path cost when the start position is already inside this region.
The pathfinding cost of traveling distances inside this region can be controlled with the [member travel_cost] multiplier.
+ [b]Note:[/b] This node caches changes to its properties, so if you make changes to the underlying region [RID] in [NavigationServer2D], they will not be reflected in this node's properties.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/NavigationRegion3D.xml b/doc/classes/NavigationRegion3D.xml
index 87e82e7b2e..85f163b3c2 100644
--- a/doc/classes/NavigationRegion3D.xml
+++ b/doc/classes/NavigationRegion3D.xml
@@ -10,6 +10,7 @@
The cost of entering this region from another region can be controlled with the [member enter_cost] value.
[b]Note:[/b] This value is not added to the path cost when the start position is already inside this region.
The cost of traveling distances inside this region can be controlled with the [member travel_cost] multiplier.
+ [b]Note:[/b] This node caches changes to its properties, so if you make changes to the underlying region [RID] in [NavigationServer3D], they will not be reflected in this node's properties.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml
index 97595a6984..7ca1d5d60d 100644
--- a/doc/classes/PackedScene.xml
+++ b/doc/classes/PackedScene.xml
@@ -41,7 +41,7 @@
# Only `node` and `body` are now packed.
var result = scene.pack(node)
if result == OK:
- var error = ResourceSaver.save("res://path/name.tscn", scene) # Or "user://..."
+ var error = ResourceSaver.save(scene, "res://path/name.tscn") # Or "user://..."
if error != OK:
push_error("An error occurred while saving the scene to disk.")
[/gdscript]
@@ -63,7 +63,7 @@
Error result = scene.Pack(node);
if (result == Error.Ok)
{
- Error error = ResourceSaver.Save("res://path/name.tscn", scene); // Or "user://..."
+ Error error = ResourceSaver.Save(scene, "res://path/name.tscn"); // Or "user://..."
if (error != Error.Ok)
{
GD.PushError("An error occurred while saving the scene to disk.");
diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml
index 4b588033c0..18ac8a11df 100644
--- a/doc/classes/PhysicsServer2D.xml
+++ b/doc/classes/PhysicsServer2D.xml
@@ -53,6 +53,20 @@
<description>
</description>
</method>
+ <method name="area_get_collision_layer" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ Returns the physics layer or layers an area belongs to.
+ </description>
+ </method>
+ <method name="area_get_collision_mask" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ Returns the physics layer or layers an area can contact with.
+ </description>
+ </method>
<method name="area_get_object_instance_id" qualifiers="const">
<return type="int" />
<param index="0" name="area" type="RID" />
diff --git a/doc/classes/PhysicsServer2DExtension.xml b/doc/classes/PhysicsServer2DExtension.xml
index 518862bb28..9bb11e0d89 100644
--- a/doc/classes/PhysicsServer2DExtension.xml
+++ b/doc/classes/PhysicsServer2DExtension.xml
@@ -47,6 +47,18 @@
<description>
</description>
</method>
+ <method name="_area_get_collision_layer" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_collision_mask" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
<method name="_area_get_object_instance_id" qualifiers="virtual const">
<return type="int" />
<param index="0" name="area" type="RID" />
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
index da9e10c420..95f7fb69a2 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -40,6 +40,20 @@
Creates an [Area3D].
</description>
</method>
+ <method name="area_get_collision_layer" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ Returns the physics layer or layers an area belongs to.
+ </description>
+ </method>
+ <method name="area_get_collision_mask" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ Returns the physics layer or layers an area can contact with.
+ </description>
+ </method>
<method name="area_get_object_instance_id" qualifiers="const">
<return type="int" />
<param index="0" name="area" type="RID" />
diff --git a/doc/classes/PhysicsServer3DExtension.xml b/doc/classes/PhysicsServer3DExtension.xml
index ab00f63359..1e9df54de5 100644
--- a/doc/classes/PhysicsServer3DExtension.xml
+++ b/doc/classes/PhysicsServer3DExtension.xml
@@ -34,6 +34,18 @@
<description>
</description>
</method>
+ <method name="_area_get_collision_layer" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_area_get_collision_mask" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="area" type="RID" />
+ <description>
+ </description>
+ </method>
<method name="_area_get_object_instance_id" qualifiers="virtual const">
<return type="int" />
<param index="0" name="area" type="RID" />
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 4c2cf330af..498283b2f3 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -571,15 +571,25 @@
Forces the main window to be borderless.
[b]Note:[/b] This setting is ignored on iOS, Android, and Web.
</member>
- <member name="display/window/size/fullscreen" type="bool" setter="" getter="" default="false">
- Sets the main window to full screen when the project starts. Note that this is not [i]exclusive[/i] fullscreen. On Windows and Linux, a borderless window is used to emulate fullscreen. On macOS, a new desktop is used to display the running project.
- Regardless of the platform, enabling fullscreen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling fullscreen mode.
- [b]Note:[/b] This setting is ignored on iOS, Android, and Web.
+ <member name="display/window/size/extend_to_title" type="bool" setter="" getter="" default="false">
+ Main window content is expanded to the full size of the window. Unlike borderless window, the frame is left intact and can be used to resize the window, title bar is transparent, but have minimize/maximize/close buttons.
+ [b]Note:[/b] This setting is implemented on macOS.
+ </member>
+ <member name="display/window/size/mode" type="int" setter="" getter="" default="0">
+ Main window mode. See [enum DisplayServer.WindowMode] for possible values and how each mode behaves.
+ </member>
+ <member name="display/window/size/no_focus" type="bool" setter="" getter="" default="false">
+ Main window can't be focused. No-focus window will ignore all input, except mouse clicks.
</member>
<member name="display/window/size/resizable" type="bool" setter="" getter="" default="true">
Allows the window to be resizable by default.
[b]Note:[/b] This setting is ignored on iOS.
</member>
+ <member name="display/window/size/transparent" type="bool" setter="" getter="" default="false">
+ Main window background can be transparent.
+ [b]Note:[/b] To use transparent splash screen, set [member application/boot_splash/bg_color] to [code]Color(0, 0, 0, 0)[/code].
+ [b]Note:[/b] This setting has no effect if [member display/window/per_pixel_transparency/allowed] is set to [code]false[/code].
+ </member>
<member name="display/window/size/viewport_height" type="int" setter="" getter="" default="648">
Sets the game's main viewport height. On desktop platforms, this is also the initial window height, represented by an indigo-colored rectangle in the 2D editor. Stretch mode settings also use this as a reference when using the [code]canvas_items[/code] or [code]viewport[/code] stretch modes. See also [member display/window/size/viewport_width], [member display/window/size/window_width_override] and [member display/window/size/window_height_override].
</member>
diff --git a/doc/classes/QuadMesh.xml b/doc/classes/QuadMesh.xml
index 7469338ef9..b869774601 100644
--- a/doc/classes/QuadMesh.xml
+++ b/doc/classes/QuadMesh.xml
@@ -12,5 +12,6 @@
</tutorials>
<members>
<member name="orientation" type="int" setter="set_orientation" getter="get_orientation" overrides="PlaneMesh" enum="PlaneMesh.Orientation" default="2" />
+ <member name="size" type="Vector2" setter="set_size" getter="get_size" overrides="PlaneMesh" default="Vector2(1, 1)" />
</members>
</class>
diff --git a/doc/classes/RefCounted.xml b/doc/classes/RefCounted.xml
index 3daf3534b0..223e572254 100644
--- a/doc/classes/RefCounted.xml
+++ b/doc/classes/RefCounted.xml
@@ -13,6 +13,12 @@
<link title="When and how to avoid using nodes for everything">$DOCS_URL/tutorials/best_practices/node_alternatives.html</link>
</tutorials>
<methods>
+ <method name="get_reference_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the current reference count.
+ </description>
+ </method>
<method name="init_ref">
<return type="bool" />
<description>
diff --git a/doc/classes/ScriptEditorBase.xml b/doc/classes/ScriptEditorBase.xml
index 68834839f3..a3fcf53228 100644
--- a/doc/classes/ScriptEditorBase.xml
+++ b/doc/classes/ScriptEditorBase.xml
@@ -35,6 +35,13 @@
Emitted when the user requests a specific documentation page.
</description>
</signal>
+ <signal name="go_to_method">
+ <param index="0" name="script" type="Object" />
+ <param index="1" name="method" type="String" />
+ <description>
+ Emitted when the user requests to view a specific method of a script, similar to [signal request_open_script_at_line].
+ </description>
+ </signal>
<signal name="name_changed">
<description>
Emitted after script validation or when the edited resource has changed.
@@ -56,7 +63,7 @@
<param index="0" name="script" type="Object" />
<param index="1" name="line" type="int" />
<description>
- Emitted when the user requests a script.
+ Emitted when the user requests to view a specific line of a script, similar to [signal go_to_method].
</description>
</signal>
<signal name="request_save_history">
diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml
index f6a078602c..539ca38190 100644
--- a/doc/classes/Tree.xml
+++ b/doc/classes/Tree.xml
@@ -312,6 +312,9 @@
The drop mode as an OR combination of flags. See [enum DropModeFlags] constants. Once dropping is done, reverts to [constant DROP_MODE_DISABLED]. Setting this during [method Control._can_drop_data] is recommended.
This controls the drop sections, i.e. the decision and drawing of possible drop locations based on the mouse position.
</member>
+ <member name="enable_recursive_folding" type="bool" setter="set_enable_recursive_folding" getter="is_recursive_folding_enabled" default="true">
+ If [code]true[/code], recursive folding is enabled for this [Tree]. Holding down Shift while clicking the fold arrow collapses or uncollapses the [TreeItem] and all its descendants.
+ </member>
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" />
<member name="hide_folding" type="bool" setter="set_hide_folding" getter="is_folding_hidden" default="false">
If [code]true[/code], the folding arrow is hidden.
diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml
index fdae6d205d..c109dc57f7 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -321,6 +321,14 @@
Returns the [Tree] that owns this TreeItem.
</description>
</method>
+ <method name="is_any_collapsed">
+ <return type="bool" />
+ <param index="0" name="only_visible" type="bool" default="false" />
+ <description>
+ Returns [code]true[/code] if this [TreeItem], or any of its descendants, is collapsed.
+ If [param only_visible] is [code]true[/code] it ignores non-visible [TreeItem]s.
+ </description>
+ </method>
<method name="is_button_disabled" qualifiers="const">
<return type="bool" />
<param index="0" name="column" type="int" />
@@ -442,6 +450,13 @@
If [code]true[/code], the given [param column] is checked. Clears column's indeterminate status.
</description>
</method>
+ <method name="set_collapsed_recursive">
+ <return type="void" />
+ <param index="0" name="enable" type="bool" />
+ <description>
+ Collapses or uncollapses this [TreeItem] and all the descendants of this item.
+ </description>
+ </method>
<method name="set_custom_as_button">
<return type="void" />
<param index="0" name="column" type="int" />
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index 2c0a694ef9..c585b54ee1 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -381,7 +381,8 @@
Note that behavior might be different depending on the platform.
</member>
<member name="transparent" type="bool" setter="set_flag" getter="get_flag" default="false">
- If [code]true[/code], the [Window]'s background can be transparent. This is best used with embedded windows. Currently non-embedded [Window] transparency is implemented only for MacOS.
+ If [code]true[/code], the [Window]'s background can be transparent. This is best used with embedded windows.
+ [b]Note:[/b] This flag has no effect if [member ProjectSettings.display/window/per_pixel_transparency/allowed] is set to [code]false[/code].
</member>
<member name="unfocusable" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], the [Window] can't be focused nor interacted with. It can still be visible.
@@ -454,6 +455,11 @@
Emitted when the [constant NOTIFICATION_THEME_CHANGED] notification is sent.
</description>
</signal>
+ <signal name="titlebar_changed">
+ <description>
+ Emitted when window title bar decorations are changed, e.g., macOS window enter/exit full screen mode, or extend-to-title flag is changed.
+ </description>
+ </signal>
<signal name="visibility_changed">
<description>
Emitted when [Window] is made visible or disappears.
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index ab298a0e49..c8a42e925e 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -51,7 +51,6 @@
#include <sys/sysctl.h>
#endif
-#include <assert.h>
#include <dlfcn.h>
#include <errno.h>
#include <poll.h>
@@ -104,10 +103,6 @@ static void _setup_clock() {
}
#endif
-void OS_Unix::debug_break() {
- assert(false);
-}
-
static void handle_interrupt(int sig) {
if (!EngineDebugger::is_active()) {
return;
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index 8ef650f28b..b35f161524 100644
--- a/drivers/unix/os_unix.h
+++ b/drivers/unix/os_unix.h
@@ -86,7 +86,6 @@ public:
virtual int get_processor_count() const override;
- virtual void debug_break() override;
virtual void initialize_debugging() override;
virtual String get_executable_path() const override;
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 236f3d7b08..ddeb8643b8 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -367,6 +367,10 @@ void ConnectDialog::popup_dialog(const String &p_for_signal) {
error_label->set_visible(!_find_first_script(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root()));
}
+ if (first_popup) {
+ first_popup = false;
+ _advanced_pressed();
+ }
popup_centered();
}
@@ -389,6 +393,7 @@ void ConnectDialog::_advanced_pressed() {
}
_update_ok_enabled();
+ EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "use_advanced_connections", advanced->is_pressed());
popup_centered();
}
@@ -480,6 +485,7 @@ ConnectDialog::ConnectDialog() {
vbc_left->add_child(advanced);
advanced->set_text(TTR("Advanced"));
advanced->set_h_size_flags(Control::SIZE_SHRINK_BEGIN | Control::SIZE_EXPAND);
+ advanced->set_pressed(EditorSettings::get_singleton()->get_project_metadata("editor_metadata", "use_advanced_connections", false));
advanced->connect("pressed", callable_mp(this, &ConnectDialog::_advanced_pressed));
HBoxContainer *hbox = memnew(HBoxContainer);
diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h
index e37246e7a0..db2f855617 100644
--- a/editor/connections_dialog.h
+++ b/editor/connections_dialog.h
@@ -112,6 +112,7 @@ private:
LineEdit *dst_method = nullptr;
ConnectDialogBinds *cdbinds = nullptr;
bool edit_mode = false;
+ bool first_popup = true;
NodePath dst_path;
VBoxContainer *vbc_right = nullptr;
diff --git a/editor/debugger/editor_debugger_tree.h b/editor/debugger/editor_debugger_tree.h
index 5b2df8abd5..5af3a0d84a 100644
--- a/editor/debugger/editor_debugger_tree.h
+++ b/editor/debugger/editor_debugger_tree.h
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "scene/gui/tree.h"
-
#ifndef EDITOR_DEBUGGER_TREE_H
#define EDITOR_DEBUGGER_TREE_H
+#include "scene/gui/tree.h"
+
class SceneDebuggerTree;
class EditorFileDialog;
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index 708173ea26..9549ffb09b 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -763,7 +763,7 @@ void EditorFeatureProfileManager::_update_selected_profile() {
TreeItem *root = class_list->create_item();
TreeItem *features = class_list->create_item(root);
- TreeItem *last_feature;
+ TreeItem *last_feature = nullptr;
features->set_text(0, TTR("Main Features:"));
for (int i = 0; i < EditorFeatureProfile::FEATURE_MAX; i++) {
TreeItem *feature;
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index e786461722..5de205153d 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -1143,11 +1143,10 @@ Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) cons
}
Size2 EditorInspectorCategory::get_minimum_size() const {
- Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Tree"));
- int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Tree"));
+ Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
+ int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"));
Size2 ms;
- ms.width = 1;
ms.height = font->get_height(font_size);
if (icon.is_valid()) {
ms.height = MAX(icon->get_height(), ms.height);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 9ac6fd66ef..28768b7f34 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -429,7 +429,7 @@ void EditorNode::_version_control_menu_option(int p_idx) {
void EditorNode::_update_title() {
const String appname = ProjectSettings::get_singleton()->get("application/config/name");
- String title = (appname.is_empty() ? TTR("Unnamed Project") : appname) + String(" - ") + VERSION_NAME;
+ String title = (appname.is_empty() ? TTR("Unnamed Project") : appname);
const String edited = editor_data.get_edited_scene_root() ? editor_data.get_edited_scene_root()->get_scene_file_path() : String();
if (!edited.is_empty()) {
// Display the edited scene name before the program name so that it can be seen in the OS task bar.
@@ -439,8 +439,10 @@ void EditorNode::_update_title() {
// Display the "modified" mark before anything else so that it can always be seen in the OS task bar.
title = vformat("(*) %s", title);
}
-
- DisplayServer::get_singleton()->window_set_title(title);
+ DisplayServer::get_singleton()->window_set_title(title + String(" - ") + VERSION_NAME);
+ if (project_title) {
+ project_title->set_text(title);
+ }
}
void EditorNode::shortcut_input(const Ref<InputEvent> &p_event) {
@@ -659,6 +661,12 @@ void EditorNode::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
Engine::get_singleton()->set_editor_hint(true);
+ Window *window = static_cast<Window *>(get_tree()->get_root());
+ if (window) {
+ // Handle macOS fullscreen and extend-to-title changes.
+ window->connect("titlebar_changed", callable_mp(this, &EditorNode::_titlebar_resized));
+ }
+
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/low_processor_mode_sleep_usec")));
get_tree()->get_root()->set_as_audio_listener_3d(false);
get_tree()->get_root()->set_as_audio_listener_2d(false);
@@ -713,6 +721,8 @@ void EditorNode::_notification(int p_what) {
ProjectSettings::get_singleton()->save();
}
+ _titlebar_resized();
+
/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
} break;
@@ -750,7 +760,8 @@ void EditorNode::_notification(int p_what) {
EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor/theme") ||
EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/font") ||
EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/main_font") ||
- EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/code_font");
+ EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/code_font") ||
+ EditorSettings::get_singleton()->check_changed_settings_in_group("filesystem/file_dialog/thumbnail_size");
if (theme_changed) {
theme = create_custom_theme(theme_base->get_theme());
@@ -1169,6 +1180,18 @@ void EditorNode::_reload_project_settings() {
void EditorNode::_vp_resized() {
}
+void EditorNode::_titlebar_resized() {
+ const Size2 &margin = DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID);
+ if (left_menu_spacer) {
+ int w = (gui_base->is_layout_rtl()) ? margin.y : margin.x;
+ left_menu_spacer->set_custom_minimum_size(Size2(w, 0));
+ }
+ if (right_menu_spacer) {
+ int w = (gui_base->is_layout_rtl()) ? margin.x : margin.y;
+ right_menu_spacer->set_custom_minimum_size(Size2(w, 0));
+ }
+}
+
void EditorNode::_version_button_pressed() {
DisplayServer::get_singleton()->clipboard_set(version_btn->get_meta(META_TEXT_TO_COPY));
}
@@ -3389,7 +3412,7 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed
tb->add_theme_font_size_override("font_size", singleton->gui_base->get_theme_font_size(SNAME("main_button_font_size"), SNAME("EditorFonts")));
singleton->main_editor_buttons.push_back(tb);
- singleton->main_editor_button_vb->add_child(tb);
+ singleton->main_editor_button_hb->add_child(tb);
singleton->editor_table.push_back(p_editor);
singleton->distraction_free->move_to_front();
@@ -6589,14 +6612,14 @@ EditorNode::EditorNode() {
if (can_expand) {
// Add spacer to avoid other controls under window minimize/maximize/close buttons (left side).
- Control *menu_spacer = memnew(Control);
- menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
- menu_spacer->set_custom_minimum_size(Size2(DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID).x, 0));
- menu_hb->add_child(menu_spacer);
+ left_menu_spacer = memnew(Control);
+ left_menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ menu_hb->add_child(left_menu_spacer);
}
main_menu = memnew(MenuBar);
menu_hb->add_child(main_menu);
+
main_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
main_menu->set_flat(true);
main_menu->set_start_index(0); // Main menu, add to the start of global menu.
@@ -6765,22 +6788,30 @@ EditorNode::EditorNode() {
project_menu->add_shortcut(ED_GET_SHORTCUT("editor/quit_to_project_list"), RUN_PROJECT_MANAGER, true);
// Spacer to center 2D / 3D / Script buttons.
- Control *left_spacer = memnew(Control);
+ HBoxContainer *left_spacer = memnew(HBoxContainer);
left_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ left_spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL);
menu_hb->add_child(left_spacer);
- menu_hb->add_spacer();
+ if (can_expand && global_menu) {
+ project_title = memnew(Label);
+ project_title->add_theme_font_override("font", gui_base->get_theme_font(SNAME("bold"), SNAME("EditorFonts")));
+ project_title->add_theme_font_size_override("font_size", gui_base->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")));
+ project_title->set_focus_mode(Control::FOCUS_NONE);
+ project_title->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
+ project_title->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
+ project_title->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ left_spacer->add_child(project_title);
+ }
- main_editor_button_vb = memnew(HBoxContainer);
- menu_hb->add_child(main_editor_button_vb);
+ main_editor_button_hb = memnew(HBoxContainer);
+ menu_hb->add_child(main_editor_button_hb);
// Options are added and handled by DebuggerEditorPlugin.
debug_menu = memnew(PopupMenu);
debug_menu->set_name(TTR("Debug"));
main_menu->add_child(debug_menu);
- menu_hb->add_spacer();
-
settings_menu = memnew(PopupMenu);
settings_menu->set_name(TTR("Editor"));
main_menu->add_child(settings_menu);
@@ -6854,6 +6885,7 @@ EditorNode::EditorNode() {
// Spacer to center 2D / 3D / Script buttons.
Control *right_spacer = memnew(Control);
right_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ right_spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL);
menu_hb->add_child(right_spacer);
launch_pad = memnew(PanelContainer);
@@ -6869,23 +6901,24 @@ EditorNode::EditorNode() {
play_button->set_toggle_mode(true);
play_button->set_focus_mode(Control::FOCUS_NONE);
play_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY));
+ play_button->set_tooltip_text(TTR("Run the project's default scene."));
- ED_SHORTCUT_AND_COMMAND("editor/play", TTR("Play"), Key::F5);
- ED_SHORTCUT_OVERRIDE("editor/play", "macos", KeyModifierMask::META | Key::B);
- play_button->set_shortcut(ED_GET_SHORTCUT("editor/play"));
+ ED_SHORTCUT_AND_COMMAND("editor/run_project", TTR("Run Project"), Key::F5);
+ ED_SHORTCUT_OVERRIDE("editor/run_project", "macos", KeyModifierMask::META | Key::B);
+ play_button->set_shortcut(ED_GET_SHORTCUT("editor/run_project"));
pause_button = memnew(Button);
pause_button->set_flat(true);
pause_button->set_toggle_mode(true);
pause_button->set_icon(gui_base->get_theme_icon(SNAME("Pause"), SNAME("EditorIcons")));
pause_button->set_focus_mode(Control::FOCUS_NONE);
- pause_button->set_tooltip_text(TTR("Pause the scene execution for debugging."));
+ pause_button->set_tooltip_text(TTR("Pause the running project's execution for debugging."));
pause_button->set_disabled(true);
launch_pad_hb->add_child(pause_button);
- ED_SHORTCUT("editor/pause_scene", TTR("Pause Scene"), Key::F7);
- ED_SHORTCUT_OVERRIDE("editor/pause_scene", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::Y);
- pause_button->set_shortcut(ED_GET_SHORTCUT("editor/pause_scene"));
+ ED_SHORTCUT("editor/pause_running_project", TTR("Pause Running Project"), Key::F7);
+ ED_SHORTCUT_OVERRIDE("editor/pause_running_project", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::Y);
+ pause_button->set_shortcut(ED_GET_SHORTCUT("editor/pause_running_project"));
stop_button = memnew(Button);
stop_button->set_flat(true);
@@ -6893,12 +6926,12 @@ EditorNode::EditorNode() {
stop_button->set_focus_mode(Control::FOCUS_NONE);
stop_button->set_icon(gui_base->get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")));
stop_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_STOP));
- stop_button->set_tooltip_text(TTR("Stop the scene."));
+ stop_button->set_tooltip_text(TTR("Stop the currently running project."));
stop_button->set_disabled(true);
- ED_SHORTCUT("editor/stop", TTR("Stop"), Key::F8);
- ED_SHORTCUT_OVERRIDE("editor/stop", "macos", KeyModifierMask::META | Key::PERIOD);
- stop_button->set_shortcut(ED_GET_SHORTCUT("editor/stop"));
+ ED_SHORTCUT("editor/stop_running_project", TTR("Stop Running Project"), Key::F8);
+ ED_SHORTCUT_OVERRIDE("editor/stop_running_project", "macos", KeyModifierMask::META | Key::PERIOD);
+ stop_button->set_shortcut(ED_GET_SHORTCUT("editor/stop_running_project"));
run_native = memnew(EditorRunNative);
launch_pad_hb->add_child(run_native);
@@ -6910,10 +6943,11 @@ EditorNode::EditorNode() {
play_scene_button->set_toggle_mode(true);
play_scene_button->set_focus_mode(Control::FOCUS_NONE);
play_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_SCENE));
+ play_scene_button->set_tooltip_text(TTR("Run the currently edited scene."));
- ED_SHORTCUT_AND_COMMAND("editor/play_scene", TTR("Play Scene"), Key::F6);
- ED_SHORTCUT_OVERRIDE("editor/play_scene", "macos", KeyModifierMask::META | Key::R);
- play_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/play_scene"));
+ ED_SHORTCUT_AND_COMMAND("editor/run_current_scene", TTR("Run Current Scene"), Key::F6);
+ ED_SHORTCUT_OVERRIDE("editor/run_current_scene", "macos", KeyModifierMask::META | Key::R);
+ play_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/run_current_scene"));
play_custom_scene_button = memnew(Button);
play_custom_scene_button->set_flat(true);
@@ -6921,12 +6955,11 @@ EditorNode::EditorNode() {
play_custom_scene_button->set_toggle_mode(true);
play_custom_scene_button->set_focus_mode(Control::FOCUS_NONE);
play_custom_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_CUSTOM_SCENE));
+ play_custom_scene_button->set_tooltip_text(TTR("Run a specific scene."));
- _reset_play_buttons();
-
- ED_SHORTCUT_AND_COMMAND("editor/play_custom_scene", TTR("Play Custom Scene"), KeyModifierMask::CTRL | KeyModifierMask::SHIFT | Key::F5);
- ED_SHORTCUT_OVERRIDE("editor/play_custom_scene", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::R);
- play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/play_custom_scene"));
+ ED_SHORTCUT_AND_COMMAND("editor/run_specific_scene", TTR("Run Specific Scene"), KeyModifierMask::META | KeyModifierMask::SHIFT | Key::F5);
+ ED_SHORTCUT_OVERRIDE("editor/run_specific_scene", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::R);
+ play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/run_specific_scene"));
write_movie_panel = memnew(PanelContainer);
write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonNormal"), SNAME("EditorStyles")));
@@ -6964,10 +6997,9 @@ EditorNode::EditorNode() {
if (can_expand) {
// Add spacer to avoid other controls under the window minimize/maximize/close buttons (right side).
- Control *menu_spacer = memnew(Control);
- menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
- menu_spacer->set_custom_minimum_size(Size2(DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID).y, 0));
- menu_hb->add_child(menu_spacer);
+ right_menu_spacer = memnew(Control);
+ right_menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ menu_hb->add_child(right_menu_spacer);
}
String current_renderer = GLOBAL_GET("rendering/renderer/rendering_method");
@@ -7522,9 +7554,9 @@ EditorNode::EditorNode() {
screenshot_timer->set_owner(get_owner());
// Adjust spacers to center 2D / 3D / Script buttons.
- int max_w = MAX(launch_pad_hb->get_minimum_size().x + right_menu_hb->get_minimum_size().x, main_menu->get_minimum_size().x);
+ int max_w = MAX(launch_pad->get_minimum_size().x + right_menu_hb->get_minimum_size().x, main_menu->get_minimum_size().x);
left_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - main_menu->get_minimum_size().x), 0));
- right_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - launch_pad_hb->get_minimum_size().x - right_menu_hb->get_minimum_size().x), 0));
+ right_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - launch_pad->get_minimum_size().x - right_menu_hb->get_minimum_size().x), 0));
// Extend menu bar to window title.
if (can_expand) {
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 14dab11358..fab280bc14 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -322,6 +322,9 @@ private:
HBoxContainer *bottom_hb = nullptr;
Control *vp_base = nullptr;
+ Label *project_title = nullptr;
+ Control *left_menu_spacer = nullptr;
+ Control *right_menu_spacer = nullptr;
EditorTitleBar *menu_hb = nullptr;
VBoxContainer *main_screen_vbox = nullptr;
MenuBar *main_menu = nullptr;
@@ -397,7 +400,7 @@ private:
String current_path;
MenuButton *update_spinner = nullptr;
- HBoxContainer *main_editor_button_vb = nullptr;
+ HBoxContainer *main_editor_button_hb = nullptr;
Vector<Button *> main_editor_buttons;
Vector<EditorPlugin *> editor_table;
@@ -560,6 +563,7 @@ private:
void _close_messages();
void _show_messages();
void _vp_resized();
+ void _titlebar_resized();
void _version_button_pressed();
int _save_external_resources();
diff --git a/editor/editor_quick_open.h b/editor/editor_quick_open.h
index 86a419b538..83cbbd7cac 100644
--- a/editor/editor_quick_open.h
+++ b/editor/editor_quick_open.h
@@ -43,7 +43,7 @@ class EditorQuickOpen : public ConfirmationDialog {
Tree *search_options = nullptr;
StringName base_type;
bool allow_multi_select = false;
- bool _load_resources = true;
+ bool _load_resources = false; // Prohibitively slow for now.
Vector<String> files;
OAHashMap<String, Ref<Texture2D>> icons;
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index 48e746ac36..2c09543d92 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -772,6 +772,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
shortcut_editor = memnew(InputEventConfigurationDialog);
shortcut_editor->connect("confirmed", callable_mp(this, &EditorSettingsDialog::_event_config_confirmed));
shortcut_editor->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_KEY);
+ shortcut_editor->set_close_on_escape(false);
add_child(shortcut_editor);
set_hide_on_ok(true);
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index edbd2dd62f..486a1f5a84 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -42,10 +42,15 @@
#include "modules/svg/image_loader_svg.h"
#endif
-HashMap<Color, Color> EditorColorMap::editor_color_map;
+HashMap<Color, Color> EditorColorMap::color_conversion_map;
+HashSet<StringName> EditorColorMap::color_conversion_exceptions;
-void EditorColorMap::add_color_pair(const String p_from_color, const String p_to_color) {
- editor_color_map[Color::html(p_from_color)] = Color::html(p_to_color);
+void EditorColorMap::add_conversion_color_pair(const String p_from_color, const String p_to_color) {
+ color_conversion_map[Color::html(p_from_color)] = Color::html(p_to_color);
+}
+
+void EditorColorMap::add_conversion_exception(const StringName p_icon_name) {
+ color_conversion_exceptions.insert(p_icon_name);
}
void EditorColorMap::create() {
@@ -53,105 +58,139 @@ void EditorColorMap::create() {
// This can be a basis for proper palette validation later.
// Convert: FROM TO
- add_color_pair("#478cbf", "#478cbf"); // Godot Blue
- add_color_pair("#414042", "#414042"); // Godot Gray
+ add_conversion_color_pair("#478cbf", "#478cbf"); // Godot Blue
+ add_conversion_color_pair("#414042", "#414042"); // Godot Gray
- add_color_pair("#ffffff", "#414141"); // Pure white
- add_color_pair("#000000", "#bfbfbf"); // Pure black
+ add_conversion_color_pair("#ffffff", "#414141"); // Pure white
+ add_conversion_color_pair("#000000", "#bfbfbf"); // Pure black
// Keep pure RGB colors as is, but list them for explicitly.
- add_color_pair("#ff0000", "#ff0000"); // Pure red
- add_color_pair("#00ff00", "#00ff00"); // Pure green
- add_color_pair("#0000ff", "#0000ff"); // Pure blue
+ add_conversion_color_pair("#ff0000", "#ff0000"); // Pure red
+ add_conversion_color_pair("#00ff00", "#00ff00"); // Pure green
+ add_conversion_color_pair("#0000ff", "#0000ff"); // Pure blue
// GUI Colors
- add_color_pair("#e0e0e0", "#5a5a5a"); // Common icon color
- add_color_pair("#fefefe", "#fefefe"); // Forced light color
- add_color_pair("#808080", "#808080"); // GUI disabled color
- add_color_pair("#b3b3b3", "#363636"); // GUI disabled light color
- add_color_pair("#699ce8", "#699ce8"); // GUI highlight color
- add_color_pair("#f9f9f9", "#606060"); // Scrollbar grabber highlight color
-
- add_color_pair("#c38ef1", "#a85de9"); // Animation
- add_color_pair("#fc7f7f", "#cd3838"); // Spatial
- add_color_pair("#8da5f3", "#3d64dd"); // 2D
- add_color_pair("#4b70ea", "#1a3eac"); // 2D Dark
- add_color_pair("#8eef97", "#2fa139"); // Control
-
- add_color_pair("#5fb2ff", "#0079f0"); // Selection (blue)
- add_color_pair("#003e7a", "#2b74bb"); // Selection (darker blue)
- add_color_pair("#f7f5cf", "#615f3a"); // Gizmo (yellow)
+ add_conversion_color_pair("#e0e0e0", "#5a5a5a"); // Common icon color
+ add_conversion_color_pair("#fefefe", "#fefefe"); // Forced light color
+ add_conversion_color_pair("#808080", "#808080"); // GUI disabled color
+ add_conversion_color_pair("#b3b3b3", "#363636"); // GUI disabled light color
+ add_conversion_color_pair("#699ce8", "#699ce8"); // GUI highlight color
+ add_conversion_color_pair("#f9f9f9", "#606060"); // Scrollbar grabber highlight color
+
+ add_conversion_color_pair("#c38ef1", "#a85de9"); // Animation
+ add_conversion_color_pair("#fc7f7f", "#cd3838"); // Spatial
+ add_conversion_color_pair("#8da5f3", "#3d64dd"); // 2D
+ add_conversion_color_pair("#4b70ea", "#1a3eac"); // 2D Dark
+ add_conversion_color_pair("#8eef97", "#2fa139"); // Control
+
+ add_conversion_color_pair("#5fb2ff", "#0079f0"); // Selection (blue)
+ add_conversion_color_pair("#003e7a", "#2b74bb"); // Selection (darker blue)
+ add_conversion_color_pair("#f7f5cf", "#615f3a"); // Gizmo (yellow)
// Rainbow
- add_color_pair("#ff4545", "#ff2929"); // Red
- add_color_pair("#ffe345", "#ffe337"); // Yellow
- add_color_pair("#80ff45", "#74ff34"); // Green
- add_color_pair("#45ffa2", "#2cff98"); // Aqua
- add_color_pair("#45d7ff", "#22ccff"); // Blue
- add_color_pair("#8045ff", "#702aff"); // Purple
- add_color_pair("#ff4596", "#ff2781"); // Pink
+ add_conversion_color_pair("#ff4545", "#ff2929"); // Red
+ add_conversion_color_pair("#ffe345", "#ffe337"); // Yellow
+ add_conversion_color_pair("#80ff45", "#74ff34"); // Green
+ add_conversion_color_pair("#45ffa2", "#2cff98"); // Aqua
+ add_conversion_color_pair("#45d7ff", "#22ccff"); // Blue
+ add_conversion_color_pair("#8045ff", "#702aff"); // Purple
+ add_conversion_color_pair("#ff4596", "#ff2781"); // Pink
// Audio gradients
- add_color_pair("#e1da5b", "#d6cf4b"); // Yellow
+ add_conversion_color_pair("#e1da5b", "#d6cf4b"); // Yellow
- add_color_pair("#62aeff", "#1678e0"); // Frozen gradient top
- add_color_pair("#75d1e6", "#41acc5"); // Frozen gradient middle
- add_color_pair("#84ffee", "#49ccba"); // Frozen gradient bottom
+ add_conversion_color_pair("#62aeff", "#1678e0"); // Frozen gradient top
+ add_conversion_color_pair("#75d1e6", "#41acc5"); // Frozen gradient middle
+ add_conversion_color_pair("#84ffee", "#49ccba"); // Frozen gradient bottom
- add_color_pair("#f70000", "#c91616"); // Color track red
- add_color_pair("#eec315", "#d58c0b"); // Color track orange
- add_color_pair("#dbee15", "#b7d10a"); // Color track yellow
- add_color_pair("#288027", "#218309"); // Color track green
+ add_conversion_color_pair("#f70000", "#c91616"); // Color track red
+ add_conversion_color_pair("#eec315", "#d58c0b"); // Color track orange
+ add_conversion_color_pair("#dbee15", "#b7d10a"); // Color track yellow
+ add_conversion_color_pair("#288027", "#218309"); // Color track green
// Resource groups
- add_color_pair("#ffca5f", "#fea900"); // Mesh resource (orange)
- add_color_pair("#2998ff", "#68b6ff"); // Shape resource (blue)
- add_color_pair("#a2d2ff", "#4998e3"); // Shape resource (light blue)
+ add_conversion_color_pair("#ffca5f", "#fea900"); // Mesh resource (orange)
+ add_conversion_color_pair("#2998ff", "#68b6ff"); // Shape resource (blue)
+ add_conversion_color_pair("#a2d2ff", "#4998e3"); // Shape resource (light blue)
// Animation editor tracks
// The property track icon color is set by the common icon color.
- add_color_pair("#ea7940", "#bd5e2c"); // 3D Position track
- add_color_pair("#ff2b88", "#bd165f"); // 3D Rotation track
- add_color_pair("#eac840", "#bd9d1f"); // 3D Scale track
- add_color_pair("#3cf34e", "#16a827"); // Call Method track
- add_color_pair("#2877f6", "#236be6"); // Bezier Curve track
- add_color_pair("#eae440", "#9f9722"); // Audio Playback track
- add_color_pair("#a448f0", "#9853ce"); // Animation Playback track
- add_color_pair("#5ad5c4", "#0a9c88"); // Blend Shape track
+ add_conversion_color_pair("#ea7940", "#bd5e2c"); // 3D Position track
+ add_conversion_color_pair("#ff2b88", "#bd165f"); // 3D Rotation track
+ add_conversion_color_pair("#eac840", "#bd9d1f"); // 3D Scale track
+ add_conversion_color_pair("#3cf34e", "#16a827"); // Call Method track
+ add_conversion_color_pair("#2877f6", "#236be6"); // Bezier Curve track
+ add_conversion_color_pair("#eae440", "#9f9722"); // Audio Playback track
+ add_conversion_color_pair("#a448f0", "#9853ce"); // Animation Playback track
+ add_conversion_color_pair("#5ad5c4", "#0a9c88"); // Blend Shape track
// Control layouts
- add_color_pair("#d6d6d6", "#474747"); // Highlighted part
- add_color_pair("#474747", "#d6d6d6"); // Background part
- add_color_pair("#919191", "#6e6e6e"); // Border part
+ add_conversion_color_pair("#d6d6d6", "#474747"); // Highlighted part
+ add_conversion_color_pair("#474747", "#d6d6d6"); // Background part
+ add_conversion_color_pair("#919191", "#6e6e6e"); // Border part
// TileSet editor icons
- add_color_pair("#fce00e", "#aa8d24"); // New Single Tile
- add_color_pair("#0e71fc", "#0350bd"); // New Autotile
- add_color_pair("#c6ced4", "#828f9b"); // New Atlas
+ add_conversion_color_pair("#fce00e", "#aa8d24"); // New Single Tile
+ add_conversion_color_pair("#0e71fc", "#0350bd"); // New Autotile
+ add_conversion_color_pair("#c6ced4", "#828f9b"); // New Atlas
// Visual script
- add_color_pair("#41ecad", "#25e3a0"); // VisualScript variant
- add_color_pair("#6f91f0", "#6d8eeb"); // VisualScript bool
- add_color_pair("#5abbef", "#4fb2e9"); // VisualScript int
- add_color_pair("#35d4f4", "#27ccf0"); // VisualScript float
- add_color_pair("#4593ec", "#4690e7"); // VisualScript String
- add_color_pair("#ac73f1", "#ad76ee"); // VisualScript Vector2
- add_color_pair("#f1738f", "#ee758e"); // VisualScript Rect2
- add_color_pair("#de66f0", "#dc6aed"); // VisualScript Vector3
- add_color_pair("#b9ec41", "#96ce1a"); // VisualScript Transform2D
- add_color_pair("#f74949", "#f77070"); // VisualScript Plane
- add_color_pair("#ec418e", "#ec69a3"); // VisualScript Quat
- add_color_pair("#ee5677", "#ee7991"); // VisualScript AABB
- add_color_pair("#e1ec41", "#b2bb19"); // VisualScript Basis
- add_color_pair("#f68f45", "#f49047"); // VisualScript Transform
- add_color_pair("#417aec", "#6993ec"); // VisualScript NodePath
- add_color_pair("#41ec80", "#2ce573"); // VisualScript RID
- add_color_pair("#55f3e3", "#12d5c3"); // VisualScript Object
- add_color_pair("#54ed9e", "#57e99f"); // VisualScript Dictionary
+ add_conversion_color_pair("#41ecad", "#25e3a0"); // VisualScript variant
+ add_conversion_color_pair("#6f91f0", "#6d8eeb"); // VisualScript bool
+ add_conversion_color_pair("#5abbef", "#4fb2e9"); // VisualScript int
+ add_conversion_color_pair("#35d4f4", "#27ccf0"); // VisualScript float
+ add_conversion_color_pair("#4593ec", "#4690e7"); // VisualScript String
+ add_conversion_color_pair("#ac73f1", "#ad76ee"); // VisualScript Vector2
+ add_conversion_color_pair("#f1738f", "#ee758e"); // VisualScript Rect2
+ add_conversion_color_pair("#de66f0", "#dc6aed"); // VisualScript Vector3
+ add_conversion_color_pair("#b9ec41", "#96ce1a"); // VisualScript Transform2D
+ add_conversion_color_pair("#f74949", "#f77070"); // VisualScript Plane
+ add_conversion_color_pair("#ec418e", "#ec69a3"); // VisualScript Quat
+ add_conversion_color_pair("#ee5677", "#ee7991"); // VisualScript AABB
+ add_conversion_color_pair("#e1ec41", "#b2bb19"); // VisualScript Basis
+ add_conversion_color_pair("#f68f45", "#f49047"); // VisualScript Transform
+ add_conversion_color_pair("#417aec", "#6993ec"); // VisualScript NodePath
+ add_conversion_color_pair("#41ec80", "#2ce573"); // VisualScript RID
+ add_conversion_color_pair("#55f3e3", "#12d5c3"); // VisualScript Object
+ add_conversion_color_pair("#54ed9e", "#57e99f"); // VisualScript Dictionary
// Visual shaders
- add_color_pair("#77ce57", "#67c046"); // Vector funcs
- add_color_pair("#ea686c", "#d95256"); // Vector transforms
- add_color_pair("#eac968", "#d9b64f"); // Textures and cubemaps
- add_color_pair("#cf68ea", "#c050dd"); // Functions and expressions
+ add_conversion_color_pair("#77ce57", "#67c046"); // Vector funcs
+ add_conversion_color_pair("#ea686c", "#d95256"); // Vector transforms
+ add_conversion_color_pair("#eac968", "#d9b64f"); // Textures and cubemaps
+ add_conversion_color_pair("#cf68ea", "#c050dd"); // Functions and expressions
+
+ // These icons should not be converted.
+ add_conversion_exception("EditorPivot");
+ add_conversion_exception("EditorHandle");
+ add_conversion_exception("Editor3DHandle");
+ add_conversion_exception("EditorBoneHandle");
+ add_conversion_exception("Godot");
+ add_conversion_exception("Sky");
+ add_conversion_exception("EditorControlAnchor");
+ add_conversion_exception("DefaultProjectIcon");
+ add_conversion_exception("GuiChecked");
+ add_conversion_exception("GuiRadioChecked");
+ add_conversion_exception("GuiIndeterminate");
+ add_conversion_exception("GuiCloseCustomizable");
+ add_conversion_exception("GuiGraphNodePort");
+ add_conversion_exception("GuiResizer");
+ add_conversion_exception("ZoomMore");
+ add_conversion_exception("ZoomLess");
+ add_conversion_exception("ZoomReset");
+ add_conversion_exception("LockViewport");
+ add_conversion_exception("GroupViewport");
+ add_conversion_exception("StatusError");
+ add_conversion_exception("StatusSuccess");
+ add_conversion_exception("StatusWarning");
+ add_conversion_exception("OverbrightIndicator");
+ add_conversion_exception("GuiMiniCheckerboard");
+
+ /// Code Editor.
+ add_conversion_exception("GuiTab");
+ add_conversion_exception("GuiSpace");
+ add_conversion_exception("CodeFoldedRightArrow");
+ add_conversion_exception("CodeFoldDownArrow");
+ add_conversion_exception("TextEditorPlay");
+ add_conversion_exception("Breakpoint");
}
static Ref<StyleBoxTexture> make_stylebox(Ref<Texture2D> p_texture, float p_left, float p_top, float p_right, float p_bottom, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, bool p_draw_center = true) {
@@ -206,67 +245,49 @@ static Ref<ImageTexture> editor_generate_icon(int p_index, float p_scale, float
img->adjust_bcs(1.0, 1.0, p_saturation);
}
- // In this case filter really helps.
return ImageTexture::create_from_image(img);
}
#endif
-void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = true, int p_thumb_size = 32, bool p_only_thumbs = false, float p_icon_saturation = 1.0) {
+void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme, float p_icon_saturation, int p_thumb_size, bool p_only_thumbs = false) {
#ifdef MODULE_SVG_ENABLED
- HashMap<Color, Color> icon_color_map;
-
- // The names of the icons to never convert, even if one of their colors
- // are contained in the dictionary above.
- HashSet<StringName> exceptions;
-
+ // Before we register the icons, we adjust their colors and saturation.
+ // Most icons follow the standard rules for color conversion to follow the editor
+ // theme's polarity (dark/light). We also adjust the saturation for most icons,
+ // following the editor setting.
+ // Some icons are excluded from this conversion, and instead use the configured
+ // accent color to replace their innate accent color to match the editor theme.
+ // And then some icons are completely excluded from the conversion.
+
+ // Standard color conversion map.
+ HashMap<Color, Color> color_conversion_map;
+ // Icons by default are set up for the dark theme, so if the theme is light,
+ // we apply the dark-to-light color conversion map.
if (!p_dark_theme) {
- for (KeyValue<Color, Color> &E : EditorColorMap::get()) {
- icon_color_map[E.key] = E.value;
+ for (KeyValue<Color, Color> &E : EditorColorMap::get_color_conversion_map()) {
+ color_conversion_map[E.key] = E.value;
}
-
- exceptions.insert("EditorPivot");
- exceptions.insert("EditorHandle");
- exceptions.insert("Editor3DHandle");
- exceptions.insert("EditorBoneHandle");
- exceptions.insert("Godot");
- exceptions.insert("Sky");
- exceptions.insert("EditorControlAnchor");
- exceptions.insert("DefaultProjectIcon");
- exceptions.insert("GuiChecked");
- exceptions.insert("GuiRadioChecked");
- exceptions.insert("GuiIndeterminate");
- exceptions.insert("GuiCloseCustomizable");
- exceptions.insert("GuiGraphNodePort");
- exceptions.insert("GuiResizer");
- exceptions.insert("ZoomMore");
- exceptions.insert("ZoomLess");
- exceptions.insert("ZoomReset");
- exceptions.insert("LockViewport");
- exceptions.insert("GroupViewport");
- exceptions.insert("StatusError");
- exceptions.insert("StatusSuccess");
- exceptions.insert("StatusWarning");
- exceptions.insert("OverbrightIndicator");
- exceptions.insert("GuiMiniCheckerboard");
-
- // Prevents Code Editor icons from changing
- exceptions.insert("GuiTab");
- exceptions.insert("GuiSpace");
- exceptions.insert("CodeFoldedRightArrow");
- exceptions.insert("CodeFoldDownArrow");
- exceptions.insert("TextEditorPlay");
- exceptions.insert("Breakpoint");
}
-
- // These ones should be converted even if we are using a dark theme.
+ // These colors should be converted even if we are using a dark theme.
const Color error_color = p_theme->get_color(SNAME("error_color"), SNAME("Editor"));
const Color success_color = p_theme->get_color(SNAME("success_color"), SNAME("Editor"));
const Color warning_color = p_theme->get_color(SNAME("warning_color"), SNAME("Editor"));
- icon_color_map[Color::html("#ff5f5f")] = error_color;
- icon_color_map[Color::html("#5fff97")] = success_color;
- icon_color_map[Color::html("#ffdd65")] = warning_color;
-
- // Use the accent color for some icons (checkbox, radio, toggle, etc.).
+ color_conversion_map[Color::html("#ff5f5f")] = error_color;
+ color_conversion_map[Color::html("#5fff97")] = success_color;
+ color_conversion_map[Color::html("#ffdd65")] = warning_color;
+
+ // The names of the icons to exclude from the standard color conversion.
+ HashSet<StringName> conversion_exceptions = EditorColorMap::get_color_conversion_exceptions();
+
+ // The names of the icons to exclude when adjusting for saturation.
+ HashSet<StringName> saturation_exceptions;
+ saturation_exceptions.insert("DefaultProjectIcon");
+ saturation_exceptions.insert("Godot");
+ saturation_exceptions.insert("Logo");
+
+ // Accent color conversion map.
+ // It is used on soem icons (checkbox, radio, toggle, etc.), regardless of the dark
+ // or light mode.
HashMap<Color, Color> accent_color_map;
HashSet<StringName> accent_color_icons;
@@ -292,16 +313,14 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
icon = editor_generate_icon(i, EDSCALE, 1.0, accent_color_map);
} else {
float saturation = p_icon_saturation;
-
- if (strcmp(editor_icons_names[i], "DefaultProjectIcon") == 0 || strcmp(editor_icons_names[i], "Godot") == 0 || strcmp(editor_icons_names[i], "Logo") == 0) {
+ if (saturation_exceptions.has(editor_icons_names[i])) {
saturation = 1.0;
}
- const int is_exception = exceptions.has(editor_icons_names[i]);
- if (is_exception) {
+ if (conversion_exceptions.has(editor_icons_names[i])) {
icon = editor_generate_icon(i, EDSCALE, saturation);
} else {
- icon = editor_generate_icon(i, EDSCALE, saturation, icon_color_map);
+ icon = editor_generate_icon(i, EDSCALE, saturation, color_conversion_map);
}
}
@@ -310,19 +329,26 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
}
// Generate thumbnail icons with the given thumbnail size.
- // We don't need filtering when generating at one of the default resolutions.
- const bool force_filter = p_thumb_size != 64 && p_thumb_size != 32;
+ // See editor\icons\editor_icons_builders.py for the code that determines which icons are thumbnails.
if (p_thumb_size >= 64) {
const float scale = (float)p_thumb_size / 64.0 * EDSCALE;
for (int i = 0; i < editor_bg_thumbs_count; i++) {
const int index = editor_bg_thumbs_indices[i];
- const int is_exception = exceptions.has(editor_icons_names[index]);
-
Ref<ImageTexture> icon;
- if (!p_dark_theme && !is_exception) {
- icon = editor_generate_icon(index, scale, force_filter, icon_color_map);
+
+ if (accent_color_icons.has(editor_icons_names[index])) {
+ icon = editor_generate_icon(index, scale, 1.0, accent_color_map);
} else {
- icon = editor_generate_icon(index, scale, force_filter);
+ float saturation = p_icon_saturation;
+ if (saturation_exceptions.has(editor_icons_names[index])) {
+ saturation = 1.0;
+ }
+
+ if (conversion_exceptions.has(editor_icons_names[index])) {
+ icon = editor_generate_icon(index, scale, saturation);
+ } else {
+ icon = editor_generate_icon(index, scale, saturation, color_conversion_map);
+ }
}
p_theme->set_icon(editor_icons_names[index], SNAME("EditorIcons"), icon);
@@ -331,13 +357,21 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
const float scale = (float)p_thumb_size / 32.0 * EDSCALE;
for (int i = 0; i < editor_md_thumbs_count; i++) {
const int index = editor_md_thumbs_indices[i];
- const bool is_exception = exceptions.has(editor_icons_names[index]);
-
Ref<ImageTexture> icon;
- if (!p_dark_theme && !is_exception) {
- icon = editor_generate_icon(index, scale, force_filter, icon_color_map);
+
+ if (accent_color_icons.has(editor_icons_names[index])) {
+ icon = editor_generate_icon(index, scale, 1.0, accent_color_map);
} else {
- icon = editor_generate_icon(index, scale, force_filter);
+ float saturation = p_icon_saturation;
+ if (saturation_exceptions.has(editor_icons_names[index])) {
+ saturation = 1.0;
+ }
+
+ if (conversion_exceptions.has(editor_icons_names[index])) {
+ icon = editor_generate_icon(index, scale, saturation);
+ } else {
+ icon = editor_generate_icon(index, scale, saturation, color_conversion_map);
+ }
}
p_theme->set_icon(editor_icons_names[index], SNAME("EditorIcons"), icon);
@@ -432,7 +466,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
if (dark_theme) {
ImageLoaderSVG::set_forced_color_map(HashMap<Color, Color>());
} else {
- ImageLoaderSVG::set_forced_color_map(EditorColorMap::get());
+ ImageLoaderSVG::set_forced_color_map(EditorColorMap::get_color_conversion_map());
}
#endif
@@ -475,9 +509,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color highlight_color = Color(accent_color.r, accent_color.g, accent_color.b, 0.275);
const Color disabled_highlight_color = highlight_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.5);
- float prev_icon_saturation = theme->has_color(SNAME("icon_saturation"), SNAME("Editor")) ? theme->get_color(SNAME("icon_saturation"), SNAME("Editor")).r : 1.0;
-
- theme->set_color("icon_saturation", "Editor", Color(icon_saturation, icon_saturation, icon_saturation)); // can't save single float in theme, so using color
+ // Can't save single float in theme, so using Color.
+ theme->set_color("icon_saturation", "Editor", Color(icon_saturation, icon_saturation, icon_saturation));
theme->set_color("accent_color", "Editor", accent_color);
theme->set_color("highlight_color", "Editor", highlight_color);
theme->set_color("disabled_highlight_color", "Editor", disabled_highlight_color);
@@ -518,7 +551,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Color readonly_warning_color = error_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.25);
if (!dark_theme) {
- // Darken some colors to be readable on a light background
+ // Darken some colors to be readable on a light background.
success_color = success_color.lerp(mono_color, 0.35);
warning_color = warning_color.lerp(mono_color, 0.35);
error_color = error_color.lerp(mono_color, 0.25);
@@ -541,22 +574,43 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_constant("dark_theme", "Editor", dark_theme);
theme->set_constant("color_picker_button_height", "Editor", 28 * EDSCALE);
- // Register icons + font
+ // Register editor icons.
+ // If the settings are comparable to the old theme, then just copy them over.
+ // Otherwise, regenerate them. Also check if we need to regenerate "thumb" icons.
+ bool keep_old_icons = false;
+ bool regenerate_thumb_icons = true;
+ if (p_theme != nullptr) {
+ // We check editor scale, theme dark/light mode, icon saturation, and accent color.
+
+ // That doesn't really work as expected, since theme constants are integers, and scales are floats.
+ // So this check will never work when changing between 100-199% values.
+ const float prev_scale = (float)p_theme->get_constant(SNAME("scale"), SNAME("Editor"));
+ const bool prev_dark_theme = (bool)p_theme->get_constant(SNAME("dark_theme"), SNAME("Editor"));
+ const Color prev_accent_color = p_theme->get_color(SNAME("accent_color"), SNAME("Editor"));
+ const float prev_icon_saturation = p_theme->get_color(SNAME("icon_saturation"), SNAME("Editor")).r;
+
+ keep_old_icons = (Math::is_equal_approx(prev_scale, EDSCALE) &&
+ prev_dark_theme == dark_theme &&
+ prev_accent_color == accent_color &&
+ prev_icon_saturation == icon_saturation);
+
+ const double prev_thumb_size = (double)p_theme->get_constant(SNAME("thumb_size"), SNAME("Editor"));
+
+ regenerate_thumb_icons = !Math::is_equal_approx(prev_thumb_size, thumb_size);
+ }
- // The editor scale, icon color (dark_theme bool), icon saturation, and accent color has not changed, so we do not regenerate the icons.
- if (p_theme != nullptr && fabs(p_theme->get_constant(SNAME("scale"), SNAME("Editor")) - EDSCALE) < 0.00001 && (bool)p_theme->get_constant(SNAME("dark_theme"), SNAME("Editor")) == dark_theme && prev_icon_saturation == icon_saturation && p_theme->get_color(SNAME("accent_color"), SNAME("Editor")) == accent_color) {
- // Register already generated icons.
+ if (keep_old_icons) {
for (int i = 0; i < editor_icons_count; i++) {
theme->set_icon(editor_icons_names[i], SNAME("EditorIcons"), p_theme->get_icon(editor_icons_names[i], SNAME("EditorIcons")));
}
} else {
- editor_register_and_generate_icons(theme, dark_theme, thumb_size, false, icon_saturation);
+ editor_register_and_generate_icons(theme, dark_theme, icon_saturation, thumb_size, false);
}
- // Thumbnail size has changed, so we regenerate the medium sizes
- if (p_theme != nullptr && fabs((double)p_theme->get_constant(SNAME("thumb_size"), SNAME("Editor")) - thumb_size) > 0.00001) {
- editor_register_and_generate_icons(p_theme, dark_theme, thumb_size, true);
+ if (regenerate_thumb_icons) {
+ editor_register_and_generate_icons(theme, dark_theme, icon_saturation, thumb_size, true);
}
+ // Register editor fonts.
editor_register_fonts(theme);
// Ensure borders are visible when using an editor scale below 100%.
diff --git a/editor/editor_themes.h b/editor/editor_themes.h
index 37db8160fa..da5db95d0e 100644
--- a/editor/editor_themes.h
+++ b/editor/editor_themes.h
@@ -39,13 +39,18 @@
class EditorColorMap {
// Godot Color values are used to avoid the ambiguity of strings
// (where "#ffffff", "fff", and "white" are all equivalent).
- static HashMap<Color, Color> editor_color_map;
+ static HashMap<Color, Color> color_conversion_map;
+ // The names of the icons to never convert, even if one of their colors
+ // are contained in the color map from above.
+ static HashSet<StringName> color_conversion_exceptions;
public:
static void create();
- static void add_color_pair(const String p_from_color, const String p_to_color);
+ static void add_conversion_color_pair(const String p_from_color, const String p_to_color);
+ static void add_conversion_exception(const StringName p_icon_name);
- static HashMap<Color, Color> &get() { return editor_color_map; };
+ static HashMap<Color, Color> &get_color_conversion_map() { return color_conversion_map; };
+ static HashSet<StringName> &get_color_conversion_exceptions() { return color_conversion_exceptions; };
};
Ref<Theme> create_editor_theme(Ref<Theme> p_theme = nullptr);
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index bcc85570ed..13ab5cebf6 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -710,7 +710,7 @@ String EditorExportPlatform::_export_customize(const String &p_path, LocalVector
if (type == "PackedScene") { // Its a scene.
Ref<PackedScene> ps = ResourceLoader::load(p_path, "PackedScene", ResourceFormatLoader::CACHE_MODE_IGNORE);
ERR_FAIL_COND_V(ps.is_null(), p_path);
- Node *node = ps->instantiate();
+ Node *node = ps->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); // Make sure the child scene root gets the correct inheritance chain.
ERR_FAIL_COND_V(node == nullptr, p_path);
if (customize_scenes_plugins.size()) {
for (uint32_t i = 0; i < customize_scenes_plugins.size(); i++) {
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 19b4932d3d..424eab2f02 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1751,22 +1751,7 @@ void FileSystemDock::_tree_rmb_option(int p_option) {
case FOLDER_COLLAPSE_ALL: {
// Expand or collapse the folder
if (selected_strings.size() == 1) {
- bool is_collapsed = (p_option == FOLDER_COLLAPSE_ALL);
-
- Vector<TreeItem *> needs_check;
- needs_check.push_back(tree->get_selected());
-
- while (needs_check.size()) {
- needs_check[0]->set_collapsed(is_collapsed);
-
- TreeItem *child = needs_check[0]->get_first_child();
- while (child) {
- needs_check.push_back(child);
- child = child->get_next();
- }
-
- needs_check.remove_at(0);
- }
+ tree->get_selected()->set_collapsed_recursive(p_option == FOLDER_COLLAPSE_ALL);
}
} break;
default: {
diff --git a/editor/icons/MemberAnnotation.svg b/editor/icons/MemberAnnotation.svg
index c73ebf7b9b..39bef6d9ee 100644
--- a/editor/icons/MemberAnnotation.svg
+++ b/editor/icons/MemberAnnotation.svg
@@ -1 +1 @@
-<svg width="16" height="16" version="1.0" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><script id="custom-useragent-string-page-script"/><path d="m13.821 12.756c-5.0033 3.9148-12.551 2.248-12.49-4.538 0.67424-11.471 17.312-7.4502 12.446 2.1173-1.0549 1.1955-2.0737 1.4617-3.1983 0.4329-0.21023-0.19282-0.44783-1.1594-0.3819-1.5089 0.35827-1.8946 1.0885-4.0778-0.72151-4.7234-2.4171-0.86457-4.5592 1.6495-4.9697 4.0193-0.47396 2.7343 2.284 3.3749 4.1487 1.9879 0.4553-0.36324 1.6433-1.3796 1.6806-1.9742" fill="none" stroke="#e0e0e0" stroke-linejoin="round" stroke-width="1.4928"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13.821 12.756c-5.0033 3.9148-12.551 2.248-12.49-4.538.67424-11.471 17.312-7.4502 12.446 2.1173-1.0549 1.1955-2.0737 1.4617-3.1983.4329-.21023-.19282-.44783-1.1594-.3819-1.5089.35827-1.8946 1.0885-4.0778-.72151-4.7234-2.4171-.86457-4.5592 1.6495-4.9697 4.0193-.47396 2.7343 2.284 3.3749 4.1487 1.9879.4553-.36324 1.6433-1.3796 1.6806-1.9742" fill="none" stroke="#e0e0e0" stroke-linejoin="round" stroke-width="1.4928"/></svg>
diff --git a/editor/icons/MethodOverride.svg b/editor/icons/MethodOverride.svg
new file mode 100644
index 0000000000..004b9bf283
--- /dev/null
+++ b/editor/icons/MethodOverride.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 4.2333332 4.2333332" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m.49005985 3.3580432.83285685-.0000001v-.7093212c.0027125-.6681099.2054076-1.1321001 1.0021593-1.1328214h.3207573v-.79375l1.3229167 1.0648649-1.3229167 1.0518017v-.79375h-.3364788c-.2888876 0-.4514151.2436282-.4573001.5980603 0 .2833012.0000193.4455045.0000289.7134508h.79375v.4907171l-2.15577345.00147z" fill="#5fb2ff"/></svg>
diff --git a/editor/icons/MethodOverrideAndSlot.svg b/editor/icons/MethodOverrideAndSlot.svg
new file mode 100644
index 0000000000..d3bd9f0253
--- /dev/null
+++ b/editor/icons/MethodOverrideAndSlot.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 4.2333332 4.2333332" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m.15761184 3.636193h.37155483l.004252-.7093212c.0027092-.6681099.12999225-1.1321001.92674393-1.1328214h.1273374l.0042585-.7357171 1.3186582 1.006832-1.3229167 1.0700676v-.8531081h-.1260545c-.2888876 0-.3972562.2847204-.4031411.6391525 0 .2833012.0000193.4455045.0000289.7134508h1.2412654v.4907171h-2.14198686z" fill="#5fb2ff"/><path d="m2.38125.79375h1.5875v2.6458333h-1.5875v-.5291666h1.0583333v-1.5875h-1.0583333z" fill="#5fff97"/></svg>
diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp
index c1761339b2..1e0f45419f 100644
--- a/editor/import/dynamic_font_import_settings.cpp
+++ b/editor/import/dynamic_font_import_settings.cpp
@@ -1009,6 +1009,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) {
vars_list_root = vars_list->create_item();
+ import_settings_data->settings.clear();
import_settings_data->defaults.clear();
for (List<ResourceImporter::ImportOption>::Element *E = options_general.front(); E; E = E->next()) {
import_settings_data->defaults[E->get().option.name] = E->get().default_value;
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index 77bc06533c..386519bc59 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -35,11 +35,13 @@
#include "core/io/resource_importer.h"
#include "core/variant/dictionary.h"
#include "scene/3d/importer_mesh_instance_3d.h"
-#include "scene/3d/node_3d.h"
#include "scene/resources/animation.h"
+#include "scene/resources/box_shape_3d.h"
+#include "scene/resources/capsule_shape_3d.h"
+#include "scene/resources/cylinder_shape_3d.h"
#include "scene/resources/mesh.h"
#include "scene/resources/shape_3d.h"
-#include "scene/resources/skin.h"
+#include "scene/resources/sphere_shape_3d.h"
class Material;
class AnimationPlayer;
@@ -311,11 +313,6 @@ public:
virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
};
-#include "scene/resources/box_shape_3d.h"
-#include "scene/resources/capsule_shape_3d.h"
-#include "scene/resources/cylinder_shape_3d.h"
-#include "scene/resources/sphere_shape_3d.h"
-
template <class M>
Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Mesh> &p_mesh, const M &p_options) {
ShapeType generate_shape_type = SHAPE_TYPE_DECOMPOSE_CONVEX;
diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp
index 2df951518e..ba11479714 100644
--- a/editor/plugins/font_config_plugin.cpp
+++ b/editor/plugins/font_config_plugin.cpp
@@ -622,6 +622,16 @@ void EditorPropertyOTFeatures::update_property() {
supported = fd->get_supported_feature_list();
}
+ if (supported.is_empty()) {
+ edit->set_text(vformat(TTR("No supported features")));
+ if (container) {
+ set_bottom_editor(nullptr);
+ memdelete(container);
+ button_add = nullptr;
+ container = nullptr;
+ }
+ return;
+ }
edit->set_text(vformat(TTR("Features (%d of %d set)"), dict.size(), supported.size()));
bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property());
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 0a111aeb49..3679657567 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -227,6 +227,7 @@ void ScriptEditorBase::_bind_methods() {
// TODO: This signal is no use for VisualScript.
ADD_SIGNAL(MethodInfo("search_in_files_requested", PropertyInfo(Variant::STRING, "text")));
ADD_SIGNAL(MethodInfo("replace_in_files_requested", PropertyInfo(Variant::STRING, "text")));
+ ADD_SIGNAL(MethodInfo("go_to_method", PropertyInfo(Variant::OBJECT, "script"), PropertyInfo(Variant::STRING, "method")));
}
class EditorScriptCodeCompletionCache : public ScriptCodeCompletionCache {
@@ -2380,6 +2381,7 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
se->connect("request_save_history", callable_mp(this, &ScriptEditor::_save_history));
se->connect("search_in_files_requested", callable_mp(this, &ScriptEditor::_on_find_in_files_requested));
se->connect("replace_in_files_requested", callable_mp(this, &ScriptEditor::_on_replace_in_files_requested));
+ se->connect("go_to_method", callable_mp(this, &ScriptEditor::script_goto_method));
//test for modification, maybe the script was not edited but was loaded
@@ -2544,7 +2546,7 @@ void ScriptEditor::apply_scripts() const {
}
}
-void ScriptEditor::reload_scripts() {
+void ScriptEditor::reload_scripts(bool p_refresh_only) {
for (int i = 0; i < tab_container->get_tab_count(); i++) {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
@@ -2557,30 +2559,33 @@ void ScriptEditor::reload_scripts() {
continue; //internal script, who cares
}
- uint64_t last_date = edited_res->get_last_modified_time();
- uint64_t date = FileAccess::get_modified_time(edited_res->get_path());
+ if (!p_refresh_only) {
+ uint64_t last_date = edited_res->get_last_modified_time();
+ uint64_t date = FileAccess::get_modified_time(edited_res->get_path());
- if (last_date == date) {
- continue;
- }
+ if (last_date == date) {
+ continue;
+ }
- Ref<Script> script = edited_res;
- if (script != nullptr) {
- Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
- ERR_CONTINUE(!rel_script.is_valid());
- script->set_source_code(rel_script->get_source_code());
- script->set_last_modified_time(rel_script->get_last_modified_time());
- script->reload(true);
- }
+ Ref<Script> script = edited_res;
+ if (script != nullptr) {
+ Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
+ ERR_CONTINUE(!rel_script.is_valid());
+ script->set_source_code(rel_script->get_source_code());
+ script->set_last_modified_time(rel_script->get_last_modified_time());
+ script->reload(true);
+ }
- Ref<TextFile> text_file = edited_res;
- if (text_file != nullptr) {
- Error err;
- Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err);
- ERR_CONTINUE(!rel_text_file.is_valid());
- text_file->set_text(rel_text_file->get_text());
- text_file->set_last_modified_time(rel_text_file->get_last_modified_time());
+ Ref<TextFile> text_file = edited_res;
+ if (text_file != nullptr) {
+ Error err;
+ Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err);
+ ERR_CONTINUE(!rel_text_file.is_valid());
+ text_file->set_text(rel_text_file->get_text());
+ text_file->set_last_modified_time(rel_text_file->get_last_modified_time());
+ }
}
+
se->reload_text();
}
@@ -3059,26 +3064,15 @@ void ScriptEditor::shortcut_input(const Ref<InputEvent> &p_event) {
}
}
-void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) {
- Ref<InputEventMouseButton> mb = ev;
- if (mb.is_valid() && mb->is_pressed()) {
- switch (mb->get_button_index()) {
- case MouseButton::MIDDLE: {
- // Right-click selects automatically; middle-click does not.
- int idx = script_list->get_item_at_position(mb->get_position(), true);
- if (idx >= 0) {
- script_list->select(idx);
- _script_selected(idx);
- _menu_option(FILE_CLOSE);
- }
- } break;
+void ScriptEditor::_script_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index) {
+ if (p_mouse_button_index == MouseButton::MIDDLE) {
+ script_list->select(p_item);
+ _script_selected(p_item);
+ _menu_option(FILE_CLOSE);
+ }
- case MouseButton::RIGHT: {
- _make_script_list_context_menu();
- } break;
- default:
- break;
- }
+ if (p_mouse_button_index == MouseButton::RIGHT) {
+ _make_script_list_context_menu();
}
}
@@ -3688,7 +3682,7 @@ ScriptEditor::ScriptEditor() {
script_list->set_v_size_flags(SIZE_EXPAND_FILL);
script_split->set_split_offset(70 * EDSCALE);
_sort_list_on_update = true;
- script_list->connect("gui_input", callable_mp(this, &ScriptEditor::_script_list_gui_input), CONNECT_DEFERRED);
+ script_list->connect("item_clicked", callable_mp(this, &ScriptEditor::_script_list_clicked), CONNECT_DEFERRED);
script_list->set_allow_rmb_select(true);
script_list->set_drag_forwarding(this);
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index a8e6cc6868..1e78dc4ec4 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -426,7 +426,7 @@ class ScriptEditor : public PanelContainer {
virtual void input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
- void _script_list_gui_input(const Ref<InputEvent> &ev);
+ void _script_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index);
void _make_script_list_context_menu();
void _help_search(String p_text);
@@ -477,7 +477,7 @@ public:
bool toggle_scripts_panel();
bool is_scripts_panel_toggled();
void apply_scripts() const;
- void reload_scripts();
+ void reload_scripts(bool p_refresh_only = false);
void open_script_create_dialog(const String &p_base_name, const String &p_base_path);
void open_text_file_create_dialog(const String &p_base_path, const String &p_base_name = "");
Ref<Resource> open_file(const String &p_file);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 1ae4c530e8..7a57f8a1e2 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -956,10 +956,7 @@ void ScriptTextEditor::_update_connected_methods() {
CodeEdit *text_edit = code_editor->get_text_editor();
text_edit->set_gutter_width(connection_gutter, text_edit->get_line_height());
for (int i = 0; i < text_edit->get_line_count(); i++) {
- if (text_edit->get_line_gutter_metadata(i, connection_gutter) == "") {
- continue;
- }
- text_edit->set_line_gutter_metadata(i, connection_gutter, "");
+ text_edit->set_line_gutter_metadata(i, connection_gutter, Dictionary());
text_edit->set_line_gutter_icon(i, connection_gutter, nullptr);
text_edit->set_line_gutter_clickable(i, connection_gutter, false);
}
@@ -974,6 +971,7 @@ void ScriptTextEditor::_update_connected_methods() {
return;
}
+ // Add connection icons to methods.
Vector<Node *> nodes = _find_all_node_for_script(base, base, script);
HashSet<StringName> methods_found;
for (int i = 0; i < nodes.size(); i++) {
@@ -1002,8 +1000,11 @@ void ScriptTextEditor::_update_connected_methods() {
for (int j = 0; j < functions.size(); j++) {
String name = functions[j].get_slice(":", 0);
if (name == method) {
+ Dictionary line_meta;
+ line_meta["type"] = "connection";
+ line_meta["method"] = method;
line = functions[j].get_slice(":", 1).to_int() - 1;
- text_edit->set_line_gutter_metadata(line, connection_gutter, method);
+ text_edit->set_line_gutter_metadata(line, connection_gutter, line_meta);
text_edit->set_line_gutter_icon(line, connection_gutter, get_parent_control()->get_theme_icon(SNAME("Slot"), SNAME("EditorIcons")));
text_edit->set_line_gutter_clickable(line, connection_gutter, true);
methods_found.insert(method);
@@ -1033,6 +1034,58 @@ void ScriptTextEditor::_update_connected_methods() {
}
}
}
+
+ // Add override icons to methods.
+ methods_found.clear();
+ for (int i = 0; i < functions.size(); i++) {
+ StringName name = StringName(functions[i].get_slice(":", 0));
+ if (methods_found.has(name)) {
+ continue;
+ }
+
+ String found_base_class;
+ StringName base_class = script->get_instance_base_type();
+ Ref<Script> inherited_script = script->get_base_script();
+ while (!inherited_script.is_null()) {
+ if (inherited_script->has_method(name)) {
+ found_base_class = "script:" + inherited_script->get_path();
+ break;
+ }
+
+ base_class = inherited_script->get_instance_base_type();
+ inherited_script = inherited_script->get_base_script();
+ }
+
+ if (found_base_class.is_empty() && base_class) {
+ List<MethodInfo> methods;
+ ClassDB::get_method_list(base_class, &methods);
+ for (int j = 0; j < methods.size(); j++) {
+ if (methods[j].name == name) {
+ found_base_class = "builtin:" + base_class;
+ break;
+ }
+ }
+ }
+
+ if (!found_base_class.is_empty()) {
+ int line = functions[i].get_slice(":", 1).to_int() - 1;
+
+ Dictionary line_meta = text_edit->get_line_gutter_metadata(line, connection_gutter);
+ if (line_meta.is_empty()) {
+ // Add override icon to gutter.
+ line_meta["type"] = "inherits";
+ line_meta["method"] = name;
+ line_meta["base_class"] = found_base_class;
+ text_edit->set_line_gutter_icon(line, connection_gutter, get_parent_control()->get_theme_icon(SNAME("MethodOverride"), SNAME("EditorIcons")));
+ text_edit->set_line_gutter_clickable(line, connection_gutter, true);
+ } else {
+ // If method is also connected to signal, then merge icons and keep the click behavior of the slot.
+ text_edit->set_line_gutter_icon(line, connection_gutter, get_parent_control()->get_theme_icon(SNAME("MethodOverrideAndSlot"), SNAME("EditorIcons")));
+ }
+
+ methods_found.insert(name);
+ }
+ }
}
void ScriptTextEditor::_update_gutter_indexes() {
@@ -1054,18 +1107,40 @@ void ScriptTextEditor::_gutter_clicked(int p_line, int p_gutter) {
return;
}
- String method = code_editor->get_text_editor()->get_line_gutter_metadata(p_line, p_gutter);
- if (method.is_empty()) {
+ Dictionary meta = code_editor->get_text_editor()->get_line_gutter_metadata(p_line, p_gutter);
+ String type = meta.get("type", "");
+ if (type.is_empty()) {
return;
}
- Node *base = get_tree()->get_edited_scene_root();
- if (!base) {
+ // All types currently need a method name.
+ String method = meta.get("method", "");
+ if (method.is_empty()) {
return;
}
- Vector<Node *> nodes = _find_all_node_for_script(base, base, script);
- connection_info_dialog->popup_connections(method, nodes);
+ if (type == "connection") {
+ Node *base = get_tree()->get_edited_scene_root();
+ if (!base) {
+ return;
+ }
+
+ Vector<Node *> nodes = _find_all_node_for_script(base, base, script);
+ connection_info_dialog->popup_connections(method, nodes);
+ } else if (type == "inherits") {
+ String base_class_raw = meta["base_class"];
+ PackedStringArray base_class_split = base_class_raw.split(":", true, 1);
+
+ if (base_class_split[0] == "script") {
+ // Go to function declaration.
+ Ref<Script> base_script = ResourceLoader::load(base_class_split[1]);
+ ERR_FAIL_COND(!base_script.is_valid());
+ emit_signal(SNAME("go_to_method"), base_script, method);
+ } else if (base_class_split[0] == "builtin") {
+ // Open method documentation.
+ emit_signal(SNAME("go_to_help"), "class_method:" + base_class_split[1] + ":" + method);
+ }
+ }
}
void ScriptTextEditor::_edit_option(int p_op) {
@@ -1487,16 +1562,17 @@ bool ScriptTextEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_
}
static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) {
- if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene) {
- return nullptr;
- }
-
- Ref<Script> scr = p_current_node->get_script();
-
- if (scr.is_valid() && scr == script) {
- return p_current_node;
+ // Check scripts only for the nodes belonging to the edited scene.
+ if (p_current_node == p_edited_scene || p_current_node->get_owner() == p_edited_scene) {
+ Ref<Script> scr = p_current_node->get_script();
+ if (scr.is_valid() && scr == script) {
+ return p_current_node;
+ }
}
+ // Traverse all children, even the ones not owned by the edited scene as they
+ // can still have child nodes added within the edited scene and thus owned by
+ // it (e.g. nodes added to subscene's root or to its editable children).
for (int i = 0; i < p_current_node->get_child_count(); i++) {
Node *n = _find_script_node(p_edited_scene, p_current_node->get_child(i), script);
if (n) {
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 1fb9b42449..e2ed8e44c4 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -134,7 +134,7 @@ void ThemeItemImportTree::_update_items_tree() {
data_type_node->set_checked(IMPORT_ITEM_DATA, false);
data_type_node->set_editable(IMPORT_ITEM_DATA, true);
- List<TreeItem *> *item_list;
+ List<TreeItem *> *item_list = nullptr;
switch (dt) {
case Theme::DATA_TYPE_COLOR:
@@ -398,7 +398,7 @@ void ThemeItemImportTree::_restore_selected_item(TreeItem *p_tree_item) {
void ThemeItemImportTree::_update_total_selected(Theme::DataType p_data_type) {
ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
- Label *total_selected_items_label;
+ Label *total_selected_items_label = nullptr;
switch (p_data_type) {
case Theme::DATA_TYPE_COLOR:
total_selected_items_label = total_selected_colors_label;
@@ -562,7 +562,7 @@ void ThemeItemImportTree::_select_all_data_type_pressed(int p_data_type) {
}
Theme::DataType data_type = (Theme::DataType)p_data_type;
- List<TreeItem *> *item_list;
+ List<TreeItem *> *item_list = nullptr;
switch (data_type) {
case Theme::DATA_TYPE_COLOR:
@@ -617,7 +617,7 @@ void ThemeItemImportTree::_select_full_data_type_pressed(int p_data_type) {
}
Theme::DataType data_type = (Theme::DataType)p_data_type;
- List<TreeItem *> *item_list;
+ List<TreeItem *> *item_list = nullptr;
switch (data_type) {
case Theme::DATA_TYPE_COLOR:
@@ -674,7 +674,7 @@ void ThemeItemImportTree::_deselect_all_data_type_pressed(int p_data_type) {
}
Theme::DataType data_type = (Theme::DataType)p_data_type;
- List<TreeItem *> *item_list;
+ List<TreeItem *> *item_list = nullptr;
switch (data_type) {
case Theme::DATA_TYPE_COLOR:
@@ -982,17 +982,17 @@ ThemeItemImportTree::ThemeItemImportTree() {
for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) {
Theme::DataType dt = (Theme::DataType)i;
- TextureRect *select_items_icon;
- Label *select_items_label;
- Button *deselect_all_items_button;
- Button *select_all_items_button;
- Button *select_full_items_button;
- Label *total_selected_items_label;
-
- String items_title = "";
- String select_all_items_tooltip = "";
- String select_full_items_tooltip = "";
- String deselect_all_items_tooltip = "";
+ TextureRect *select_items_icon = nullptr;
+ Label *select_items_label = nullptr;
+ Button *deselect_all_items_button = nullptr;
+ Button *select_all_items_button = nullptr;
+ Button *select_full_items_button = nullptr;
+ Label *total_selected_items_label = nullptr;
+
+ String items_title;
+ String select_all_items_tooltip;
+ String select_full_items_tooltip;
+ String deselect_all_items_tooltip;
switch (dt) {
case Theme::DATA_TYPE_COLOR:
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index 0bd3ec0925..f8ba3f0354 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -217,6 +217,7 @@ static const char *gdscript_function_renames[][2] = {
{ "_get_configuration_warning", "_get_configuration_warnings" }, // Node
{ "_set_current", "set_current" }, // Camera2D
{ "_set_editor_description", "set_editor_description" }, // Node
+ { "_set_playing", "set_playing" }, // AnimatedSprite3D
{ "_toplevel_raise_self", "_top_level_raise_self" }, // CanvasItem
{ "_update_wrap_at", "_update_wrap_at_column" }, // TextEdit
{ "add_animation", "add_animation_library" }, // AnimationPlayer
@@ -231,6 +232,7 @@ static const char *gdscript_function_renames[][2] = {
{ "add_scene_import_plugin", "add_scene_format_importer_plugin" }, //EditorPlugin
{ "add_stylebox_override", "add_theme_stylebox_override" }, // Control
{ "add_torque", "apply_torque" }, //RigidBody2D
+ { "agent_set_neighbor_dist", "agent_set_neighbor_distance" }, // NavigationServer2D, NavigationServer3D
{ "apply_changes", "_apply_changes" }, // EditorPlugin
{ "body_add_force", "body_apply_force" }, // PhysicsServer2D
{ "body_add_torque", "body_apply_torque" }, // PhysicsServer2D
@@ -332,6 +334,7 @@ static const char *gdscript_function_renames[][2] = {
{ "get_metakey", "is_meta_pressed" }, // InputEventWithModifiers
{ "get_mid_height", "get_height" }, // CapsuleMesh
{ "get_motion_remainder", "get_remainder" }, // PhysicsTestMotionResult2D
+ { "get_neighbor_dist", "get_neighbor_distance" }, // NavigationAgent2D, NavigationAgent3D
{ "get_network_connected_peers", "get_peers" }, // Multiplayer API
{ "get_network_master", "get_multiplayer_authority" }, // Node
{ "get_network_peer", "get_multiplayer_peer" }, // Multiplayer API
@@ -512,6 +515,7 @@ static const char *gdscript_function_renames[][2] = {
{ "set_max_atlas_size", "set_max_texture_size" }, // LightmapGI
{ "set_metakey", "set_meta_pressed" }, // InputEventWithModifiers
{ "set_mid_height", "set_height" }, // CapsuleMesh
+ { "set_neighbor_dist", "set_neighbor_distance" }, // NavigationAgent2D, NavigationAgent3D
{ "set_network_master", "set_multiplayer_authority" }, // Node
{ "set_network_peer", "set_multiplayer_peer" }, // Multiplayer API
{ "set_oneshot", "set_one_shot" }, // AnimatedTexture
@@ -652,6 +656,7 @@ static const char *csharp_function_renames[][2] = {
{ "_GetConfigurationWarning", "_GetConfigurationWarnings" }, // Node
{ "_SetCurrent", "SetCurrent" }, // Camera2D
{ "_SetEditorDescription", "SetEditorDescription" }, // Node
+ { "_SetPlaying", "SetPlaying" }, // AnimatedSprite3D
{ "_ToplevelRaiseSelf", "_TopLevelRaiseSelf" }, // CanvasItem
{ "_UpdateWrapAt", "_UpdateWrapAtColumn" }, // TextEdit
{ "AddAnimation", "AddAnimationLibrary" }, // AnimationPlayer
@@ -666,6 +671,7 @@ static const char *csharp_function_renames[][2] = {
{ "AddSceneImportPlugin", "AddSceneFormatImporterPlugin" }, //EditorPlugin
{ "AddStyleboxOverride", "AddThemeStyleboxOverride" }, // Control
{ "AddTorque", "AddConstantTorque" }, //RigidBody2D
+ { "AgentSetNeighborDist", "AgentSetNeighborDistance" }, // NavigationServer2D, NavigationServer3D
{ "BindChildNodeToBone", "SetBoneChildren" }, // Skeleton3D
{ "BumpmapToNormalmap", "BumpMapToNormalMap" }, // Image
{ "CanBeHidden", "_CanBeHidden" }, // EditorNode3DGizmoPlugin
@@ -759,6 +765,7 @@ static const char *csharp_function_renames[][2] = {
{ "GetMetakey", "IsMetaPressed" }, // InputEventWithModifiers
{ "GetMidHeight", "GetHeight" }, // CapsuleMesh
{ "GetMotionRemainder", "GetRemainder" }, // PhysicsTestMotionResult2D
+ { "GetNeighborDist", "GetNeighborDistance" }, // NavigationAgent2D, NavigationAgent3D
{ "GetNetworkConnectedPeers", "GetPeers" }, // Multiplayer API
{ "GetNetworkMaster", "GetMultiplayerAuthority" }, // Node
{ "GetNetworkPeer", "GetMultiplayerPeer" }, // Multiplayer API
@@ -929,6 +936,7 @@ static const char *csharp_function_renames[][2] = {
{ "SetMaxAtlasSize", "SetMaxTextureSize" }, // LightmapGI
{ "SetMetakey", "SetMetaPressed" }, // InputEventWithModifiers
{ "SetMidHeight", "SetHeight" }, // CapsuleMesh
+ { "SetNeighborDist", "SetNeighborDistance" }, // NavigationAgent2D, NavigationAgent3D
{ "SetNetworkMaster", "SetMultiplayerAuthority" }, // Node
{ "SetNetworkPeer", "SetMultiplayerPeer" }, // Multiplayer API
{ "SetOneshot", "SetOneShot" }, // AnimatedTexture
@@ -1064,6 +1072,7 @@ static const char *gdscript_properties_renames[][2] = {
{ "focus_neighbour_left", "focus_neighbor_left" }, // Control
{ "focus_neighbour_right", "focus_neighbor_right" }, // Control
{ "focus_neighbour_top", "focus_neighbor_top" }, // Control
+ { "follow_viewport_enable", "follow_viewport_enabled" }, // CanvasItem
{ "file_icon_modulate", "file_icon_color" }, // Theme
{ "files_disabled", "file_disabled_color" }, // Theme
{ "folder_icon_modulate", "folder_icon_color" }, // Theme
@@ -1079,6 +1088,7 @@ static const char *gdscript_properties_renames[][2] = {
{ "margin_right", "offset_right" }, // Control broke NinePatchRect, StyleBox
{ "margin_top", "offset_top" }, // Control broke NinePatchRect, StyleBox
{ "mid_height", "height" }, // CapsuleMesh
+ { "neighbor_dist", "neighbor_distance" }, // NavigationAgent2D, NavigationAgent3D
{ "offset_h", "drag_horizontal_offset" }, // Camera2D
{ "offset_v", "drag_vertical_offset" }, // Camera2D
{ "off", "unchecked" }, // Theme
@@ -1167,6 +1177,7 @@ static const char *csharp_properties_renames[][2] = {
{ "FocusNeighbourLeft", "FocusNeighborLeft" }, // Control
{ "FocusNeighbourRight", "FocusNeighborRight" }, // Control
{ "FocusNeighbourTop", "FocusNeighborTop" }, // Control
+ { "FollowViewportEnable", "FollowViewportEnabled" }, // CanvasItem
{ "GlobalRateScale", "PlaybackSpeedScale" }, // AudioServer
{ "GravityDistanceScale", "GravityPointDistanceScale" }, // Area2D
{ "GravityVec", "GravityDirection" }, // Area2D
@@ -1179,6 +1190,7 @@ static const char *csharp_properties_renames[][2] = {
{ "MarginRight", "OffsetRight" }, // Control broke NinePatchRect, StyleBox
{ "MarginTop", "OffsetTop" }, // Control broke NinePatchRect, StyleBox
{ "MidHeight", "Height" }, // CapsuleMesh
+ { "NeighborDist", "NeighborDistance" }, // NavigationAgent2D, NavigationAgent3D
{ "OffsetH", "DragHorizontalOffset" }, // Camera2D
{ "OffsetV", "DragVerticalOffset" }, // Camera2D
{ "Ofs", "Offset" }, // Theme
@@ -2335,12 +2347,13 @@ bool ProjectConverter3To4::test_conversion(RegExContainer &reg_container) {
valid = valid && test_conversion_with_regex("[Master]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
valid = valid && test_conversion_with_regex("[MasterSync]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
- valid = valid && test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\"display/window/size/fullscreen\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true);
+ valid = valid && test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "if Settings.fullscreen:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)\nelse:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("OS.get_window_safe_area()", "DisplayServer.get_display_safe_area()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tmove_and_slide( a, b, c, d, e, f ) # Roman", "\tset_velocity(a)\n\tset_up_direction(b)\n\tset_floor_stop_on_slope_enabled(c)\n\tset_max_slides(d)\n\tset_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tmove_and_slide() # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide_with_snap( a, g, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tmove_and_slide_with_snap( a, g, b, c, d, e, f ) # Roman", "\tset_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tset_up_direction(b)\n\tset_floor_stop_on_slope_enabled(c)\n\tset_max_slides(d)\n\tset_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tmove_and_slide() # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a , b )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
@@ -3094,13 +3107,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
line = reg_container.reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true);
}
- // OS.window_fullscreen = true -> ProjectSettings.set("display/window/size/fullscreen",true)
+ // OS.window_fullscreen = a -> if a: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN) else: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
if (line.contains("window_fullscreen")) {
- if (builtin) {
- line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", $1)", true);
- } else {
- line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true);
- }
+ line = reg_container.reg_os_fullscreen.sub(line, "if $1:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)\nelse:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)", true);
}
// Instantiate
@@ -3148,8 +3157,13 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[5] + "`\n";
}
- line_new += starting_space + base_obj + "move_and_slide()\n";
- line = line_new + line.substr(0, start) + "velocity" + line.substr(end + start);
+ line_new += starting_space + base_obj + "move_and_slide()";
+
+ if (!line.begins_with(starting_space + "move_and_slide")) {
+ line = line_new + "\n" + line.substr(0, start) + "velocity" + line.substr(end + start);
+ } else {
+ line = line_new + line.substr(end + start);
+ }
}
}
}
@@ -3199,8 +3213,13 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[6] + "`\n";
}
- line_new += starting_space + base_obj + "move_and_slide()\n";
- line = line_new + line.substr(0, start) + "velocity" + line.substr(end + start); // move_and_slide used to return velocity
+ line_new += starting_space + base_obj + "move_and_slide()";
+
+ if (!line.begins_with(starting_space + "move_and_slide_with_snap")) {
+ line = line_new + "\n" + line.substr(0, start) + "velocity" + line.substr(end + start);
+ } else {
+ line = line_new + line.substr(end + start);
+ }
}
}
}
diff --git a/editor/scene_create_dialog.cpp b/editor/scene_create_dialog.cpp
index 573e57ca04..4563dbb0f7 100644
--- a/editor/scene_create_dialog.cpp
+++ b/editor/scene_create_dialog.cpp
@@ -133,7 +133,7 @@ void SceneCreateDialog::update_dialog() {
root_name = scene_name.get_file().get_basename();
}
- if (!root_name.is_valid_identifier()) {
+ if (root_name.is_empty() || root_name.validate_node_name().size() != root_name.size()) {
update_error(node_error_label, MSG_ERROR, TTR("Invalid root node name."));
is_valid = false;
}
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index aefb2c78c1..d1dc188be9 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -441,8 +441,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
}
- bool collapsed = _is_collapsed_recursive(selected_item);
- _set_collapsed_recursive(selected_item, !collapsed);
+ bool collapsed = selected_item->is_any_collapsed();
+ selected_item->set_collapsed_recursive(!collapsed);
tree->ensure_cursor_is_visible();
@@ -1223,17 +1223,6 @@ void SceneTreeDock::add_root_node(Node *p_node) {
editor_data->get_undo_redo()->commit_action();
}
-void SceneTreeDock::_node_collapsed(Object *p_obj) {
- TreeItem *ti = Object::cast_to<TreeItem>(p_obj);
- if (!ti) {
- return;
- }
-
- if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
- _set_collapsed_recursive(ti, ti->is_collapsed());
- }
-}
-
void SceneTreeDock::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
@@ -1945,48 +1934,6 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
editor_data->get_undo_redo()->commit_action();
}
-bool SceneTreeDock::_is_collapsed_recursive(TreeItem *p_item) const {
- bool is_branch_collapsed = false;
-
- List<TreeItem *> needs_check;
- needs_check.push_back(p_item);
-
- while (!needs_check.is_empty()) {
- TreeItem *item = needs_check.back()->get();
- needs_check.pop_back();
-
- TreeItem *child = item->get_first_child();
- is_branch_collapsed = item->is_collapsed() && child;
-
- if (is_branch_collapsed) {
- break;
- }
- while (child) {
- needs_check.push_back(child);
- child = child->get_next();
- }
- }
- return is_branch_collapsed;
-}
-
-void SceneTreeDock::_set_collapsed_recursive(TreeItem *p_item, bool p_collapsed) {
- List<TreeItem *> to_collapse;
- to_collapse.push_back(p_item);
-
- while (!to_collapse.is_empty()) {
- TreeItem *item = to_collapse.back()->get();
- to_collapse.pop_back();
-
- item->set_collapsed(p_collapsed);
-
- TreeItem *child = item->get_first_child();
- while (child) {
- to_collapse.push_back(child);
- child = child->get_next();
- }
- }
-}
-
void SceneTreeDock::_script_created(Ref<Script> p_script) {
List<Node *> selected = editor_selection->get_selected_node_list();
@@ -3532,7 +3479,6 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
scene_tree->connect("nodes_dragged", callable_mp(this, &SceneTreeDock::_nodes_drag_begin));
scene_tree->get_scene_tree()->connect("item_double_clicked", callable_mp(this, &SceneTreeDock::_focus_node));
- scene_tree->get_scene_tree()->connect("item_collapsed", callable_mp(this, &SceneTreeDock::_node_collapsed));
editor_selection->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed));
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index dc228e1c93..e48b518252 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -137,7 +137,6 @@ class SceneTreeDock : public VBoxContainer {
HBoxContainer *tool_hbc = nullptr;
void _tool_selected(int p_tool, bool p_confirm_override = false);
void _property_selected(int p_idx);
- void _node_collapsed(Object *p_obj);
Node *property_drop_node = nullptr;
String resource_drop_path;
@@ -188,9 +187,6 @@ class SceneTreeDock : public VBoxContainer {
void _node_reparent(NodePath p_path, bool p_keep_global_xform);
void _do_reparent(Node *p_new_parent, int p_position_in_parent, Vector<Node *> p_nodes, bool p_keep_global_xform);
- bool _is_collapsed_recursive(TreeItem *p_item) const;
- void _set_collapsed_recursive(TreeItem *p_item, bool p_collapsed);
-
void _set_owners(Node *p_owner, const Array &p_nodes);
enum ReplaceOwnerMode {
@@ -228,8 +224,6 @@ class SceneTreeDock : public VBoxContainer {
virtual void input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
- void _import_subscene();
-
void _new_scene_from(String p_file);
void _set_node_owner_recursive(Node *p_node, Node *p_owner);
@@ -292,7 +286,6 @@ public:
void _focus_node();
- void import_subscene();
void add_root_node(Node *p_node);
void set_edited_scene(Node *p_scene);
void instantiate(const String &p_file);
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index 6fff2ab7cb..0b1e9719b7 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -30,6 +30,7 @@
#include "scene_tree_editor.h"
+#include "core/config/project_settings.h"
#include "core/object/message_queue.h"
#include "core/string/print_string.h"
#include "editor/editor_file_system.h"
@@ -942,14 +943,16 @@ void SceneTreeEditor::_renamed() {
Node *n = get_node(np);
ERR_FAIL_COND(!n);
- // Empty node names are not allowed, so resets it to previous text and show warning
- if (which->get_text(0).strip_edges().is_empty()) {
- which->set_text(0, n->get_name());
- EditorNode::get_singleton()->show_warning(TTR("No name provided."));
- return;
+ String raw_new_name = which->get_text(0);
+ if (raw_new_name.strip_edges().is_empty()) {
+ // If name is empty, fallback to class name.
+ if (GLOBAL_GET("editor/node_naming/name_casing").operator int() != NAME_CASING_PASCAL_CASE) {
+ raw_new_name = Node::adjust_name_casing(n->get_class());
+ } else {
+ raw_new_name = n->get_class();
+ }
}
- String raw_new_name = which->get_text(0);
String new_name = raw_new_name.validate_node_name();
if (new_name != raw_new_name) {
diff --git a/main/main.cpp b/main/main.cpp
index 5fd3786af9..aac77c1625 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -157,6 +157,7 @@ static bool show_help = false;
static bool auto_quit = false;
static OS::ProcessID editor_pid = 0;
#ifdef TOOLS_ENABLED
+static bool found_project = false;
static bool auto_build_solutions = false;
static String debug_server_uri;
static int converter_max_kb_file = 4 * 1024; // 4MB
@@ -707,9 +708,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
Vector<String> breakpoints;
bool use_custom_res = true;
bool force_res = false;
-#ifdef TOOLS_ENABLED
- bool found_project = false;
-#endif
String default_renderer = "";
String renderer_hints = "";
@@ -1672,13 +1670,19 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (bool(GLOBAL_GET("display/window/size/borderless"))) {
window_flags |= DisplayServer::WINDOW_FLAG_BORDERLESS_BIT;
}
- if (bool(GLOBAL_GET("display/window/size/fullscreen"))) {
- window_mode = DisplayServer::WINDOW_MODE_FULLSCREEN;
- }
-
if (bool(GLOBAL_GET("display/window/size/always_on_top"))) {
window_flags |= DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP_BIT;
}
+ if (bool(GLOBAL_GET("display/window/size/transparent"))) {
+ window_flags |= DisplayServer::WINDOW_FLAG_TRANSPARENT_BIT;
+ }
+ if (bool(GLOBAL_GET("display/window/size/extend_to_title"))) {
+ window_flags |= DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE_BIT;
+ }
+ if (bool(GLOBAL_GET("display/window/size/no_focus"))) {
+ window_flags |= DisplayServer::WINDOW_FLAG_NO_FOCUS_BIT;
+ }
+ window_mode = (DisplayServer::WindowMode)(GLOBAL_GET("display/window/size/mode").operator int());
}
GLOBAL_DEF_RST("internationalization/rendering/force_right_to_left_layout_direction", false);
@@ -1932,6 +1936,13 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
#ifdef TOOLS_ENABLED
if (editor || project_manager || cmdline_tool) {
EditorPaths::create();
+ if (found_project && EditorPaths::get_singleton()->is_self_contained()) {
+ if (ProjectSettings::get_singleton()->get_resource_path() == OS::get_singleton()->get_executable_path().get_base_dir()) {
+ ERR_PRINT("You are trying to run a self-contained editor at the same location as a project. This is not allowed, since editor files will mix with project files.");
+ OS::get_singleton()->set_exit_code(EXIT_FAILURE);
+ return FAILED;
+ }
+ }
}
#endif
diff --git a/methods.py b/methods.py
index 78ec9b8674..97a1e15e35 100644
--- a/methods.py
+++ b/methods.py
@@ -105,7 +105,7 @@ def get_version_info(module_version_string="", silent=False):
if os.getenv("GODOT_VERSION_STATUS") != None:
version_info["status"] = str(os.getenv("GODOT_VERSION_STATUS"))
if not silent:
- print(f"Using version status '{version_info.status}', overriding the original '{version.status}'.")
+ print(f"Using version status '{version_info['status']}', overriding the original '{version.status}'.")
# Parse Git hash if we're in a Git repo.
githash = ""
@@ -846,7 +846,8 @@ def generate_vs_project(env, num_jobs):
add_to_vs_project(env, env.servers_sources)
if env["tests"]:
add_to_vs_project(env, env.tests_sources)
- add_to_vs_project(env, env.editor_sources)
+ if env["tools"]:
+ add_to_vs_project(env, env.editor_sources)
for header in glob_recursive("**/*.h"):
env.vs_incs.append(str(header))
diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
index 467aa3ce83..b58f002f3c 100644
--- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
+++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
@@ -249,7 +249,6 @@
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
diff --git a/misc/scripts/header_guards.sh b/misc/scripts/header_guards.sh
index 9a830f3ad2..9fdc864f8c 100755
--- a/misc/scripts/header_guards.sh
+++ b/misc/scripts/header_guards.sh
@@ -5,11 +5,15 @@ if [ ! -f "version.py" ]; then
echo "Some of the paths checks may not work as intended from a different folder."
fi
+files_invalid_guard=""
+
for file in $(find -name "thirdparty" -prune -o -name "*.h" -print); do
# Skip *.gen.h and *-so_wrap.h, they're generated.
if [[ "$file" == *".gen.h" || "$file" == *"-so_wrap.h" ]]; then continue; fi
# Has important define before normal header guards.
if [[ "$file" == *"thread.h" || "$file" == *"platform_config.h" ]]; then continue; fi
+ # Obj-C files don't use header guards.
+ if grep -q "#import " "$file"; then continue; fi
bname=$(basename $file .h)
@@ -43,8 +47,21 @@ for file in $(find -name "thirdparty" -prune -o -name "*.h" -print); do
sed -i $file -e "$ s/#endif.*/\n#endif \/\/ $guard/"
# Removes redundant \n added before, if they weren't needed.
sed -i $file -e "/^$/N;/^\n$/D"
+
+ # Check that first ifndef (should be header guard) is at the expected position.
+ # If not it can mean we have some code before the guard that should be after.
+ # "31" is the expected line with the copyright header.
+ first_ifndef=$(grep -n -m 1 "ifndef" $file | sed 's/\([0-9]*\).*/\1/')
+ if [[ "$first_ifndef" != "31" ]]; then
+ files_invalid_guard+="$file\n"
+ fi
done
+if [[ ! -z "$files_invalid_guard" ]]; then
+ echo -e "The following files were found to have potentially invalid header guard:\n"
+ echo -e "$files_invalid_guard"
+fi
+
diff=$(git diff --color)
# If no diff has been generated all is OK, clean up, and exit.
diff --git a/modules/csg/csg.h b/modules/csg/csg.h
index 738e3d68ea..aae99c52a3 100644
--- a/modules/csg/csg.h
+++ b/modules/csg/csg.h
@@ -39,7 +39,6 @@
#include "core/object/ref_counted.h"
#include "core/templates/list.h"
#include "core/templates/oa_hash_map.h"
-#include "core/templates/rb_map.h"
#include "core/templates/vector.h"
#include "scene/resources/material.h"
diff --git a/modules/denoise/SCsub b/modules/denoise/SCsub
index 97feea2b44..779ce165d2 100644
--- a/modules/denoise/SCsub
+++ b/modules/denoise/SCsub
@@ -103,9 +103,9 @@ env_oidn.Append(
"__STDC_LIMIT_MACROS",
"DISABLE_VERBOSE",
"MKLDNN_ENABLE_CONCURRENT_EXEC",
- "NDEBUG",
]
)
+env_oidn.AppendUnique(CPPDEFINES=["NDEBUG"]) # No assert() even in debug builds.
env_thirdparty = env_oidn.Clone()
env_thirdparty.disable_warnings()
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 1cff2181af..54cadf7df3 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -2390,7 +2390,7 @@ Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const Str
}
Error err;
- Ref<GDScript> script = GDScriptCache::get_full_script(p_path, err);
+ Ref<GDScript> script = GDScriptCache::get_full_script(p_path, err, "", p_cache_mode == CACHE_MODE_IGNORE);
// TODO: Reintroduce binary and encrypted scripts.
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index c25f5b58d5..271296c2f9 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -183,20 +183,26 @@ Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, const Stri
return script;
}
-Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_error, const String &p_owner) {
+Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_error, const String &p_owner, bool p_update_from_disk) {
MutexLock lock(singleton->lock);
if (!p_owner.is_empty()) {
singleton->dependencies[p_owner].insert(p_path);
}
+ Ref<GDScript> script;
r_error = OK;
if (singleton->full_gdscript_cache.has(p_path)) {
- return singleton->full_gdscript_cache[p_path];
+ script = Ref<GDScript>(singleton->full_gdscript_cache[p_path]);
+ if (!p_update_from_disk) {
+ return script;
+ }
}
- Ref<GDScript> script = get_shallow_script(p_path);
- ERR_FAIL_COND_V(script.is_null(), Ref<GDScript>());
+ if (script.is_null()) {
+ script = get_shallow_script(p_path);
+ ERR_FAIL_COND_V(script.is_null(), Ref<GDScript>());
+ }
r_error = script->load_source_code(p_path);
diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h
index b971bdd984..3d111ea229 100644
--- a/modules/gdscript/gdscript_cache.h
+++ b/modules/gdscript/gdscript_cache.h
@@ -88,7 +88,7 @@ public:
static Ref<GDScriptParserRef> get_parser(const String &p_path, GDScriptParserRef::Status status, Error &r_error, const String &p_owner = String());
static String get_source_code(const String &p_path);
static Ref<GDScript> get_shallow_script(const String &p_path, const String &p_owner = String());
- static Ref<GDScript> get_full_script(const String &p_path, Error &r_error, const String &p_owner = String());
+ static Ref<GDScript> get_full_script(const String &p_path, Error &r_error, const String &p_owner = String(), bool p_update_from_disk = false);
static Error finish_compiling(const String &p_owner);
GDScriptCache();
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index d8a06a8663..b4da94e448 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -4001,7 +4001,7 @@ String GDScriptParser::DataType::to_string() const {
if (is_meta_type) {
return script_type->get_class_name().operator String();
}
- String name = script_type->get_name();
+ String name = script_type != nullptr ? script_type->get_name() : "";
if (!name.is_empty()) {
return name;
}
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index 5ad9680ea0..ccde0521f2 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -422,6 +422,7 @@ void GDScriptTextDocument::sync_script_content(const String &p_path, const Strin
if (error == OK) {
if (script->load_source_code(path) == OK) {
script->reload(true);
+ ScriptEditor::get_singleton()->reload_scripts(true); // Refresh scripts opened in the internal editor.
}
}
}
diff --git a/modules/gltf/register_types.h b/modules/gltf/register_types.h
index 90b9a83c88..bf2730d2ef 100644
--- a/modules/gltf/register_types.h
+++ b/modules/gltf/register_types.h
@@ -28,7 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef GLTF_REGISTER_TYPES_H
+#define GLTF_REGISTER_TYPES_H
+
#include "modules/register_module_types.h"
void initialize_gltf_module(ModuleInitializationLevel p_level);
void uninitialize_gltf_module(ModuleInitializationLevel p_level);
+
+#endif // GLTF_REGISTER_TYPES_H
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 8fd3626a20..97a1d5c8d8 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -1299,7 +1299,7 @@ GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token,
MonoGCHandleData &gchandle = script_binding.gchandle;
- int refcount = rc_owner->reference_get_count();
+ int refcount = rc_owner->get_reference_count();
if (!script_binding.inited) {
return refcount == 0;
@@ -1818,7 +1818,7 @@ void CSharpInstance::refcount_incremented() {
RefCounted *rc_owner = Object::cast_to<RefCounted>(owner);
- if (rc_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ if (rc_owner->get_reference_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
// The reference count was increased after the managed side was the only one referencing our owner.
// This means the owner is being referenced again by the unmanaged side,
// so the owner must hold the managed side alive again to avoid it from being GCed.
@@ -1849,7 +1849,7 @@ bool CSharpInstance::refcount_decremented() {
RefCounted *rc_owner = Object::cast_to<RefCounted>(owner);
- int refcount = rc_owner->reference_get_count();
+ int refcount = rc_owner->get_reference_count();
if (refcount == 1 && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
// If owner owner is no longer referenced by the unmanaged side,
@@ -1995,7 +1995,7 @@ CSharpInstance::~CSharpInstance() {
#ifdef DEBUG_ENABLED
// The "instance binding" holds a reference so the refcount should be at least 2 before `scope_keep_owner_alive` goes out of scope
- CRASH_COND(rc_owner->reference_get_count() <= 1);
+ CRASH_COND(rc_owner->get_reference_count() <= 1);
#endif
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/EventHandlerSuffixSuppressor.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/EventHandlerSuffixSuppressor.cs
new file mode 100644
index 0000000000..ddde730fa2
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/EventHandlerSuffixSuppressor.cs
@@ -0,0 +1,53 @@
+using System.Collections.Immutable;
+using System.Linq;
+using System.Threading;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace Godot.SourceGenerators
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class EventHandlerSuffixSuppressor : DiagnosticSuppressor
+ {
+ private static readonly SuppressionDescriptor _descriptor = new(
+ id: "GDSP0001",
+ suppressedDiagnosticId: "CA1711",
+ justification: "Signal delegates are used in events so the naming follows the guidelines.");
+
+ public override ImmutableArray<SuppressionDescriptor> SupportedSuppressions =>
+ ImmutableArray.Create(_descriptor);
+
+ public override void ReportSuppressions(SuppressionAnalysisContext context)
+ {
+ foreach (var diagnostic in context.ReportedDiagnostics)
+ {
+ AnalyzeDiagnostic(context, diagnostic, context.CancellationToken);
+ }
+ }
+
+ private static void AnalyzeDiagnostic(SuppressionAnalysisContext context, Diagnostic diagnostic, CancellationToken cancellationToken = default)
+ {
+ var location = diagnostic.Location;
+ var root = location.SourceTree?.GetRoot(cancellationToken);
+ var dds = root?
+ .FindNode(location.SourceSpan)
+ .DescendantNodesAndSelf()
+ .OfType<DelegateDeclarationSyntax>()
+ .FirstOrDefault();
+
+ if (dds == null)
+ return;
+
+ var semanticModel = context.GetSemanticModel(dds.SyntaxTree);
+ var delegateSymbol = semanticModel.GetDeclaredSymbol(dds, cancellationToken);
+ if (delegateSymbol == null)
+ return;
+
+ if (delegateSymbol.GetAttributes().Any(a => a.AttributeClass?.IsGodotSignalAttribute() ?? false))
+ {
+ context.ReportSuppression(Suppression.Create(_descriptor, diagnostic));
+ }
+ }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
index de3b6c862a..8de12de23b 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
@@ -29,7 +29,7 @@ namespace Godot.SourceGenerators
{
while (symbol != null)
{
- if (symbol.ContainingAssembly.Name == assemblyName &&
+ if (symbol.ContainingAssembly?.Name == assemblyName &&
symbol.ToString() == typeFullName)
{
return true;
@@ -47,7 +47,7 @@ namespace Godot.SourceGenerators
while (symbol != null)
{
- if (symbol.ContainingAssembly.Name == "GodotSharp")
+ if (symbol.ContainingAssembly?.Name == "GodotSharp")
return symbol;
symbol = symbol.BaseType;
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
index f31ded4d77..bd40675fd3 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
@@ -124,8 +124,8 @@ namespace Godot.SourceGenerators
if (typeKind == TypeKind.Struct)
{
- if (type.ContainingAssembly.Name == "GodotSharp" &&
- type.ContainingNamespace.Name == "Godot")
+ if (type.ContainingAssembly?.Name == "GodotSharp" &&
+ type.ContainingNamespace?.Name == "Godot")
{
return type switch
{
@@ -208,9 +208,9 @@ namespace Godot.SourceGenerators
if (type.SimpleDerivesFrom(typeCache.GodotObjectType))
return MarshalType.GodotObjectOrDerived;
- if (type.ContainingAssembly.Name == "GodotSharp")
+ if (type.ContainingAssembly?.Name == "GodotSharp")
{
- switch (type.ContainingNamespace.Name)
+ switch (type.ContainingNamespace?.Name)
{
case "Godot":
return type switch
@@ -220,7 +220,7 @@ namespace Godot.SourceGenerators
_ => null
};
case "Collections"
- when type.ContainingNamespace.FullQualifiedName() == "Godot.Collections":
+ when type.ContainingNamespace?.FullQualifiedName() == "Godot.Collections":
return type switch
{
{ Name: "Dictionary" } =>
diff --git a/modules/mono/utils/macos_utils.h b/modules/mono/utils/macos_utils.h
index ca4957f5a7..0b74114685 100644
--- a/modules/mono/utils/macos_utils.h
+++ b/modules/mono/utils/macos_utils.h
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "core/string/ustring.h"
-
#ifndef MONO_MACOS_UTILS_H
#define MONO_MACOS_UTILS_H
#ifdef MACOS_ENABLED
+#include "core/string/ustring.h"
+
bool macos_is_app_bundle_installed(const String &p_bundle_id);
#endif
diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub
index 593d1ff3c1..298977f96d 100644
--- a/modules/openxr/SCsub
+++ b/modules/openxr/SCsub
@@ -18,38 +18,36 @@ env_openxr.Prepend(
thirdparty_dir + "/src",
thirdparty_dir + "/src/common",
thirdparty_dir + "/src/external/jsoncpp/include",
- thirdparty_dir + "/src/loader",
]
)
-# may need to check and set:
-# - XR_USE_TIMESPEC
-
-env_thirdparty = env_openxr.Clone()
-env_thirdparty.disable_warnings()
-env_thirdparty.AppendUnique(CPPDEFINES=["DISABLE_STD_FILESYSTEM"])
-
if env["platform"] == "android":
# may need to set OPENXR_ANDROID_VERSION_SUFFIX
- env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_ANDROID", "XR_USE_PLATFORM_ANDROID"])
+ env_openxr.AppendUnique(CPPDEFINES=["XR_OS_ANDROID", "XR_USE_PLATFORM_ANDROID"])
+ env_openxr.AppendUnique(CPPDEFINES=["JSON_USE_EXCEPTION=0"])
# may need to include java parts of the openxr loader
elif env["platform"] == "linuxbsd":
- env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_LINUX"])
+ env_openxr.AppendUnique(CPPDEFINES=["XR_OS_LINUX"])
if env["x11"]:
- env_thirdparty.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_XLIB"])
+ env_openxr.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_XLIB"])
# FIXME: Review what needs to be set for Android and macOS.
- env_thirdparty.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"])
+ env_openxr.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"])
elif env["platform"] == "windows":
- env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_WINDOWS", "NOMINMAX", "XR_USE_PLATFORM_WIN32"])
+ env_openxr.AppendUnique(CPPDEFINES=["XR_OS_WINDOWS", "NOMINMAX", "XR_USE_PLATFORM_WIN32"])
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/xr_generated_dispatch_table.c")
+# may need to check and set:
+# - XR_USE_TIMESPEC
-# add in common files (hope these don't clash with us)
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/common/filesystem_utils.cpp")
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/common/object_info.cpp")
+env_thirdparty = env_openxr.Clone()
+env_thirdparty.disable_warnings()
+env_thirdparty.AppendUnique(CPPDEFINES=["DISABLE_STD_FILESYSTEM"])
+
+if "-fno-exceptions" in env_thirdparty["CXXFLAGS"]:
+ env_thirdparty["CXXFLAGS"].remove("-fno-exceptions")
+env_thirdparty.Append(CPPPATH=[thirdparty_dir + "/src/loader"])
# add in external jsoncpp dependency
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_reader.cpp")
@@ -57,17 +55,24 @@ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_writer.cpp")
# add in load
-if env["platform"] == "android":
- env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/android_utilities.cpp")
-
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/api_layer_interface.cpp")
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_core.cpp")
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_instance.cpp")
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_logger_recorders.cpp")
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_logger.cpp")
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/manifest_file.cpp")
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/runtime_interface.cpp")
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/xr_generated_loader.cpp")
+if env["platform"] != "android":
+ # On Android the openxr_loader is provided by separate plugins for each device
+ # Build the engine using object files
+ khrloader_obj = []
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/xr_generated_dispatch_table.c")
+
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/filesystem_utils.cpp")
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/object_info.cpp")
+
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/api_layer_interface.cpp")
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_core.cpp")
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_instance.cpp")
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_logger_recorders.cpp")
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_logger.cpp")
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/manifest_file.cpp")
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/runtime_interface.cpp")
+ env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/xr_generated_loader.cpp")
+ env.modules_sources += khrloader_obj
env.modules_sources += thirdparty_obj
diff --git a/modules/openxr/config.py b/modules/openxr/config.py
index f91cb1359f..650146fdd3 100644
--- a/modules/openxr/config.py
+++ b/modules/openxr/config.py
@@ -1,7 +1,5 @@
def can_build(env, platform):
- if (
- platform == "linuxbsd" or platform == "windows"
- ): # or platform == "android" -- temporarily disabled android support
+ if platform in ("linuxbsd", "windows", "android"):
return env["openxr"]
else:
# not supported on these platforms
diff --git a/modules/openxr/extensions/openxr_android_extension.cpp b/modules/openxr/extensions/openxr_android_extension.cpp
index 3bd4db169c..8f6d5c28db 100644
--- a/modules/openxr/extensions/openxr_android_extension.cpp
+++ b/modules/openxr/extensions/openxr_android_extension.cpp
@@ -29,7 +29,12 @@
/*************************************************************************/
#include "openxr_android_extension.h"
+#include "java_godot_wrapper.h"
+#include "os_android.h"
+#include "thread_jandroid.h"
+#include <jni.h>
+#include <modules/openxr/openxr_api.h>
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
@@ -42,19 +47,16 @@ OpenXRAndroidExtension *OpenXRAndroidExtension::get_singleton() {
OpenXRAndroidExtension::OpenXRAndroidExtension(OpenXRAPI *p_openxr_api) :
OpenXRExtensionWrapper(p_openxr_api) {
singleton = this;
-
request_extensions[XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME] = nullptr; // must be available
+}
- // Initialize the loader
- PFN_xrInitializeLoaderKHR xrInitializeLoaderKHR;
- result = xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", (PFN_xrVoidFunction *)(&xrInitializeLoaderKHR));
- ERR_FAIL_COND_MSG(XR_FAILED(result), "Failed to retrieve pointer to xrInitializeLoaderKHR");
+void OpenXRAndroidExtension::on_before_instance_created() {
+ EXT_INIT_XR_FUNC(xrInitializeLoaderKHR);
- // TODO fix this code, this is still code from GDNative!
- JNIEnv *env = android_api->godot_android_get_env();
+ JNIEnv *env = get_jni_env();
JavaVM *vm;
env->GetJavaVM(&vm);
- jobject activity_object = env->NewGlobalRef(android_api->godot_android_get_activity());
+ jobject activity_object = env->NewGlobalRef(static_cast<OS_Android *>(OS::get_singleton())->get_godot_java()->get_activity());
XrLoaderInitInfoAndroidKHR loader_init_info_android = {
.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR,
@@ -62,7 +64,7 @@ OpenXRAndroidExtension::OpenXRAndroidExtension(OpenXRAPI *p_openxr_api) :
.applicationVM = vm,
.applicationContext = activity_object
};
- xrInitializeLoaderKHR((const XrLoaderInitInfoBaseHeaderKHR *)&loader_init_info_android);
+ XrResult result = xrInitializeLoaderKHR((const XrLoaderInitInfoBaseHeaderKHR *)&loader_init_info_android);
ERR_FAIL_COND_MSG(XR_FAILED(result), "Failed to call xrInitializeLoaderKHR");
}
diff --git a/modules/openxr/extensions/openxr_android_extension.h b/modules/openxr/extensions/openxr_android_extension.h
index 88b0e310e7..eda7022064 100644
--- a/modules/openxr/extensions/openxr_android_extension.h
+++ b/modules/openxr/extensions/openxr_android_extension.h
@@ -31,6 +31,7 @@
#ifndef OPENXR_ANDROID_EXTENSION_H
#define OPENXR_ANDROID_EXTENSION_H
+#include "../util.h"
#include "openxr_extension_wrapper.h"
class OpenXRAndroidExtension : public OpenXRExtensionWrapper {
@@ -38,10 +39,16 @@ public:
static OpenXRAndroidExtension *get_singleton();
OpenXRAndroidExtension(OpenXRAPI *p_openxr_api);
+
+ virtual void on_before_instance_created() override;
+
virtual ~OpenXRAndroidExtension() override;
private:
static OpenXRAndroidExtension *singleton;
+
+ // Initialize the loader
+ EXT_PROTO_XRRESULT_FUNC1(xrInitializeLoaderKHR, (const XrLoaderInitInfoBaseHeaderKHR *), loaderInitInfo)
};
#endif // OPENXR_ANDROID_EXTENSION_H
diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h
index ecc6e0dd4e..0ed0155fc7 100644
--- a/modules/openxr/extensions/openxr_extension_wrapper.h
+++ b/modules/openxr/extensions/openxr_extension_wrapper.h
@@ -66,6 +66,7 @@ public:
virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; }
virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; }
+ virtual void on_before_instance_created() {}
virtual void on_instance_created(const XrInstance p_instance) {}
virtual void on_instance_destroyed() {}
virtual void on_session_created(const XrSession p_instance) {}
diff --git a/modules/openxr/extensions/openxr_vulkan_extension.cpp b/modules/openxr/extensions/openxr_vulkan_extension.cpp
index 2608c4ac17..f9e771c934 100644
--- a/modules/openxr/extensions/openxr_vulkan_extension.cpp
+++ b/modules/openxr/extensions/openxr_vulkan_extension.cpp
@@ -31,30 +31,12 @@
#include "core/string/print_string.h"
#include "../extensions/openxr_vulkan_extension.h"
-#include "../openxr_api.h"
#include "../openxr_util.h"
#include "servers/rendering/renderer_rd/effects/copy_effects.h"
#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
#include "servers/rendering/rendering_server_globals.h"
#include "servers/rendering_server.h"
-// need to include Vulkan so we know of type definitions
-#define XR_USE_GRAPHICS_API_VULKAN
-
-#ifdef WINDOWS_ENABLED
-// Including windows.h here is absolutely evil, we shouldn't be doing this outside of platform
-// however due to the way the openxr headers are put together, we have no choice.
-#include <windows.h>
-#endif
-
-// include platform dependent structs
-#include <openxr/openxr_platform.h>
-
-PFN_xrGetVulkanGraphicsRequirements2KHR xrGetVulkanGraphicsRequirements2KHR_ptr = nullptr;
-PFN_xrCreateVulkanInstanceKHR xrCreateVulkanInstanceKHR_ptr = nullptr;
-PFN_xrGetVulkanGraphicsDevice2KHR xrGetVulkanGraphicsDevice2KHR_ptr = nullptr;
-PFN_xrCreateVulkanDeviceKHR xrCreateVulkanDeviceKHR_ptr = nullptr;
-
OpenXRVulkanExtension::OpenXRVulkanExtension(OpenXRAPI *p_openxr_api) :
OpenXRGraphicsExtensionWrapper(p_openxr_api) {
VulkanContext::set_vulkan_hooks(this);
@@ -69,36 +51,15 @@ OpenXRVulkanExtension::~OpenXRVulkanExtension() {
}
void OpenXRVulkanExtension::on_instance_created(const XrInstance p_instance) {
- XrResult result;
-
ERR_FAIL_NULL(openxr_api);
// Obtain pointers to functions we're accessing here, they are (not yet) part of core.
- result = xrGetInstanceProcAddr(p_instance, "xrGetVulkanGraphicsRequirements2KHR", (PFN_xrVoidFunction *)&xrGetVulkanGraphicsRequirements2KHR_ptr);
- if (XR_FAILED(result)) {
- print_line("OpenXR: Failed to xrGetVulkanGraphicsRequirements2KHR entry point [", openxr_api->get_error_string(result), "]");
- }
- result = xrGetInstanceProcAddr(p_instance, "xrCreateVulkanInstanceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanInstanceKHR_ptr);
- if (XR_FAILED(result)) {
- print_line("OpenXR: Failed to xrCreateVulkanInstanceKHR entry point [", openxr_api->get_error_string(result), "]");
- }
-
- result = xrGetInstanceProcAddr(p_instance, "xrGetVulkanGraphicsDevice2KHR", (PFN_xrVoidFunction *)&xrGetVulkanGraphicsDevice2KHR_ptr);
- if (XR_FAILED(result)) {
- print_line("OpenXR: Failed to xrGetVulkanGraphicsDevice2KHR entry point [", openxr_api->get_error_string(result), "]");
- }
-
- result = xrGetInstanceProcAddr(p_instance, "xrCreateVulkanDeviceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanDeviceKHR_ptr);
- if (XR_FAILED(result)) {
- print_line("OpenXR: Failed to xrCreateVulkanDeviceKHR entry point [", openxr_api->get_error_string(result), "]");
- }
-}
-
-XrResult OpenXRVulkanExtension::xrGetVulkanGraphicsRequirements2KHR(XrInstance p_instance, XrSystemId p_system_id, XrGraphicsRequirementsVulkanKHR *p_graphics_requirements) {
- ERR_FAIL_NULL_V(xrGetVulkanGraphicsRequirements2KHR_ptr, XR_ERROR_HANDLE_INVALID);
-
- return (*xrGetVulkanGraphicsRequirements2KHR_ptr)(p_instance, p_system_id, p_graphics_requirements);
+ EXT_INIT_XR_FUNC(xrGetVulkanGraphicsRequirements2KHR);
+ EXT_INIT_XR_FUNC(xrCreateVulkanInstanceKHR);
+ EXT_INIT_XR_FUNC(xrGetVulkanGraphicsDevice2KHR);
+ EXT_INIT_XR_FUNC(xrCreateVulkanDeviceKHR);
+ EXT_INIT_XR_FUNC(xrEnumerateSwapchainImages);
}
bool OpenXRVulkanExtension::check_graphics_api_support(XrVersion p_desired_version) {
@@ -141,12 +102,6 @@ bool OpenXRVulkanExtension::check_graphics_api_support(XrVersion p_desired_versi
return true;
}
-XrResult OpenXRVulkanExtension::xrCreateVulkanInstanceKHR(XrInstance p_instance, const XrVulkanInstanceCreateInfoKHR *p_create_info, VkInstance *r_vulkan_instance, VkResult *r_vulkan_result) {
- ERR_FAIL_NULL_V(xrCreateVulkanInstanceKHR_ptr, XR_ERROR_HANDLE_INVALID);
-
- return (*xrCreateVulkanInstanceKHR_ptr)(p_instance, p_create_info, r_vulkan_instance, r_vulkan_result);
-}
-
bool OpenXRVulkanExtension::create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance) {
// get the vulkan version we are creating
uint32_t vulkan_version = p_vulkan_create_info->pApplicationInfo->apiVersion;
@@ -195,12 +150,6 @@ bool OpenXRVulkanExtension::create_vulkan_instance(const VkInstanceCreateInfo *p
return true;
}
-XrResult OpenXRVulkanExtension::xrGetVulkanGraphicsDevice2KHR(XrInstance p_instance, const XrVulkanGraphicsDeviceGetInfoKHR *p_get_info, VkPhysicalDevice *r_vulkan_physical_device) {
- ERR_FAIL_NULL_V(xrGetVulkanGraphicsDevice2KHR_ptr, XR_ERROR_HANDLE_INVALID);
-
- return (*xrGetVulkanGraphicsDevice2KHR_ptr)(p_instance, p_get_info, r_vulkan_physical_device);
-}
-
bool OpenXRVulkanExtension::get_physical_device(VkPhysicalDevice *r_device) {
ERR_FAIL_NULL_V(openxr_api, false);
@@ -222,12 +171,6 @@ bool OpenXRVulkanExtension::get_physical_device(VkPhysicalDevice *r_device) {
return true;
}
-XrResult OpenXRVulkanExtension::xrCreateVulkanDeviceKHR(XrInstance p_instance, const XrVulkanDeviceCreateInfoKHR *p_create_info, VkDevice *r_device, VkResult *r_result) {
- ERR_FAIL_NULL_V(xrCreateVulkanDeviceKHR_ptr, XR_ERROR_HANDLE_INVALID);
-
- return (*xrCreateVulkanDeviceKHR_ptr)(p_instance, p_create_info, r_device, r_result);
-}
-
bool OpenXRVulkanExtension::create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) {
ERR_FAIL_NULL_V(openxr_api, false);
diff --git a/modules/openxr/extensions/openxr_vulkan_extension.h b/modules/openxr/extensions/openxr_vulkan_extension.h
index 5dddc4b9c9..d6e9917900 100644
--- a/modules/openxr/extensions/openxr_vulkan_extension.h
+++ b/modules/openxr/extensions/openxr_vulkan_extension.h
@@ -36,16 +36,25 @@
#include "drivers/vulkan/vulkan_context.h"
-// Forward declare these so we don't need OpenXR headers where-ever this is included
-// Including OpenXR at this point gives loads and loads of compile issues especially
-// on Windows because windows.h is EVIL and really shouldn't be included outside of platform
-// but we really don't have a choice in the matter
+#include "../openxr_api.h"
+#include "../util.h"
-struct XrGraphicsRequirementsVulkanKHR;
-struct XrVulkanInstanceCreateInfoKHR;
-struct XrVulkanGraphicsDeviceGetInfoKHR;
-struct XrVulkanDeviceCreateInfoKHR;
-struct XrGraphicsBindingVulkanKHR;
+// need to include Vulkan so we know of type definitions
+#define XR_USE_GRAPHICS_API_VULKAN
+
+#ifdef WINDOWS_ENABLED
+// Including windows.h here is absolutely evil, we shouldn't be doing this outside of platform
+// however due to the way the openxr headers are put together, we have no choice.
+#include <windows.h>
+#endif
+
+#ifdef ANDROID_ENABLED
+// The jobject type from jni.h is used by openxr_platform.h on Android.
+#include <jni.h>
+#endif
+
+// include platform dependent structs
+#include <openxr/openxr_platform.h>
class OpenXRVulkanExtension : public OpenXRGraphicsExtensionWrapper, VulkanHooks {
public:
@@ -84,10 +93,11 @@ private:
uint32_t vulkan_queue_family_index = 0;
uint32_t vulkan_queue_index = 0;
- XrResult xrGetVulkanGraphicsRequirements2KHR(XrInstance p_instance, XrSystemId p_system_id, XrGraphicsRequirementsVulkanKHR *p_graphics_requirements);
- XrResult xrCreateVulkanInstanceKHR(XrInstance p_instance, const XrVulkanInstanceCreateInfoKHR *p_create_info, VkInstance *r_vulkan_instance, VkResult *r_vulkan_result);
- XrResult xrGetVulkanGraphicsDevice2KHR(XrInstance p_instance, const XrVulkanGraphicsDeviceGetInfoKHR *p_get_info, VkPhysicalDevice *r_vulkan_physical_device);
- XrResult xrCreateVulkanDeviceKHR(XrInstance p_instance, const XrVulkanDeviceCreateInfoKHR *p_create_info, VkDevice *r_device, VkResult *r_result);
+ EXT_PROTO_XRRESULT_FUNC3(xrGetVulkanGraphicsRequirements2KHR, (XrInstance), p_instance, (XrSystemId), p_system_id, (XrGraphicsRequirementsVulkanKHR *), p_graphics_requirements)
+ EXT_PROTO_XRRESULT_FUNC4(xrCreateVulkanInstanceKHR, (XrInstance), p_instance, (const XrVulkanInstanceCreateInfoKHR *), p_create_info, (VkInstance *), r_vulkan_instance, (VkResult *), r_vulkan_result)
+ EXT_PROTO_XRRESULT_FUNC3(xrGetVulkanGraphicsDevice2KHR, (XrInstance), p_instance, (const XrVulkanGraphicsDeviceGetInfoKHR *), p_get_info, (VkPhysicalDevice *), r_vulkan_physical_device)
+ EXT_PROTO_XRRESULT_FUNC4(xrCreateVulkanDeviceKHR, (XrInstance), p_instance, (const XrVulkanDeviceCreateInfoKHR *), p_create_info, (VkDevice *), r_device, (VkResult *), r_result)
+ EXT_PROTO_XRRESULT_FUNC4(xrEnumerateSwapchainImages, (XrSwapchain), p_swapchain, (uint32_t), p_image_capacity_input, (uint32_t *), p_image_count_output, (XrSwapchainImageBaseHeader *), p_images)
};
#endif // OPENXR_VULKAN_EXTENSION_H
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 94095eb61c..76f7b2a60a 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -41,6 +41,7 @@
#endif
#ifdef ANDROID_ENABLED
+#define OPENXR_LOADER_NAME "libopenxr_loader.so"
#include "extensions/openxr_android_extension.h"
#endif
@@ -284,6 +285,9 @@ bool OpenXRAPI::create_instance() {
0, // runtimeVersion, from here will be set by our get call
"" // runtimeName
};
+
+ OPENXR_API_INIT_XR_FUNC_V(xrGetInstanceProperties);
+
result = xrGetInstanceProperties(instance, &instanceProps);
if (XR_FAILED(result)) {
// not fatal probably
@@ -992,9 +996,94 @@ bool OpenXRAPI::is_running() {
return running;
}
+bool OpenXRAPI::openxr_loader_init() {
+#ifdef ANDROID_ENABLED
+ ERR_FAIL_COND_V_MSG(openxr_loader_library_handle != nullptr, false, "OpenXR Loader library is already loaded.");
+
+ {
+ Error error_code = OS::get_singleton()->open_dynamic_library(OPENXR_LOADER_NAME, openxr_loader_library_handle);
+ ERR_FAIL_COND_V_MSG(error_code != OK, false, "OpenXR loader not found.");
+ }
+
+ {
+ Error error_code = OS::get_singleton()->get_dynamic_library_symbol_handle(openxr_loader_library_handle, "xrGetInstanceProcAddr", (void *&)xrGetInstanceProcAddr);
+ ERR_FAIL_COND_V_MSG(error_code != OK, false, "Symbol xrGetInstanceProcAddr not found in OpenXR Loader library.");
+ }
+#endif
+
+ // Resolve the symbols that don't require an instance
+ OPENXR_API_INIT_XR_FUNC_V(xrCreateInstance);
+ OPENXR_API_INIT_XR_FUNC_V(xrEnumerateApiLayerProperties);
+ OPENXR_API_INIT_XR_FUNC_V(xrEnumerateInstanceExtensionProperties);
+
+ return true;
+}
+
+bool OpenXRAPI::resolve_instance_openxr_symbols() {
+ ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false);
+
+ OPENXR_API_INIT_XR_FUNC_V(xrAcquireSwapchainImage);
+ OPENXR_API_INIT_XR_FUNC_V(xrApplyHapticFeedback);
+ OPENXR_API_INIT_XR_FUNC_V(xrAttachSessionActionSets);
+ OPENXR_API_INIT_XR_FUNC_V(xrBeginFrame);
+ OPENXR_API_INIT_XR_FUNC_V(xrBeginSession);
+ OPENXR_API_INIT_XR_FUNC_V(xrCreateAction);
+ OPENXR_API_INIT_XR_FUNC_V(xrCreateActionSet);
+ OPENXR_API_INIT_XR_FUNC_V(xrCreateActionSpace);
+ OPENXR_API_INIT_XR_FUNC_V(xrCreateReferenceSpace);
+ OPENXR_API_INIT_XR_FUNC_V(xrCreateSession);
+ OPENXR_API_INIT_XR_FUNC_V(xrCreateSwapchain);
+ OPENXR_API_INIT_XR_FUNC_V(xrDestroyAction);
+ OPENXR_API_INIT_XR_FUNC_V(xrDestroyActionSet);
+ OPENXR_API_INIT_XR_FUNC_V(xrDestroyInstance);
+ OPENXR_API_INIT_XR_FUNC_V(xrDestroySession);
+ OPENXR_API_INIT_XR_FUNC_V(xrDestroySpace);
+ OPENXR_API_INIT_XR_FUNC_V(xrDestroySwapchain);
+ OPENXR_API_INIT_XR_FUNC_V(xrEndFrame);
+ OPENXR_API_INIT_XR_FUNC_V(xrEndSession);
+ OPENXR_API_INIT_XR_FUNC_V(xrEnumerateReferenceSpaces);
+ OPENXR_API_INIT_XR_FUNC_V(xrEnumerateSwapchainFormats);
+ OPENXR_API_INIT_XR_FUNC_V(xrEnumerateViewConfigurations);
+ OPENXR_API_INIT_XR_FUNC_V(xrEnumerateViewConfigurationViews);
+ OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateBoolean);
+ OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateFloat);
+ OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateVector2f);
+ OPENXR_API_INIT_XR_FUNC_V(xrGetCurrentInteractionProfile);
+ OPENXR_API_INIT_XR_FUNC_V(xrGetSystem);
+ OPENXR_API_INIT_XR_FUNC_V(xrGetSystemProperties);
+ OPENXR_API_INIT_XR_FUNC_V(xrLocateViews);
+ OPENXR_API_INIT_XR_FUNC_V(xrLocateSpace);
+ OPENXR_API_INIT_XR_FUNC_V(xrPathToString);
+ OPENXR_API_INIT_XR_FUNC_V(xrPollEvent);
+ OPENXR_API_INIT_XR_FUNC_V(xrReleaseSwapchainImage);
+ OPENXR_API_INIT_XR_FUNC_V(xrResultToString);
+ OPENXR_API_INIT_XR_FUNC_V(xrStringToPath);
+ OPENXR_API_INIT_XR_FUNC_V(xrSuggestInteractionProfileBindings);
+ OPENXR_API_INIT_XR_FUNC_V(xrSyncActions);
+ OPENXR_API_INIT_XR_FUNC_V(xrWaitFrame);
+ OPENXR_API_INIT_XR_FUNC_V(xrWaitSwapchainImage);
+
+ return true;
+}
+
+XrResult OpenXRAPI::get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr) {
+ XrResult result = xrGetInstanceProcAddr(instance, p_name, p_addr);
+
+ if (result != XR_SUCCESS) {
+ String error_message = String("Symbol ") + p_name + " not found in OpenXR instance.";
+ ERR_FAIL_COND_V_MSG(true, result, error_message.utf8().get_data());
+ }
+
+ return result;
+}
+
bool OpenXRAPI::initialize(const String &p_rendering_driver) {
ERR_FAIL_COND_V_MSG(instance != XR_NULL_HANDLE, false, "OpenXR instance was already created");
+ if (!openxr_loader_init()) {
+ return false;
+ }
+
if (p_rendering_driver == "vulkan") {
#ifdef VULKAN_ENABLED
graphics_extension = memnew(OpenXRVulkanExtension(this));
@@ -1017,6 +1106,10 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) {
}
// initialize
+ for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
+ wrapper->on_before_instance_created();
+ }
+
if (!load_layer_properties()) {
destroy_instance();
return false;
@@ -1032,6 +1125,11 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) {
return false;
}
+ if (!resolve_instance_openxr_symbols()) {
+ destroy_instance();
+ return false;
+ }
+
if (!get_system_info()) {
destroy_instance();
return false;
@@ -1669,6 +1767,13 @@ OpenXRAPI::~OpenXRAPI() {
layer_properties = nullptr;
}
+#ifdef ANDROID_ENABLED
+ if (openxr_loader_library_handle) {
+ OS::get_singleton()->close_dynamic_library(openxr_loader_library_handle);
+ openxr_loader_library_handle = nullptr;
+ }
+#endif
+
singleton = nullptr;
}
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index dc224c4237..4f84cc3b5b 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -50,6 +50,8 @@
#include "extensions/openxr_composition_layer_provider.h"
#include "extensions/openxr_extension_wrapper.h"
+#include "util.h"
+
// Note, OpenXR code that we wrote for our plugin makes use of C++20 notation for initialising structs which ensures zeroing out unspecified members.
// Godot is currently restricted to C++17 which doesn't allow this notation. Make sure critical fields are set.
@@ -134,6 +136,61 @@ private:
bool load_supported_extensions();
bool is_extension_supported(const String &p_extension) const;
+ bool openxr_loader_init();
+ bool resolve_instance_openxr_symbols();
+
+ void *openxr_loader_library_handle = nullptr;
+
+ // function pointers
+#ifdef ANDROID_ENABLED
+ // On non-Android platforms we use the OpenXR symbol linked into the engine binary.
+ PFN_xrGetInstanceProcAddr xrGetInstanceProcAddr = nullptr;
+#endif
+ EXT_PROTO_XRRESULT_FUNC3(xrAcquireSwapchainImage, (XrSwapchain), swapchain, (const XrSwapchainImageAcquireInfo *), acquireInfo, (uint32_t *), index)
+ EXT_PROTO_XRRESULT_FUNC3(xrApplyHapticFeedback, (XrSession), session, (const XrHapticActionInfo *), hapticActionInfo, (const XrHapticBaseHeader *), hapticFeedback)
+ EXT_PROTO_XRRESULT_FUNC2(xrAttachSessionActionSets, (XrSession), session, (const XrSessionActionSetsAttachInfo *), attachInfo)
+ EXT_PROTO_XRRESULT_FUNC2(xrBeginFrame, (XrSession), session, (const XrFrameBeginInfo *), frameBeginInfo)
+ EXT_PROTO_XRRESULT_FUNC2(xrBeginSession, (XrSession), session, (const XrSessionBeginInfo *), beginInfo)
+ EXT_PROTO_XRRESULT_FUNC3(xrCreateAction, (XrActionSet), actionSet, (const XrActionCreateInfo *), createInfo, (XrAction *), action)
+ EXT_PROTO_XRRESULT_FUNC3(xrCreateActionSet, (XrInstance), instance, (const XrActionSetCreateInfo *), createInfo, (XrActionSet *), actionSet)
+ EXT_PROTO_XRRESULT_FUNC3(xrCreateActionSpace, (XrSession), session, (const XrActionSpaceCreateInfo *), createInfo, (XrSpace *), space)
+ EXT_PROTO_XRRESULT_FUNC2(xrCreateInstance, (const XrInstanceCreateInfo *), createInfo, (XrInstance *), instance)
+ EXT_PROTO_XRRESULT_FUNC3(xrCreateReferenceSpace, (XrSession), session, (const XrReferenceSpaceCreateInfo *), createInfo, (XrSpace *), space)
+ EXT_PROTO_XRRESULT_FUNC3(xrCreateSession, (XrInstance), instance, (const XrSessionCreateInfo *), createInfo, (XrSession *), session)
+ EXT_PROTO_XRRESULT_FUNC3(xrCreateSwapchain, (XrSession), session, (const XrSwapchainCreateInfo *), createInfo, (XrSwapchain *), swapchain)
+ EXT_PROTO_XRRESULT_FUNC1(xrDestroyAction, (XrAction), action)
+ EXT_PROTO_XRRESULT_FUNC1(xrDestroyActionSet, (XrActionSet), actionSet)
+ EXT_PROTO_XRRESULT_FUNC1(xrDestroyInstance, (XrInstance), instance)
+ EXT_PROTO_XRRESULT_FUNC1(xrDestroySession, (XrSession), session)
+ EXT_PROTO_XRRESULT_FUNC1(xrDestroySpace, (XrSpace), space)
+ EXT_PROTO_XRRESULT_FUNC1(xrDestroySwapchain, (XrSwapchain), swapchain)
+ EXT_PROTO_XRRESULT_FUNC2(xrEndFrame, (XrSession), session, (const XrFrameEndInfo *), frameEndInfo)
+ EXT_PROTO_XRRESULT_FUNC1(xrEndSession, (XrSession), session)
+ EXT_PROTO_XRRESULT_FUNC3(xrEnumerateApiLayerProperties, (uint32_t), propertyCapacityInput, (uint32_t *), propertyCountOutput, (XrApiLayerProperties *), properties)
+ EXT_PROTO_XRRESULT_FUNC4(xrEnumerateInstanceExtensionProperties, (const char *), layerName, (uint32_t), propertyCapacityInput, (uint32_t *), propertyCountOutput, (XrExtensionProperties *), properties)
+ EXT_PROTO_XRRESULT_FUNC4(xrEnumerateReferenceSpaces, (XrSession), session, (uint32_t), spaceCapacityInput, (uint32_t *), spaceCountOutput, (XrReferenceSpaceType *), spaces)
+ EXT_PROTO_XRRESULT_FUNC4(xrEnumerateSwapchainFormats, (XrSession), session, (uint32_t), formatCapacityInput, (uint32_t *), formatCountOutput, (int64_t *), formats)
+ EXT_PROTO_XRRESULT_FUNC5(xrEnumerateViewConfigurations, (XrInstance), instance, (XrSystemId), systemId, (uint32_t), viewConfigurationTypeCapacityInput, (uint32_t *), viewConfigurationTypeCountOutput, (XrViewConfigurationType *), viewConfigurationTypes)
+ EXT_PROTO_XRRESULT_FUNC6(xrEnumerateViewConfigurationViews, (XrInstance), instance, (XrSystemId), systemId, (XrViewConfigurationType), viewConfigurationType, (uint32_t), viewCapacityInput, (uint32_t *), viewCountOutput, (XrViewConfigurationView *), views)
+ EXT_PROTO_XRRESULT_FUNC3(xrGetActionStateBoolean, (XrSession), session, (const XrActionStateGetInfo *), getInfo, (XrActionStateBoolean *), state)
+ EXT_PROTO_XRRESULT_FUNC3(xrGetActionStateFloat, (XrSession), session, (const XrActionStateGetInfo *), getInfo, (XrActionStateFloat *), state)
+ EXT_PROTO_XRRESULT_FUNC3(xrGetActionStateVector2f, (XrSession), session, (const XrActionStateGetInfo *), getInfo, (XrActionStateVector2f *), state)
+ EXT_PROTO_XRRESULT_FUNC3(xrGetCurrentInteractionProfile, (XrSession), session, (XrPath), topLevelUserPath, (XrInteractionProfileState *), interactionProfile)
+ EXT_PROTO_XRRESULT_FUNC2(xrGetInstanceProperties, (XrInstance), instance, (XrInstanceProperties *), instanceProperties)
+ EXT_PROTO_XRRESULT_FUNC3(xrGetSystem, (XrInstance), instance, (const XrSystemGetInfo *), getInfo, (XrSystemId *), systemId)
+ EXT_PROTO_XRRESULT_FUNC3(xrGetSystemProperties, (XrInstance), instance, (XrSystemId), systemId, (XrSystemProperties *), properties)
+ EXT_PROTO_XRRESULT_FUNC4(xrLocateSpace, (XrSpace), space, (XrSpace), baseSpace, (XrTime), time, (XrSpaceLocation *), location)
+ EXT_PROTO_XRRESULT_FUNC6(xrLocateViews, (XrSession), session, (const XrViewLocateInfo *), viewLocateInfo, (XrViewState *), viewState, (uint32_t), viewCapacityInput, (uint32_t *), viewCountOutput, (XrView *), views)
+ EXT_PROTO_XRRESULT_FUNC5(xrPathToString, (XrInstance), instance, (XrPath), path, (uint32_t), bufferCapacityInput, (uint32_t *), bufferCountOutput, (char *), buffer)
+ EXT_PROTO_XRRESULT_FUNC2(xrPollEvent, (XrInstance), instance, (XrEventDataBuffer *), eventData)
+ EXT_PROTO_XRRESULT_FUNC2(xrReleaseSwapchainImage, (XrSwapchain), swapchain, (const XrSwapchainImageReleaseInfo *), releaseInfo)
+ EXT_PROTO_XRRESULT_FUNC3(xrResultToString, (XrInstance), instance, (XrResult), value, (char *), buffer)
+ EXT_PROTO_XRRESULT_FUNC3(xrStringToPath, (XrInstance), instance, (const char *), pathString, (XrPath *), path)
+ EXT_PROTO_XRRESULT_FUNC2(xrSuggestInteractionProfileBindings, (XrInstance), instance, (const XrInteractionProfileSuggestedBinding *), suggestedBindings)
+ EXT_PROTO_XRRESULT_FUNC2(xrSyncActions, (XrSession), session, (const XrActionsSyncInfo *), syncInfo)
+ EXT_PROTO_XRRESULT_FUNC3(xrWaitFrame, (XrSession), session, (const XrFrameWaitInfo *), frameWaitInfo, (XrFrameState *), frameState)
+ EXT_PROTO_XRRESULT_FUNC2(xrWaitSwapchainImage, (XrSwapchain), swapchain, (const XrSwapchainImageWaitInfo *), waitInfo)
+
// instance
bool create_instance();
bool get_system_info();
@@ -231,6 +288,7 @@ public:
static bool openxr_is_enabled(bool p_check_run_in_editor = true);
static OpenXRAPI *get_singleton();
+ XrResult get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr);
String get_error_string(XrResult result);
String get_swapchain_format_name(int64_t p_swapchain_format) const;
diff --git a/modules/openxr/util.h b/modules/openxr/util.h
new file mode 100644
index 0000000000..5c79890830
--- /dev/null
+++ b/modules/openxr/util.h
@@ -0,0 +1,110 @@
+/*************************************************************************/
+/* util.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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. */
+/*************************************************************************/
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#define UNPACK(...) __VA_ARGS__
+
+#define INIT_XR_FUNC_V(openxr_api, name) \
+ do { \
+ XrResult get_instance_proc_addr_result; \
+ get_instance_proc_addr_result = openxr_api->get_instance_proc_addr(#name, (PFN_xrVoidFunction *)&name##_ptr); \
+ ERR_FAIL_COND_V(XR_FAILED(get_instance_proc_addr_result), false); \
+ } while (0)
+
+#define EXT_INIT_XR_FUNC_V(name) INIT_XR_FUNC_V(openxr_api, name)
+#define OPENXR_API_INIT_XR_FUNC_V(name) INIT_XR_FUNC_V(this, name)
+
+#define INIT_XR_FUNC(openxr_api, name) \
+ do { \
+ XrResult get_instance_proc_addr_result; \
+ get_instance_proc_addr_result = openxr_api->get_instance_proc_addr(#name, (PFN_xrVoidFunction *)&name##_ptr); \
+ ERR_FAIL_COND(XR_FAILED(get_instance_proc_addr_result)); \
+ } while (0)
+
+#define EXT_INIT_XR_FUNC(name) INIT_XR_FUNC(openxr_api, name)
+#define OPENXR_API_INIT_XR_FUNC(name) INIT_XR_FUNC(this, name)
+
+#define EXT_PROTO_XRRESULT_FUNC1(func_name, arg1_type, arg1) \
+ PFN_##func_name func_name##_ptr = nullptr; \
+ XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1) const { \
+ if (!func_name##_ptr) { \
+ return XR_ERROR_HANDLE_INVALID; \
+ } \
+ return (*func_name##_ptr)(arg1); \
+ }
+
+#define EXT_PROTO_XRRESULT_FUNC2(func_name, arg1_type, arg1, arg2_type, arg2) \
+ PFN_##func_name func_name##_ptr = nullptr; \
+ XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1, UNPACK arg2_type arg2) const { \
+ if (!func_name##_ptr) { \
+ return XR_ERROR_HANDLE_INVALID; \
+ } \
+ return (*func_name##_ptr)(arg1, arg2); \
+ }
+
+#define EXT_PROTO_XRRESULT_FUNC3(func_name, arg1_type, arg1, arg2_type, arg2, arg3_type, arg3) \
+ PFN_##func_name func_name##_ptr = nullptr; \
+ XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1, UNPACK arg2_type arg2, UNPACK arg3_type arg3) const { \
+ if (!func_name##_ptr) { \
+ return XR_ERROR_HANDLE_INVALID; \
+ } \
+ return (*func_name##_ptr)(arg1, arg2, arg3); \
+ }
+
+#define EXT_PROTO_XRRESULT_FUNC4(func_name, arg1_type, arg1, arg2_type, arg2, arg3_type, arg3, arg4_type, arg4) \
+ PFN_##func_name func_name##_ptr = nullptr; \
+ XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1, UNPACK arg2_type arg2, UNPACK arg3_type arg3, UNPACK arg4_type arg4) const { \
+ if (!func_name##_ptr) { \
+ return XR_ERROR_HANDLE_INVALID; \
+ } \
+ return (*func_name##_ptr)(arg1, arg2, arg3, arg4); \
+ }
+
+#define EXT_PROTO_XRRESULT_FUNC5(func_name, arg1_type, arg1, arg2_type, arg2, arg3_type, arg3, arg4_type, arg4, arg5_type, arg5) \
+ PFN_##func_name func_name##_ptr = nullptr; \
+ XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1, UNPACK arg2_type arg2, UNPACK arg3_type arg3, UNPACK arg4_type arg4, UNPACK arg5_type arg5) const { \
+ if (!func_name##_ptr) { \
+ return XR_ERROR_HANDLE_INVALID; \
+ } \
+ return (*func_name##_ptr)(arg1, arg2, arg3, arg4, arg5); \
+ }
+
+#define EXT_PROTO_XRRESULT_FUNC6(func_name, arg1_type, arg1, arg2_type, arg2, arg3_type, arg3, arg4_type, arg4, arg5_type, arg5, arg6_type, arg6) \
+ PFN_##func_name func_name##_ptr = nullptr; \
+ XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1, UNPACK arg2_type arg2, UNPACK arg3_type arg3, UNPACK arg4_type arg4, UNPACK arg5_type arg5, UNPACK arg6_type arg6) const { \
+ if (!func_name##_ptr) { \
+ return XR_ERROR_HANDLE_INVALID; \
+ } \
+ return (*func_name##_ptr)(arg1, arg2, arg3, arg4, arg5, arg6); \
+ }
+
+#endif // UTIL_H
diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub
index 074795759a..0670c7f468 100644
--- a/modules/raycast/SCsub
+++ b/modules/raycast/SCsub
@@ -63,7 +63,8 @@ if env["builtin_embree"]:
thirdparty_sources = [thirdparty_dir + file for file in embree_src]
env_raycast.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "include"])
- env_raycast.Append(CPPDEFINES=["EMBREE_TARGET_SSE2", "EMBREE_LOWEST_ISA", "TASKING_INTERNAL", "NDEBUG"])
+ env_raycast.Append(CPPDEFINES=["EMBREE_TARGET_SSE2", "EMBREE_LOWEST_ISA", "TASKING_INTERNAL"])
+ env_raycast.AppendUnique(CPPDEFINES=["NDEBUG"]) # No assert() even in debug builds.
if not env.msvc:
if env["arch"] == "x86_64":
diff --git a/modules/raycast/lightmap_raycaster.cpp b/modules/raycast/lightmap_raycaster_embree.cpp
index 9b35b5616e..e6a579bd3a 100644
--- a/modules/raycast/lightmap_raycaster.cpp
+++ b/modules/raycast/lightmap_raycaster_embree.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* lightmap_raycaster.cpp */
+/* lightmap_raycaster_embree.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -30,7 +30,7 @@
#ifdef TOOLS_ENABLED
-#include "lightmap_raycaster.h"
+#include "lightmap_raycaster_embree.h"
#ifdef __SSE2__
#include <pmmintrin.h>
@@ -193,4 +193,4 @@ LightmapRaycasterEmbree::~LightmapRaycasterEmbree() {
}
}
-#endif
+#endif // TOOLS_ENABLED
diff --git a/modules/raycast/lightmap_raycaster.h b/modules/raycast/lightmap_raycaster_embree.h
index 2e9f59dda4..0c3371f07c 100644
--- a/modules/raycast/lightmap_raycaster.h
+++ b/modules/raycast/lightmap_raycaster_embree.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* lightmap_raycaster.h */
+/* lightmap_raycaster_embree.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,6 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef LIGHTMAP_RAYCASTER_EMBREE_H
+#define LIGHTMAP_RAYCASTER_EMBREE_H
+
#ifdef TOOLS_ENABLED
#include "core/io/image.h"
@@ -74,4 +77,6 @@ public:
~LightmapRaycasterEmbree();
};
-#endif // LIGHTMAP_RAYCASTER_H
+#endif // TOOLS_ENABLED
+
+#endif // LIGHTMAP_RAYCASTER_EMBREE_H
diff --git a/modules/raycast/register_types.cpp b/modules/raycast/register_types.cpp
index 42de1d971d..a8380b00ba 100644
--- a/modules/raycast/register_types.cpp
+++ b/modules/raycast/register_types.cpp
@@ -30,9 +30,9 @@
#include "register_types.h"
-#include "lightmap_raycaster.h"
+#include "lightmap_raycaster_embree.h"
#include "raycast_occlusion_cull.h"
-#include "static_raycaster.h"
+#include "static_raycaster_embree.h"
RaycastOcclusionCull *raycast_occlusion_cull = nullptr;
diff --git a/modules/raycast/register_types.h b/modules/raycast/register_types.h
index a917285390..25a6c346b9 100644
--- a/modules/raycast/register_types.h
+++ b/modules/raycast/register_types.h
@@ -28,7 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef RAYCAST_REGISTER_TYPES_H
+#define RAYCAST_REGISTER_TYPES_H
+
#include "modules/register_module_types.h"
void initialize_raycast_module(ModuleInitializationLevel p_level);
void uninitialize_raycast_module(ModuleInitializationLevel p_level);
+
+#endif // RAYCAST_REGISTER_TYPES_H
diff --git a/modules/raycast/static_raycaster.cpp b/modules/raycast/static_raycaster_embree.cpp
index 7659eea27f..b5a4ab42d4 100644
--- a/modules/raycast/static_raycaster.cpp
+++ b/modules/raycast/static_raycaster_embree.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* static_raycaster.cpp */
+/* static_raycaster_embree.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -30,7 +30,7 @@
#ifdef TOOLS_ENABLED
-#include "static_raycaster.h"
+#include "static_raycaster_embree.h"
#ifdef __SSE2__
#include <pmmintrin.h>
@@ -134,4 +134,4 @@ StaticRaycasterEmbree::~StaticRaycasterEmbree() {
}
}
-#endif
+#endif // TOOLS_ENABLED
diff --git a/modules/raycast/static_raycaster.h b/modules/raycast/static_raycaster_embree.h
index 607a392683..4d631e3ca0 100644
--- a/modules/raycast/static_raycaster.h
+++ b/modules/raycast/static_raycaster_embree.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* static_raycaster.h */
+/* static_raycaster_embree.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,6 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef STATIC_RAYCASTER_EMBREE_H
+#define STATIC_RAYCASTER_EMBREE_H
+
#ifdef TOOLS_ENABLED
#include "core/math/static_raycaster.h"
@@ -61,4 +64,6 @@ public:
~StaticRaycasterEmbree();
};
-#endif // STATIC_RAYCASTER_H
+#endif // TOOLS_ENABLED
+
+#endif // STATIC_RAYCASTER_EMBREE_H
diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct
index 0170c007ae..488d1f641b 100644
--- a/modules/text_server_adv/gdextension_build/SConstruct
+++ b/modules/text_server_adv/gdextension_build/SConstruct
@@ -19,6 +19,7 @@ env = SConscript("./godot-cpp/SConstruct")
env.__class__.disable_warnings = methods.disable_warnings
opts = Variables([], ARGUMENTS)
+opts.Add(BoolVariable("brotli_enabled", "Use Brotli library", True))
opts.Add(BoolVariable("freetype_enabled", "Use FreeType library", True))
opts.Add(BoolVariable("msdfgen_enabled", "Use MSDFgen library (require FreeType)", True))
opts.Add(BoolVariable("graphite_enabled", "Use Graphite library (require FreeType)", True))
@@ -162,6 +163,25 @@ if env["freetype_enabled"]:
]
thirdparty_freetype_sources += [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources]
+ if env["brotli_enabled"]:
+ thirdparty_brotli_dir = "../../../thirdparty/brotli/"
+ thirdparty_brotli_sources = [
+ "common/constants.c",
+ "common/context.c",
+ "common/dictionary.c",
+ "common/platform.c",
+ "common/shared_dictionary.c",
+ "common/transform.c",
+ "dec/bit_reader.c",
+ "dec/decode.c",
+ "dec/huffman.c",
+ "dec/state.c",
+ ]
+ thirdparty_freetype_sources += [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources]
+ env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
+ env_freetype.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"])
+ env.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
+
env_freetype.Append(CPPPATH=[thirdparty_freetype_dir + "/include", thirdparty_zlib_dir, thirdparty_png_dir])
env.Append(CPPPATH=[thirdparty_freetype_dir + "/include"])
@@ -265,6 +285,7 @@ env_harfbuzz.Append(
CPPPATH=[
"../../../thirdparty/harfbuzz/src",
"../../../thirdparty/icu4c/common/",
+ "../../../thirdparty/icu4c/i18n/",
]
)
@@ -569,6 +590,10 @@ thirdparty_icu_sources = [
"common/uvectr32.cpp",
"common/uvectr64.cpp",
"common/wintz.cpp",
+ "i18n/scriptset.cpp",
+ "i18n/ucln_in.cpp",
+ "i18n/uspoof.cpp",
+ "i18n/uspoof_impl.cpp",
]
thirdparty_icu_sources = [thirdparty_icu_dir + file for file in thirdparty_icu_sources]
@@ -584,7 +609,7 @@ if env["static_icu_data"]:
else:
thirdparty_sources += ["../icu_data/icudata_stub.cpp"]
-env_icu.Append(CPPPATH=["../../../thirdparty/icu4c/common/"])
+env_icu.Append(CPPPATH=["../../../thirdparty/icu4c/common/", "../../../thirdparty/icu4c/i18n/"])
env_icu.Append(
CXXFLAGS=[
"-DU_STATIC_IMPLEMENTATION",
@@ -610,7 +635,7 @@ env.Append(
"-DICU_DATA_NAME=" + icu_data_name,
]
)
-env.Append(CPPPATH=["../../../thirdparty/icu4c/common/"])
+env.Append(CPPPATH=["../../../thirdparty/icu4c/common/", "../../../thirdparty/icu4c/i18n/"])
if env["platform"] == "windows":
env.Append(LIBS=["advapi32"])
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index b0f414f7f0..1a4831857f 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -3065,8 +3065,10 @@ int64_t TextServerAdvanced::font_get_glyph_index(const RID &p_font_rid, int64_t
bool TextServerAdvanced::font_has_char(const RID &p_font_rid, int64_t p_char) const {
FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, false);
ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), false, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + ".");
+ if (!fd) {
+ return false;
+ }
MutexLock lock(fd->mutex);
if (fd->cache.is_empty()) {
@@ -4495,35 +4497,40 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(const RID &p_shaped_l
int glyphs_to = (is_rtl) ? sd_size - 1 : -1;
int glyphs_delta = (is_rtl) ? +1 : -1;
- for (int i = glyphs_from; i != glyphs_to; i += glyphs_delta) {
- if (!is_rtl) {
- width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
- }
- if (sd_glyphs[i].count > 0) {
- bool above_min_char_threshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters;
+ if (enforce_ellipsis && (width + ellipsis_width <= p_width)) {
+ trim_pos = -1;
+ ellipsis_pos = (is_rtl) ? 0 : sd_size;
+ } else {
+ for (int i = glyphs_from; i != glyphs_to; i += glyphs_delta) {
+ if (!is_rtl) {
+ width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
+ }
+ if (sd_glyphs[i].count > 0) {
+ bool above_min_char_threshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters;
- if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {
- if (cut_per_word && above_min_char_threshold) {
- if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
+ if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {
+ if (cut_per_word && above_min_char_threshold) {
+ if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
+ last_valid_cut = i;
+ found = true;
+ }
+ } else {
last_valid_cut = i;
found = true;
}
- } else {
- last_valid_cut = i;
- found = true;
- }
- if (found) {
- trim_pos = last_valid_cut;
+ if (found) {
+ trim_pos = last_valid_cut;
- if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {
- ellipsis_pos = trim_pos;
+ if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {
+ ellipsis_pos = trim_pos;
+ }
+ break;
}
- break;
}
}
- }
- if (is_rtl) {
- width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
+ if (is_rtl) {
+ width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
+ }
}
}
@@ -5423,7 +5430,10 @@ bool TextServerAdvanced::shaped_text_shape(const RID &p_shaped) {
Array fonts_scr_only;
Array fonts_no_match;
int font_count = span.fonts.size();
- for (int l = 0; l < font_count; l++) {
+ if (font_count > 0) {
+ fonts.push_back(sd->spans[k].fonts[0]);
+ }
+ for (int l = 1; l < font_count; l++) {
if (font_is_script_supported(span.fonts[l], script)) {
if (font_is_language_supported(span.fonts[l], span.language)) {
fonts.push_back(sd->spans[k].fonts[l]);
@@ -5844,9 +5854,9 @@ String TextServerAdvanced::percent_sign(const String &p_language) const {
return "%";
}
-int TextServerAdvanced::is_confusable(const String &p_string, const PackedStringArray &p_dict) const {
+int64_t TextServerAdvanced::is_confusable(const String &p_string, const PackedStringArray &p_dict) const {
UErrorCode status = U_ZERO_ERROR;
- int match_index = -1;
+ int64_t match_index = -1;
Char16String utf16 = p_string.utf16();
Vector<UChar *> skeletons;
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 1db95d153b..b9633a9b71 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -52,6 +52,7 @@
#include <godot_cpp/variant/rect2.hpp>
#include <godot_cpp/variant/rid.hpp>
#include <godot_cpp/variant/string.hpp>
+#include <godot_cpp/variant/typed_array.hpp>
#include <godot_cpp/variant/vector2.hpp>
#include <godot_cpp/variant/vector2i.hpp>
@@ -705,7 +706,7 @@ public:
virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override;
- virtual int is_confusable(const String &p_string, const PackedStringArray &p_dict) const override;
+ virtual int64_t is_confusable(const String &p_string, const PackedStringArray &p_dict) const override;
virtual bool spoof_check(const String &p_string) const override;
virtual String strip_diacritics(const String &p_string) const override;
diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct
index de0a549900..488f9ca24e 100644
--- a/modules/text_server_fb/gdextension_build/SConstruct
+++ b/modules/text_server_fb/gdextension_build/SConstruct
@@ -19,6 +19,7 @@ env = SConscript("./godot-cpp/SConstruct")
env.__class__.disable_warnings = methods.disable_warnings
opts = Variables([], ARGUMENTS)
+opts.Add(BoolVariable("brotli_enabled", "Use Brotli library", True))
opts.Add(BoolVariable("freetype_enabled", "Use FreeType library", True))
opts.Add(BoolVariable("msdfgen_enabled", "Use MSDFgen library (require FreeType)", True))
opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False))
@@ -157,6 +158,25 @@ if env["freetype_enabled"]:
]
thirdparty_freetype_sources += [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources]
+ if env["brotli_enabled"]:
+ thirdparty_brotli_dir = "../../../thirdparty/brotli/"
+ thirdparty_brotli_sources = [
+ "common/constants.c",
+ "common/context.c",
+ "common/dictionary.c",
+ "common/platform.c",
+ "common/shared_dictionary.c",
+ "common/transform.c",
+ "dec/bit_reader.c",
+ "dec/decode.c",
+ "dec/huffman.c",
+ "dec/state.c",
+ ]
+ thirdparty_freetype_sources += [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources]
+ env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
+ env_freetype.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"])
+ env.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
+
env_freetype.Append(CPPPATH=[thirdparty_freetype_dir + "/include", thirdparty_zlib_dir, thirdparty_png_dir])
env.Append(CPPPATH=[thirdparty_freetype_dir + "/include"])
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 23662bf2c4..9ef0f0ad82 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -2127,8 +2127,10 @@ int64_t TextServerFallback::font_get_glyph_index(const RID &p_font_rid, int64_t
bool TextServerFallback::font_has_char(const RID &p_font_rid, int64_t p_char) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, false);
ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), false, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + ".");
+ if (!fd) {
+ return false;
+ }
MutexLock lock(fd->mutex);
if (fd->cache.is_empty()) {
@@ -2842,7 +2844,10 @@ bool TextServerFallback::shaped_text_add_string(const RID &p_shaped, const Strin
// Pre-sort fonts, push fonts with the language support first.
Array fonts_no_match;
int font_count = p_fonts.size();
- for (int i = 0; i < font_count; i++) {
+ if (font_count > 0) {
+ span.fonts.push_back(p_fonts[0]);
+ }
+ for (int i = 1; i < font_count; i++) {
if (font_is_language_supported(p_fonts[i], p_language)) {
span.fonts.push_back(p_fonts[i]);
} else {
@@ -3453,29 +3458,34 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(const RID &p_shaped_l
int last_valid_cut = 0;
bool found = false;
- for (int i = sd_size - 1; i != -1; i--) {
- width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
+ if (enforce_ellipsis && (width + ellipsis_width <= p_width)) {
+ trim_pos = -1;
+ ellipsis_pos = sd_size;
+ } else {
+ for (int i = sd_size - 1; i != -1; i--) {
+ width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
- if (sd_glyphs[i].count > 0) {
- bool above_min_char_threshold = (i >= ell_min_characters);
+ if (sd_glyphs[i].count > 0) {
+ bool above_min_char_threshold = (i >= ell_min_characters);
- if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {
- if (cut_per_word && above_min_char_threshold) {
- if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
+ if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {
+ if (cut_per_word && above_min_char_threshold) {
+ if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
+ last_valid_cut = i;
+ found = true;
+ }
+ } else {
last_valid_cut = i;
found = true;
}
- } else {
- last_valid_cut = i;
- found = true;
- }
- if (found) {
- trim_pos = last_valid_cut;
+ if (found) {
+ trim_pos = last_valid_cut;
- if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {
- ellipsis_pos = trim_pos;
+ if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {
+ ellipsis_pos = trim_pos;
+ }
+ break;
}
- break;
}
}
}
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index cbb2fb03f2..42f311f5ad 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -52,6 +52,7 @@
#include <godot_cpp/variant/rect2.hpp>
#include <godot_cpp/variant/rid.hpp>
#include <godot_cpp/variant/string.hpp>
+#include <godot_cpp/variant/typed_array.hpp>
#include <godot_cpp/variant/vector2.hpp>
#include <godot_cpp/variant/vector2i.hpp>
diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp
index 00ba32eae1..aed95294e7 100644
--- a/modules/tga/image_loader_tga.cpp
+++ b/modules/tga/image_loader_tga.cpp
@@ -100,7 +100,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
uint32_t width = p_header.image_width;
uint32_t height = p_header.image_height;
tga_origin_e origin = static_cast<tga_origin_e>((p_header.image_descriptor & TGA_ORIGIN_MASK) >> TGA_ORIGIN_SHIFT);
-
+ uint8_t alpha_bits = p_header.image_descriptor & TGA_IMAGE_DESCRIPTOR_ALPHA_MASK;
uint32_t x_start;
int32_t x_step;
uint32_t x_end;
@@ -184,6 +184,27 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
y += y_step;
}
}
+ } else if (p_header.pixel_depth == 16) {
+ while (y != y_end) {
+ while (x != x_end) {
+ if (i + 1 >= p_input_size) {
+ return ERR_PARSE_ERROR;
+ }
+
+ // Always stored as RGBA5551
+ uint8_t r = (p_buffer[i + 1] & 0x7c) << 1;
+ uint8_t g = ((p_buffer[i + 1] & 0x03) << 6) | ((p_buffer[i + 0] & 0xe0) >> 2);
+ uint8_t b = (p_buffer[i + 0] & 0x1f) << 3;
+ uint8_t a = (p_buffer[i + 1] & 0x80) ? 0xff : 0;
+
+ TGA_PUT_PIXEL(r, g, b, alpha_bits ? a : 0xff);
+
+ x += x_step;
+ i += 2;
+ }
+ x = x_start;
+ y += y_step;
+ }
} else if (p_header.pixel_depth == 24) {
while (y != y_end) {
while (x != x_end) {
@@ -277,7 +298,7 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField
err = FAILED;
}
- if (!(tga_header.pixel_depth == 8 || tga_header.pixel_depth == 24 || tga_header.pixel_depth == 32)) {
+ if (!(tga_header.pixel_depth == 8 || tga_header.pixel_depth == 16 || tga_header.pixel_depth == 24 || tga_header.pixel_depth == 32)) {
err = FAILED;
}
diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h
index b257ed110d..de964373ed 100644
--- a/modules/tga/image_loader_tga.h
+++ b/modules/tga/image_loader_tga.h
@@ -33,6 +33,8 @@
#include "core/io/image_loader.h"
+#define TGA_IMAGE_DESCRIPTOR_ALPHA_MASK 0xf
+
class ImageLoaderTGA : public ImageFormatLoader {
enum tga_type_e {
TGA_TYPE_NO_DATA = 0,
diff --git a/platform/android/detect.py b/platform/android/detect.py
index a31bba745f..2ff9cd3dc5 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -121,16 +121,12 @@ def configure(env):
# `-O2` is more friendly to debuggers than `-O3`, leading to better crash backtraces
# when using `target=release_debug`.
opt = "-O3" if env["target"] == "release" else "-O2"
- env.Append(CCFLAGS=[opt, "-fomit-frame-pointer"])
+ env.Append(CCFLAGS=[opt])
elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["-Oz"])
- env.Append(CPPDEFINES=["NDEBUG"])
- env.Append(CCFLAGS=["-ftree-vectorize"])
elif env["target"] == "debug":
env.Append(LINKFLAGS=["-O0"])
- env.Append(CCFLAGS=["-O0", "-g", "-fno-limit-debug-info"])
- env.Append(CPPDEFINES=["_DEBUG"])
- env.Append(CPPFLAGS=["-UNDEBUG"])
+ env.Append(CCFLAGS=["-O0", "-g"])
# LTO
diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h
index 9a1a877b6f..24995147d4 100644
--- a/platform/android/java_godot_io_wrapper.h
+++ b/platform/android/java_godot_io_wrapper.h
@@ -28,9 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-// note, swapped java and godot around in the file name so all the java
-// wrappers are together
-
#ifndef JAVA_GODOT_IO_WRAPPER_H
#define JAVA_GODOT_IO_WRAPPER_H
diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h
index a6c7853107..0e96a4e1f3 100644
--- a/platform/android/java_godot_wrapper.h
+++ b/platform/android/java_godot_wrapper.h
@@ -28,9 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-// note, swapped java and godot around in the file name so all the java
-// wrappers are together
-
#ifndef JAVA_GODOT_WRAPPER_H
#define JAVA_GODOT_WRAPPER_H
diff --git a/platform/ios/detect.py b/platform/ios/detect.py
index d5e6ee4b46..0f277d6b3a 100644
--- a/platform/ios/detect.py
+++ b/platform/ios/detect.py
@@ -55,20 +55,19 @@ def configure(env):
## Build type
if env["target"].startswith("release"):
- env.Append(CPPDEFINES=["NDEBUG", ("NS_BLOCK_ASSERTIONS", 1)])
+ env.Append(CPPDEFINES=[("NS_BLOCK_ASSERTIONS", 1)])
if env["optimize"] == "speed": # optimize for speed (default)
# `-O2` is more friendly to debuggers than `-O3`, leading to better crash backtraces
# when using `target=release_debug`.
opt = "-O3" if env["target"] == "release" else "-O2"
- env.Append(CCFLAGS=[opt, "-ftree-vectorize", "-fomit-frame-pointer"])
+ env.Append(CCFLAGS=[opt])
env.Append(LINKFLAGS=[opt])
elif env["optimize"] == "size": # optimize for size
- env.Append(CCFLAGS=["-Os", "-ftree-vectorize"])
+ env.Append(CCFLAGS=["-Os"])
env.Append(LINKFLAGS=["-Os"])
elif env["target"] == "debug":
- env.Append(CCFLAGS=["-gdwarf-2", "-O0"])
- env.Append(CPPDEFINES=["_DEBUG", ("DEBUG", 1)])
+ env.Append(CCFLAGS=["-g", "-O0"])
## LTO
diff --git a/platform/ios/os_ios.h b/platform/ios/os_ios.h
index 00d91da771..400040875f 100644
--- a/platform/ios/os_ios.h
+++ b/platform/ios/os_ios.h
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef IOS_ENABLED
-
#ifndef OS_IOS_H
#define OS_IOS_H
+#ifdef IOS_ENABLED
+
#include "drivers/coreaudio/audio_driver_coreaudio.h"
#include "drivers/unix/os_unix.h"
#include "ios.h"
@@ -124,6 +124,6 @@ public:
void on_focus_in();
};
-#endif // OS_IOS_H
+#endif // IOS_ENABLED
#endif // OS_IOS_H
diff --git a/platform/linuxbsd/detect_prime_x11.h b/platform/linuxbsd/detect_prime_x11.h
index 21ebaead32..7eb7064cc5 100644
--- a/platform/linuxbsd/detect_prime_x11.h
+++ b/platform/linuxbsd/detect_prime_x11.h
@@ -28,11 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef X11_ENABLED
-#if defined(GLES3_ENABLED)
+#ifndef DETECT_PRIME_X11_H
+#define DETECT_PRIME_X11_H
+
+#if defined(X11_ENABLED) && defined(GLES3_ENABLED)
int detect_prime();
-#endif
+#endif // X11_ENABLED && GLES3_ENABLED
#endif // DETECT_PRIME_X11_H
diff --git a/platform/macos/detect.py b/platform/macos/detect.py
index 834ac935d8..58d9c0e99f 100644
--- a/platform/macos/detect.py
+++ b/platform/macos/detect.py
@@ -88,9 +88,9 @@ def configure(env):
if env["target"] == "release":
if env["optimize"] == "speed": # optimize for speed (default)
- env.Prepend(CCFLAGS=["-O3", "-fomit-frame-pointer", "-ftree-vectorize"])
+ env.Prepend(CCFLAGS=["-O3"])
elif env["optimize"] == "size": # optimize for size
- env.Prepend(CCFLAGS=["-Os", "-ftree-vectorize"])
+ env.Prepend(CCFLAGS=["-Os"])
if env["arch"] != "arm64":
env.Prepend(CCFLAGS=["-msse2"])
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index a27e0d5efa..e72273a681 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -179,6 +179,12 @@ private:
IOPMAssertionID screen_keep_on_assertion = kIOPMNullAssertionID;
+ struct MenuCall {
+ Variant tag;
+ Callable callback;
+ };
+ Vector<MenuCall> deferred_menu_calls;
+
const NSMenu *_get_menu_root(const String &p_menu_root) const;
NSMenu *_get_menu_root(const String &p_menu_root);
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index e1d0d99165..1914c5f35d 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -565,11 +565,11 @@ void DisplayServerMacOS::menu_callback(id p_sender) {
}
if (value->callback != Callable()) {
- Variant tag = value->meta;
- Variant *tagp = &tag;
- Variant ret;
- Callable::CallError ce;
- value->callback.callp((const Variant **)&tagp, 1, ret, ce);
+ MenuCall mc;
+ mc.tag = value->meta;
+ mc.callback = value->callback;
+ deferred_menu_calls.push_back(mc);
+ // Do not run callback from here! If it is opening a new window or calling process_events, it will corrupt OS event queue and crash.
}
}
}
@@ -2213,7 +2213,9 @@ void DisplayServerMacOS::show_window(WindowID p_id) {
WindowData &wd = windows[p_id];
popup_open(p_id);
- if (wd.no_focus || wd.is_popup) {
+ if ([wd.window_object isMiniaturized]) {
+ return;
+ } else if (wd.no_focus || wd.is_popup) {
[wd.window_object orderFront:nil];
} else {
[wd.window_object makeKeyAndOrderFront:nil];
@@ -2370,6 +2372,10 @@ void DisplayServerMacOS::window_set_position(const Point2i &p_position, WindowID
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
+ if ([wd.window_object isZoomed]) {
+ return;
+ }
+
Point2i position = p_position;
// OS X native y-coordinate relative to _get_screens_origin() is negative,
// Godot passes a positive value.
@@ -2494,6 +2500,10 @@ void DisplayServerMacOS::window_set_size(const Size2i p_size, WindowID p_window)
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
+ if ([wd.window_object isZoomed]) {
+ return;
+ }
+
Size2i size = p_size / screen_get_max_scale();
NSPoint top_left;
@@ -2654,21 +2664,17 @@ Vector2i DisplayServerMacOS::window_get_safe_title_margins(WindowID p_window) co
ERR_FAIL_COND_V(!windows.has(p_window), Vector2i());
const WindowData &wd = windows[p_window];
- float max_x = 0.f;
- NSButton *cb = [wd.window_object standardWindowButton:NSWindowCloseButton];
- if (cb) {
- max_x = MAX(max_x, [cb frame].origin.x + [cb frame].size.width);
- }
- NSButton *mb = [wd.window_object standardWindowButton:NSWindowMiniaturizeButton];
- if (mb) {
- max_x = MAX(max_x, [mb frame].origin.x + [mb frame].size.width);
- }
- NSButton *zb = [wd.window_object standardWindowButton:NSWindowZoomButton];
- if (zb) {
- max_x = MAX(max_x, [zb frame].origin.x + [zb frame].size.width);
+ if (!wd.window_button_view) {
+ return Vector2i();
}
- return Vector2i(max_x * screen_get_max_scale(), 0);
+ float max_x = wd.wb_offset.x + [wd.window_button_view frame].size.width;
+
+ if ([wd.window_object windowTitlebarLayoutDirection] == NSUserInterfaceLayoutDirectionRightToLeft) {
+ return Vector2i(0, max_x * screen_get_max_scale());
+ } else {
+ return Vector2i(max_x * screen_get_max_scale(), 0);
+ }
}
void DisplayServerMacOS::window_set_custom_window_buttons(WindowData &p_wd, bool p_enabled) {
@@ -2677,7 +2683,11 @@ void DisplayServerMacOS::window_set_custom_window_buttons(WindowData &p_wd, bool
p_wd.window_button_view = nil;
}
if (p_enabled) {
- float window_buttons_spacing = NSMinX([[p_wd.window_object standardWindowButton:NSWindowMiniaturizeButton] frame]) - NSMinX([[p_wd.window_object standardWindowButton:NSWindowCloseButton] frame]);
+ float cb_frame = NSMinX([[p_wd.window_object standardWindowButton:NSWindowCloseButton] frame]);
+ float mb_frame = NSMinX([[p_wd.window_object standardWindowButton:NSWindowMiniaturizeButton] frame]);
+ bool is_rtl = ([p_wd.window_object windowTitlebarLayoutDirection] == NSUserInterfaceLayoutDirectionRightToLeft);
+
+ float window_buttons_spacing = (is_rtl) ? (cb_frame - mb_frame) : (mb_frame - cb_frame);
[p_wd.window_object setTitleVisibility:NSWindowTitleHidden];
[[p_wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:YES];
@@ -2685,7 +2695,7 @@ void DisplayServerMacOS::window_set_custom_window_buttons(WindowData &p_wd, bool
[[p_wd.window_object standardWindowButton:NSWindowCloseButton] setHidden:YES];
p_wd.window_button_view = [[GodotButtonView alloc] initWithFrame:NSZeroRect];
- [p_wd.window_button_view initButtons:window_buttons_spacing offset:NSMakePoint(p_wd.wb_offset.x, p_wd.wb_offset.y)];
+ [p_wd.window_button_view initButtons:window_buttons_spacing offset:NSMakePoint(p_wd.wb_offset.x, p_wd.wb_offset.y) rtl:is_rtl];
[p_wd.window_view addSubview:p_wd.window_button_view];
} else {
[p_wd.window_object setTitleVisibility:NSWindowTitleVisible];
@@ -2731,6 +2741,7 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win
}
}
[wd.window_object setFrame:rect display:YES];
+ send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_TITLEBAR_CHANGE);
} break;
case WINDOW_FLAG_BORDERLESS: {
// OrderOut prevents a lose focus bug with the window.
@@ -2750,7 +2761,9 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win
}
_update_window_style(wd);
if ([wd.window_object isVisible]) {
- if (wd.no_focus || wd.is_popup) {
+ if ([wd.window_object isMiniaturized]) {
+ return;
+ } else if (wd.no_focus || wd.is_popup) {
[wd.window_object orderFront:nil];
} else {
[wd.window_object makeKeyAndOrderFront:nil];
@@ -3267,6 +3280,16 @@ void DisplayServerMacOS::process_events() {
[NSApp sendEvent:event];
}
+ // Process "menu_callback"s.
+ for (MenuCall &E : deferred_menu_calls) {
+ Variant tag = E.tag;
+ Variant *tagp = &tag;
+ Variant ret;
+ Callable::CallError ce;
+ E.callback.callp((const Variant **)&tagp, 1, ret, ce);
+ }
+ deferred_menu_calls.clear();
+
if (!drop_events) {
_process_key_events();
Input::get_singleton()->flush_buffered_events();
diff --git a/platform/macos/export/codesign.h b/platform/macos/export/codesign.h
index fea7b117d0..01e97bca81 100644
--- a/platform/macos/export/codesign.h
+++ b/platform/macos/export/codesign.h
@@ -28,6 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef MACOS_CODESIGN_H
+#define MACOS_CODESIGN_H
+
// macOS code signature creation utility.
//
// Current implementation has the following limitation:
@@ -38,9 +41,6 @@
// - Requirements code generator is not implemented (only hard-coded requirements for the ad-hoc signing is supported).
// - RFC5652/CMS blob generation is not implemented, supports ad-hoc signing only.
-#ifndef MACOS_CODESIGN_H
-#define MACOS_CODESIGN_H
-
#include "core/crypto/crypto_core.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
diff --git a/platform/macos/export/lipo.h b/platform/macos/export/lipo.h
index 516ef99860..6378f9899c 100644
--- a/platform/macos/export/lipo.h
+++ b/platform/macos/export/lipo.h
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-// Universal / Universal 2 fat binary file creator and extractor.
-
#ifndef MACOS_LIPO_H
#define MACOS_LIPO_H
+// Universal / Universal 2 fat binary file creator and extractor.
+
#include "core/io/file_access.h"
#include "core/object/ref_counted.h"
#include "modules/modules_enabled.gen.h" // For regex.
diff --git a/platform/macos/export/macho.h b/platform/macos/export/macho.h
index 7ef0d9067e..0d42a7013f 100644
--- a/platform/macos/export/macho.h
+++ b/platform/macos/export/macho.h
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-// Mach-O binary object file format parser and editor.
-
#ifndef MACOS_MACHO_H
#define MACOS_MACHO_H
+// Mach-O binary object file format parser and editor.
+
#include "core/crypto/crypto.h"
#include "core/crypto/crypto_core.h"
#include "core/io/file_access.h"
diff --git a/platform/macos/export/plist.h b/platform/macos/export/plist.h
index 79cb928d0a..b3c51a9635 100644
--- a/platform/macos/export/plist.h
+++ b/platform/macos/export/plist.h
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-// Property list file format (application/x-plist) parser, property list ASN-1 serialization.
-
#ifndef MACOS_PLIST_H
#define MACOS_PLIST_H
+// Property list file format (application/x-plist) parser, property list ASN-1 serialization.
+
#include "core/crypto/crypto_core.h"
#include "core/io/file_access.h"
#include "modules/modules_enabled.gen.h" // For regex.
diff --git a/platform/macos/godot_button_view.h b/platform/macos/godot_button_view.h
index e41910878d..e7627a9e9b 100644
--- a/platform/macos/godot_button_view.h
+++ b/platform/macos/godot_button_view.h
@@ -41,9 +41,10 @@
NSPoint offset;
CGFloat spacing;
bool mouse_in_group;
+ bool rtl;
}
-- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset;
+- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset rtl:(bool)is_rtl;
- (void)displayButtons;
@end
diff --git a/platform/macos/godot_button_view.mm b/platform/macos/godot_button_view.mm
index ae04c02bd5..9106f0b0db 100644
--- a/platform/macos/godot_button_view.mm
+++ b/platform/macos/godot_button_view.mm
@@ -39,15 +39,17 @@
offset = NSMakePoint(8, 8);
spacing = 20;
mouse_in_group = false;
+ rtl = false;
return self;
}
-- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset {
+- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset rtl:(bool)is_rtl {
spacing = button_spacing;
+ rtl = is_rtl;
NSButton *close_button = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:NSWindowStyleMaskTitled];
- [close_button setFrameOrigin:NSMakePoint(0, 0)];
+ [close_button setFrameOrigin:NSMakePoint(rtl ? spacing * 2 : 0, 0)];
[self addSubview:close_button];
NSButton *miniaturize_button = [NSWindow standardWindowButton:NSWindowMiniaturizeButton forStyleMask:NSWindowStyleMaskTitled];
@@ -55,13 +57,17 @@
[self addSubview:miniaturize_button];
NSButton *zoom_button = [NSWindow standardWindowButton:NSWindowZoomButton forStyleMask:NSWindowStyleMaskTitled];
- [zoom_button setFrameOrigin:NSMakePoint(spacing * 2, 0)];
+ [zoom_button setFrameOrigin:NSMakePoint(rtl ? 0 : spacing * 2, 0)];
[self addSubview:zoom_button];
offset.y = button_offset.y - zoom_button.frame.size.height / 2;
offset.x = button_offset.x - zoom_button.frame.size.width / 2;
- [self setFrameSize:NSMakeSize(zoom_button.frame.origin.x + zoom_button.frame.size.width, zoom_button.frame.size.height)];
+ if (rtl) {
+ [self setFrameSize:NSMakeSize(close_button.frame.origin.x + close_button.frame.size.width, close_button.frame.size.height)];
+ } else {
+ [self setFrameSize:NSMakeSize(zoom_button.frame.origin.x + zoom_button.frame.size.width, zoom_button.frame.size.height)];
+ }
[self displayButtons];
}
@@ -70,8 +76,13 @@
return;
}
- [self setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
- [self setFrameOrigin:NSMakePoint(offset.x, self.window.frame.size.height - self.frame.size.height - offset.y)];
+ if (rtl) {
+ [self setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
+ [self setFrameOrigin:NSMakePoint(self.window.frame.size.width - self.frame.size.width - offset.x, self.window.frame.size.height - self.frame.size.height - offset.y)];
+ } else {
+ [self setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
+ [self setFrameOrigin:NSMakePoint(offset.x, self.window.frame.size.height - self.frame.size.height - offset.y)];
+ }
}
- (BOOL)_mouseInGroup:(NSButton *)button {
diff --git a/platform/macos/godot_window.h b/platform/macos/godot_window.h
index 9fc5599e86..d3653fda82 100644
--- a/platform/macos/godot_window.h
+++ b/platform/macos/godot_window.h
@@ -38,9 +38,11 @@
@interface GodotWindow : NSWindow {
DisplayServer::WindowID window_id;
+ NSTimeInterval anim_duration;
}
- (void)setWindowID:(DisplayServer::WindowID)wid;
+- (void)setAnimDuration:(NSTimeInterval)duration;
@end
diff --git a/platform/macos/godot_window.mm b/platform/macos/godot_window.mm
index e205e7546d..bc51da4f72 100644
--- a/platform/macos/godot_window.mm
+++ b/platform/macos/godot_window.mm
@@ -37,9 +37,22 @@
- (id)init {
self = [super init];
window_id = DisplayServer::INVALID_WINDOW_ID;
+ anim_duration = -1.0f;
return self;
}
+- (void)setAnimDuration:(NSTimeInterval)duration {
+ anim_duration = duration;
+}
+
+- (NSTimeInterval)animationResizeTime:(NSRect)newFrame {
+ if (anim_duration > 0) {
+ return anim_duration;
+ } else {
+ return [super animationResizeTime:newFrame];
+ }
+}
+
- (void)setWindowID:(DisplayServerMacOS::WindowID)wid {
window_id = wid;
}
diff --git a/platform/macos/godot_window_delegate.h b/platform/macos/godot_window_delegate.h
index 98c226aa2f..01cc13a016 100644
--- a/platform/macos/godot_window_delegate.h
+++ b/platform/macos/godot_window_delegate.h
@@ -38,6 +38,8 @@
@interface GodotWindowDelegate : NSObject <NSWindowDelegate> {
DisplayServer::WindowID window_id;
+ NSRect old_frame;
+ NSWindowStyleMask old_style_mask;
}
- (void)setWindowID:(DisplayServer::WindowID)wid;
diff --git a/platform/macos/godot_window_delegate.mm b/platform/macos/godot_window_delegate.mm
index 94d40924b2..279fd2a359 100644
--- a/platform/macos/godot_window_delegate.mm
+++ b/platform/macos/godot_window_delegate.mm
@@ -32,6 +32,7 @@
#include "display_server_macos.h"
#include "godot_button_view.h"
+#include "godot_window.h"
@implementation GodotWindowDelegate
@@ -69,6 +70,26 @@
ds->window_destroy(window_id);
}
+- (NSArray<NSWindow *> *)customWindowsToEnterFullScreenForWindow:(NSWindow *)window {
+ DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
+ if (!ds || !ds->has_window(window_id)) {
+ return nullptr;
+ }
+
+ old_frame = [window frame];
+ old_style_mask = [window styleMask];
+
+ NSMutableArray<NSWindow *> *windows = [[NSMutableArray alloc] init];
+ [windows addObject:window];
+
+ return windows;
+}
+
+- (void)window:(NSWindow *)window startCustomAnimationToEnterFullScreenWithDuration:(NSTimeInterval)duration {
+ [(GodotWindow *)window setAnimDuration:duration];
+ [window setFrame:[[window screen] frame] display:YES animate:YES];
+}
+
- (void)windowDidEnterFullScreen:(NSNotification *)notification {
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
if (!ds || !ds->has_window(window_id)) {
@@ -81,6 +102,7 @@
// Reset window size limits.
[wd.window_object setContentMinSize:NSMakeSize(0, 0)];
[wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
+ [(GodotWindow *)wd.window_object setAnimDuration:-1.0f];
// Reset custom window buttons.
if ([wd.window_object styleMask] & NSWindowStyleMaskFullSizeContentView) {
@@ -89,6 +111,33 @@
// Force window resize event.
[self windowDidResize:notification];
+ ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_TITLEBAR_CHANGE);
+}
+
+- (NSArray<NSWindow *> *)customWindowsToExitFullScreenForWindow:(NSWindow *)window {
+ DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
+ if (!ds || !ds->has_window(window_id)) {
+ return nullptr;
+ }
+
+ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
+
+ // Restore custom window buttons.
+ if ([wd.window_object styleMask] & NSWindowStyleMaskFullSizeContentView) {
+ ds->window_set_custom_window_buttons(wd, true);
+ }
+
+ ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_TITLEBAR_CHANGE);
+
+ NSMutableArray<NSWindow *> *windows = [[NSMutableArray alloc] init];
+ [windows addObject:wd.window_object];
+ return windows;
+}
+
+- (void)window:(NSWindow *)window startCustomAnimationToExitFullScreenWithDuration:(NSTimeInterval)duration {
+ [(GodotWindow *)window setAnimDuration:duration];
+ [window setStyleMask:old_style_mask];
+ [window setFrame:old_frame display:YES animate:YES];
}
- (void)windowDidExitFullScreen:(NSNotification *)notification {
@@ -100,6 +149,8 @@
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
wd.fullscreen = false;
+ [(GodotWindow *)wd.window_object setAnimDuration:-1.0f];
+
// Set window size limits.
const float scale = ds->screen_get_max_scale();
if (wd.min_size != Size2i()) {
@@ -111,11 +162,6 @@
[wd.window_object setContentMaxSize:NSMakeSize(size.x, size.y)];
}
- // Restore custom window buttons.
- if ([wd.window_object styleMask] & NSWindowStyleMaskFullSizeContentView) {
- ds->window_set_custom_window_buttons(wd, true);
- }
-
// Restore resizability state.
if (wd.resize_disabled) {
[wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable];
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 52a959b34a..095d688213 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -350,7 +350,6 @@ def configure_msvc(env, vcvars_msvc_config):
elif env["target"] == "debug":
env.AppendUnique(CCFLAGS=["/Zi", "/FS", "/Od", "/EHsc"])
- # Allow big objects. Only needed for debug, see MinGW branch for rationale.
env.Append(LINKFLAGS=["/DEBUG"])
if env["debug_symbols"]:
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 4553f31480..b9e6f7b843 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -685,7 +685,13 @@ void DisplayServerWindows::show_window(WindowID p_id) {
_update_window_style(p_id);
}
- if (wd.no_focus || wd.is_popup) {
+ if (wd.maximized) {
+ ShowWindow(wd.hWnd, SW_SHOWMAXIMIZED);
+ SetForegroundWindow(wd.hWnd); // Slightly higher priority.
+ SetFocus(wd.hWnd); // Set keyboard focus.
+ } else if (wd.minimized) {
+ ShowWindow(wd.hWnd, SW_SHOWMINIMIZED);
+ } else if (wd.no_focus || wd.is_popup) {
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
ShowWindow(wd.hWnd, SW_SHOWNA);
} else {
@@ -926,7 +932,7 @@ 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 || wd.maximized) {
return;
}
@@ -1059,6 +1065,10 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
+ if (wd.fullscreen || wd.maximized) {
+ return;
+ }
+
int w = p_size.width;
int h = p_size.height;
@@ -1076,10 +1086,6 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo
}
#endif
- if (wd.fullscreen) {
- return;
- }
-
RECT rect;
GetWindowRect(wd.hWnd, &rect);
@@ -3346,7 +3352,7 @@ void DisplayServerWindows::_process_key_events() {
k->set_ctrl_pressed(ke.control);
k->set_meta_pressed(ke.meta);
k->set_pressed(true);
- k->set_keycode((Key)KeyMappingWindows::get_keysym(ke.wParam));
+ k->set_keycode((Key)KeyMappingWindows::get_keysym(MapVirtualKey((ke.lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK)));
k->set_physical_keycode((Key)(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24))));
k->set_unicode(unicode);
if (k->get_unicode() && gr_mem) {
@@ -3599,6 +3605,16 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
wd.wtctx = 0;
}
+ if (p_mode == WINDOW_MODE_MAXIMIZED) {
+ wd.maximized = true;
+ wd.minimized = false;
+ }
+
+ if (p_mode == WINDOW_MODE_MINIMIZED) {
+ wd.maximized = false;
+ wd.minimized = true;
+ }
+
wd.last_pressure = 0;
wd.last_pressure_update = 0;
wd.last_tilt = Vector2();
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index b1e2875a8b..6e8ecb13b1 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -354,10 +354,13 @@ void NavigationPolygon::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines");
}
+/////////////////////////////
+
void NavigationRegion2D::set_enabled(bool p_enabled) {
if (enabled == p_enabled) {
return;
}
+
enabled = p_enabled;
if (!is_inside_tree()) {
@@ -384,35 +387,50 @@ bool NavigationRegion2D::is_enabled() const {
}
void NavigationRegion2D::set_navigation_layers(uint32_t p_navigation_layers) {
- NavigationServer2D::get_singleton()->region_set_navigation_layers(region, p_navigation_layers);
+ if (navigation_layers == p_navigation_layers) {
+ return;
+ }
+
+ navigation_layers = p_navigation_layers;
+
+ NavigationServer2D::get_singleton()->region_set_navigation_layers(region, navigation_layers);
}
uint32_t NavigationRegion2D::get_navigation_layers() const {
- return NavigationServer2D::get_singleton()->region_get_navigation_layers(region);
+ return navigation_layers;
}
void NavigationRegion2D::set_navigation_layer_value(int p_layer_number, bool p_value) {
ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive.");
+
uint32_t _navigation_layers = get_navigation_layers();
+
if (p_value) {
_navigation_layers |= 1 << (p_layer_number - 1);
} else {
_navigation_layers &= ~(1 << (p_layer_number - 1));
}
+
set_navigation_layers(_navigation_layers);
}
bool NavigationRegion2D::get_navigation_layer_value(int p_layer_number) const {
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive.");
+
return get_navigation_layers() & (1 << (p_layer_number - 1));
}
void NavigationRegion2D::set_enter_cost(real_t p_enter_cost) {
ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive.");
- enter_cost = MAX(p_enter_cost, 0.0);
- NavigationServer2D::get_singleton()->region_set_enter_cost(region, p_enter_cost);
+ if (Math::is_equal_approx(enter_cost, p_enter_cost)) {
+ return;
+ }
+
+ enter_cost = p_enter_cost;
+
+ NavigationServer2D::get_singleton()->region_set_enter_cost(region, enter_cost);
}
real_t NavigationRegion2D::get_enter_cost() const {
@@ -421,7 +439,12 @@ real_t NavigationRegion2D::get_enter_cost() const {
void NavigationRegion2D::set_travel_cost(real_t p_travel_cost) {
ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
- travel_cost = MAX(p_travel_cost, 0.0);
+ if (Math::is_equal_approx(travel_cost, p_travel_cost)) {
+ return;
+ }
+
+ travel_cost = p_travel_cost;
+
NavigationServer2D::get_singleton()->region_set_travel_cost(region, travel_cost);
}
@@ -433,7 +456,6 @@ RID NavigationRegion2D::get_region_rid() const {
return region;
}
-/////////////////////////////
#ifdef TOOLS_ENABLED
Rect2 NavigationRegion2D::_edit_get_rect() const {
return navpoly.is_valid() ? navpoly->_edit_get_rect() : Rect2();
diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h
index 893de41a94..c630e20780 100644
--- a/scene/2d/navigation_region_2d.h
+++ b/scene/2d/navigation_region_2d.h
@@ -96,10 +96,10 @@ class NavigationRegion2D : public Node2D {
bool enabled = true;
RID region;
- Ref<NavigationPolygon> navpoly;
-
+ uint32_t navigation_layers = 1;
real_t enter_cost = 0.0;
real_t travel_cost = 1.0;
+ Ref<NavigationPolygon> navpoly;
void _navpoly_changed();
void _map_changed(RID p_RID);
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 16686f4fe6..4e6b37a860 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -62,7 +62,7 @@ Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_distance, bool p
if (move_and_collide(parameters, result, p_test_only)) {
// Create a new instance when the cached reference is invalid or still in use in script.
- if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) {
+ if (motion_cache.is_null() || motion_cache->get_reference_count() > 1) {
motion_cache.instantiate();
motion_cache->owner = this;
}
@@ -1544,7 +1544,7 @@ Ref<KinematicCollision2D> CharacterBody2D::_get_slide_collision(int p_bounce) {
}
// Create a new instance when the cached reference is invalid or still in use in script.
- if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->reference_get_count() > 1) {
+ if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->get_reference_count() > 1) {
slide_colliders.write[p_bounce].instantiate();
slide_colliders.write[p_bounce]->owner = this;
}
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index bfc4353138..b060d314ba 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -37,6 +37,7 @@ void NavigationRegion3D::set_enabled(bool p_enabled) {
if (enabled == p_enabled) {
return;
}
+
enabled = p_enabled;
if (!is_inside_tree()) {
@@ -81,35 +82,50 @@ bool NavigationRegion3D::is_enabled() const {
}
void NavigationRegion3D::set_navigation_layers(uint32_t p_navigation_layers) {
- NavigationServer3D::get_singleton()->region_set_navigation_layers(region, p_navigation_layers);
+ if (navigation_layers == p_navigation_layers) {
+ return;
+ }
+
+ navigation_layers = p_navigation_layers;
+
+ NavigationServer3D::get_singleton()->region_set_navigation_layers(region, navigation_layers);
}
uint32_t NavigationRegion3D::get_navigation_layers() const {
- return NavigationServer3D::get_singleton()->region_get_navigation_layers(region);
+ return navigation_layers;
}
void NavigationRegion3D::set_navigation_layer_value(int p_layer_number, bool p_value) {
ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive.");
+
uint32_t _navigation_layers = get_navigation_layers();
+
if (p_value) {
_navigation_layers |= 1 << (p_layer_number - 1);
} else {
_navigation_layers &= ~(1 << (p_layer_number - 1));
}
+
set_navigation_layers(_navigation_layers);
}
bool NavigationRegion3D::get_navigation_layer_value(int p_layer_number) const {
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive.");
+
return get_navigation_layers() & (1 << (p_layer_number - 1));
}
void NavigationRegion3D::set_enter_cost(real_t p_enter_cost) {
ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive.");
- enter_cost = MAX(p_enter_cost, 0.0);
- NavigationServer3D::get_singleton()->region_set_enter_cost(region, p_enter_cost);
+ if (Math::is_equal_approx(enter_cost, p_enter_cost)) {
+ return;
+ }
+
+ enter_cost = p_enter_cost;
+
+ NavigationServer3D::get_singleton()->region_set_enter_cost(region, enter_cost);
}
real_t NavigationRegion3D::get_enter_cost() const {
@@ -118,7 +134,12 @@ real_t NavigationRegion3D::get_enter_cost() const {
void NavigationRegion3D::set_travel_cost(real_t p_travel_cost) {
ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
- travel_cost = MAX(p_travel_cost, 0.0);
+ if (Math::is_equal_approx(travel_cost, p_travel_cost)) {
+ return;
+ }
+
+ travel_cost = p_travel_cost;
+
NavigationServer3D::get_singleton()->region_set_travel_cost(region, travel_cost);
}
@@ -130,8 +151,6 @@ RID NavigationRegion3D::get_region_rid() const {
return region;
}
-/////////////////////////////
-
void NavigationRegion3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h
index 7d16d81d77..660538d314 100644
--- a/scene/3d/navigation_region_3d.h
+++ b/scene/3d/navigation_region_3d.h
@@ -39,10 +39,10 @@ class NavigationRegion3D : public Node3D {
bool enabled = true;
RID region;
- Ref<NavigationMesh> navmesh;
-
+ uint32_t navigation_layers = 1;
real_t enter_cost = 0.0;
real_t travel_cost = 1.0;
+ Ref<NavigationMesh> navmesh;
Thread bake_thread;
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 0eefb45c04..594e94644c 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -100,7 +100,7 @@ Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_distance, bool p
if (move_and_collide(parameters, result, p_test_only)) {
// Create a new instance when the cached reference is invalid or still in use in script.
- if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) {
+ if (motion_cache.is_null() || motion_cache->get_reference_count() > 1) {
motion_cache.instantiate();
motion_cache->owner = this;
}
@@ -1797,7 +1797,7 @@ Ref<KinematicCollision3D> CharacterBody3D::_get_slide_collision(int p_bounce) {
}
// Create a new instance when the cached reference is invalid or still in use in script.
- if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->reference_get_count() > 1) {
+ if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->get_reference_count() > 1) {
slide_colliders.write[p_bounce].instantiate();
slide_colliders.write[p_bounce]->owner = this;
}
diff --git a/scene/animation/easing_equations.h b/scene/animation/easing_equations.h
index 094829e406..03d9e16454 100644
--- a/scene/animation/easing_equations.h
+++ b/scene/animation/easing_equations.h
@@ -28,6 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef EASING_EQUATIONS_H
+#define EASING_EQUATIONS_H
+
/*
* Derived from Robert Penner's easing equations: http://robertpenner.com/easing/
*
@@ -52,9 +55,6 @@
* SOFTWARE.
*/
-#ifndef EASING_EQUATIONS_H
-#define EASING_EQUATIONS_H
-
namespace linear {
static real_t in(real_t t, real_t b, real_t c, real_t d) {
return c * t / d + b;
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index f6e0e4216d..8069ab465b 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -1216,30 +1216,39 @@ bool CodeEdit::is_drawing_executing_lines_gutter() const {
}
void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) {
+ bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT);
+
if (draw_breakpoints && breakpoint_icon.is_valid()) {
bool hovering = p_region.has_point(get_local_mouse_pos());
bool breakpointed = is_line_breakpointed(p_line);
- if (breakpointed || (hovering && !is_dragging_cursor())) {
+ if (breakpointed || (hovering && !is_dragging_cursor() && !shift_pressed)) {
int padding = p_region.size.x / 6;
Rect2 icon_region = p_region;
icon_region.position += Point2(padding, padding);
icon_region.size -= Point2(padding, padding) * 2;
- // Darken icon when hovering & not yet breakpointed.
- Color use_color = hovering && !breakpointed ? breakpoint_color.darkened(0.4) : breakpoint_color;
+ // Darken icon when hovering, shift not pressed & not yet breakpointed.
+ Color use_color = hovering && !breakpointed && !shift_pressed ? breakpoint_color.darkened(0.4) : breakpoint_color;
breakpoint_icon->draw_rect(get_canvas_item(), icon_region, false, use_color);
}
}
- if (draw_bookmarks && is_line_bookmarked(p_line) && bookmark_icon.is_valid()) {
- int horizontal_padding = p_region.size.x / 2;
- int vertical_padding = p_region.size.y / 4;
+ if (draw_bookmarks && bookmark_icon.is_valid()) {
+ bool hovering = p_region.has_point(get_local_mouse_pos());
+ bool bookmarked = is_line_bookmarked(p_line);
- Rect2 bookmark_region = p_region;
- bookmark_region.position += Point2(horizontal_padding, 0);
- bookmark_region.size -= Point2(horizontal_padding * 1.1, vertical_padding);
- bookmark_icon->draw_rect(get_canvas_item(), bookmark_region, false, bookmark_color);
+ if (bookmarked || (hovering && !is_dragging_cursor() && shift_pressed)) {
+ int horizontal_padding = p_region.size.x / 2;
+ int vertical_padding = p_region.size.y / 4;
+ Rect2 icon_region = p_region;
+ icon_region.position += Point2(horizontal_padding, 0);
+ icon_region.size -= Point2(horizontal_padding * 1.1, vertical_padding);
+
+ // Darken icon when hovering, shift pressed & not yet bookmarked.
+ Color use_color = hovering && !bookmarked && shift_pressed ? bookmark_color.darkened(0.4) : bookmark_color;
+ bookmark_icon->draw_rect(get_canvas_item(), icon_region, false, use_color);
+ }
}
if (draw_executing_lines && is_line_executing(p_line) && executing_line_icon.is_valid()) {
@@ -2378,9 +2387,13 @@ int CodeEdit::_get_auto_brace_pair_close_at_pos(int p_line, int p_col) {
/* Gutters */
void CodeEdit::_gutter_clicked(int p_line, int p_gutter) {
+ bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT);
+
if (p_gutter == main_gutter) {
- if (draw_breakpoints) {
+ if (draw_breakpoints && !shift_pressed) {
set_line_as_breakpoint(p_line, !is_line_breakpointed(p_line));
+ } else if (draw_bookmarks && shift_pressed) {
+ set_line_as_bookmarked(p_line, !is_line_bookmarked(p_line));
}
return;
}
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 4a1f2ab7c6..5751c54877 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -427,12 +427,15 @@ void ColorPicker::_html_submitted(const String &p_html) {
return;
}
- float last_alpha = color.a;
+ Color previous_color = color;
color = Color::html(p_html);
if (!is_editing_alpha()) {
- color.a = last_alpha;
+ color.a = previous_color.a;
}
+ if (color == previous_color) {
+ return;
+ }
if (!is_inside_tree()) {
return;
}
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 008109da65..357f2480bd 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -662,19 +662,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
pos.x = get_size().width - pos.x;
}
- int closest = -1;
-
- for (int i = 0; i < items.size(); i++) {
- Rect2 rc = items[i].rect_cache;
- if (i % current_columns == current_columns - 1) {
- rc.size.width = get_size().width; //not right but works
- }
-
- if (rc.has_point(pos)) {
- closest = i;
- break;
- }
- }
+ int closest = get_item_at_position(mb->get_position(), true);
if (closest != -1 && (mb->get_button_index() == MouseButton::LEFT || (allow_rmb_select && mb->get_button_index() == MouseButton::RIGHT))) {
int i = closest;
@@ -1467,7 +1455,7 @@ int ItemList::get_item_at_position(const Point2 &p_pos, bool p_exact) const {
for (int i = 0; i < items.size(); i++) {
Rect2 rc = items[i].rect_cache;
if (i % current_columns == current_columns - 1) {
- rc.size.width = get_size().width - rc.position.x; //make sure you can still select the last item when clicking past the column
+ rc.size.width = get_size().width - rc.position.x; // Make sure you can still select the last item when clicking past the column.
}
if (rc.has_point(pos)) {
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index ef0172c612..3c45b90612 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -4703,7 +4703,10 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p
queue_redraw();
return true;
}
- p_search_previous ? current_line-- : current_line++;
+
+ if (current_line != ending_line) {
+ p_search_previous ? current_line-- : current_line++;
+ }
}
if (p_from_selection && selection.active) {
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 318447ecd8..38302136d6 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1201,13 +1201,14 @@ void TextEdit::_notification(int p_what) {
current_color.a = font_readonly_color.a;
}
}
+ Color gl_color = current_color;
if (selection.active && line >= selection.from_line && line <= selection.to_line) { // Selection
int sel_from = (line > selection.from_line) ? TS->shaped_text_get_range(rid).x : selection.from_column;
int sel_to = (line < selection.to_line) ? TS->shaped_text_get_range(rid).y : selection.to_column;
if (glyphs[j].start >= sel_from && glyphs[j].end <= sel_to && override_selected_font_color) {
- current_color = font_selected_color;
+ gl_color = font_selected_color;
}
}
@@ -1217,29 +1218,29 @@ void TextEdit::_notification(int p_what) {
if ((brace_open_match_line == line && brace_open_match_column == glyphs[j].start) ||
(caret.column == glyphs[j].start && caret.line == line && caret_wrap_index == line_wrap_index && (brace_open_matching || brace_open_mismatch))) {
if (brace_open_mismatch) {
- current_color = brace_mismatch_color;
+ gl_color = brace_mismatch_color;
}
Rect2 rect = Rect2(char_pos, ofs_y + font->get_underline_position(font_size), glyphs[j].advance * glyphs[j].repeat, MAX(font->get_underline_thickness(font_size) * get_theme_default_base_scale(), 1));
- draw_rect(rect, current_color);
+ draw_rect(rect, gl_color);
}
if ((brace_close_match_line == line && brace_close_match_column == glyphs[j].start) ||
(caret.column == glyphs[j].start + 1 && caret.line == line && caret_wrap_index == line_wrap_index && (brace_close_matching || brace_close_mismatch))) {
if (brace_close_mismatch) {
- current_color = brace_mismatch_color;
+ gl_color = brace_mismatch_color;
}
Rect2 rect = Rect2(char_pos, ofs_y + font->get_underline_position(font_size), glyphs[j].advance * glyphs[j].repeat, MAX(font->get_underline_thickness(font_size) * get_theme_default_base_scale(), 1));
- draw_rect(rect, current_color);
+ draw_rect(rect, gl_color);
}
}
if (draw_tabs && ((glyphs[j].flags & TextServer::GRAPHEME_IS_TAB) == TextServer::GRAPHEME_IS_TAB)) {
int yofs = (text_height - tab_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index);
- tab_icon->draw(ci, Point2(char_pos, ofs_y + yofs), current_color);
+ tab_icon->draw(ci, Point2(char_pos, ofs_y + yofs), gl_color);
} else if (draw_spaces && ((glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE)) {
int yofs = (text_height - space_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index);
int xofs = (glyphs[j].advance * glyphs[j].repeat - space_icon->get_width()) / 2;
- space_icon->draw(ci, Point2(char_pos + xofs, ofs_y + yofs), current_color);
+ space_icon->draw(ci, Point2(char_pos + xofs, ofs_y + yofs), gl_color);
}
}
@@ -1247,10 +1248,10 @@ void TextEdit::_notification(int p_what) {
for (int k = 0; k < glyphs[j].repeat; k++) {
if (!clipped && (char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) {
if (glyphs[j].font_rid != RID()) {
- TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, current_color);
+ TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, gl_color);
had_glyphs_drawn = true;
} else if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
- TS->draw_hex_code_box(ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, current_color);
+ TS->draw_hex_code_box(ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, gl_color);
had_glyphs_drawn = true;
}
}
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 237c78407b..f82a853e56 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -563,6 +563,57 @@ bool TreeItem::is_collapsed() {
return collapsed;
}
+void TreeItem::set_collapsed_recursive(bool p_collapsed) {
+ if (!tree) {
+ return;
+ }
+
+ set_collapsed(p_collapsed);
+
+ TreeItem *child = get_first_child();
+ while (child) {
+ child->set_collapsed_recursive(p_collapsed);
+ child = child->get_next();
+ }
+}
+
+bool TreeItem::_is_any_collapsed(bool p_only_visible) {
+ TreeItem *child = get_first_child();
+
+ // Check on children directly first (avoid recursing if possible).
+ while (child) {
+ if (child->get_first_child() && child->is_collapsed() && (!p_only_visible || (child->is_visible() && child->get_visible_child_count()))) {
+ return true;
+ }
+ child = child->get_next();
+ }
+
+ child = get_first_child();
+
+ // Otherwise recurse on children.
+ while (child) {
+ if (child->get_first_child() && (!p_only_visible || (child->is_visible() && child->get_visible_child_count())) && child->_is_any_collapsed(p_only_visible)) {
+ return true;
+ }
+ child = child->get_next();
+ }
+
+ return false;
+}
+
+bool TreeItem::is_any_collapsed(bool p_only_visible) {
+ if (p_only_visible && !is_visible()) {
+ return false;
+ }
+
+ // Collapsed if this is collapsed and it has children (only considers visible if only visible is set).
+ if (is_collapsed() && get_first_child() && (!p_only_visible || get_visible_child_count())) {
+ return true;
+ }
+
+ return _is_any_collapsed(p_only_visible);
+}
+
void TreeItem::set_visible(bool p_visible) {
if (visible == p_visible) {
return;
@@ -1406,6 +1457,9 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collapsed", "enable"), &TreeItem::set_collapsed);
ClassDB::bind_method(D_METHOD("is_collapsed"), &TreeItem::is_collapsed);
+ ClassDB::bind_method(D_METHOD("set_collapsed_recursive", "enable"), &TreeItem::set_collapsed_recursive);
+ ClassDB::bind_method(D_METHOD("is_any_collapsed", "only_visible"), &TreeItem::is_any_collapsed, DEFVAL(false));
+
ClassDB::bind_method(D_METHOD("set_visible", "enable"), &TreeItem::set_visible);
ClassDB::bind_method(D_METHOD("is_visible"), &TreeItem::is_visible);
@@ -2572,7 +2626,11 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
}
if (!p_item->disable_folding && !hide_folding && p_item->first_child && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + theme_cache.item_margin))) {
- p_item->set_collapsed(!p_item->is_collapsed());
+ if (enable_recursive_folding && p_mod->is_shift_pressed()) {
+ p_item->set_collapsed_recursive(!p_item->is_collapsed());
+ } else {
+ p_item->set_collapsed(!p_item->is_collapsed());
+ }
return -1;
}
@@ -2623,7 +2681,11 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
}
if (!p_item->disable_folding && !hide_folding && !p_item->cells[col].editable && !p_item->cells[col].selectable && p_item->get_first_child()) {
- p_item->set_collapsed(!p_item->is_collapsed());
+ if (enable_recursive_folding && p_mod->is_shift_pressed()) {
+ p_item->set_collapsed_recursive(!p_item->is_collapsed());
+ } else {
+ p_item->set_collapsed(!p_item->is_collapsed());
+ }
return -1; //collapse/uncollapse because nothing can be done with item
}
@@ -5026,6 +5088,14 @@ bool Tree::is_folding_hidden() const {
return hide_folding;
}
+void Tree::set_enable_recursive_folding(bool p_enable) {
+ enable_recursive_folding = p_enable;
+}
+
+bool Tree::is_recursive_folding_enabled() const {
+ return enable_recursive_folding;
+}
+
void Tree::set_drop_mode_flags(int p_flags) {
if (drop_mode_flags == p_flags) {
return;
@@ -5129,6 +5199,9 @@ void Tree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_hide_folding", "hide"), &Tree::set_hide_folding);
ClassDB::bind_method(D_METHOD("is_folding_hidden"), &Tree::is_folding_hidden);
+ ClassDB::bind_method(D_METHOD("set_enable_recursive_folding", "enable"), &Tree::set_enable_recursive_folding);
+ ClassDB::bind_method(D_METHOD("is_recursive_folding_enabled"), &Tree::is_recursive_folding_enabled);
+
ClassDB::bind_method(D_METHOD("set_drop_mode_flags", "flags"), &Tree::set_drop_mode_flags);
ClassDB::bind_method(D_METHOD("get_drop_mode_flags"), &Tree::get_drop_mode_flags);
@@ -5143,6 +5216,7 @@ void Tree::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_reselect"), "set_allow_reselect", "get_allow_reselect");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_folding"), "set_hide_folding", "is_folding_hidden");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_recursive_folding"), "set_enable_recursive_folding", "is_recursive_folding_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_root"), "set_hide_root", "is_root_hidden");
ADD_PROPERTY(PropertyInfo(Variant::INT, "drop_mode_flags", PROPERTY_HINT_FLAGS, "On Item,In Between"), "set_drop_mode_flags", "get_drop_mode_flags");
ADD_PROPERTY(PropertyInfo(Variant::INT, "select_mode", PROPERTY_HINT_ENUM, "Single,Row,Multi"), "set_select_mode", "get_select_mode");
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 450943c048..f994a5cec1 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -173,6 +173,8 @@ private:
}
}
+ bool _is_any_collapsed(bool p_only_visible);
+
protected:
static void _bind_methods();
@@ -272,6 +274,9 @@ public:
void set_collapsed(bool p_collapsed);
bool is_collapsed();
+ void set_collapsed_recursive(bool p_collapsed);
+ bool is_any_collapsed(bool p_only_visible = false);
+
void set_visible(bool p_visible);
bool is_visible();
@@ -613,6 +618,8 @@ private:
bool hide_folding = false;
+ bool enable_recursive_folding = true;
+
int _count_selected_items(TreeItem *p_from) const;
bool _is_branch_selected(TreeItem *p_from) const;
bool _is_sibling_branch_selected(TreeItem *p_from) const;
@@ -712,6 +719,9 @@ public:
void set_hide_folding(bool p_hide);
bool is_folding_hidden() const;
+ void set_enable_recursive_folding(bool p_enable);
+ bool is_recursive_folding_enabled() const;
+
void set_drop_mode_flags(int p_flags);
int get_drop_mode_flags() const;
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index ebe9587b31..cf30ca259d 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -389,6 +389,9 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) {
_propagate_window_notification(this, NOTIFICATION_WM_DPI_CHANGE);
emit_signal(SNAME("dpi_changed"));
} break;
+ case DisplayServer::WINDOW_EVENT_TITLEBAR_CHANGE: {
+ emit_signal(SNAME("titlebar_changed"));
+ } break;
}
}
@@ -1782,6 +1785,7 @@ void Window::_bind_methods() {
ADD_SIGNAL(MethodInfo("visibility_changed"));
ADD_SIGNAL(MethodInfo("about_to_popup"));
ADD_SIGNAL(MethodInfo("theme_changed"));
+ ADD_SIGNAL(MethodInfo("titlebar_changed"));
BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
BIND_CONSTANT(NOTIFICATION_THEME_CHANGED);
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 3d9e4e4a63..bbc4029764 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -272,13 +272,15 @@ Size2 Font::get_string_size(const String &p_text, HorizontalAlignment p_alignmen
buffer->set_direction(p_direction);
buffer->set_orientation(p_orientation);
buffer->add_string(p_text, Ref<Font>(this), p_font_size);
- if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- buffer->set_horizontal_alignment(p_alignment);
- buffer->set_width(p_width);
- buffer->set_flags(p_jst_flags);
- }
cache.insert(hash, buffer);
}
+
+ buffer->set_width(p_width);
+ buffer->set_horizontal_alignment(p_alignment);
+ if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ buffer->set_flags(p_jst_flags);
+ }
+
return buffer->get_size();
}
diff --git a/scene/resources/particle_process_material.h b/scene/resources/particle_process_material.h
index fe4741d6e5..9430e5797d 100644
--- a/scene/resources/particle_process_material.h
+++ b/scene/resources/particle_process_material.h
@@ -28,12 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "core/templates/rid.h"
-#include "scene/resources/material.h"
-
#ifndef PARTICLE_PROCESS_MATERIAL_H
#define PARTICLE_PROCESS_MATERIAL_H
+#include "core/templates/rid.h"
+#include "scene/resources/material.h"
+
/*
TODO:
-Path following
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index 65823a8f7f..ee61f0ac55 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -271,6 +271,7 @@ class QuadMesh : public PlaneMesh {
public:
QuadMesh() {
set_orientation(FACE_Z);
+ set_size(Size2(1, 1));
}
};
diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h
index fbb202d8d8..3de1a4b26f 100644
--- a/scene/resources/sky_material.h
+++ b/scene/resources/sky_material.h
@@ -28,12 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "core/templates/rid.h"
-#include "scene/resources/material.h"
-
#ifndef SKY_MATERIAL_H
#define SKY_MATERIAL_H
+#include "core/templates/rid.h"
+#include "scene/resources/material.h"
+
class ProceduralSkyMaterial : public Material {
GDCLASS(ProceduralSkyMaterial, Material);
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index da4b8046a5..4e529de8ee 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -769,15 +769,6 @@ public:
class GradientTexture1D : public Texture2D {
GDCLASS(GradientTexture1D, Texture2D);
-public:
- struct Point {
- float offset = 0.0;
- Color color;
- bool operator<(const Point &p_ponit) const {
- return offset < p_ponit.offset;
- }
- };
-
private:
Ref<Gradient> gradient;
bool update_pending = false;
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 4116eaa196..3aba550f03 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -90,11 +90,10 @@ public:
struct Varying {
String name;
- VaryingMode mode;
- VaryingType type;
+ VaryingMode mode = VARYING_MODE_MAX;
+ VaryingType type = VARYING_TYPE_MAX;
- Varying() {
- }
+ Varying() {}
Varying(String p_name, VaryingMode p_mode, VaryingType p_type) :
name(p_name), mode(p_mode), type(p_type) {}
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index e1a1c71420..4b97bede56 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -824,6 +824,7 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(WINDOW_EVENT_CLOSE_REQUEST);
BIND_ENUM_CONSTANT(WINDOW_EVENT_GO_BACK_REQUEST);
BIND_ENUM_CONSTANT(WINDOW_EVENT_DPI_CHANGE);
+ BIND_ENUM_CONSTANT(WINDOW_EVENT_TITLEBAR_CHANGE);
BIND_ENUM_CONSTANT(VSYNC_DISABLED);
BIND_ENUM_CONSTANT(VSYNC_ENABLED);
diff --git a/servers/display_server.h b/servers/display_server.h
index 42c254cd2f..8eafccc040 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -336,6 +336,7 @@ public:
WINDOW_EVENT_CLOSE_REQUEST,
WINDOW_EVENT_GO_BACK_REQUEST,
WINDOW_EVENT_DPI_CHANGE,
+ WINDOW_EVENT_TITLEBAR_CHANGE,
};
virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0;
virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0;
diff --git a/servers/extensions/physics_server_2d_extension.cpp b/servers/extensions/physics_server_2d_extension.cpp
index 769315daa7..e5920c78d4 100644
--- a/servers/extensions/physics_server_2d_extension.cpp
+++ b/servers/extensions/physics_server_2d_extension.cpp
@@ -189,7 +189,10 @@ void PhysicsServer2DExtension::_bind_methods() {
GDVIRTUAL_BIND(_area_get_transform, "area");
GDVIRTUAL_BIND(_area_set_collision_layer, "area", "layer");
+ GDVIRTUAL_BIND(_area_get_collision_layer, "area");
+
GDVIRTUAL_BIND(_area_set_collision_mask, "area", "mask");
+ GDVIRTUAL_BIND(_area_get_collision_mask, "area");
GDVIRTUAL_BIND(_area_set_monitorable, "area", "monitorable");
GDVIRTUAL_BIND(_area_set_pickable, "area", "pickable");
diff --git a/servers/extensions/physics_server_2d_extension.h b/servers/extensions/physics_server_2d_extension.h
index a6dbe35264..573b51ee12 100644
--- a/servers/extensions/physics_server_2d_extension.h
+++ b/servers/extensions/physics_server_2d_extension.h
@@ -268,8 +268,11 @@ public:
EXBIND2RC(Variant, area_get_param, RID, AreaParameter)
EXBIND1RC(Transform2D, area_get_transform, RID)
- EXBIND2(area_set_collision_mask, RID, uint32_t)
EXBIND2(area_set_collision_layer, RID, uint32_t)
+ EXBIND1RC(uint32_t, area_get_collision_layer, RID)
+
+ EXBIND2(area_set_collision_mask, RID, uint32_t)
+ EXBIND1RC(uint32_t, area_get_collision_mask, RID)
EXBIND2(area_set_monitorable, RID, bool)
EXBIND2(area_set_pickable, RID, bool)
diff --git a/servers/extensions/physics_server_3d_extension.cpp b/servers/extensions/physics_server_3d_extension.cpp
index 4785fa33fb..27f9ed2cb3 100644
--- a/servers/extensions/physics_server_3d_extension.cpp
+++ b/servers/extensions/physics_server_3d_extension.cpp
@@ -192,7 +192,10 @@ void PhysicsServer3DExtension::_bind_methods() {
GDVIRTUAL_BIND(_area_get_transform, "area");
GDVIRTUAL_BIND(_area_set_collision_layer, "area", "layer");
+ GDVIRTUAL_BIND(_area_get_collision_layer, "area");
+
GDVIRTUAL_BIND(_area_set_collision_mask, "area", "mask");
+ GDVIRTUAL_BIND(_area_get_collision_mask, "area");
GDVIRTUAL_BIND(_area_set_monitorable, "area", "monitorable");
GDVIRTUAL_BIND(_area_set_ray_pickable, "area", "enable");
diff --git a/servers/extensions/physics_server_3d_extension.h b/servers/extensions/physics_server_3d_extension.h
index f1e522aca8..57f2a2d790 100644
--- a/servers/extensions/physics_server_3d_extension.h
+++ b/servers/extensions/physics_server_3d_extension.h
@@ -271,8 +271,11 @@ public:
EXBIND2RC(Variant, area_get_param, RID, AreaParameter)
EXBIND1RC(Transform3D, area_get_transform, RID)
- EXBIND2(area_set_collision_mask, RID, uint32_t)
EXBIND2(area_set_collision_layer, RID, uint32_t)
+ EXBIND1RC(uint32_t, area_get_collision_layer, RID)
+
+ EXBIND2(area_set_collision_mask, RID, uint32_t)
+ EXBIND1RC(uint32_t, area_get_collision_mask, RID)
EXBIND2(area_set_monitorable, RID, bool)
EXBIND2(area_set_ray_pickable, RID, bool)
diff --git a/servers/physics_2d/godot_physics_server_2d.cpp b/servers/physics_2d/godot_physics_server_2d.cpp
index 11f6bd9c1e..6ce8175e6c 100644
--- a/servers/physics_2d/godot_physics_server_2d.cpp
+++ b/servers/physics_2d/godot_physics_server_2d.cpp
@@ -485,6 +485,20 @@ void GodotPhysicsServer2D::area_set_monitorable(RID p_area, bool p_monitorable)
area->set_monitorable(p_monitorable);
}
+void GodotPhysicsServer2D::area_set_collision_layer(RID p_area, uint32_t p_layer) {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_collision_layer(p_layer);
+}
+
+uint32_t GodotPhysicsServer2D::area_get_collision_layer(RID p_area) const {
+ GodotArea2D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND_V(!area, 0);
+
+ return area->get_collision_layer();
+}
+
void GodotPhysicsServer2D::area_set_collision_mask(RID p_area, uint32_t p_mask) {
GodotArea2D *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
@@ -492,11 +506,11 @@ void GodotPhysicsServer2D::area_set_collision_mask(RID p_area, uint32_t p_mask)
area->set_collision_mask(p_mask);
}
-void GodotPhysicsServer2D::area_set_collision_layer(RID p_area, uint32_t p_layer) {
+uint32_t GodotPhysicsServer2D::area_get_collision_mask(RID p_area) const {
GodotArea2D *area = area_owner.get_or_null(p_area);
- ERR_FAIL_COND(!area);
+ ERR_FAIL_COND_V(!area, 0);
- area->set_collision_layer(p_layer);
+ return area->get_collision_mask();
}
void GodotPhysicsServer2D::area_set_monitor_callback(RID p_area, const Callable &p_callback) {
diff --git a/servers/physics_2d/godot_physics_server_2d.h b/servers/physics_2d/godot_physics_server_2d.h
index c780ef3b66..b96677700c 100644
--- a/servers/physics_2d/godot_physics_server_2d.h
+++ b/servers/physics_2d/godot_physics_server_2d.h
@@ -151,8 +151,12 @@ public:
virtual Variant area_get_param(RID p_area, AreaParameter p_param) const override;
virtual Transform2D area_get_transform(RID p_area) const override;
virtual void area_set_monitorable(RID p_area, bool p_monitorable) override;
- virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) override;
+
virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) override;
+ virtual uint32_t area_get_collision_layer(RID p_area) const override;
+
+ virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) override;
+ virtual uint32_t area_get_collision_mask(RID p_area) const override;
virtual void area_set_monitor_callback(RID p_area, const Callable &p_callback) override;
virtual void area_set_area_monitor_callback(RID p_area, const Callable &p_callback) override;
diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/servers/physics_3d/godot_physics_server_3d.cpp
index 7f2ec72921..f3a589d469 100644
--- a/servers/physics_3d/godot_physics_server_3d.cpp
+++ b/servers/physics_3d/godot_physics_server_3d.cpp
@@ -387,6 +387,13 @@ void GodotPhysicsServer3D::area_set_collision_layer(RID p_area, uint32_t p_layer
area->set_collision_layer(p_layer);
}
+uint32_t GodotPhysicsServer3D::area_get_collision_layer(RID p_area) const {
+ GodotArea3D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND_V(!area, 0);
+
+ return area->get_collision_layer();
+}
+
void GodotPhysicsServer3D::area_set_collision_mask(RID p_area, uint32_t p_mask) {
GodotArea3D *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
@@ -394,6 +401,13 @@ void GodotPhysicsServer3D::area_set_collision_mask(RID p_area, uint32_t p_mask)
area->set_collision_mask(p_mask);
}
+uint32_t GodotPhysicsServer3D::area_get_collision_mask(RID p_area) const {
+ GodotArea3D *area = area_owner.get_or_null(p_area);
+ ERR_FAIL_COND_V(!area, 0);
+
+ return area->get_collision_mask();
+}
+
void GodotPhysicsServer3D::area_set_monitorable(RID p_area, bool p_monitorable) {
GodotArea3D *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
diff --git a/servers/physics_3d/godot_physics_server_3d.h b/servers/physics_3d/godot_physics_server_3d.h
index 6dc9330caf..e3e649da57 100644
--- a/servers/physics_3d/godot_physics_server_3d.h
+++ b/servers/physics_3d/godot_physics_server_3d.h
@@ -148,8 +148,11 @@ public:
virtual void area_set_ray_pickable(RID p_area, bool p_enable) override;
- virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) override;
virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) override;
+ virtual uint32_t area_get_collision_layer(RID p_area) const override;
+
+ virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) override;
+ virtual uint32_t area_get_collision_mask(RID p_area) const override;
virtual void area_set_monitorable(RID p_area, bool p_monitorable) override;
diff --git a/servers/physics_3d/joints/godot_cone_twist_joint_3d.h b/servers/physics_3d/joints/godot_cone_twist_joint_3d.h
index fdcc2ceea3..1651d34916 100644
--- a/servers/physics_3d/joints/godot_cone_twist_joint_3d.h
+++ b/servers/physics_3d/joints/godot_cone_twist_joint_3d.h
@@ -28,6 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef GODOT_CONE_TWIST_JOINT_3D_H
+#define GODOT_CONE_TWIST_JOINT_3D_H
+
/*
Adapted to Godot from the Bullet library.
*/
@@ -49,9 +52,6 @@ subject to the following restrictions:
Written by: Marcus Hennix
*/
-#ifndef GODOT_CONE_TWIST_JOINT_3D_H
-#define GODOT_CONE_TWIST_JOINT_3D_H
-
#include "servers/physics_3d/godot_joint_3d.h"
#include "servers/physics_3d/joints/godot_jacobian_entry_3d.h"
diff --git a/servers/physics_3d/joints/godot_generic_6dof_joint_3d.h b/servers/physics_3d/joints/godot_generic_6dof_joint_3d.h
index bcf2d18647..6a0ab81461 100644
--- a/servers/physics_3d/joints/godot_generic_6dof_joint_3d.h
+++ b/servers/physics_3d/joints/godot_generic_6dof_joint_3d.h
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef GODOT_GENERIC_6DOF_JOINT_3D_H
+#define GODOT_GENERIC_6DOF_JOINT_3D_H
+
/*
Adapted to Godot from the Bullet library.
*/
-#ifndef GODOT_GENERIC_6DOF_JOINT_3D_H
-#define GODOT_GENERIC_6DOF_JOINT_3D_H
-
#include "servers/physics_3d/godot_joint_3d.h"
#include "servers/physics_3d/joints/godot_jacobian_entry_3d.h"
diff --git a/servers/physics_3d/joints/godot_hinge_joint_3d.h b/servers/physics_3d/joints/godot_hinge_joint_3d.h
index b934540e8d..f1187771af 100644
--- a/servers/physics_3d/joints/godot_hinge_joint_3d.h
+++ b/servers/physics_3d/joints/godot_hinge_joint_3d.h
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef GODOT_HINGE_JOINT_3D_H
+#define GODOT_HINGE_JOINT_3D_H
+
/*
Adapted to Godot from the Bullet library.
*/
-#ifndef GODOT_HINGE_JOINT_3D_H
-#define GODOT_HINGE_JOINT_3D_H
-
#include "servers/physics_3d/godot_joint_3d.h"
#include "servers/physics_3d/joints/godot_jacobian_entry_3d.h"
diff --git a/servers/physics_3d/joints/godot_jacobian_entry_3d.h b/servers/physics_3d/joints/godot_jacobian_entry_3d.h
index 0fe15751d5..a46ce830ec 100644
--- a/servers/physics_3d/joints/godot_jacobian_entry_3d.h
+++ b/servers/physics_3d/joints/godot_jacobian_entry_3d.h
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef GODOT_JACOBIAN_ENTRY_3D_H
+#define GODOT_JACOBIAN_ENTRY_3D_H
+
/*
Adapted to Godot from the Bullet library.
*/
-#ifndef GODOT_JACOBIAN_ENTRY_3D_H
-#define GODOT_JACOBIAN_ENTRY_3D_H
-
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
diff --git a/servers/physics_3d/joints/godot_pin_joint_3d.h b/servers/physics_3d/joints/godot_pin_joint_3d.h
index eeeaa650bd..b3e2389d5a 100644
--- a/servers/physics_3d/joints/godot_pin_joint_3d.h
+++ b/servers/physics_3d/joints/godot_pin_joint_3d.h
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef GODOT_PIN_JOINT_3D_H
+#define GODOT_PIN_JOINT_3D_H
+
/*
Adapted to Godot from the Bullet library.
*/
-#ifndef GODOT_PIN_JOINT_3D_H
-#define GODOT_PIN_JOINT_3D_H
-
#include "servers/physics_3d/godot_joint_3d.h"
#include "servers/physics_3d/joints/godot_jacobian_entry_3d.h"
diff --git a/servers/physics_3d/joints/godot_slider_joint_3d.h b/servers/physics_3d/joints/godot_slider_joint_3d.h
index f596c9ff75..29d19be0d7 100644
--- a/servers/physics_3d/joints/godot_slider_joint_3d.h
+++ b/servers/physics_3d/joints/godot_slider_joint_3d.h
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef GODOT_SLIDER_JOINT_3D_H
+#define GODOT_SLIDER_JOINT_3D_H
+
/*
Adapted to Godot from the Bullet library.
*/
-#ifndef GODOT_SLIDER_JOINT_3D_H
-#define GODOT_SLIDER_JOINT_3D_H
-
#include "servers/physics_3d/godot_joint_3d.h"
#include "servers/physics_3d/joints/godot_jacobian_entry_3d.h"
diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp
index abaa473017..21be311637 100644
--- a/servers/physics_server_2d.cpp
+++ b/servers/physics_server_2d.cpp
@@ -652,7 +652,10 @@ void PhysicsServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("area_clear_shapes", "area"), &PhysicsServer2D::area_clear_shapes);
ClassDB::bind_method(D_METHOD("area_set_collision_layer", "area", "layer"), &PhysicsServer2D::area_set_collision_layer);
+ ClassDB::bind_method(D_METHOD("area_get_collision_layer", "area"), &PhysicsServer2D::area_get_collision_layer);
+
ClassDB::bind_method(D_METHOD("area_set_collision_mask", "area", "mask"), &PhysicsServer2D::area_set_collision_mask);
+ ClassDB::bind_method(D_METHOD("area_get_collision_mask", "area"), &PhysicsServer2D::area_get_collision_mask);
ClassDB::bind_method(D_METHOD("area_set_param", "area", "param", "value"), &PhysicsServer2D::area_set_param);
ClassDB::bind_method(D_METHOD("area_set_transform", "area", "transform"), &PhysicsServer2D::area_set_transform);
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
index bd57a6a375..a3feb97d5d 100644
--- a/servers/physics_server_2d.h
+++ b/servers/physics_server_2d.h
@@ -332,8 +332,11 @@ public:
virtual Variant area_get_param(RID p_parea, AreaParameter p_param) const = 0;
virtual Transform2D area_get_transform(RID p_area) const = 0;
- virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) = 0;
virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) = 0;
+ virtual uint32_t area_get_collision_layer(RID p_area) const = 0;
+
+ virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) = 0;
+ virtual uint32_t area_get_collision_mask(RID p_area) const = 0;
virtual void area_set_monitorable(RID p_area, bool p_monitorable) = 0;
virtual void area_set_pickable(RID p_area, bool p_pickable) = 0;
diff --git a/servers/physics_server_2d_wrap_mt.h b/servers/physics_server_2d_wrap_mt.h
index 1353d8de6d..14a6a5c2a1 100644
--- a/servers/physics_server_2d_wrap_mt.h
+++ b/servers/physics_server_2d_wrap_mt.h
@@ -156,8 +156,11 @@ public:
FUNC2RC(Variant, area_get_param, RID, AreaParameter);
FUNC1RC(Transform2D, area_get_transform, RID);
- FUNC2(area_set_collision_mask, RID, uint32_t);
FUNC2(area_set_collision_layer, RID, uint32_t);
+ FUNC1RC(uint32_t, area_get_collision_layer, RID);
+
+ FUNC2(area_set_collision_mask, RID, uint32_t);
+ FUNC1RC(uint32_t, area_get_collision_mask, RID);
FUNC2(area_set_monitorable, RID, bool);
FUNC2(area_set_pickable, RID, bool);
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index b4f30d7649..24cc7e8459 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -720,7 +720,10 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("area_clear_shapes", "area"), &PhysicsServer3D::area_clear_shapes);
ClassDB::bind_method(D_METHOD("area_set_collision_layer", "area", "layer"), &PhysicsServer3D::area_set_collision_layer);
+ ClassDB::bind_method(D_METHOD("area_get_collision_layer", "area"), &PhysicsServer3D::area_get_collision_layer);
+
ClassDB::bind_method(D_METHOD("area_set_collision_mask", "area", "mask"), &PhysicsServer3D::area_set_collision_mask);
+ ClassDB::bind_method(D_METHOD("area_get_collision_mask", "area"), &PhysicsServer3D::area_get_collision_mask);
ClassDB::bind_method(D_METHOD("area_set_param", "area", "param", "value"), &PhysicsServer3D::area_set_param);
ClassDB::bind_method(D_METHOD("area_set_transform", "area", "transform"), &PhysicsServer3D::area_set_transform);
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index 2151d84e40..b21c4e9249 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -364,8 +364,11 @@ public:
virtual Variant area_get_param(RID p_parea, AreaParameter p_param) const = 0;
virtual Transform3D area_get_transform(RID p_area) const = 0;
- virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) = 0;
virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) = 0;
+ virtual uint32_t area_get_collision_layer(RID p_area) const = 0;
+
+ virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) = 0;
+ virtual uint32_t area_get_collision_mask(RID p_area) const = 0;
virtual void area_set_monitorable(RID p_area, bool p_monitorable) = 0;
diff --git a/servers/physics_server_3d_wrap_mt.h b/servers/physics_server_3d_wrap_mt.h
index 9b07e19e50..1d5fa95bfb 100644
--- a/servers/physics_server_3d_wrap_mt.h
+++ b/servers/physics_server_3d_wrap_mt.h
@@ -157,8 +157,11 @@ public:
FUNC2RC(Variant, area_get_param, RID, AreaParameter);
FUNC1RC(Transform3D, area_get_transform, RID);
- FUNC2(area_set_collision_mask, RID, uint32_t);
FUNC2(area_set_collision_layer, RID, uint32_t);
+ FUNC1RC(uint32_t, area_get_collision_layer, RID);
+
+ FUNC2(area_set_collision_mask, RID, uint32_t);
+ FUNC1RC(uint32_t, area_get_collision_mask, RID);
FUNC2(area_set_monitorable, RID, bool);
FUNC2(area_set_ray_pickable, RID, bool);
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 63fd10886d..35953a7120 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -479,6 +479,9 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
if ((surf->owner->base_flags & (INSTANCE_DATA_FLAG_MULTIMESH | INSTANCE_DATA_FLAG_PARTICLES)) == INSTANCE_DATA_FLAG_MULTIMESH) {
mesh_storage->_multimesh_get_motion_vectors_offsets(surf->owner->data->base, push_constant.multimesh_motion_vectors_current_offset, push_constant.multimesh_motion_vectors_previous_offset);
+ } else {
+ push_constant.multimesh_motion_vectors_current_offset = 0;
+ push_constant.multimesh_motion_vectors_previous_offset = 0;
}
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(SceneState::PushConstant));
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 2190f41603..ac1daad05c 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -3302,7 +3302,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
ERR_FAIL_COND(!light_instance);
Rect2i atlas_rect;
- uint32_t atlas_size;
+ uint32_t atlas_size = 1;
RID atlas_fb;
bool using_dual_paraboloid = false;
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index 459d798a80..a3734a7218 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -597,7 +597,7 @@ void main() {
#ifdef MODE_LIGHT_ONLY
color = vec4(0.0);
-#else
+#elif !defined(MODE_UNSHADED)
color *= canvas_data.canvas_modulation;
#endif
diff --git a/servers/rendering/renderer_rd/shaders/effects/SCsub b/servers/rendering/renderer_rd/shaders/effects/SCsub
index 741da8fe69..f06a2d86e2 100644
--- a/servers/rendering/renderer_rd/shaders/effects/SCsub
+++ b/servers/rendering/renderer_rd/shaders/effects/SCsub
@@ -4,7 +4,7 @@ Import("env")
if "RD_GLSL" in env["BUILDERS"]:
# find all include files
- gl_include_files = [str(f) for f in Glob("*_inc.glsl")]
+ gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")]
# find all shader code(all glsl files excluding our include files)
glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
diff --git a/servers/rendering/renderer_rd/shaders/environment/SCsub b/servers/rendering/renderer_rd/shaders/environment/SCsub
index 741da8fe69..f06a2d86e2 100644
--- a/servers/rendering/renderer_rd/shaders/environment/SCsub
+++ b/servers/rendering/renderer_rd/shaders/environment/SCsub
@@ -4,7 +4,7 @@ Import("env")
if "RD_GLSL" in env["BUILDERS"]:
# find all include files
- gl_include_files = [str(f) for f in Glob("*_inc.glsl")]
+ gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")]
# find all shader code(all glsl files excluding our include files)
glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub b/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub
index 741da8fe69..f06a2d86e2 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub
@@ -4,7 +4,7 @@ Import("env")
if "RD_GLSL" in env["BUILDERS"]:
# find all include files
- gl_include_files = [str(f) for f in Glob("*_inc.glsl")]
+ gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")]
# find all shader code(all glsl files excluding our include files)
glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub b/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub
index 741da8fe69..f06a2d86e2 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub
@@ -4,7 +4,7 @@ Import("env")
if "RD_GLSL" in env["BUILDERS"]:
# find all include files
- gl_include_files = [str(f) for f in Glob("*_inc.glsl")]
+ gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")]
# find all shader code(all glsl files excluding our include files)
glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index b87b4d4a0f..800a742cb6 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -795,6 +795,8 @@ void TextureStorage::texture_2d_layered_initialize(RID p_texture, const Vector<R
case RS::TEXTURE_LAYERED_CUBEMAP_ARRAY: {
texture.rd_type = RD::TEXTURE_TYPE_CUBE_ARRAY;
} break;
+ default:
+ ERR_FAIL(); // Shouldn't happen, silence warnings.
}
texture.rd_format = ret_format.format;
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index b9df0ec8ac..57378708ba 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -743,7 +743,7 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i
r_attrib_element_size = 0;
r_skin_element_size = 0;
- uint32_t *size_accum;
+ uint32_t *size_accum = nullptr;
for (int i = 0; i < RS::ARRAY_MAX; i++) {
r_offsets[i] = 0; // Reset
@@ -847,8 +847,12 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i
}
}
- r_offsets[i] = (*size_accum);
- (*size_accum) += elem_size;
+ if (size_accum != nullptr) {
+ r_offsets[i] = (*size_accum);
+ (*size_accum) += elem_size;
+ } else {
+ r_offsets[i] = 0;
+ }
}
}
diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp
index ebd35b0f75..7a8a298dbd 100644
--- a/servers/text/text_server_extension.cpp
+++ b/servers/text/text_server_extension.cpp
@@ -1550,8 +1550,8 @@ PackedInt32Array TextServerExtension::string_get_word_breaks(const String &p_str
return PackedInt32Array();
}
-int TextServerExtension::is_confusable(const String &p_string, const PackedStringArray &p_dict) const {
- int ret;
+int64_t TextServerExtension::is_confusable(const String &p_string, const PackedStringArray &p_dict) const {
+ int64_t ret;
if (GDVIRTUAL_CALL(is_confusable, p_string, p_dict, ret)) {
return ret;
}
diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h
index 700d08f7d7..fbaa4961e1 100644
--- a/servers/text/text_server_extension.h
+++ b/servers/text/text_server_extension.h
@@ -508,9 +508,9 @@ public:
TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
GDVIRTUAL3RC(TypedArray<Vector2i>, parse_structured_text, StructuredTextParser, const Array &, const String &);
- virtual int is_confusable(const String &p_string, const PackedStringArray &p_dict) const override;
+ virtual int64_t is_confusable(const String &p_string, const PackedStringArray &p_dict) const override;
virtual bool spoof_check(const String &p_string) const override;
- GDVIRTUAL2RC(int, is_confusable, const String &, const PackedStringArray &);
+ GDVIRTUAL2RC(int64_t, is_confusable, const String &, const PackedStringArray &);
GDVIRTUAL1RC(bool, spoof_check, const String &);
TextServerExtension();
diff --git a/servers/text_server.h b/servers/text_server.h
index b62d418fc8..a0624c2c05 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -485,7 +485,7 @@ public:
// String functions.
virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const = 0;
- virtual int is_confusable(const String &p_string, const PackedStringArray &p_dict) const { return -1; };
+ virtual int64_t is_confusable(const String &p_string, const PackedStringArray &p_dict) const { return -1; };
virtual bool spoof_check(const String &p_string) const { return false; };
virtual String strip_diacritics(const String &p_string) const;
diff --git a/tests/core/math/test_vector2.h b/tests/core/math/test_vector2.h
index 9b7800164a..0d7f1163e4 100644
--- a/tests/core/math/test_vector2.h
+++ b/tests/core/math/test_vector2.h
@@ -37,6 +37,14 @@
namespace TestVector2 {
+TEST_CASE("[Vector2] Constructor methods") {
+ const Vector2 vector_empty = Vector2();
+ const Vector2 vector_zero = Vector2(0.0, 0.0);
+ CHECK_MESSAGE(
+ vector_empty == vector_zero,
+ "Vector2 Constructor with no inputs should return a zero Vector2.");
+}
+
TEST_CASE("[Vector2] Angle methods") {
const Vector2 vector_x = Vector2(1, 0);
const Vector2 vector_y = Vector2(0, 1);
@@ -102,6 +110,9 @@ TEST_CASE("[Vector2] Interpolation methods") {
Vector2(1, 1).slerp(Vector2(), 0.5) == Vector2(0.5, 0.5),
"Vector2 slerp with one input as zero should behave like a regular lerp.");
CHECK_MESSAGE(
+ Vector2(4, 6).slerp(Vector2(8, 10), 0.5).is_equal_approx(Vector2(5.9076470794008017626, 8.07918879020090480697)),
+ "Vector2 slerp should work as expected.");
+ CHECK_MESSAGE(
Math::is_equal_approx(vector1.slerp(vector2, 0.5).length(), (real_t)4.31959610746631919),
"Vector2 slerp with different length input should return a vector with an interpolated length.");
CHECK_MESSAGE(
@@ -171,6 +182,15 @@ TEST_CASE("[Vector2] Normalization methods") {
CHECK_MESSAGE(
Vector2(1, 1).normalized().is_equal_approx(Vector2(Math_SQRT12, Math_SQRT12)),
"Vector2 normalized should work as expected.");
+
+ Vector2 vector = Vector2(3.2, -5.4);
+ vector.normalize();
+ CHECK_MESSAGE(
+ vector == Vector2(3.2, -5.4).normalized(),
+ "Vector2 normalize should convert same way as Vector2 normalized.");
+ CHECK_MESSAGE(
+ vector.is_equal_approx(Vector2(0.509802390301732898898, -0.860291533634174266891)),
+ "Vector2 normalize should work as expected.");
}
TEST_CASE("[Vector2] Operators") {
@@ -276,12 +296,14 @@ TEST_CASE("[Vector2] Other methods") {
CHECK_MESSAGE(
Math::is_equal_approx(vector.aspect(), (real_t)1.2 / (real_t)3.4),
"Vector2 aspect should work as expected.");
+
CHECK_MESSAGE(
vector.direction_to(Vector2()).is_equal_approx(-vector.normalized()),
"Vector2 direction_to should work as expected.");
CHECK_MESSAGE(
Vector2(1, 1).direction_to(Vector2(2, 2)).is_equal_approx(Vector2(Math_SQRT12, Math_SQRT12)),
"Vector2 direction_to should work as expected.");
+
CHECK_MESSAGE(
vector.posmod(2).is_equal_approx(Vector2(1.2, 1.4)),
"Vector2 posmod should work as expected.");
@@ -294,10 +316,21 @@ TEST_CASE("[Vector2] Other methods") {
CHECK_MESSAGE(
(-vector).posmodv(Vector2(2, 3)).is_equal_approx(Vector2(0.8, 2.6)),
"Vector2 posmodv should work as expected.");
+
+ CHECK_MESSAGE(
+ vector.rotated(Math_TAU).is_equal_approx(Vector2(1.2, 3.4)),
+ "Vector2 rotated should work as expected.");
CHECK_MESSAGE(
vector.rotated(Math_TAU / 4).is_equal_approx(Vector2(-3.4, 1.2)),
"Vector2 rotated should work as expected.");
CHECK_MESSAGE(
+ vector.rotated(Math_TAU / 3).is_equal_approx(Vector2(-3.544486372867091398996, -0.660769515458673623883)),
+ "Vector2 rotated should work as expected.");
+ CHECK_MESSAGE(
+ vector.rotated(Math_TAU / 2).is_equal_approx(vector.rotated(Math_TAU / -2)),
+ "Vector2 rotated should work as expected.");
+
+ CHECK_MESSAGE(
vector.snapped(Vector2(1, 1)) == Vector2(1, 3),
"Vector2 snapped to integers should be the same as rounding.");
CHECK_MESSAGE(
@@ -306,23 +339,57 @@ TEST_CASE("[Vector2] Other methods") {
CHECK_MESSAGE(
vector.snapped(Vector2(0.25, 0.25)) == Vector2(1.25, 3.5),
"Vector2 snapped to 0.25 should give exact results.");
+
+ CHECK_MESSAGE(
+ Vector2(1.2, 2.5).is_equal_approx(vector.min(Vector2(3.0, 2.5))),
+ "Vector2 min should return expected value.");
+
+ CHECK_MESSAGE(
+ Vector2(5.3, 3.4).is_equal_approx(vector.max(Vector2(5.3, 2.0))),
+ "Vector2 max should return expected value.");
}
TEST_CASE("[Vector2] Plane methods") {
const Vector2 vector = Vector2(1.2, 3.4);
const Vector2 vector_y = Vector2(0, 1);
+ const Vector2 vector_normal = Vector2(0.95879811270838721622267, 0.2840883296913739899919);
+ const Vector2 vector_non_normal = Vector2(5.4, 1.6);
CHECK_MESSAGE(
vector.bounce(vector_y) == Vector2(1.2, -3.4),
"Vector2 bounce on a plane with normal of the Y axis should.");
CHECK_MESSAGE(
+ vector.bounce(vector_normal).is_equal_approx(Vector2(-2.85851197982345523329, 2.197477931904161412358)),
+ "Vector2 bounce with normal should return expected value.");
+ CHECK_MESSAGE(
vector.reflect(vector_y) == Vector2(-1.2, 3.4),
"Vector2 reflect on a plane with normal of the Y axis should.");
CHECK_MESSAGE(
+ vector.reflect(vector_normal).is_equal_approx(Vector2(2.85851197982345523329, -2.197477931904161412358)),
+ "Vector2 reflect with normal should return expected value.");
+ CHECK_MESSAGE(
vector.project(vector_y) == Vector2(0, 3.4),
- "Vector2 projected on the X axis should only give the Y component.");
+ "Vector2 projected on the Y axis should only give the Y component.");
+ CHECK_MESSAGE(
+ vector.project(vector_normal).is_equal_approx(Vector2(2.0292559899117276166, 0.60126103404791929382)),
+ "Vector2 projected on a normal should return expected value.");
CHECK_MESSAGE(
vector.slide(vector_y) == Vector2(1.2, 0),
"Vector2 slide on a plane with normal of the Y axis should set the Y to zero.");
+ CHECK_MESSAGE(
+ vector.slide(vector_normal).is_equal_approx(Vector2(-0.8292559899117276166456, 2.798738965952080706179)),
+ "Vector2 slide with normal should return expected value.");
+ // There's probably a better way to test these ones?
+ ERR_PRINT_OFF;
+ CHECK_MESSAGE(
+ vector.bounce(vector_non_normal).is_equal_approx(Vector2()),
+ "Vector2 bounce should return empty Vector2 with non-normalised input.");
+ CHECK_MESSAGE(
+ vector.reflect(vector_non_normal).is_equal_approx(Vector2()),
+ "Vector2 reflect should return empty Vector2 with non-normalised input.");
+ CHECK_MESSAGE(
+ vector.slide(vector_non_normal).is_equal_approx(Vector2()),
+ "Vector2 slide should return empty Vector2 with non-normalised input.");
+ ERR_PRINT_ON;
}
TEST_CASE("[Vector2] Rounding methods") {
@@ -367,12 +434,20 @@ TEST_CASE("[Vector2] Rounding methods") {
TEST_CASE("[Vector2] Linear algebra methods") {
const Vector2 vector_x = Vector2(1, 0);
const Vector2 vector_y = Vector2(0, 1);
+ const Vector2 a = Vector2(3.5, 8.5);
+ const Vector2 b = Vector2(5.2, 4.6);
CHECK_MESSAGE(
vector_x.cross(vector_y) == 1,
"Vector2 cross product of X and Y should give 1.");
CHECK_MESSAGE(
vector_y.cross(vector_x) == -1,
"Vector2 cross product of Y and X should give negative 1.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(a.cross(b), (real_t)-28.1),
+ "Vector2 cross should return expected value.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(Vector2(-a.x, a.y).cross(Vector2(b.x, -b.y)), (real_t)-28.1),
+ "Vector2 cross should return expected value.");
CHECK_MESSAGE(
vector_x.dot(vector_y) == 0.0,
@@ -383,6 +458,12 @@ TEST_CASE("[Vector2] Linear algebra methods") {
CHECK_MESSAGE(
(vector_x * 10).dot(vector_x * 10) == 100.0,
"Vector2 dot product of same direction vectors should behave as expected.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(a.dot(b), (real_t)57.3),
+ "Vector2 dot should return expected value.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(Vector2(-a.x, a.y).dot(Vector2(b.x, -b.y)), (real_t)-57.3),
+ "Vector2 dot should return expected value.");
}
} // namespace TestVector2
diff --git a/tests/core/math/test_vector2i.h b/tests/core/math/test_vector2i.h
index 841bb793a4..49b0632e3c 100644
--- a/tests/core/math/test_vector2i.h
+++ b/tests/core/math/test_vector2i.h
@@ -37,6 +37,14 @@
namespace TestVector2i {
+TEST_CASE("[Vector2i] Constructor methods") {
+ const Vector2i vector_empty = Vector2i();
+ const Vector2i vector_zero = Vector2i(0, 0);
+ CHECK_MESSAGE(
+ vector_empty == vector_zero,
+ "Vector2i Constructor with no inputs should return a zero Vector2i.");
+}
+
TEST_CASE("[Vector2i] Axis methods") {
Vector2i vector = Vector2i(2, 3);
CHECK_MESSAGE(
@@ -121,6 +129,14 @@ TEST_CASE("[Vector2i] Other methods") {
CHECK_MESSAGE(
Math::is_equal_approx(vector.aspect(), (real_t)1.0 / (real_t)3.0),
"Vector2i aspect should work as expected.");
+
+ CHECK_MESSAGE(
+ Vector2i(1, 2) == vector.min(Vector2i(3, 2)),
+ "Vector2i min should return expected value.");
+
+ CHECK_MESSAGE(
+ Vector2i(5, 3) == vector.max(Vector2i(5, 2)),
+ "Vector2i max should return expected value.");
}
TEST_CASE("[Vector2i] Abs and sign methods") {
diff --git a/tests/core/math/test_vector3.h b/tests/core/math/test_vector3.h
index 6f99fada2b..52118fa943 100644
--- a/tests/core/math/test_vector3.h
+++ b/tests/core/math/test_vector3.h
@@ -39,6 +39,14 @@
namespace TestVector3 {
+TEST_CASE("[Vector3] Constructor methods") {
+ const Vector3 vector_empty = Vector3();
+ const Vector3 vector_zero = Vector3(0.0, 0.0, 0.0);
+ CHECK_MESSAGE(
+ vector_empty == vector_zero,
+ "Vector3 Constructor with no inputs should return a zero Vector3.");
+}
+
TEST_CASE("[Vector3] Angle methods") {
const Vector3 vector_x = Vector3(1, 0, 0);
const Vector3 vector_y = Vector3(0, 1, 0);
@@ -123,6 +131,9 @@ TEST_CASE("[Vector3] Interpolation methods") {
Vector3(1, 1, 1).slerp(Vector3(), 0.5) == Vector3(0.5, 0.5, 0.5),
"Vector3 slerp with one input as zero should behave like a regular lerp.");
CHECK_MESSAGE(
+ Vector3(4, 6, 2).slerp(Vector3(8, 10, 3), 0.5).is_equal_approx(Vector3(5.90194219811429941053, 8.06758688849378394534, 2.558307894718317120038)),
+ "Vector3 slerp should work as expected.");
+ CHECK_MESSAGE(
Math::is_equal_approx(vector1.slerp(vector2, 0.5).length(), (real_t)6.25831088708303172),
"Vector3 slerp with different length input should return a vector with an interpolated length.");
CHECK_MESSAGE(
@@ -195,6 +206,15 @@ TEST_CASE("[Vector3] Normalization methods") {
CHECK_MESSAGE(
Vector3(1, 1, 1).normalized().is_equal_approx(Vector3(Math_SQRT13, Math_SQRT13, Math_SQRT13)),
"Vector3 normalized should work as expected.");
+
+ Vector3 vector = Vector3(3.2, -5.4, 6);
+ vector.normalize();
+ CHECK_MESSAGE(
+ vector == Vector3(3.2, -5.4, 6).normalized(),
+ "Vector3 normalize should convert same way as Vector3 normalized.");
+ CHECK_MESSAGE(
+ vector.is_equal_approx(Vector3(0.368522751763902980457, -0.621882143601586279522, 0.6909801595573180883585)),
+ "Vector3 normalize should work as expected.");
}
TEST_CASE("[Vector3] Operators") {
@@ -318,10 +338,21 @@ TEST_CASE("[Vector3] Other methods") {
CHECK_MESSAGE(
(-vector).posmodv(Vector3(2, 3, 4)).is_equal_approx(Vector3(0.8, 2.6, 2.4)),
"Vector3 posmodv should work as expected.");
+
+ CHECK_MESSAGE(
+ vector.rotated(Vector3(0, 1, 0), Math_TAU).is_equal_approx(vector),
+ "Vector3 rotated should work as expected.");
CHECK_MESSAGE(
vector.rotated(Vector3(0, 1, 0), Math_TAU / 4).is_equal_approx(Vector3(5.6, 3.4, -1.2)),
"Vector3 rotated should work as expected.");
CHECK_MESSAGE(
+ vector.rotated(Vector3(1, 0, 0), Math_TAU / 3).is_equal_approx(Vector3(1.2, -6.54974226119285642, 0.1444863728670914)),
+ "Vector3 rotated should work as expected.");
+ CHECK_MESSAGE(
+ vector.rotated(Vector3(0, 0, 1), Math_TAU / 2).is_equal_approx(vector.rotated(Vector3(0, 0, 1), Math_TAU / -2)),
+ "Vector3 rotated should work as expected.");
+
+ CHECK_MESSAGE(
vector.snapped(Vector3(1, 1, 1)) == Vector3(1, 3, 6),
"Vector3 snapped to integers should be the same as rounding.");
CHECK_MESSAGE(
@@ -332,18 +363,44 @@ TEST_CASE("[Vector3] Other methods") {
TEST_CASE("[Vector3] Plane methods") {
const Vector3 vector = Vector3(1.2, 3.4, 5.6);
const Vector3 vector_y = Vector3(0, 1, 0);
+ const Vector3 vector_normal = Vector3(0.88763458893247992491, 0.26300284116517923701, 0.37806658417494515320);
+ const Vector3 vector_non_normal = Vector3(5.4, 1.6, 2.3);
CHECK_MESSAGE(
vector.bounce(vector_y) == Vector3(1.2, -3.4, 5.6),
"Vector3 bounce on a plane with normal of the Y axis should.");
CHECK_MESSAGE(
+ vector.bounce(vector_normal).is_equal_approx(Vector3(-6.0369629829775736287, 1.25571467171034855444, 2.517589840583626047)),
+ "Vector3 bounce with normal should return expected value.");
+ CHECK_MESSAGE(
vector.reflect(vector_y) == Vector3(-1.2, 3.4, -5.6),
"Vector3 reflect on a plane with normal of the Y axis should.");
CHECK_MESSAGE(
+ vector.reflect(vector_normal).is_equal_approx(Vector3(6.0369629829775736287, -1.25571467171034855444, -2.517589840583626047)),
+ "Vector3 reflect with normal should return expected value.");
+ CHECK_MESSAGE(
vector.project(vector_y) == Vector3(0, 3.4, 0),
- "Vector3 projected on the X axis should only give the Y component.");
+ "Vector3 projected on the Y axis should only give the Y component.");
+ CHECK_MESSAGE(
+ vector.project(vector_normal).is_equal_approx(Vector3(3.61848149148878681437, 1.0721426641448257227776, 1.54120507970818697649)),
+ "Vector3 projected on a normal should return expected value.");
CHECK_MESSAGE(
vector.slide(vector_y) == Vector3(1.2, 0, 5.6),
"Vector3 slide on a plane with normal of the Y axis should set the Y to zero.");
+ CHECK_MESSAGE(
+ vector.slide(vector_normal).is_equal_approx(Vector3(-2.41848149148878681437, 2.32785733585517427722237, 4.0587949202918130235)),
+ "Vector3 slide with normal should return expected value.");
+ // There's probably a better way to test these ones?
+ ERR_PRINT_OFF;
+ CHECK_MESSAGE(
+ vector.bounce(vector_non_normal).is_equal_approx(Vector3()),
+ "Vector3 bounce should return empty Vector3 with non-normalised input.");
+ CHECK_MESSAGE(
+ vector.reflect(vector_non_normal).is_equal_approx(Vector3()),
+ "Vector3 reflect should return empty Vector3 with non-normalised input.");
+ CHECK_MESSAGE(
+ vector.slide(vector_non_normal).is_equal_approx(Vector3()),
+ "Vector3 slide should return empty Vector3 with non-normalised input.");
+ ERR_PRINT_ON;
}
TEST_CASE("[Vector3] Rounding methods") {
@@ -389,6 +446,8 @@ TEST_CASE("[Vector3] Linear algebra methods") {
const Vector3 vector_x = Vector3(1, 0, 0);
const Vector3 vector_y = Vector3(0, 1, 0);
const Vector3 vector_z = Vector3(0, 0, 1);
+ const Vector3 a = Vector3(3.5, 8.5, 2.3);
+ const Vector3 b = Vector3(5.2, 4.6, 7.8);
CHECK_MESSAGE(
vector_x.cross(vector_y) == vector_z,
"Vector3 cross product of X and Y should give Z.");
@@ -401,6 +460,12 @@ TEST_CASE("[Vector3] Linear algebra methods") {
CHECK_MESSAGE(
vector_z.cross(vector_x) == vector_y,
"Vector3 cross product of Z and X should give Y.");
+ CHECK_MESSAGE(
+ a.cross(b).is_equal_approx(Vector3(55.72, -15.34, -28.1)),
+ "Vector3 cross should return expected value.");
+ CHECK_MESSAGE(
+ Vector3(-a.x, a.y, -a.z).cross(Vector3(b.x, -b.y, b.z)).is_equal_approx(Vector3(55.72, 15.34, -28.1)),
+ "Vector2 cross should return expected value.");
CHECK_MESSAGE(
vector_x.dot(vector_y) == 0.0,
@@ -411,6 +476,12 @@ TEST_CASE("[Vector3] Linear algebra methods") {
CHECK_MESSAGE(
(vector_x * 10).dot(vector_x * 10) == 100.0,
"Vector3 dot product of same direction vectors should behave as expected.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(a.dot(b), (real_t)75.24),
+ "Vector3 dot should return expected value.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(Vector3(-a.x, a.y, -a.z).dot(Vector3(b.x, -b.y, b.z)), (real_t)-75.24),
+ "Vector3 dot should return expected value.");
}
} // namespace TestVector3
diff --git a/tests/core/math/test_vector3i.h b/tests/core/math/test_vector3i.h
index b1c6944eba..6c52781556 100644
--- a/tests/core/math/test_vector3i.h
+++ b/tests/core/math/test_vector3i.h
@@ -36,6 +36,14 @@
namespace TestVector3i {
+TEST_CASE("[Vector3i] Constructor methods") {
+ const Vector3i vector_empty = Vector3i();
+ const Vector3i vector_zero = Vector3i(0, 0, 0);
+ CHECK_MESSAGE(
+ vector_empty == vector_zero,
+ "Vector3i Constructor with no inputs should return a zero Vector3i.");
+}
+
TEST_CASE("[Vector3i] Axis methods") {
Vector3i vector = Vector3i(1, 2, 3);
CHECK_MESSAGE(
diff --git a/tests/core/math/test_vector4.h b/tests/core/math/test_vector4.h
index ccf991401b..25ec8929b8 100644
--- a/tests/core/math/test_vector4.h
+++ b/tests/core/math/test_vector4.h
@@ -38,6 +38,14 @@
namespace TestVector4 {
+TEST_CASE("[Vector4] Constructor methods") {
+ const Vector4 vector_empty = Vector4();
+ const Vector4 vector_zero = Vector4(0.0, 0.0, 0.0, 0.0);
+ CHECK_MESSAGE(
+ vector_empty == vector_zero,
+ "Vector4 Constructor with no inputs should return a zero Vector4.");
+}
+
TEST_CASE("[Vector4] Axis methods") {
Vector4 vector = Vector4(1.2, 3.4, 5.6, -0.9);
CHECK_MESSAGE(
diff --git a/tests/core/math/test_vector4i.h b/tests/core/math/test_vector4i.h
index ac63001b24..e106099914 100644
--- a/tests/core/math/test_vector4i.h
+++ b/tests/core/math/test_vector4i.h
@@ -36,6 +36,14 @@
namespace TestVector4i {
+TEST_CASE("[Vector4i] Constructor methods") {
+ const Vector4i vector_empty = Vector4i();
+ const Vector4i vector_zero = Vector4i(0, 0, 0, 0);
+ CHECK_MESSAGE(
+ vector_empty == vector_zero,
+ "Vector4i Constructor with no inputs should return a zero Vector4i.");
+}
+
TEST_CASE("[Vector4i] Axis methods") {
Vector4i vector = Vector4i(1, 2, 3, 4);
CHECK_MESSAGE(