summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.yml2
-rw-r--r--.github/workflows/linux_builds.yml3
-rw-r--r--.github/workflows/windows_builds.yml4
-rw-r--r--core/config/project_settings.cpp19
-rw-r--r--core/extension/extension_api_dump.cpp9
-rw-r--r--core/extension/gdnative_interface.cpp69
-rw-r--r--core/extension/gdnative_interface.h76
-rw-r--r--core/extension/native_extension.cpp109
-rw-r--r--core/extension/native_extension.h16
-rw-r--r--core/input/input_event.cpp2
-rw-r--r--core/object/class_db.cpp10
-rw-r--r--core/object/make_virtuals.py6
-rw-r--r--core/object/object.cpp3
-rw-r--r--core/object/object.h20
-rw-r--r--core/object/script_language_extension.h18
-rw-r--r--core/string/optimized_translation.cpp33
-rw-r--r--core/string/optimized_translation.h1
-rw-r--r--core/string/translation.cpp13
-rw-r--r--core/string/translation.h1
-rw-r--r--core/string/translation_po.cpp17
-rw-r--r--core/string/translation_po.h1
-rw-r--r--core/string/ustring.cpp37
-rw-r--r--core/string/ustring.h4
-rw-r--r--core/variant/callable.h10
-rw-r--r--core/variant/variant_call.cpp4
-rw-r--r--doc/classes/AnimatedTexture.xml1
-rw-r--r--doc/classes/AtlasTexture.xml1
-rw-r--r--doc/classes/BaseButton.xml17
-rw-r--r--doc/classes/CameraAttributes.xml10
-rw-r--r--doc/classes/CameraTexture.xml1
-rw-r--r--doc/classes/CanvasTexture.xml1
-rw-r--r--doc/classes/CompressedCubemap.xml9
-rw-r--r--doc/classes/CompressedCubemapArray.xml9
-rw-r--r--doc/classes/CompressedTexture2D.xml15
-rw-r--r--doc/classes/CompressedTexture2DArray.xml9
-rw-r--r--doc/classes/CompressedTexture3D.xml6
-rw-r--r--doc/classes/CompressedTextureLayered.xml10
-rw-r--r--doc/classes/Cubemap.xml5
-rw-r--r--doc/classes/CubemapArray.xml5
-rw-r--r--doc/classes/CurveTexture.xml1
-rw-r--r--doc/classes/CurveXYZTexture.xml1
-rw-r--r--doc/classes/DisplayServer.xml13
-rw-r--r--doc/classes/EditorFeatureProfile.xml5
-rw-r--r--doc/classes/EditorSpinSlider.xml3
-rw-r--r--doc/classes/GPUParticles2D.xml7
-rw-r--r--doc/classes/GPUParticles3D.xml6
-rw-r--r--doc/classes/GeometryInstance3D.xml24
-rw-r--r--doc/classes/GradientTexture1D.xml1
-rw-r--r--doc/classes/GradientTexture2D.xml1
-rw-r--r--doc/classes/Image.xml2
-rw-r--r--doc/classes/ImageTexture.xml3
-rw-r--r--doc/classes/ImageTexture3D.xml5
-rw-r--r--doc/classes/ImageTextureLayered.xml6
-rw-r--r--doc/classes/Label3D.xml2
-rw-r--r--doc/classes/LinkButton.xml2
-rw-r--r--doc/classes/Mesh.xml2
-rw-r--r--doc/classes/MeshTexture.xml1
-rw-r--r--doc/classes/MissingNode.xml2
-rw-r--r--doc/classes/MissingResource.xml2
-rw-r--r--doc/classes/PhysicsDirectBodyState2D.xml2
-rw-r--r--doc/classes/PhysicsDirectBodyState3D.xml2
-rw-r--r--doc/classes/PlaceholderCubemap.xml4
-rw-r--r--doc/classes/PlaceholderCubemapArray.xml4
-rw-r--r--doc/classes/PlaceholderMaterial.xml4
-rw-r--r--doc/classes/PlaceholderMesh.xml5
-rw-r--r--doc/classes/PlaceholderTexture2D.xml6
-rw-r--r--doc/classes/PlaceholderTexture2DArray.xml4
-rw-r--r--doc/classes/PlaceholderTexture3D.xml5
-rw-r--r--doc/classes/PlaceholderTextureLayered.xml6
-rw-r--r--doc/classes/PortableCompressedTexture2D.xml1
-rw-r--r--doc/classes/PrimitiveMesh.xml10
-rw-r--r--doc/classes/ProjectSettings.xml6
-rw-r--r--doc/classes/Range.xml19
-rw-r--r--doc/classes/RenderingDevice.xml9
-rw-r--r--doc/classes/RenderingServer.xml8
-rw-r--r--doc/classes/RigidBody2D.xml2
-rw-r--r--doc/classes/RigidBody3D.xml2
-rw-r--r--doc/classes/ScrollBar.xml1
-rw-r--r--doc/classes/Slider.xml2
-rw-r--r--doc/classes/SpinBox.xml2
-rw-r--r--doc/classes/String.xml8
-rw-r--r--doc/classes/StyleBox.xml8
-rw-r--r--doc/classes/Texture.xml2
-rw-r--r--doc/classes/Texture2D.xml16
-rw-r--r--doc/classes/Texture2DArray.xml3
-rw-r--r--doc/classes/Texture3D.xml16
-rw-r--r--doc/classes/TextureLayered.xml22
-rw-r--r--doc/classes/TextureProgressBar.xml3
-rw-r--r--doc/classes/Translation.xml6
-rw-r--r--doc/classes/Tree.xml8
-rw-r--r--doc/classes/VisualInstance3D.xml2
-rw-r--r--doc/classes/XRInterface.xml20
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp8
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp36
-rw-r--r--drivers/gles3/storage/material_storage.cpp3
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.cpp62
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.h3
-rw-r--r--drivers/gles3/storage/texture_storage.cpp317
-rw-r--r--drivers/gles3/storage/texture_storage.h30
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp12
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp70
-rw-r--r--drivers/wasapi/audio_driver_wasapi.h8
-rw-r--r--editor/action_map_editor.cpp7
-rw-r--r--editor/code_editor.cpp4
-rw-r--r--editor/create_dialog.cpp8
-rw-r--r--editor/debugger/editor_performance_profiler.cpp1
-rw-r--r--editor/doc_tools.cpp2
-rw-r--r--editor/editor_audio_buses.h1
-rw-r--r--editor/editor_build_profile.h1
-rw-r--r--editor/editor_command_palette.cpp2
-rw-r--r--editor/editor_feature_profile.cpp4
-rw-r--r--editor/editor_feature_profile.h3
-rw-r--r--editor/editor_fonts.cpp2
-rw-r--r--editor/editor_help.cpp59
-rw-r--r--editor/editor_node.cpp35
-rw-r--r--editor/editor_node.h2
-rw-r--r--editor/editor_plugin.cpp4
-rw-r--r--editor/editor_plugin.h31
-rw-r--r--editor/editor_properties.cpp3
-rw-r--r--editor/editor_resource_picker.cpp16
-rw-r--r--editor/editor_run.cpp8
-rw-r--r--editor/editor_settings.cpp2
-rw-r--r--editor/editor_settings_dialog.cpp1
-rw-r--r--editor/editor_themes.cpp10
-rw-r--r--editor/editor_undo_redo_manager.cpp1
-rw-r--r--editor/filesystem_dock.cpp1
-rw-r--r--editor/find_in_files.cpp3
-rw-r--r--editor/import/audio_stream_import_settings.cpp1
-rw-r--r--editor/import/audio_stream_import_settings.h3
-rw-r--r--editor/import/dynamic_font_import_settings.cpp177
-rw-r--r--editor/import/dynamic_font_import_settings.h16
-rw-r--r--editor/import/resource_importer_imagefont.cpp49
-rw-r--r--editor/import/resource_importer_scene.cpp2
-rw-r--r--editor/plugin_config_dialog.cpp1
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.h1
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.h3
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp1
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.h4
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h7
-rw-r--r--editor/plugins/animation_state_machine_editor.h5
-rw-r--r--editor/plugins/asset_library_editor_plugin.h3
-rw-r--r--editor/plugins/bit_map_editor_plugin.h3
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp26
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h3
-rw-r--r--editor/plugins/control_editor_plugin.cpp14
-rw-r--r--editor/plugins/control_editor_plugin.h3
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.h5
-rw-r--r--editor/plugins/curve_editor_plugin.h1
-rw-r--r--editor/plugins/gdextension_export_plugin.h2
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.h4
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.h4
-rw-r--r--editor/plugins/gpu_particles_collision_sdf_editor_plugin.h1
-rw-r--r--editor/plugins/gradient_editor_plugin.h1
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.cpp16
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.h1
-rw-r--r--editor/plugins/material_editor_plugin.h1
-rw-r--r--editor/plugins/mesh_editor_plugin.h1
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.h4
-rw-r--r--editor/plugins/multimesh_editor_plugin.h4
-rw-r--r--editor/plugins/node_3d_editor_plugin.h6
-rw-r--r--editor/plugins/path_2d_editor_plugin.h2
-rw-r--r--editor/plugins/path_3d_editor_plugin.h2
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.h6
-rw-r--r--editor/plugins/polygon_3d_editor_plugin.h2
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.h1
-rw-r--r--editor/plugins/root_motion_editor_plugin.cpp2
-rw-r--r--editor/plugins/root_motion_editor_plugin.h5
-rw-r--r--editor/plugins/script_editor_plugin.h1
-rw-r--r--editor/plugins/shader_editor_plugin.h1
-rw-r--r--editor/plugins/skeleton_2d_editor_plugin.h3
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.h4
-rw-r--r--editor/plugins/texture_3d_editor_plugin.h1
-rw-r--r--editor/plugins/texture_editor_plugin.h4
-rw-r--r--editor/plugins/texture_layered_editor_plugin.h1
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp2
-rw-r--r--editor/plugins/texture_region_editor_plugin.h2
-rw-r--r--editor/plugins/theme_editor_plugin.h2
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp52
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h9
-rw-r--r--editor/plugins/voxel_gi_editor_plugin.h1
-rw-r--r--editor/project_manager.cpp2
-rw-r--r--editor/scene_tree_dock.h2
-rw-r--r--editor/script_create_dialog.cpp4
-rw-r--r--main/main.cpp120
-rw-r--r--modules/gdscript/gdscript_compiler.cpp3
-rw-r--r--modules/gdscript/gdscript_parser.cpp2
-rw-r--r--modules/gdscript/gdscript_parser.h2
-rw-r--r--modules/gltf/editor/editor_scene_exporter_gltf_plugin.h2
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.h3
-rw-r--r--modules/lightmapper_rd/register_types.cpp1
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs2
-rw-r--r--modules/multiplayer/editor/replication_editor_plugin.cpp1
-rw-r--r--modules/multiplayer/editor/replication_editor_plugin.h12
-rw-r--r--modules/navigation/editor/navigation_mesh_editor_plugin.h2
-rw-r--r--modules/noise/doc_classes/NoiseTexture2D.xml1
-rw-r--r--modules/noise/editor/noise_editor_plugin.cpp2
-rw-r--r--modules/openxr/SCsub2
-rw-r--r--modules/openxr/extensions/openxr_opengl_extension.cpp466
-rw-r--r--modules/openxr/extensions/openxr_opengl_extension.h120
-rw-r--r--modules/openxr/openxr_api.cpp35
-rw-r--r--modules/openxr/openxr_interface.cpp2
-rw-r--r--modules/websocket/emws_peer.cpp4
-rw-r--r--modules/zip/zip_packer.cpp12
-rw-r--r--platform/android/android_keys_utils.h6
-rw-r--r--platform/android/display_server_android.cpp5
-rw-r--r--platform/android/export/export_plugin.cpp92
-rw-r--r--platform/android/export/export_plugin.h22
-rw-r--r--platform/android/java/app/config.gradle8
-rw-r--r--platform/android/java/gradle/wrapper/gradle-wrapper.properties2
-rw-r--r--platform/android/java/lib/AndroidManifest.xml3
-rw-r--r--platform/android/java/lib/build.gradle13
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java4
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt59
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java5
-rw-r--r--platform/android/java_godot_view_wrapper.cpp2
-rw-r--r--platform/android/os_android.cpp9
-rw-r--r--platform/ios/display_server_ios.mm4
-rw-r--r--platform/linuxbsd/x11/detect_prime_x11.cpp5
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp20
-rw-r--r--platform/linuxbsd/x11/gl_manager_x11.cpp11
-rw-r--r--platform/linuxbsd/x11/gl_manager_x11.h2
-rw-r--r--platform/macos/display_server_macos.h1
-rw-r--r--platform/macos/display_server_macos.mm47
-rw-r--r--platform/macos/gl_manager_macos_legacy.h2
-rw-r--r--platform/macos/gl_manager_macos_legacy.mm9
-rw-r--r--platform/macos/godot_window_delegate.mm5
-rw-r--r--platform/web/display_server_web.cpp37
-rw-r--r--platform/web/display_server_web.h1
-rw-r--r--platform/web/js/engine/config.js2
-rw-r--r--platform/web/web_main.cpp36
-rw-r--r--platform/windows/display_server_windows.cpp15
-rw-r--r--platform/windows/gl_manager_windows.cpp10
-rw-r--r--platform/windows/gl_manager_windows.h3
-rw-r--r--scene/2d/gpu_particles_2d.cpp18
-rw-r--r--scene/2d/gpu_particles_2d.h6
-rw-r--r--scene/3d/collision_object_3d.cpp2
-rw-r--r--scene/3d/gpu_particles_3d.cpp20
-rw-r--r--scene/3d/gpu_particles_3d.h6
-rw-r--r--scene/3d/visual_instance_3d.cpp30
-rw-r--r--scene/3d/visual_instance_3d.h6
-rw-r--r--scene/3d/xr_nodes.cpp6
-rw-r--r--scene/gui/code_edit.cpp4
-rw-r--r--scene/gui/item_list.cpp5
-rw-r--r--scene/gui/line_edit.cpp29
-rw-r--r--scene/gui/option_button.cpp2
-rw-r--r--scene/gui/popup_menu.cpp2
-rw-r--r--scene/gui/scroll_container.cpp8
-rw-r--r--scene/gui/text_edit.cpp6
-rw-r--r--scene/gui/tree.cpp9
-rw-r--r--scene/gui/tree.h1
-rw-r--r--scene/main/viewport.cpp72
-rw-r--r--scene/main/viewport.h1
-rw-r--r--scene/resources/animation.cpp84
-rw-r--r--scene/resources/font.cpp5
-rw-r--r--scene/resources/mesh.cpp12
-rw-r--r--scene/resources/primitive_meshes.cpp479
-rw-r--r--scene/resources/primitive_meshes.h35
-rw-r--r--scene/resources/shader.cpp2
-rw-r--r--scene/resources/shape_2d.cpp2
-rw-r--r--scene/resources/text_line.cpp6
-rw-r--r--scene/resources/visual_shader_nodes.cpp4
-rw-r--r--servers/display_server.cpp12
-rw-r--r--servers/display_server.h1
-rw-r--r--servers/physics_2d/godot_space_2d.cpp2
-rw-r--r--servers/physics_3d/godot_space_3d.cpp2
-rw-r--r--servers/rendering/dummy/storage/mesh_storage.h1
-rw-r--r--servers/rendering/dummy/storage/texture_storage.h2
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp4
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.cpp4
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp4
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp3
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp13
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp3
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/shaders/cluster_render.glsl12
-rw-r--r--servers/rendering/renderer_rd/shaders/particles.glsl2
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.cpp4
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.h8
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp7
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.h2
-rw-r--r--servers/rendering/renderer_rd/storage_rd/utilities.cpp4
-rw-r--r--servers/rendering/rendering_device.cpp1
-rw-r--r--servers/rendering/rendering_server_default.h1
-rw-r--r--servers/rendering/shader_language.cpp4
-rw-r--r--servers/rendering/storage/texture_storage.h2
-rw-r--r--servers/rendering_server.cpp10
-rw-r--r--servers/rendering_server.h2
-rw-r--r--servers/xr/xr_interface.cpp2
-rw-r--r--tests/core/io/test_json.h2
-rw-r--r--tests/core/math/test_aabb.h8
-rw-r--r--tests/core/math/test_basis.h10
-rw-r--r--tests/core/math/test_color.h6
-rw-r--r--tests/core/math/test_expression.h20
-rw-r--r--tests/core/math/test_geometry_2d.h24
-rw-r--r--tests/core/math/test_rect2.h8
-rw-r--r--tests/core/math/test_vector2.h28
-rw-r--r--tests/core/math/test_vector2i.h6
-rw-r--r--tests/core/math/test_vector3.h28
-rw-r--r--tests/core/math/test_vector3i.h4
-rw-r--r--tests/core/math/test_vector4.h10
-rw-r--r--tests/core/math/test_vector4i.h4
-rw-r--r--tests/core/string/test_string.h8
-rw-r--r--tests/scene/test_animation.h82
-rw-r--r--tests/scene/test_audio_stream_wav.h2
-rw-r--r--tests/scene/test_curve.h54
-rw-r--r--tests/scene/test_primitives.h40
-rw-r--r--tests/scene/test_text_edit.h34
-rw-r--r--tests/test_main.cpp3
308 files changed, 3485 insertions, 1243 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 2c2a963a26..690e74855f 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -53,4 +53,4 @@ body:
label: Minimal reproduction project
description: |
A small Godot project which reproduces the issue. Highly recommended to speed up troubleshooting.
- Drag and drop a ZIP archive to upload it.
+ Drag and drop a ZIP archive to upload it. Be sure to not include the ".godot" folder in the archive.
diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml
index 3a92b8ffb4..95d216deb3 100644
--- a/.github/workflows/linux_builds.yml
+++ b/.github/workflows/linux_builds.yml
@@ -102,6 +102,9 @@ jobs:
with:
dotnet-version: '6.0.x'
+ - name: Setup GCC problem matcher
+ uses: ammaraskar/gcc-problem-matcher@master
+
- name: Compilation
uses: ./.github/actions/godot-build
with:
diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml
index 31661e3f90..7f04c3475e 100644
--- a/.github/workflows/windows_builds.yml
+++ b/.github/workflows/windows_builds.yml
@@ -45,10 +45,12 @@ jobs:
cache-name: ${{ matrix.cache-name }}
continue-on-error: true
-
- name: Setup python and scons
uses: ./.github/actions/godot-deps
+ - name: Setup MSVC problem matcher
+ uses: ammaraskar/msvc-problem-matcher@master
+
- name: Compilation
uses: ./.github/actions/godot-build
with:
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 7a10390d72..4d2006d42a 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -619,7 +619,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bool p_upwards, bool p_ignore_override) {
Error err = _setup(p_path, p_main_pack, p_upwards, p_ignore_override);
if (err == OK) {
- String custom_settings = GLOBAL_DEF("application/config/project_settings_override", "");
+ String custom_settings = GLOBAL_GET("application/config/project_settings_override");
if (!custom_settings.is_empty()) {
_load_settings_text(custom_settings);
}
@@ -1276,6 +1276,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("physics/2d/run_on_separate_thread", false);
GLOBAL_DEF("physics/3d/run_on_separate_thread", false);
+ GLOBAL_DEF("debug/disable_touch", false);
GLOBAL_DEF("debug/settings/profiler/max_functions", 16384);
custom_prop_info["debug/settings/profiler/max_functions"] = PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1");
@@ -1292,6 +1293,22 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("compression/formats/gzip/compression_level", Compression::gzip_level);
custom_prop_info["compression/formats/gzip/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/gzip/compression_level", PROPERTY_HINT_RANGE, "-1,9,1");
+ GLOBAL_DEF("debug/settings/crash_handler/message",
+ String("Please include this when reporting the bug to the project developer."));
+ GLOBAL_DEF("debug/settings/crash_handler/message.editor",
+ String("Please include this when reporting the bug on: https://github.com/godotengine/godot/issues"));
+ GLOBAL_DEF_RST("rendering/occlusion_culling/bvh_build_quality", 2);
+ GLOBAL_DEF("memory/limits/multithreaded_server/rid_pool_prealloc", 60);
+ GLOBAL_DEF_RST("internationalization/rendering/force_right_to_left_layout_direction", false);
+
+ GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/incremental_search_max_interval_msec", PropertyInfo(Variant::INT, "gui/timers/incremental_search_max_interval_msec", PROPERTY_HINT_RANGE, "0,10000,1,or_greater")); // No negative numbers.
+
+ GLOBAL_DEF("rendering/rendering_device/staging_buffer/block_size_kb", 256);
+ GLOBAL_DEF("rendering/rendering_device/staging_buffer/max_size_mb", 128);
+ GLOBAL_DEF("rendering/rendering_device/staging_buffer/texture_upload_region_size_px", 64);
+ GLOBAL_DEF("rendering/rendering_device/vulkan/max_descriptors_per_pool", 64);
+
// These properties will not show up in the dialog nor in the documentation. If you want to exclude whole groups, see _get_property_list() method.
GLOBAL_DEF_INTERNAL("application/config/features", PackedStringArray());
GLOBAL_DEF_INTERNAL("internationalization/locale/translation_remaps", PackedStringArray());
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index 96b396caa9..a2c507e350 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "extension_api_dump.h"
+
#include "core/config/engine.h"
#include "core/core_constants.h"
#include "core/io/file_access.h"
@@ -938,9 +939,9 @@ void NativeExtensionAPIDump::generate_extension_json_file(const String &p_path)
Ref<JSON> json;
json.instantiate();
- String text = json->stringify(api, "\t", false);
+ String text = json->stringify(api, "\t", false) + "\n";
Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE);
- CharString cs = text.ascii();
- fa->store_buffer((const uint8_t *)cs.ptr(), cs.length());
+ fa->store_string(text);
}
-#endif
+
+#endif // TOOLS_ENABLED
diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp
index 193fcb8916..864f2fa86b 100644
--- a/core/extension/gdnative_interface.cpp
+++ b/core/extension/gdnative_interface.cpp
@@ -61,8 +61,9 @@ static void gdnative_print_script_error(const char *p_description, const char *p
_err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_SCRIPT);
}
-uint64_t gdnative_get_native_struct_size(const char *p_name) {
- return ClassDB::get_native_struct_size(p_name);
+uint64_t gdnative_get_native_struct_size(const GDNativeStringNamePtr p_name) {
+ const StringName name = *reinterpret_cast<const StringName *>(p_name);
+ return ClassDB::get_native_struct_size(name);
}
// Variant functions
@@ -81,11 +82,11 @@ static void gdnative_variant_destroy(GDNativeVariantPtr p_self) {
static void gdnative_variant_call(GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argcount, GDNativeVariantPtr r_return, GDNativeCallError *r_error) {
Variant *self = (Variant *)p_self;
- const StringName *method = (const StringName *)p_method;
+ const StringName method = *reinterpret_cast<const StringName *>(p_method);
const Variant **args = (const Variant **)p_args;
Variant ret;
Callable::CallError error;
- self->callp(*method, args, p_argcount, ret, error);
+ self->callp(method, args, p_argcount, ret, error);
memnew_placement(r_return, Variant(ret));
if (r_error) {
@@ -97,11 +98,11 @@ static void gdnative_variant_call(GDNativeVariantPtr p_self, const GDNativeStrin
static void gdnative_variant_call_static(GDNativeVariantType p_type, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argcount, GDNativeVariantPtr r_return, GDNativeCallError *r_error) {
Variant::Type type = (Variant::Type)p_type;
- const StringName *method = (const StringName *)p_method;
+ const StringName method = *reinterpret_cast<const StringName *>(p_method);
const Variant **args = (const Variant **)p_args;
Variant ret;
Callable::CallError error;
- Variant::call_static(type, *method, args, p_argcount, ret, error);
+ Variant::call_static(type, method, args, p_argcount, ret, error);
memnew_placement(r_return, Variant(ret));
if (r_error) {
@@ -469,11 +470,11 @@ static GDNativeTypeFromVariantConstructorFunc gdnative_get_type_from_variant_con
static GDNativePtrOperatorEvaluator gdnative_variant_get_ptr_operator_evaluator(GDNativeVariantOperator p_operator, GDNativeVariantType p_type_a, GDNativeVariantType p_type_b) {
return (GDNativePtrOperatorEvaluator)Variant::get_ptr_operator_evaluator(Variant::Operator(p_operator), Variant::Type(p_type_a), Variant::Type(p_type_b));
}
-static GDNativePtrBuiltInMethod gdnative_variant_get_ptr_builtin_method(GDNativeVariantType p_type, const char *p_method, GDNativeInt p_hash) {
- StringName method = p_method;
+static GDNativePtrBuiltInMethod gdnative_variant_get_ptr_builtin_method(GDNativeVariantType p_type, const GDNativeStringNamePtr p_method, GDNativeInt p_hash) {
+ const StringName method = *reinterpret_cast<const StringName *>(p_method);
uint32_t hash = Variant::get_builtin_method_hash(Variant::Type(p_type), method);
if (hash != p_hash) {
- ERR_PRINT_ONCE("Error getting method " + String(method) + ", hash mismatch.");
+ ERR_PRINT_ONCE("Error getting method " + method + ", hash mismatch.");
return nullptr;
}
@@ -497,11 +498,13 @@ static void gdnative_variant_construct(GDNativeVariantType p_type, GDNativeVaria
r_error->expected = error.expected;
}
}
-static GDNativePtrSetter gdnative_variant_get_ptr_setter(GDNativeVariantType p_type, const char *p_member) {
- return (GDNativePtrSetter)Variant::get_member_ptr_setter(Variant::Type(p_type), p_member);
+static GDNativePtrSetter gdnative_variant_get_ptr_setter(GDNativeVariantType p_type, const GDNativeStringNamePtr p_member) {
+ const StringName member = *reinterpret_cast<const StringName *>(p_member);
+ return (GDNativePtrSetter)Variant::get_member_ptr_setter(Variant::Type(p_type), member);
}
-static GDNativePtrGetter gdnative_variant_get_ptr_getter(GDNativeVariantType p_type, const char *p_member) {
- return (GDNativePtrGetter)Variant::get_member_ptr_getter(Variant::Type(p_type), p_member);
+static GDNativePtrGetter gdnative_variant_get_ptr_getter(GDNativeVariantType p_type, const GDNativeStringNamePtr p_member) {
+ const StringName member = *reinterpret_cast<const StringName *>(p_member);
+ return (GDNativePtrGetter)Variant::get_member_ptr_getter(Variant::Type(p_type), member);
}
static GDNativePtrIndexedSetter gdnative_variant_get_ptr_indexed_setter(GDNativeVariantType p_type) {
return (GDNativePtrIndexedSetter)Variant::get_member_ptr_indexed_setter(Variant::Type(p_type));
@@ -518,14 +521,15 @@ static GDNativePtrKeyedGetter gdnative_variant_get_ptr_keyed_getter(GDNativeVari
static GDNativePtrKeyedChecker gdnative_variant_get_ptr_keyed_checker(GDNativeVariantType p_type) {
return (GDNativePtrKeyedChecker)Variant::get_member_ptr_keyed_checker(Variant::Type(p_type));
}
-static void gdnative_variant_get_constant_value(GDNativeVariantType p_type, const char *p_constant, GDNativeVariantPtr r_ret) {
- memnew_placement(r_ret, Variant(Variant::get_constant_value(Variant::Type(p_type), p_constant)));
+static void gdnative_variant_get_constant_value(GDNativeVariantType p_type, const GDNativeStringNamePtr p_constant, GDNativeVariantPtr r_ret) {
+ StringName constant = *reinterpret_cast<const StringName *>(p_constant);
+ memnew_placement(r_ret, Variant(Variant::get_constant_value(Variant::Type(p_type), constant)));
}
-static GDNativePtrUtilityFunction gdnative_variant_get_ptr_utility_function(const char *p_function, GDNativeInt p_hash) {
- StringName function = p_function;
+static GDNativePtrUtilityFunction gdnative_variant_get_ptr_utility_function(const GDNativeStringNamePtr p_function, GDNativeInt p_hash) {
+ StringName function = *reinterpret_cast<const StringName *>(p_function);
uint32_t hash = Variant::get_utility_function_hash(function);
if (hash != p_hash) {
- ERR_PRINT_ONCE("Error getting utility function " + String(function) + ", hash mismatch.");
+ ERR_PRINT_ONCE("Error getting utility function " + function + ", hash mismatch.");
return nullptr;
}
return (GDNativePtrUtilityFunction)Variant::get_ptr_utility_function(function);
@@ -836,8 +840,9 @@ static void gdnative_object_destroy(GDNativeObjectPtr p_o) {
memdelete((Object *)p_o);
}
-static GDNativeObjectPtr gdnative_global_get_singleton(const char *p_name) {
- return (GDNativeObjectPtr)Engine::get_singleton()->get_singleton_object(String(p_name));
+static GDNativeObjectPtr gdnative_global_get_singleton(const GDNativeStringNamePtr p_name) {
+ const StringName name = *reinterpret_cast<const StringName *>(p_name);
+ return (GDNativeObjectPtr)Engine::get_singleton()->get_singleton_object(name);
}
static void *gdnative_object_get_instance_binding(GDNativeObjectPtr p_object, void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks) {
@@ -850,9 +855,10 @@ static void gdnative_object_set_instance_binding(GDNativeObjectPtr p_object, voi
o->set_instance_binding(p_token, p_binding, p_callbacks);
}
-static void gdnative_object_set_instance(GDNativeObjectPtr p_object, const char *p_classname, GDExtensionClassInstancePtr p_instance) {
+static void gdnative_object_set_instance(GDNativeObjectPtr p_object, const GDNativeStringNamePtr p_classname, GDExtensionClassInstancePtr p_instance) {
+ const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
Object *o = (Object *)p_object;
- ClassDB::set_object_extension_instance(o, p_classname, p_instance);
+ ClassDB::set_object_extension_instance(o, classname, p_instance);
}
static GDNativeObjectPtr gdnative_object_get_instance_from_id(GDObjectInstanceID p_instance_id) {
@@ -880,23 +886,26 @@ static GDNativeScriptInstancePtr gdnative_script_instance_create(const GDNativeE
return reinterpret_cast<GDNativeScriptInstancePtr>(script_instance_extension);
}
-static GDNativeMethodBindPtr gdnative_classdb_get_method_bind(const char *p_classname, const char *p_methodname, GDNativeInt p_hash) {
- MethodBind *mb = ClassDB::get_method(StringName(p_classname), StringName(p_methodname));
+static GDNativeMethodBindPtr gdnative_classdb_get_method_bind(const GDNativeStringNamePtr p_classname, const GDNativeStringNamePtr p_methodname, GDNativeInt p_hash) {
+ const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
+ const StringName methodname = *reinterpret_cast<const StringName *>(p_methodname);
+ MethodBind *mb = ClassDB::get_method(classname, methodname);
ERR_FAIL_COND_V(!mb, nullptr);
if (mb->get_hash() != p_hash) {
- ERR_PRINT("Hash mismatch for method '" + String(p_classname) + "." + String(p_methodname) + "'.");
+ ERR_PRINT("Hash mismatch for method '" + classname + "." + methodname + "'.");
return nullptr;
}
- // MethodBind *mb = ClassDB::get_method("Node", "get_name");
return (GDNativeMethodBindPtr)mb;
}
-static GDNativeObjectPtr gdnative_classdb_construct_object(const char *p_classname) {
- return (GDNativeObjectPtr)ClassDB::instantiate(p_classname);
+static GDNativeObjectPtr gdnative_classdb_construct_object(const GDNativeStringNamePtr p_classname) {
+ const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
+ return (GDNativeObjectPtr)ClassDB::instantiate(classname);
}
-static void *gdnative_classdb_get_class_tag(const char *p_classname) {
- ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(p_classname);
+static void *gdnative_classdb_get_class_tag(const GDNativeStringNamePtr p_classname) {
+ const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
+ ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(classname);
return class_info ? class_info->class_ptr : nullptr;
}
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
index 1ce50bc186..a361e40096 100644
--- a/core/extension/gdnative_interface.h
+++ b/core/extension/gdnative_interface.h
@@ -202,21 +202,21 @@ typedef uint64_t (*GDNativeExtensionClassGetRID)(GDExtensionClassInstancePtr p_i
typedef struct {
GDNativeVariantType type;
- const char *name;
- const char *class_name;
+ GDNativeStringNamePtr name;
+ GDNativeStringNamePtr class_name;
uint32_t hint; // Bitfield of `PropertyHint` (defined in `extension_api.json`)
- const char *hint_string;
+ GDNativeStringPtr hint_string;
uint32_t usage; // Bitfield of `PropertyUsageFlags` (defined in `extension_api.json`)
} GDNativePropertyInfo;
typedef struct {
- const char *name;
+ GDNativeStringNamePtr name;
GDNativePropertyInfo return_value;
uint32_t flags; // Bitfield of `GDNativeExtensionClassMethodFlags`
int32_t id;
- GDNativePropertyInfo *arguments;
+ GDNativePropertyInfo *arguments; // array of `argument_count` size
uint32_t argument_count;
- GDNativeVariantPtr default_arguments;
+ GDNativeVariantPtr *default_arguments; // array of `default_argument_count` size
uint32_t default_argument_count;
} GDNativeMethodInfo;
@@ -225,13 +225,13 @@ typedef void (*GDNativeExtensionClassFreePropertyList)(GDExtensionClassInstanceP
typedef GDNativeBool (*GDNativeExtensionClassPropertyCanRevert)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name);
typedef GDNativeBool (*GDNativeExtensionClassPropertyGetRevert)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret);
typedef void (*GDNativeExtensionClassNotification)(GDExtensionClassInstancePtr p_instance, int32_t p_what);
-typedef void (*GDNativeExtensionClassToString)(GDExtensionClassInstancePtr p_instance, GDNativeStringPtr p_out);
+typedef void (*GDNativeExtensionClassToString)(GDExtensionClassInstancePtr p_instance, GDNativeBool *r_is_valid, GDNativeStringPtr p_out);
typedef void (*GDNativeExtensionClassReference)(GDExtensionClassInstancePtr p_instance);
typedef void (*GDNativeExtensionClassUnreference)(GDExtensionClassInstancePtr p_instance);
typedef void (*GDNativeExtensionClassCallVirtual)(GDExtensionClassInstancePtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
typedef GDNativeObjectPtr (*GDNativeExtensionClassCreateInstance)(void *p_userdata);
typedef void (*GDNativeExtensionClassFreeInstance)(void *p_userdata, GDExtensionClassInstancePtr p_instance);
-typedef GDNativeExtensionClassCallVirtual (*GDNativeExtensionClassGetVirtual)(void *p_userdata, const char *p_name);
+typedef GDNativeExtensionClassCallVirtual (*GDNativeExtensionClassGetVirtual)(void *p_userdata, const GDNativeStringNamePtr p_name);
typedef struct {
GDNativeBool is_virtual;
@@ -284,24 +284,21 @@ typedef enum {
typedef void (*GDNativeExtensionClassMethodCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error);
typedef void (*GDNativeExtensionClassMethodPtrCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
-/* passing -1 as argument in the following functions refers to the return type */
-typedef GDNativeVariantType (*GDNativeExtensionClassMethodGetArgumentType)(void *p_method_userdata, int32_t p_argument);
-typedef void (*GDNativeExtensionClassMethodGetArgumentInfo)(void *p_method_userdata, int32_t p_argument, GDNativePropertyInfo *r_info);
-typedef GDNativeExtensionClassMethodArgumentMetadata (*GDNativeExtensionClassMethodGetArgumentMetadata)(void *p_method_userdata, int32_t p_argument);
-
typedef struct {
- const char *name;
+ GDNativeStringNamePtr name;
void *method_userdata;
GDNativeExtensionClassMethodCall call_func;
GDNativeExtensionClassMethodPtrCall ptrcall_func;
uint32_t method_flags; // Bitfield of `GDNativeExtensionClassMethodFlags`
uint32_t argument_count;
GDNativeBool has_return_value;
- GDNativeExtensionClassMethodGetArgumentType get_argument_type_func;
- GDNativeExtensionClassMethodGetArgumentInfo get_argument_info_func; /* name and hint information for the argument can be omitted in release builds. Class name should always be present if it applies. */
- GDNativeExtensionClassMethodGetArgumentMetadata get_argument_metadata_func;
+ GDNativePropertyInfo *return_value_info; // Ignored if `has_return_value` is false
+ GDNativeExtensionClassMethodArgumentMetadata return_value_metadata; // Ignored if `has_return_value` is false
+ /* name and hint information for the argument can be omitted in release builds. Class name should always be present if it applies. */
+ GDNativePropertyInfo *aguments_info; // array of `argument_count` size
+ GDNativeExtensionClassMethodArgumentMetadata *aguments_metadata; // array of `argument_count` size
uint32_t default_argument_count;
- GDNativeVariantPtr *default_arguments;
+ GDNativeVariantPtr *default_arguments; // array of `default_argument_count` size
} GDNativeExtensionClassMethodInfo;
/* SCRIPT INSTANCE EXTENSION */
@@ -328,7 +325,7 @@ typedef GDNativeBool (*GDNativeExtensionScriptInstanceHasMethod)(GDNativeExtensi
typedef void (*GDNativeExtensionScriptInstanceCall)(GDNativeExtensionScriptInstanceDataPtr p_self, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error);
typedef void (*GDNativeExtensionScriptInstanceNotification)(GDNativeExtensionScriptInstanceDataPtr p_instance, int32_t p_what);
-typedef const char *(*GDNativeExtensionScriptInstanceToString)(GDNativeExtensionScriptInstanceDataPtr p_instance, GDNativeBool *r_is_valid);
+typedef void (*GDNativeExtensionScriptInstanceToString)(GDNativeExtensionScriptInstanceDataPtr p_instance, GDNativeBool *r_is_valid, GDNativeStringPtr r_out);
typedef void (*GDNativeExtensionScriptInstanceRefCountIncremented)(GDNativeExtensionScriptInstanceDataPtr p_instance);
typedef GDNativeBool (*GDNativeExtensionScriptInstanceRefCountDecremented)(GDNativeExtensionScriptInstanceDataPtr p_instance);
@@ -349,7 +346,6 @@ typedef struct {
GDNativeExtensionScriptInstanceGet get_func;
GDNativeExtensionScriptInstanceGetPropertyList get_property_list_func;
GDNativeExtensionScriptInstanceFreePropertyList free_property_list_func;
- GDNativeExtensionScriptInstanceGetPropertyType get_property_type_func;
GDNativeExtensionScriptInstancePropertyCanRevert property_can_revert_func;
GDNativeExtensionScriptInstancePropertyGetRevert property_get_revert_func;
@@ -359,6 +355,7 @@ typedef struct {
GDNativeExtensionScriptInstanceGetMethodList get_method_list_func;
GDNativeExtensionScriptInstanceFreeMethodList free_method_list_func;
+ GDNativeExtensionScriptInstanceGetPropertyType get_property_type_func;
GDNativeExtensionScriptInstanceHasMethod has_method_func;
@@ -400,7 +397,7 @@ typedef struct {
void (*print_warning)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
void (*print_script_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
- uint64_t (*get_native_struct_size)(const char *p_name);
+ uint64_t (*get_native_struct_size)(const GDNativeStringNamePtr p_name);
/* GODOT VARIANT */
@@ -443,19 +440,19 @@ typedef struct {
GDNativeVariantFromTypeConstructorFunc (*get_variant_from_type_constructor)(GDNativeVariantType p_type);
GDNativeTypeFromVariantConstructorFunc (*get_variant_to_type_constructor)(GDNativeVariantType p_type);
GDNativePtrOperatorEvaluator (*variant_get_ptr_operator_evaluator)(GDNativeVariantOperator p_operator, GDNativeVariantType p_type_a, GDNativeVariantType p_type_b);
- GDNativePtrBuiltInMethod (*variant_get_ptr_builtin_method)(GDNativeVariantType p_type, const char *p_method, GDNativeInt p_hash);
+ GDNativePtrBuiltInMethod (*variant_get_ptr_builtin_method)(GDNativeVariantType p_type, const GDNativeStringNamePtr p_method, GDNativeInt p_hash);
GDNativePtrConstructor (*variant_get_ptr_constructor)(GDNativeVariantType p_type, int32_t p_constructor);
GDNativePtrDestructor (*variant_get_ptr_destructor)(GDNativeVariantType p_type);
void (*variant_construct)(GDNativeVariantType p_type, GDNativeVariantPtr p_base, const GDNativeVariantPtr *p_args, int32_t p_argument_count, GDNativeCallError *r_error);
- GDNativePtrSetter (*variant_get_ptr_setter)(GDNativeVariantType p_type, const char *p_member);
- GDNativePtrGetter (*variant_get_ptr_getter)(GDNativeVariantType p_type, const char *p_member);
+ GDNativePtrSetter (*variant_get_ptr_setter)(GDNativeVariantType p_type, const GDNativeStringNamePtr p_member);
+ GDNativePtrGetter (*variant_get_ptr_getter)(GDNativeVariantType p_type, const GDNativeStringNamePtr p_member);
GDNativePtrIndexedSetter (*variant_get_ptr_indexed_setter)(GDNativeVariantType p_type);
GDNativePtrIndexedGetter (*variant_get_ptr_indexed_getter)(GDNativeVariantType p_type);
GDNativePtrKeyedSetter (*variant_get_ptr_keyed_setter)(GDNativeVariantType p_type);
GDNativePtrKeyedGetter (*variant_get_ptr_keyed_getter)(GDNativeVariantType p_type);
GDNativePtrKeyedChecker (*variant_get_ptr_keyed_checker)(GDNativeVariantType p_type);
- void (*variant_get_constant_value)(GDNativeVariantType p_type, const char *p_constant, GDNativeVariantPtr r_ret);
- GDNativePtrUtilityFunction (*variant_get_ptr_utility_function)(const char *p_function, GDNativeInt p_hash);
+ void (*variant_get_constant_value)(GDNativeVariantType p_type, const GDNativeStringNamePtr p_constant, GDNativeVariantPtr r_ret);
+ GDNativePtrUtilityFunction (*variant_get_ptr_utility_function)(const GDNativeStringNamePtr p_function, GDNativeInt p_hash);
/* extra utilities */
@@ -524,12 +521,12 @@ typedef struct {
void (*object_method_bind_call)(const GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeVariantPtr *p_args, GDNativeInt p_arg_count, GDNativeVariantPtr r_ret, GDNativeCallError *r_error);
void (*object_method_bind_ptrcall)(const GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
void (*object_destroy)(GDNativeObjectPtr p_o);
- GDNativeObjectPtr (*global_get_singleton)(const char *p_name);
+ GDNativeObjectPtr (*global_get_singleton)(const GDNativeStringNamePtr p_name);
void *(*object_get_instance_binding)(GDNativeObjectPtr p_o, void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks);
void (*object_set_instance_binding)(GDNativeObjectPtr p_o, void *p_token, void *p_binding, const GDNativeInstanceBindingCallbacks *p_callbacks);
- void (*object_set_instance)(GDNativeObjectPtr p_o, const char *p_classname, GDExtensionClassInstancePtr p_instance); /* p_classname should be a registered extension class and should extend the p_o object's class. */
+ void (*object_set_instance)(GDNativeObjectPtr p_o, const GDNativeStringNamePtr p_classname, GDExtensionClassInstancePtr p_instance); /* p_classname should be a registered extension class and should extend the p_o object's class. */
GDNativeObjectPtr (*object_cast_to)(const GDNativeObjectPtr p_object, void *p_class_tag);
GDNativeObjectPtr (*object_get_instance_from_id)(GDObjectInstanceID p_instance_id);
@@ -540,20 +537,21 @@ typedef struct {
GDNativeScriptInstancePtr (*script_instance_create)(const GDNativeExtensionScriptInstanceInfo *p_info, GDNativeExtensionScriptInstanceDataPtr p_instance_data);
/* CLASSDB */
- GDNativeObjectPtr (*classdb_construct_object)(const char *p_classname); /* The passed class must be a built-in godot class, or an already-registered extension class. In both case, object_set_instance should be called to fully initialize the object. */
- GDNativeMethodBindPtr (*classdb_get_method_bind)(const char *p_classname, const char *p_methodname, GDNativeInt p_hash);
- void *(*classdb_get_class_tag)(const char *p_classname);
+ GDNativeObjectPtr (*classdb_construct_object)(const GDNativeStringNamePtr p_classname); /* The passed class must be a built-in godot class, or an already-registered extension class. In both case, object_set_instance should be called to fully initialize the object. */
+ GDNativeMethodBindPtr (*classdb_get_method_bind)(const GDNativeStringNamePtr p_classname, const GDNativeStringNamePtr p_methodname, GDNativeInt p_hash);
+ void *(*classdb_get_class_tag)(const GDNativeStringNamePtr p_classname);
/* CLASSDB EXTENSION */
- void (*classdb_register_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs);
- void (*classdb_register_extension_class_method)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info);
- void (*classdb_register_extension_class_integer_constant)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield);
- void (*classdb_register_extension_class_property)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter);
- void (*classdb_register_extension_class_property_group)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_group_name, const char *p_prefix);
- void (*classdb_register_extension_class_property_subgroup)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_subgroup_name, const char *p_prefix);
- void (*classdb_register_extension_class_signal)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count);
- void (*classdb_unregister_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name); /* Unregistering a parent class before a class that inherits it will result in failure. Inheritors must be unregistered first. */
+ // Provided parameters for `classdb_register_extension_*` can be safely freed once the function returns
+ void (*classdb_register_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs);
+ void (*classdb_register_extension_class_method)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info);
+ void (*classdb_register_extension_class_integer_constant)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_enum_name, const GDNativeStringNamePtr p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield);
+ void (*classdb_register_extension_class_property)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativePropertyInfo *p_info, const GDNativeStringNamePtr p_setter, const GDNativeStringNamePtr p_getter);
+ void (*classdb_register_extension_class_property_group)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringPtr p_group_name, const GDNativeStringPtr p_prefix);
+ void (*classdb_register_extension_class_property_subgroup)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringPtr p_subgroup_name, const GDNativeStringPtr p_prefix);
+ void (*classdb_register_extension_class_signal)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count);
+ void (*classdb_unregister_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name); /* Unregistering a parent class before a class that inherits it will result in failure. Inheritors must be unregistered first. */
void (*get_library_path)(const GDNativeExtensionClassLibraryPtr p_library, GDNativeStringPtr r_path);
diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp
index cc019584a5..8bbb72fd82 100644
--- a/core/extension/native_extension.cpp
+++ b/core/extension/native_extension.cpp
@@ -42,26 +42,37 @@ String NativeExtension::get_extension_list_config_file() {
class NativeExtensionMethodBind : public MethodBind {
GDNativeExtensionClassMethodCall call_func;
GDNativeExtensionClassMethodPtrCall ptrcall_func;
- GDNativeExtensionClassMethodGetArgumentType get_argument_type_func;
- GDNativeExtensionClassMethodGetArgumentInfo get_argument_info_func;
- GDNativeExtensionClassMethodGetArgumentMetadata get_argument_metadata_func;
void *method_userdata;
bool vararg;
+ PropertyInfo return_value_info;
+ GodotTypeInfo::Metadata return_value_metadata;
+ List<PropertyInfo> arguments_info;
+ List<GodotTypeInfo::Metadata> arguments_metadata;
protected:
virtual Variant::Type _gen_argument_type(int p_arg) const override {
- return Variant::Type(get_argument_type_func(method_userdata, p_arg));
+ if (p_arg < 0) {
+ return return_value_info.type;
+ } else {
+ return arguments_info[p_arg].type;
+ }
}
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
- GDNativePropertyInfo pinfo;
- get_argument_info_func(method_userdata, p_arg, &pinfo);
- return PropertyInfo(pinfo);
+ if (p_arg < 0) {
+ return return_value_info;
+ } else {
+ return arguments_info[p_arg];
+ }
}
public:
#ifdef DEBUG_METHODS_ENABLED
virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const override {
- return GodotTypeInfo::Metadata(get_argument_metadata_func(method_userdata, p_arg));
+ if (p_arg < 0) {
+ return return_value_metadata;
+ } else {
+ return arguments_metadata[p_arg];
+ }
}
#endif
@@ -89,10 +100,17 @@ public:
method_userdata = p_method_info->method_userdata;
call_func = p_method_info->call_func;
ptrcall_func = p_method_info->ptrcall_func;
- get_argument_type_func = p_method_info->get_argument_type_func;
- get_argument_info_func = p_method_info->get_argument_info_func;
- get_argument_metadata_func = p_method_info->get_argument_metadata_func;
- set_name(p_method_info->name);
+ set_name(*reinterpret_cast<StringName *>(p_method_info->name));
+
+ if (p_method_info->has_return_value) {
+ return_value_info = PropertyInfo(*p_method_info->return_value_info);
+ return_value_metadata = GodotTypeInfo::Metadata(p_method_info->return_value_metadata);
+ }
+
+ for (uint32_t i = 0; i < p_method_info->argument_count; i++) {
+ arguments_info.push_back(PropertyInfo(p_method_info->aguments_info[i]));
+ arguments_metadata.push_back(GodotTypeInfo::Metadata(p_method_info->aguments_metadata[i]));
+ }
set_hint_flags(p_method_info->method_flags);
@@ -117,15 +135,15 @@ public:
static GDNativeInterface gdnative_interface;
-void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs) {
+void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs) {
NativeExtension *self = static_cast<NativeExtension *>(p_library);
- StringName class_name = p_class_name;
+ StringName class_name = *reinterpret_cast<StringName *>(p_class_name);
+ StringName parent_class_name = *reinterpret_cast<StringName *>(p_parent_class_name);
ERR_FAIL_COND_MSG(!String(class_name).is_valid_identifier(), "Attempt to register extension class '" + class_name + "', which is not a valid class identifier.");
ERR_FAIL_COND_MSG(ClassDB::class_exists(class_name), "Attempt to register extension class '" + class_name + "', which appears to be already registered.");
Extension *parent_extension = nullptr;
- StringName parent_class_name = p_parent_class_name;
if (self->extension_classes.has(parent_class_name)) {
parent_extension = &self->extension_classes[parent_class_name];
@@ -172,11 +190,11 @@ void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibr
ClassDB::register_extension_class(&extension->native_extension);
}
-void NativeExtension::_register_extension_class_method(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info) {
+void NativeExtension::_register_extension_class_method(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info) {
NativeExtension *self = static_cast<NativeExtension *>(p_library);
- StringName class_name = p_class_name;
- StringName method_name = p_method_info->name;
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ StringName method_name = *reinterpret_cast<const StringName *>(p_method_info->name);
ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension method '" + String(method_name) + "' for unexisting class '" + class_name + "'.");
//Extension *extension = &self->extension_classes[class_name];
@@ -186,56 +204,63 @@ void NativeExtension::_register_extension_class_method(const GDNativeExtensionCl
ClassDB::bind_method_custom(class_name, method);
}
-void NativeExtension::_register_extension_class_integer_constant(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield) {
+void NativeExtension::_register_extension_class_integer_constant(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_enum_name, const GDNativeStringNamePtr p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield) {
NativeExtension *self = static_cast<NativeExtension *>(p_library);
- StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension constant '" + String(p_constant_name) + "' for unexisting class '" + class_name + "'.");
-
- //Extension *extension = &self->extension_classes[class_name];
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ StringName enum_name = *reinterpret_cast<const StringName *>(p_enum_name);
+ StringName constant_name = *reinterpret_cast<const StringName *>(p_constant_name);
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension constant '" + constant_name + "' for unexisting class '" + class_name + "'.");
- ClassDB::bind_integer_constant(class_name, p_enum_name, p_constant_name, p_constant_value, p_is_bitfield);
+ ClassDB::bind_integer_constant(class_name, enum_name, constant_name, p_constant_value, p_is_bitfield);
}
-void NativeExtension::_register_extension_class_property(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter) {
+void NativeExtension::_register_extension_class_property(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativePropertyInfo *p_info, const GDNativeStringNamePtr p_setter, const GDNativeStringNamePtr p_getter) {
NativeExtension *self = static_cast<NativeExtension *>(p_library);
- StringName class_name = p_class_name;
- String property_name = p_info->name;
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ StringName setter = *reinterpret_cast<const StringName *>(p_setter);
+ StringName getter = *reinterpret_cast<const StringName *>(p_getter);
+ String property_name = *reinterpret_cast<const StringName *>(p_info->name);
ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property '" + property_name + "' for unexisting class '" + class_name + "'.");
//Extension *extension = &self->extension_classes[class_name];
PropertyInfo pinfo(*p_info);
- ClassDB::add_property(class_name, pinfo, p_setter, p_getter);
+ ClassDB::add_property(class_name, pinfo, setter, getter);
}
-void NativeExtension::_register_extension_class_property_group(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_group_name, const char *p_prefix) {
+void NativeExtension::_register_extension_class_property_group(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringPtr p_group_name, const GDNativeStringPtr p_prefix) {
NativeExtension *self = static_cast<NativeExtension *>(p_library);
- StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property group '" + String(p_group_name) + "' for unexisting class '" + class_name + "'.");
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ String group_name = *reinterpret_cast<const String *>(p_group_name);
+ String prefix = *reinterpret_cast<const String *>(p_prefix);
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property group '" + group_name + "' for unexisting class '" + class_name + "'.");
- ClassDB::add_property_group(class_name, p_group_name, p_prefix);
+ ClassDB::add_property_group(class_name, group_name, prefix);
}
-void NativeExtension::_register_extension_class_property_subgroup(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_subgroup_name, const char *p_prefix) {
+void NativeExtension::_register_extension_class_property_subgroup(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringPtr p_subgroup_name, const GDNativeStringPtr p_prefix) {
NativeExtension *self = static_cast<NativeExtension *>(p_library);
- StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property subgroup '" + String(p_subgroup_name) + "' for unexisting class '" + class_name + "'.");
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ String subgroup_name = *reinterpret_cast<const String *>(p_subgroup_name);
+ String prefix = *reinterpret_cast<const String *>(p_prefix);
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property subgroup '" + subgroup_name + "' for unexisting class '" + class_name + "'.");
- ClassDB::add_property_subgroup(class_name, p_subgroup_name, p_prefix);
+ ClassDB::add_property_subgroup(class_name, subgroup_name, prefix);
}
-void NativeExtension::_register_extension_class_signal(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count) {
+void NativeExtension::_register_extension_class_signal(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count) {
NativeExtension *self = static_cast<NativeExtension *>(p_library);
- StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class signal '" + String(p_signal_name) + "' for unexisting class '" + class_name + "'.");
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ StringName signal_name = *reinterpret_cast<const StringName *>(p_signal_name);
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class signal '" + signal_name + "' for unexisting class '" + class_name + "'.");
MethodInfo s;
- s.name = p_signal_name;
+ s.name = signal_name;
for (int i = 0; i < p_argument_count; i++) {
PropertyInfo arg(p_argument_info[i]);
s.arguments.push_back(arg);
@@ -243,10 +268,10 @@ void NativeExtension::_register_extension_class_signal(const GDNativeExtensionCl
ClassDB::add_signal(class_name, s);
}
-void NativeExtension::_unregister_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name) {
+void NativeExtension::_unregister_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name) {
NativeExtension *self = static_cast<NativeExtension *>(p_library);
- StringName class_name = p_class_name;
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to unregister unexisting extension class '" + class_name + "'.");
Extension *ext = &self->extension_classes[class_name];
ERR_FAIL_COND_MSG(ext->native_extension.children.size(), "Attempt to unregister class '" + class_name + "' while other extension classes inherit from it.");
diff --git a/core/extension/native_extension.h b/core/extension/native_extension.h
index b7238d2899..70f6f9f039 100644
--- a/core/extension/native_extension.h
+++ b/core/extension/native_extension.h
@@ -47,14 +47,14 @@ class NativeExtension : public Resource {
HashMap<StringName, Extension> extension_classes;
- static void _register_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs);
- static void _register_extension_class_method(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info);
- static void _register_extension_class_integer_constant(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield);
- static void _register_extension_class_property(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter);
- static void _register_extension_class_property_group(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_group_name, const char *p_prefix);
- static void _register_extension_class_property_subgroup(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_subgroup_name, const char *p_prefix);
- static void _register_extension_class_signal(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count);
- static void _unregister_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name);
+ static void _register_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs);
+ static void _register_extension_class_method(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info);
+ static void _register_extension_class_integer_constant(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_enum_name, const GDNativeStringNamePtr p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield);
+ static void _register_extension_class_property(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativePropertyInfo *p_info, const GDNativeStringNamePtr p_setter, const GDNativeStringNamePtr p_getter);
+ static void _register_extension_class_property_group(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_group_name, const GDNativeStringNamePtr p_prefix);
+ static void _register_extension_class_property_subgroup(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_subgroup_name, const GDNativeStringNamePtr p_prefix);
+ static void _register_extension_class_signal(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count);
+ static void _unregister_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name);
static void _get_library_path(const GDNativeExtensionClassLibraryPtr p_library, GDNativeStringPtr r_path);
GDNativeInitialization initialization;
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 9dc071de9c..0a32b4bf68 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -1562,7 +1562,7 @@ String InputEventMIDI::as_text() const {
}
String InputEventMIDI::to_string() {
- return vformat("InputEventMIDI: channel=%d, message=%d, pitch=%d, velocity=%d, pressure=%d", channel, message, pitch, velocity, pressure);
+ return vformat("InputEventMIDI: channel=%d, message=%d, pitch=%d, velocity=%d, pressure=%d, controller_number=%d, controller_value=%d", channel, message, pitch, velocity, pressure, controller_number, controller_value);
}
void InputEventMIDI::_bind_methods() {
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index 41585943b3..ac6ad0fdd2 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -31,6 +31,7 @@
#include "class_db.h"
#include "core/config/engine.h"
+#include "core/object/script_language.h"
#include "core/os/mutex.h"
#include "core/version.h"
@@ -376,7 +377,12 @@ bool ClassDB::is_virtual(const StringName &p_class) {
OBJTYPE_RLOCK;
ClassInfo *ti = classes.getptr(p_class);
- ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'.");
+ if (!ti) {
+ if (!ScriptServer::is_global_class(p_class)) {
+ ERR_FAIL_V_MSG(false, "Cannot get class '" + String(p_class) + "'.");
+ }
+ return false;
+ }
#ifdef TOOLS_ENABLED
if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) {
return false;
@@ -1454,7 +1460,7 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con
if (Engine::get_singleton()->has_singleton(p_class)) {
c = Engine::get_singleton()->get_singleton_object(p_class);
cleanup_c = false;
- } else if (ClassDB::can_instantiate(p_class) && !ClassDB::is_virtual(p_class)) {
+ } else if (ClassDB::can_instantiate(p_class) && !ClassDB::is_virtual(p_class)) { // Keep this condition in sync with doc_tools.cpp get_documentation_default_value.
c = ClassDB::instantiate(p_class);
cleanup_c = true;
}
diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py
index 326a9277ff..61bf6d900a 100644
--- a/core/object/make_virtuals.py
+++ b/core/object/make_virtuals.py
@@ -16,7 +16,8 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\
} \\
}\\
if (unlikely(_get_extension() && !_gdvirtual_##m_name##_initialized)) {\\
- _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, #m_name) : (GDNativeExtensionClassCallVirtual) nullptr;\\
+ /* TODO: C-style cast because GDNativeStringNamePtr's const qualifier is broken (see https://github.com/godotengine/godot/pull/67751) */\\
+ _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, (GDNativeStringNamePtr)&_gdvirtual_##m_name##_sn) : (GDNativeExtensionClassCallVirtual) nullptr;\\
_gdvirtual_##m_name##_initialized = true;\\
}\\
if (_gdvirtual_##m_name) {\\
@@ -40,7 +41,8 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_overridden() const { \\
return _script_instance->has_method(_gdvirtual_##m_name##_sn);\\
}\\
if (unlikely(_get_extension() && !_gdvirtual_##m_name##_initialized)) {\\
- _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, #m_name) : (GDNativeExtensionClassCallVirtual) nullptr;\\
+ /* TODO: C-style cast because GDNativeStringNamePtr's const qualifier is broken (see https://github.com/godotengine/godot/pull/67751) */\\
+ _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, (GDNativeStringNamePtr)&_gdvirtual_##m_name##_sn) : (GDNativeExtensionClassCallVirtual) nullptr;\\
_gdvirtual_##m_name##_initialized = true;\\
}\\
if (_gdvirtual_##m_name) {\\
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 540b9a8f19..d27e0d7621 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -808,7 +808,8 @@ String Object::to_string() {
}
if (_extension && _extension->to_string) {
String ret;
- _extension->to_string(_extension_instance, &ret);
+ GDNativeBool is_valid;
+ _extension->to_string(_extension_instance, &is_valid, &ret);
return ret;
}
return "<" + get_class() + "#" + itos(get_instance_id()) + ">";
diff --git a/core/object/object.h b/core/object/object.h
index 8c647cda40..7bb88998a2 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -192,10 +192,10 @@ struct PropertyInfo {
explicit PropertyInfo(const GDNativePropertyInfo &pinfo) :
type((Variant::Type)pinfo.type),
- name(pinfo.name),
- class_name(pinfo.class_name), // can be null
+ name(*reinterpret_cast<StringName *>(pinfo.name)),
+ class_name(*reinterpret_cast<StringName *>(pinfo.class_name)),
hint((PropertyHint)pinfo.hint),
- hint_string(pinfo.hint_string), // can be null
+ hint_string(*reinterpret_cast<String *>(pinfo.hint_string)),
usage(pinfo.usage) {}
bool operator==(const PropertyInfo &p_info) const {
@@ -242,6 +242,20 @@ struct MethodInfo {
MethodInfo() {}
+ explicit MethodInfo(const GDNativeMethodInfo &pinfo) :
+ name(*reinterpret_cast<StringName *>(pinfo.name)),
+ return_val(PropertyInfo(pinfo.return_value)),
+ flags(pinfo.flags),
+ id(pinfo.id) {
+ for (uint32_t j = 0; j < pinfo.argument_count; j++) {
+ arguments.push_back(PropertyInfo(pinfo.arguments[j]));
+ }
+ const Variant *def_values = (const Variant *)pinfo.default_arguments;
+ for (uint32_t j = 0; j < pinfo.default_argument_count; j++) {
+ default_arguments.push_back(def_values[j]);
+ }
+ }
+
void _push_params(const PropertyInfo &p_param) {
arguments.push_back(p_param);
}
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
index c32fb9d85b..9a2a176096 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -687,7 +687,6 @@ public:
if (r_is_valid) {
*r_is_valid = is_valid != 0;
}
-
return Variant::Type(type);
}
return Variant::NIL;
@@ -727,19 +726,7 @@ public:
uint32_t mcount;
const GDNativeMethodInfo *minfo = native_info->get_method_list_func(instance, &mcount);
for (uint32_t i = 0; i < mcount; i++) {
- MethodInfo m;
- m.name = minfo[i].name;
- m.flags = minfo[i].flags;
- m.id = minfo[i].id;
- m.return_val = PropertyInfo(minfo[i].return_value);
- for (uint32_t j = 0; j < minfo[i].argument_count; j++) {
- m.arguments.push_back(PropertyInfo(minfo[i].arguments[j]));
- }
- const Variant *def_values = (const Variant *)minfo[i].default_arguments;
- for (uint32_t j = 0; j < minfo[i].default_argument_count; j++) {
- m.default_arguments.push_back(def_values[j]);
- }
- p_list->push_back(m);
+ p_list->push_back(MethodInfo(minfo[i]));
}
if (native_info->free_method_list_func) {
native_info->free_method_list_func(instance, minfo);
@@ -773,7 +760,8 @@ public:
virtual String to_string(bool *r_valid) override {
if (native_info->to_string_func) {
GDNativeBool valid;
- String ret = native_info->to_string_func(instance, &valid);
+ String ret;
+ native_info->to_string_func(instance, &valid, reinterpret_cast<GDNativeStringPtr>(&ret));
if (r_valid) {
*r_valid = valid != 0;
}
diff --git a/core/string/optimized_translation.cpp b/core/string/optimized_translation.cpp
index b130c2fc79..2fb3b54e27 100644
--- a/core/string/optimized_translation.cpp
+++ b/core/string/optimized_translation.cpp
@@ -267,6 +267,39 @@ StringName OptimizedTranslation::get_message(const StringName &p_src_text, const
}
}
+Vector<String> OptimizedTranslation::get_translated_message_list() const {
+ Vector<String> msgs;
+
+ const int *htr = hash_table.ptr();
+ const uint32_t *htptr = (const uint32_t *)&htr[0];
+ const int *btr = bucket_table.ptr();
+ const uint32_t *btptr = (const uint32_t *)&btr[0];
+ const uint8_t *sr = strings.ptr();
+ const char *sptr = (const char *)&sr[0];
+
+ for (int i = 0; i < hash_table.size(); i++) {
+ uint32_t p = htptr[i];
+ if (p != 0xFFFFFFFF) {
+ const Bucket &bucket = *(const Bucket *)&btptr[p];
+ for (int j = 0; j < bucket.size; j++) {
+ if (bucket.elem[j].comp_size == bucket.elem[j].uncomp_size) {
+ String rstr;
+ rstr.parse_utf8(&sptr[bucket.elem[j].str_offset], bucket.elem[j].uncomp_size);
+ msgs.push_back(rstr);
+ } else {
+ CharString uncomp;
+ uncomp.resize(bucket.elem[j].uncomp_size + 1);
+ smaz_decompress(&sptr[bucket.elem[j].str_offset], bucket.elem[j].comp_size, uncomp.ptrw(), bucket.elem[j].uncomp_size);
+ String rstr;
+ rstr.parse_utf8(uncomp.get_data());
+ msgs.push_back(rstr);
+ }
+ }
+ }
+ }
+ return msgs;
+}
+
StringName OptimizedTranslation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const {
// The use of plurals translation is not yet supported in OptimizedTranslation.
return get_message(p_src_text, p_context);
diff --git a/core/string/optimized_translation.h b/core/string/optimized_translation.h
index f3dbfe8f5c..1cd12782d0 100644
--- a/core/string/optimized_translation.h
+++ b/core/string/optimized_translation.h
@@ -81,6 +81,7 @@ protected:
public:
virtual StringName get_message(const StringName &p_src_text, const StringName &p_context = "") const override; //overridable for other implementations
virtual StringName get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context = "") const override;
+ virtual Vector<String> get_translated_message_list() const override;
void generate(const Ref<Translation> &p_from);
OptimizedTranslation() {}
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index 2bed3543dc..d1ac91957a 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -59,6 +59,18 @@ Vector<String> Translation::_get_message_list() const {
return msgs;
}
+Vector<String> Translation::get_translated_message_list() const {
+ Vector<String> msgs;
+ msgs.resize(translation_map.size());
+ int idx = 0;
+ for (const KeyValue<StringName, StringName> &E : translation_map) {
+ msgs.set(idx, E.value);
+ idx += 1;
+ }
+
+ return msgs;
+}
+
void Translation::_set_messages(const Dictionary &p_messages) {
List<Variant> keys;
p_messages.get_key_list(&keys);
@@ -140,6 +152,7 @@ void Translation::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_plural_message", "src_message", "src_plural_message", "n", "context"), &Translation::get_plural_message, DEFVAL(""));
ClassDB::bind_method(D_METHOD("erase_message", "src_message", "context"), &Translation::erase_message, DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_message_list"), &Translation::_get_message_list);
+ ClassDB::bind_method(D_METHOD("get_translated_message_list"), &Translation::get_translated_message_list);
ClassDB::bind_method(D_METHOD("get_message_count"), &Translation::get_message_count);
ClassDB::bind_method(D_METHOD("_set_messages", "messages"), &Translation::_set_messages);
ClassDB::bind_method(D_METHOD("_get_messages"), &Translation::_get_messages);
diff --git a/core/string/translation.h b/core/string/translation.h
index 9a369b0b05..5e8344baac 100644
--- a/core/string/translation.h
+++ b/core/string/translation.h
@@ -64,6 +64,7 @@ public:
virtual void erase_message(const StringName &p_src_text, const StringName &p_context = "");
virtual void get_message_list(List<StringName> *r_messages) const;
virtual int get_message_count() const;
+ virtual Vector<String> get_translated_message_list() const;
Translation() {}
};
diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp
index fa656b634d..724c1d42bc 100644
--- a/core/string/translation_po.cpp
+++ b/core/string/translation_po.cpp
@@ -103,6 +103,23 @@ void TranslationPO::_set_messages(const Dictionary &p_messages) {
}
}
+Vector<String> TranslationPO::get_translated_message_list() const {
+ Vector<String> msgs;
+ for (const KeyValue<StringName, HashMap<StringName, Vector<StringName>>> &E : translation_map) {
+ if (E.key != StringName()) {
+ continue;
+ }
+
+ for (const KeyValue<StringName, Vector<StringName>> &E2 : E.value) {
+ for (const StringName &E3 : E2.value) {
+ msgs.push_back(E3);
+ }
+ }
+ }
+
+ return msgs;
+}
+
Vector<String> TranslationPO::_get_message_list() const {
// Return all keys in translation_map.
diff --git a/core/string/translation_po.h b/core/string/translation_po.h
index 7d63af2246..c50ea85744 100644
--- a/core/string/translation_po.h
+++ b/core/string/translation_po.h
@@ -70,6 +70,7 @@ protected:
static void _bind_methods();
public:
+ Vector<String> get_translated_message_list() const override;
void get_message_list(List<StringName> *r_messages) const override;
int get_message_count() const override;
void add_message(const StringName &p_src_text, const StringName &p_xlated_text, const StringName &p_context = "") override;
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index c86c8316fe..2ba389fc4d 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -1180,9 +1180,14 @@ Vector<String> String::split(const String &p_splitter, bool p_allow_empty, int p
int len = length();
while (true) {
- int end = find(p_splitter, from);
- if (end < 0) {
- end = len;
+ int end;
+ if (p_splitter.is_empty()) {
+ end = from + 1;
+ } else {
+ end = find(p_splitter, from);
+ if (end < 0) {
+ end = len;
+ }
}
if (p_allow_empty || (end > from)) {
if (p_maxsplit <= 0) {
@@ -1223,7 +1228,15 @@ Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int
break;
}
- int left_edge = rfind(p_splitter, remaining_len - p_splitter.length());
+ int left_edge;
+ if (p_splitter.is_empty()) {
+ left_edge = remaining_len - 1;
+ if (left_edge == 0) {
+ left_edge--; // Skip to the < 0 condition.
+ }
+ } else {
+ left_edge = rfind(p_splitter, remaining_len - p_splitter.length());
+ }
if (left_edge < 0) {
// no more splitters, we're done
@@ -1447,15 +1460,25 @@ String String::num(double p_num, int p_decimals) {
fmt[5] = 'f';
fmt[6] = 0;
}
- char buf[256];
+ // if we want to convert a double with as much decimal places as as
+ // DBL_MAX or DBL_MIN then we would theoretically need a buffer of at least
+ // DBL_MAX_10_EXP + 2 for DBL_MAX and DBL_MAX_10_EXP + 4 for DBL_MIN.
+ // BUT those values where still giving me exceptions, so I tested from
+ // DBL_MAX_10_EXP + 10 incrementing one by one and DBL_MAX_10_EXP + 17 (325)
+ // was the first buffer size not to throw an exception
+ char buf[325];
#if defined(__GNUC__) || defined(_MSC_VER)
- snprintf(buf, 256, fmt, p_num);
+ // PLEASE NOTE that, albeit vcrt online reference states that snprintf
+ // should safely truncate the output to the given buffer size, we have
+ // found a case where this is not true, so we should create a buffer
+ // as big as needed
+ snprintf(buf, 325, fmt, p_num);
#else
sprintf(buf, fmt, p_num);
#endif
- buf[255] = 0;
+ buf[324] = 0;
//destroy trailing zeroes
{
bool period = false;
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 4b6568a502..8af74584f3 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -345,8 +345,8 @@ public:
String get_slice(String p_splitter, int p_slice) const;
String get_slicec(char32_t p_splitter, int p_slice) const;
- Vector<String> split(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const;
- Vector<String> rsplit(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const;
+ Vector<String> split(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
+ Vector<String> rsplit(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
Vector<String> split_spaces() const;
Vector<float> split_floats(const String &p_splitter, bool p_allow_empty = true) const;
Vector<float> split_floats_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const;
diff --git a/core/variant/callable.h b/core/variant/callable.h
index 0305dc55c3..32770bd663 100644
--- a/core/variant/callable.h
+++ b/core/variant/callable.h
@@ -73,6 +73,16 @@ public:
void call_deferredp(const Variant **p_arguments, int p_argcount) const;
Variant callv(const Array &p_arguments) const;
+ template <typename... VarArgs>
+ void call_deferred(VarArgs... p_args) const {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., 0 }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return call_deferredp(sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
Error rpcp(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const;
_FORCE_INLINE_ bool is_null() const {
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 7da46a2d05..91af2bab85 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1509,8 +1509,8 @@ static void _register_variant_builtin_methods() {
bind_method(String, to_camel_case, sarray(), varray());
bind_method(String, to_pascal_case, sarray(), varray());
bind_method(String, to_snake_case, sarray(), varray());
- bind_method(String, split, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0));
- bind_method(String, rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0));
+ bind_method(String, split, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
+ bind_method(String, rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
bind_method(String, split_floats, sarray("delimiter", "allow_empty"), varray(true));
bind_method(String, join, sarray("parts"), varray());
diff --git a/doc/classes/AnimatedTexture.xml b/doc/classes/AnimatedTexture.xml
index f0c86ba47b..57a7f86901 100644
--- a/doc/classes/AnimatedTexture.xml
+++ b/doc/classes/AnimatedTexture.xml
@@ -57,6 +57,7 @@
<member name="pause" type="bool" setter="set_pause" getter="get_pause" default="false">
If [code]true[/code], the animation will pause where it currently is (i.e. at [member current_frame]). The animation will continue from where it was paused when changing this property to [code]false[/code].
</member>
+ <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
<member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
The animation speed is multiplied by this value. If set to a negative value, the animation is played in reverse.
</member>
diff --git a/doc/classes/AtlasTexture.xml b/doc/classes/AtlasTexture.xml
index 809d983a9d..fc75459e46 100644
--- a/doc/classes/AtlasTexture.xml
+++ b/doc/classes/AtlasTexture.xml
@@ -23,5 +23,6 @@
<member name="region" type="Rect2" setter="set_region" getter="get_region" default="Rect2(0, 0, 0, 0)">
The region used to draw the [member atlas].
</member>
+ <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
</members>
</class>
diff --git a/doc/classes/BaseButton.xml b/doc/classes/BaseButton.xml
index 638934bc9e..c92e39e08a 100644
--- a/doc/classes/BaseButton.xml
+++ b/doc/classes/BaseButton.xml
@@ -44,37 +44,38 @@
</method>
</methods>
<members>
- <member name="action_mode" type="int" setter="set_action_mode" getter="get_action_mode" enum="BaseButton.ActionMode">
+ <member name="action_mode" type="int" setter="set_action_mode" getter="get_action_mode" enum="BaseButton.ActionMode" default="1">
Determines when the button is considered clicked, one of the [enum ActionMode] constants.
</member>
<member name="button_group" type="ButtonGroup" setter="set_button_group" getter="get_button_group">
The [ButtonGroup] associated with the button. Not to be confused with node groups.
</member>
- <member name="button_mask" type="int" setter="set_button_mask" getter="get_button_mask" enum="MouseButton">
+ <member name="button_mask" type="int" setter="set_button_mask" getter="get_button_mask" enum="MouseButton" default="1">
Binary mask to choose which mouse buttons this button will respond to.
To allow both left-click and right-click, use [code]MOUSE_BUTTON_MASK_LEFT | MOUSE_BUTTON_MASK_RIGHT[/code].
</member>
- <member name="button_pressed" type="bool" setter="set_pressed" getter="is_pressed">
+ <member name="button_pressed" type="bool" setter="set_pressed" getter="is_pressed" default="false">
If [code]true[/code], the button's state is pressed. Means the button is pressed down or toggled (if [member toggle_mode] is active). Only works if [member toggle_mode] is [code]true[/code].
[b]Note:[/b] Setting [member button_pressed] will result in [signal toggled] to be emitted. If you want to change the pressed state without emitting that signal, use [method set_pressed_no_signal].
</member>
- <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled">
+ <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false">
If [code]true[/code], the button is in disabled state and can't be clicked or toggled.
</member>
- <member name="keep_pressed_outside" type="bool" setter="set_keep_pressed_outside" getter="is_keep_pressed_outside">
+ <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" />
+ <member name="keep_pressed_outside" type="bool" setter="set_keep_pressed_outside" getter="is_keep_pressed_outside" default="false">
If [code]true[/code], the button stays pressed when moving the cursor outside the button while pressing it.
[b]Note:[/b] This property only affects the button's visual appearance. Signals will be emitted at the same moment regardless of this property's value.
</member>
<member name="shortcut" type="Shortcut" setter="set_shortcut" getter="get_shortcut">
[Shortcut] associated to the button.
</member>
- <member name="shortcut_feedback" type="bool" setter="set_shortcut_feedback" getter="is_shortcut_feedback">
+ <member name="shortcut_feedback" type="bool" setter="set_shortcut_feedback" getter="is_shortcut_feedback" default="true">
If [code]true[/code], the button will appear pressed when its shortcut is activated. If [code]false[/code] and [member toggle_mode] is [code]false[/code], the shortcut will activate the button without appearing to press the button.
</member>
- <member name="shortcut_in_tooltip" type="bool" setter="set_shortcut_in_tooltip" getter="is_shortcut_in_tooltip_enabled">
+ <member name="shortcut_in_tooltip" type="bool" setter="set_shortcut_in_tooltip" getter="is_shortcut_in_tooltip_enabled" default="true">
If [code]true[/code], the button will add information about its shortcut in the tooltip.
</member>
- <member name="toggle_mode" type="bool" setter="set_toggle_mode" getter="is_toggle_mode">
+ <member name="toggle_mode" type="bool" setter="set_toggle_mode" getter="is_toggle_mode" default="false">
If [code]true[/code], the button is in toggle mode. Makes the button flip state between pressed and unpressed each time its area is clicked.
</member>
</members>
diff --git a/doc/classes/CameraAttributes.xml b/doc/classes/CameraAttributes.xml
index a741728c14..23dc212069 100644
--- a/doc/classes/CameraAttributes.xml
+++ b/doc/classes/CameraAttributes.xml
@@ -12,19 +12,19 @@
<tutorials>
</tutorials>
<members>
- <member name="auto_exposure_enabled" type="bool" setter="set_auto_exposure_enabled" getter="is_auto_exposure_enabled">
+ <member name="auto_exposure_enabled" type="bool" setter="set_auto_exposure_enabled" getter="is_auto_exposure_enabled" default="false">
If [code]true[/code], enables the tonemapping auto exposure mode of the scene renderer. If [code]true[/code], the renderer will automatically determine the exposure setting to adapt to the scene's illumination and the observed light.
</member>
- <member name="auto_exposure_scale" type="float" setter="set_auto_exposure_scale" getter="get_auto_exposure_scale">
+ <member name="auto_exposure_scale" type="float" setter="set_auto_exposure_scale" getter="get_auto_exposure_scale" default="0.4">
The scale of the auto exposure effect. Affects the intensity of auto exposure.
</member>
- <member name="auto_exposure_speed" type="float" setter="set_auto_exposure_speed" getter="get_auto_exposure_speed">
+ <member name="auto_exposure_speed" type="float" setter="set_auto_exposure_speed" getter="get_auto_exposure_speed" default="0.5">
The speed of the auto exposure effect. Affects the time needed for the camera to perform auto exposure.
</member>
- <member name="exposure_multiplier" type="float" setter="set_exposure_multiplier" getter="get_exposure_multiplier">
+ <member name="exposure_multiplier" type="float" setter="set_exposure_multiplier" getter="get_exposure_multiplier" default="1.0">
Multiplier for the exposure amount. A higher value results in a brighter image.
</member>
- <member name="exposure_sensitivity" type="float" setter="set_exposure_sensitivity" getter="get_exposure_sensitivity">
+ <member name="exposure_sensitivity" type="float" setter="set_exposure_sensitivity" getter="get_exposure_sensitivity" default="100.0">
Sensitivity of camera sensors, measured in ISO. A higher sensitivity results in a brighter image. Only available when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is enabled. When [member auto_exposure_enabled] this can be used as a method of exposure compensation, doubling the value will increase the exposure value (measured in EV100) by 1 stop.
</member>
</members>
diff --git a/doc/classes/CameraTexture.xml b/doc/classes/CameraTexture.xml
index 8eedfe3580..e7020c869e 100644
--- a/doc/classes/CameraTexture.xml
+++ b/doc/classes/CameraTexture.xml
@@ -16,6 +16,7 @@
<member name="camera_is_active" type="bool" setter="set_camera_active" getter="get_camera_active" default="false">
Convenience property that gives access to the active property of the [CameraFeed].
</member>
+ <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
<member name="which_feed" type="int" setter="set_which_feed" getter="get_which_feed" enum="CameraServer.FeedImage" default="0">
Which image within the [CameraFeed] we want access to, important if the camera image is split in a Y and CbCr component.
</member>
diff --git a/doc/classes/CanvasTexture.xml b/doc/classes/CanvasTexture.xml
index 2dc83790c7..d5bf65835f 100644
--- a/doc/classes/CanvasTexture.xml
+++ b/doc/classes/CanvasTexture.xml
@@ -17,6 +17,7 @@
The normal map texture to use. Only has a visible effect if [Light2D]s are affecting this [CanvasTexture].
[b]Note:[/b] Godot expects the normal map to use X+, Y+, and Z+ coordinates. See [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates]this page[/url] for a comparison of normal map coordinates expected by popular engines.
</member>
+ <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
<member name="specular_color" type="Color" setter="set_specular_color" getter="get_specular_color" default="Color(1, 1, 1, 1)">
The multiplier for specular reflection colors. The [Light2D]'s color is also taken into account when determining the reflection color. Only has a visible effect if [Light2D]s are affecting this [CanvasTexture].
</member>
diff --git a/doc/classes/CompressedCubemap.xml b/doc/classes/CompressedCubemap.xml
index fbb0879fdc..10ee266897 100644
--- a/doc/classes/CompressedCubemap.xml
+++ b/doc/classes/CompressedCubemap.xml
@@ -1,8 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="CompressedCubemap" inherits="CompressedTextureLayered" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ 6-sided texture typically used in 3D rendering, optionally compressed.
</brief_description>
<description>
+ A cubemap that is loaded from a [code].ccube[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedCubemap] can use one of 4 compresson methods:
+ - Uncompressed (uncompressed on the GPU)
+ - Lossless (WebP or PNG, uncompressed on the GPU)
+ - Lossy (WebP, uncompressed on the GPU)
+ - VRAM Compressed (compressed on the GPU)
+ Only [b]VRAM Compressed[/b] actually reduces the memory usage on the GPU. The [b]Lossless[/b] and [b]Lossy[/b] compression methods will reduce the required storage on disk, but they will not reduce memory usage on the GPU as the texture is sent to the GPU uncompressed.
+ Using [b]VRAM Compressed[/b] also improves loading times, as VRAM-compressed textures are faster to load compared to textures using lossless or lossy compression. VRAM compression can exhibit noticeable artifacts and is intended to be used for 3D rendering, not 2D.
+ See [Cubemap] for a general description of cubemaps.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/CompressedCubemapArray.xml b/doc/classes/CompressedCubemapArray.xml
index ff096cea47..4221241910 100644
--- a/doc/classes/CompressedCubemapArray.xml
+++ b/doc/classes/CompressedCubemapArray.xml
@@ -1,8 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="CompressedCubemapArray" inherits="CompressedTextureLayered" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Array of 6-sided textures typically used in 3D rendering, optionally compressed.
</brief_description>
<description>
+ A cubemap array that is loaded from a [code].ccubearray[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedCubemapArray] can use one of 4 compresson methods:
+ - Uncompressed (uncompressed on the GPU)
+ - Lossless (WebP or PNG, uncompressed on the GPU)
+ - Lossy (WebP, uncompressed on the GPU)
+ - VRAM Compressed (compressed on the GPU)
+ Only [b]VRAM Compressed[/b] actually reduces the memory usage on the GPU. The [b]Lossless[/b] and [b]Lossy[/b] compression methods will reduce the required storage on disk, but they will not reduce memory usage on the GPU as the texture is sent to the GPU uncompressed.
+ Using [b]VRAM Compressed[/b] also improves loading times, as VRAM-compressed textures are faster to load compared to textures using lossless or lossy compression. VRAM compression can exhibit noticeable artifacts and is intended to be used for 3D rendering, not 2D.
+ See [CubemapArray] for a general description of cubemap arrays.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/CompressedTexture2D.xml b/doc/classes/CompressedTexture2D.xml
index f74265b8d5..660062af7b 100644
--- a/doc/classes/CompressedTexture2D.xml
+++ b/doc/classes/CompressedTexture2D.xml
@@ -1,10 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="CompressedTexture2D" inherits="Texture2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- A [code].ctex[/code] texture.
+ Texture with 2 dimensions, optionally compressed.
</brief_description>
<description>
- A texture that is loaded from a [code].ctex[/code] file.
+ A texture that is loaded from a [code].ctex[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedTexture2D] can use one of 4 compression methods (including a lack of any compression):
+ - Uncompressed (uncompressed on the GPU)
+ - Lossless (WebP or PNG, uncompressed on the GPU)
+ - Lossy (WebP, uncompressed on the GPU)
+ - VRAM Compressed (compressed on the GPU)
+ Only [b]VRAM Compressed[/b] actually reduces the memory usage on the GPU. The [b]Lossless[/b] and [b]Lossy[/b] compression methods will reduce the required storage on disk, but they will not reduce memory usage on the GPU as the texture is sent to the GPU uncompressed.
+ Using [b]VRAM Compressed[/b] also improves loading times, as VRAM-compressed textures are faster to load compared to textures using lossless or lossy compression. VRAM compression can exhibit noticeable artifacts and is intended to be used for 3D rendering, not 2D.
</description>
<tutorials>
</tutorials>
@@ -13,13 +19,14 @@
<return type="int" enum="Error" />
<param index="0" name="path" type="String" />
<description>
- Loads the texture from the given path.
+ Loads the texture from the specified [param path].
</description>
</method>
</methods>
<members>
<member name="load_path" type="String" setter="load" getter="get_load_path" default="&quot;&quot;">
- The CompressedTexture's file path to a [code].ctex[/code] file.
+ The [CompressedTexture2D]'s file path to a [code].ctex[/code] file.
</member>
+ <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
</members>
</class>
diff --git a/doc/classes/CompressedTexture2DArray.xml b/doc/classes/CompressedTexture2DArray.xml
index 0c751759af..0bd894a2da 100644
--- a/doc/classes/CompressedTexture2DArray.xml
+++ b/doc/classes/CompressedTexture2DArray.xml
@@ -1,8 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="CompressedTexture2DArray" inherits="CompressedTextureLayered" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Array of 2-dimensional textures, optionally compressed.
</brief_description>
<description>
+ A texture array that is loaded from a [code].ctexarray[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedTexture2DArray] can use one of 4 compresson methods:
+ - Uncompressed (uncompressed on the GPU)
+ - Lossless (WebP or PNG, uncompressed on the GPU)
+ - Lossy (WebP, uncompressed on the GPU)
+ - VRAM Compressed (compressed on the GPU)
+ Only [b]VRAM Compressed[/b] actually reduces the memory usage on the GPU. The [b]Lossless[/b] and [b]Lossy[/b] compression methods will reduce the required storage on disk, but they will not reduce memory usage on the GPU as the texture is sent to the GPU uncompressed.
+ Using [b]VRAM Compressed[/b] also improves loading times, as VRAM-compressed textures are faster to load compared to textures using lossless or lossy compression. VRAM compression can exhibit noticeable artifacts and is intended to be used for 3D rendering, not 2D.
+ See [Texture2DArray] for a general description of texture arrays.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/CompressedTexture3D.xml b/doc/classes/CompressedTexture3D.xml
index 50bd025861..b11583b684 100644
--- a/doc/classes/CompressedTexture3D.xml
+++ b/doc/classes/CompressedTexture3D.xml
@@ -1,8 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="CompressedTexture3D" inherits="Texture3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Texture with 3 dimensions, optionally compressed.
</brief_description>
<description>
+ [CompressedTexture3D] is the VRAM-compressed counterpart of [ImageTexture3D]. The file extension for [CompressedTexture3D] files is [code].ctex3d[/code]. This file format is internal to Godot; it is created by importing other image formats with the import system.
+ [CompressedTexture3D] uses VRAM compression, which allows to reduce memory usage on the GPU when rendering the texture. This also improves loading times, as VRAM-compressed textures are faster to load compared to textures using lossless compression. VRAM compression can exhibit noticeable artifacts and is intended to be used for 3D rendering, not 2D.
+ See [Texture3D] for a general description of 3D textures.
</description>
<tutorials>
</tutorials>
@@ -11,11 +15,13 @@
<return type="int" enum="Error" />
<param index="0" name="path" type="String" />
<description>
+ Loads the texture from the specified [param path].
</description>
</method>
</methods>
<members>
<member name="load_path" type="String" setter="load" getter="get_load_path" default="&quot;&quot;">
+ The [CompressedTexture3D]'s file path to a [code].ctex3d[/code] file.
</member>
</members>
</class>
diff --git a/doc/classes/CompressedTextureLayered.xml b/doc/classes/CompressedTextureLayered.xml
index 547679c0f0..376483ae5c 100644
--- a/doc/classes/CompressedTextureLayered.xml
+++ b/doc/classes/CompressedTextureLayered.xml
@@ -1,8 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="CompressedTextureLayered" inherits="TextureLayered" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Base class for texture arrays that can optionally be compressed.
</brief_description>
<description>
+ A texture array that is loaded from a [code].ctexarray[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedTexture2D] can use one of 4 compresson methods:
+ - Uncompressed (uncompressed on the GPU)
+ - Lossless (WebP or PNG, uncompressed on the GPU)
+ - Lossy (WebP, uncompressed on the GPU)
+ - VRAM Compressed (compressed on the GPU)
+ Only [b]VRAM Compressed[/b] actually reduces the memory usage on the GPU. The [b]Lossless[/b] and [b]Lossy[/b] compression methods will reduce the required storage on disk, but they will not reduce memory usage on the GPU as the texture is sent to the GPU uncompressed.
+ Using [b]VRAM Compressed[/b] also improves loading times, as VRAM-compressed textures are faster to load compared to textures using lossless or lossy compression. VRAM compression can exhibit noticeable artifacts and is intended to be used for 3D rendering, not 2D.
</description>
<tutorials>
</tutorials>
@@ -11,11 +19,13 @@
<return type="int" enum="Error" />
<param index="0" name="path" type="String" />
<description>
+ Loads the texture at [param path].
</description>
</method>
</methods>
<members>
<member name="load_path" type="String" setter="load" getter="get_load_path" default="&quot;&quot;">
+ The path the texture should be loaded from.
</member>
</members>
</class>
diff --git a/doc/classes/Cubemap.xml b/doc/classes/Cubemap.xml
index 0cdebeda95..46ddede9b1 100644
--- a/doc/classes/Cubemap.xml
+++ b/doc/classes/Cubemap.xml
@@ -4,8 +4,9 @@
6-sided texture typically used in 3D rendering.
</brief_description>
<description>
- A cubemap is made of 6 textures organized in layers. They are typically used for faking reflections (see [ReflectionProbe]) in 3D rendering. It can be used to make an object look as if it's reflecting its surroundings. This usually delivers much better performance than other reflection methods.
- This resource is typically used as a uniform in custom shaders. Few core Godot methods make use of Cubemap resources.
+ A cubemap is made of 6 textures organized in layers. They are typically used for faking reflections in 3D rendering (see [ReflectionProbe]). It can be used to make an object look as if it's reflecting its surroundings. This usually delivers much better performance than other reflection methods.
+ This resource is typically used as a uniform in custom shaders. Few core Godot methods make use of [Cubemap] resources.
+ To create such a texture file yourself, reimport your image files using the Godot Editor import presets.
[b]Note:[/b] Godot doesn't support using cubemaps in a [PanoramaSkyMaterial]. You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html]this tool[/url] to convert a cubemap to an equirectangular sky map.
</description>
<tutorials>
diff --git a/doc/classes/CubemapArray.xml b/doc/classes/CubemapArray.xml
index 07e401a13d..2fd55b66c6 100644
--- a/doc/classes/CubemapArray.xml
+++ b/doc/classes/CubemapArray.xml
@@ -5,8 +5,9 @@
</brief_description>
<description>
[CubemapArray]s are made of an array of [Cubemap]s. Accordingly, like [Cubemap]s they are made of multiple textures the amount of which must be divisible by 6 (one image for each face of the cube). The primary benefit of [CubemapArray]s is that they can be accessed in shader code using a single texture reference. In other words, you can pass multiple [Cubemap]s into a shader using a single [CubemapArray].
- Generally, [CubemapArray]s provide a more efficient way for storing multiple [Cubemap]s, than storing multiple [Cubemap]s themselves in an array.
- Internally Godot, uses [CubemapArray]s for many effects including the [Sky], if you set [member ProjectSettings.rendering/reflections/sky_reflections/texture_array_reflections] to [code]true[/code].
+ Generally, [CubemapArray]s provide a more efficient way for storing multiple [Cubemap]s compared to storing multiple [Cubemap]s themselves in an array.
+ Internally, Godot uses [CubemapArray]s for many effects including the [Sky], if you set [member ProjectSettings.rendering/reflections/sky_reflections/texture_array_reflections] to [code]true[/code].
+ To create such a texture file yourself, reimport your image files using the Godot Editor import presets.
[b]Note:[/b] [CubemapArray] is not supported in the OpenGL 3 rendering backend.
</description>
<tutorials>
diff --git a/doc/classes/CurveTexture.xml b/doc/classes/CurveTexture.xml
index 85473fc237..03e008d738 100644
--- a/doc/classes/CurveTexture.xml
+++ b/doc/classes/CurveTexture.xml
@@ -13,6 +13,7 @@
<member name="curve" type="Curve" setter="set_curve" getter="get_curve">
The [Curve] that is rendered onto the texture.
</member>
+ <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
<member name="texture_mode" type="int" setter="set_texture_mode" getter="get_texture_mode" enum="CurveTexture.TextureMode" default="0">
The format the texture should be generated with. When passing a CurveTexture as a input to a [Shader], this may need to be adjusted.
</member>
diff --git a/doc/classes/CurveXYZTexture.xml b/doc/classes/CurveXYZTexture.xml
index e3f2e8fc45..8c4e2dce0f 100644
--- a/doc/classes/CurveXYZTexture.xml
+++ b/doc/classes/CurveXYZTexture.xml
@@ -19,6 +19,7 @@
<member name="curve_z" type="Curve" setter="set_curve_z" getter="get_curve_z">
The [Curve] that is rendered onto the texture's blue channel.
</member>
+ <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
<member name="width" type="int" setter="set_width" getter="get_width" default="256">
The width of the texture (in pixels). Higher values make it possible to represent high-frequency data better (such as sudden direction changes), at the cost of increased generation time and memory usage.
</member>
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index 113987bb52..0039301bf6 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -1638,8 +1638,9 @@
Regardless of the platform, enabling full screen 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 full screen mode.
</constant>
<constant name="WINDOW_MODE_EXCLUSIVE_FULLSCREEN" value="4" enum="WindowMode">
- Exclusive full screen window mode. This mode is implemented on Windows only. On other platforms, it is equivalent to [constant WINDOW_MODE_FULLSCREEN].
- Only one window in exclusive full screen mode can be visible on a given screen at a time. If multiple windows are in exclusive full screen mode for the same screen, the last one being set to this mode takes precedence.
+ Exclusive full screen window mode. This mode is implemented on Windows and macOS only. On other platforms, it is equivalent to [constant WINDOW_MODE_FULLSCREEN].
+ [b]On Windows:[/b] Only one window in exclusive full screen mode can be visible on a given screen at a time. If multiple windows are in exclusive full screen mode for the same screen, the last one being set to this mode takes precedence.
+ [b]On macOS:[/b] Exclusive full-screen mode prevents Dock and Menu from showing up when the mouse pointer is hovering the edge of the screen.
Regardless of the platform, enabling full screen 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 full screen mode.
</constant>
<constant name="WINDOW_FLAG_RESIZE_DISABLED" value="0" enum="WindowFlags">
@@ -1725,9 +1726,17 @@
</constant>
<constant name="WINDOW_VIEW" value="2" enum="HandleType">
Window view:
+ - Windows: [code]HDC[/code] for the window (only with the GL Compatibility renderer).
- macOS: [code]NSView*[/code] for the window main view.
- iOS: [code]UIView*[/code] for the window main view.
</constant>
+ <constant name="OPENGL_CONTEXT" value="3" enum="HandleType">
+ OpenGL context (only with the GL Compatibility renderer):
+ - Windows: [code]HGLRC[/code] for the window.
+ - Linux: [code]GLXContext*[/code] for the window.
+ - MacOS: [code]NSOpenGLContext*[/code] for the window.
+ - Android: [code]EGLContext[/code] for the window.
+ </constant>
<constant name="TTS_UTTERANCE_STARTED" value="0" enum="TTSUtteranceEvent">
Utterance has begun to be spoken.
</constant>
diff --git a/doc/classes/EditorFeatureProfile.xml b/doc/classes/EditorFeatureProfile.xml
index 99e97fc25f..27f61f1bd8 100644
--- a/doc/classes/EditorFeatureProfile.xml
+++ b/doc/classes/EditorFeatureProfile.xml
@@ -116,7 +116,10 @@
<constant name="FEATURE_IMPORT_DOCK" value="6" enum="Feature">
The Import dock. If this feature is disabled, the Import dock won't be visible.
</constant>
- <constant name="FEATURE_MAX" value="7" enum="Feature">
+ <constant name="FEATURE_HISTORY_DOCK" value="7" enum="Feature">
+ The History dock. If this feature is disabled, the History dock won't be visible.
+ </constant>
+ <constant name="FEATURE_MAX" value="8" enum="Feature">
Represents the size of the [enum Feature] enum.
</constant>
</constants>
diff --git a/doc/classes/EditorSpinSlider.xml b/doc/classes/EditorSpinSlider.xml
index 9961e11f7d..de105b32e1 100644
--- a/doc/classes/EditorSpinSlider.xml
+++ b/doc/classes/EditorSpinSlider.xml
@@ -12,6 +12,7 @@
<member name="flat" type="bool" setter="set_flat" getter="is_flat" default="false">
If [code]true[/code], the slider will not draw background.
</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_slider" type="bool" setter="set_hide_slider" getter="is_hiding_slider" default="false">
If [code]true[/code], the slider is hidden.
</member>
@@ -21,6 +22,8 @@
<member name="read_only" type="bool" setter="set_read_only" getter="is_read_only" default="false">
If [code]true[/code], the slider can't be interacted with.
</member>
+ <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" default="1" />
+ <member name="step" type="float" setter="set_step" getter="get_step" overrides="Range" default="1.0" />
<member name="suffix" type="String" setter="set_suffix" getter="get_suffix" default="&quot;&quot;">
The suffix to display after the value (in a faded color). This should generally be a plural word. You may have to use an abbreviation if the suffix is too long to be displayed.
</member>
diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml
index 4916171900..c7d10078e8 100644
--- a/doc/classes/GPUParticles2D.xml
+++ b/doc/classes/GPUParticles2D.xml
@@ -89,12 +89,17 @@
Particle texture. If [code]null[/code], particles will be squares.
</member>
<member name="trail_enabled" type="bool" setter="set_trail_enabled" getter="is_trail_enabled" default="false">
+ If [code]true[/code], enables particle trails using a mesh skinning system.
+ [b]Note:[/b] Unlike [GPUParticles3D], the number of trail sections and subdivisions is set with the [member trail_sections] and [member trail_section_subdivisions] properties.
</member>
- <member name="trail_length_secs" type="float" setter="set_trail_length" getter="get_trail_length" default="0.3">
+ <member name="trail_lifetime" type="float" setter="set_trail_lifetime" getter="get_trail_lifetime" default="0.3">
+ The amount of time the particle's trail should represent (in seconds). Only effective if [member trail_enabled] is [code]true[/code].
</member>
<member name="trail_section_subdivisions" type="int" setter="set_trail_section_subdivisions" getter="get_trail_section_subdivisions" default="4">
+ The number of subdivisions to use for the particle trail rendering. Higher values can result in smoother trail curves, at the cost of performance due to increased mesh complexity. See also [member trail_sections]. Only effective if [member trail_enabled] is [code]true[/code].
</member>
<member name="trail_sections" type="int" setter="set_trail_sections" getter="get_trail_sections" default="8">
+ The number of sections to use for the particle trail rendering. Higher values can result in smoother trail curves, at the cost of performance due to increased mesh complexity. See also [member trail_section_subdivisions]. Only effective if [member trail_enabled] is [code]true[/code].
</member>
<member name="visibility_rect" type="Rect2" setter="set_visibility_rect" getter="get_visibility_rect" default="Rect2(-100, -100, 200, 200)">
The [Rect2] that determines the node's region which needs to be visible on screen for the particle system to be active.
diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml
index d0be4d784a..ea53c5b4b5 100644
--- a/doc/classes/GPUParticles3D.xml
+++ b/doc/classes/GPUParticles3D.xml
@@ -116,8 +116,12 @@
<member name="sub_emitter" type="NodePath" setter="set_sub_emitter" getter="get_sub_emitter" default="NodePath(&quot;&quot;)">
</member>
<member name="trail_enabled" type="bool" setter="set_trail_enabled" getter="is_trail_enabled" default="false">
+ If [code]true[/code], enables particle trails using a mesh skinning system. Designed to work with [RibbonTrailMesh] and [TubeTrailMesh].
+ [b]Note:[/b] [member BaseMaterial3D.use_particle_trails] must also be enabled on the particle mesh's material. Otherwise, setting [member trail_enabled] to [code]true[/code] will have no effect.
+ [b]Note:[/b] Unlike [GPUParticles2D], the number of trail sections and subdivisions is set in the [RibbonTrailMesh] or the [TubeTrailMesh]'s properties.
</member>
- <member name="trail_length_secs" type="float" setter="set_trail_length" getter="get_trail_length" default="0.3">
+ <member name="trail_lifetime" type="float" setter="set_trail_lifetime" getter="get_trail_lifetime" default="0.3">
+ The amount of time the particle's trail should represent (in seconds). Only effective if [member trail_enabled] is [code]true[/code].
</member>
<member name="transform_align" type="int" setter="set_transform_align" getter="get_transform_align" enum="GPUParticles3D.TransformAlign" default="0">
</member>
diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml
index 4d8ab91718..86d52ae9be 100644
--- a/doc/classes/GeometryInstance3D.xml
+++ b/doc/classes/GeometryInstance3D.xml
@@ -31,22 +31,22 @@
</method>
</methods>
<members>
- <member name="cast_shadow" type="int" setter="set_cast_shadows_setting" getter="get_cast_shadows_setting" enum="GeometryInstance3D.ShadowCastingSetting">
+ <member name="cast_shadow" type="int" setter="set_cast_shadows_setting" getter="get_cast_shadows_setting" enum="GeometryInstance3D.ShadowCastingSetting" default="1">
The selected shadow casting flag. See [enum ShadowCastingSetting] for possible values.
</member>
- <member name="extra_cull_margin" type="float" setter="set_extra_cull_margin" getter="get_extra_cull_margin">
+ <member name="extra_cull_margin" type="float" setter="set_extra_cull_margin" getter="get_extra_cull_margin" default="0.0">
The extra distance added to the GeometryInstance3D's bounding box ([AABB]) to increase its cull box.
</member>
- <member name="gi_lightmap_scale" type="int" setter="set_lightmap_scale" getter="get_lightmap_scale" enum="GeometryInstance3D.LightmapScale">
+ <member name="gi_lightmap_scale" type="int" setter="set_lightmap_scale" getter="get_lightmap_scale" enum="GeometryInstance3D.LightmapScale" default="0">
The texel density to use for lightmapping in [LightmapGI]. Greater scale values provide higher resolution in the lightmap, which can result in sharper shadows for lights that have both direct and indirect light baked. However, greater scale values will also increase the space taken by the mesh in the lightmap texture, which increases the memory, storage, and bake time requirements. When using a single mesh at different scales, consider adjusting this value to keep the lightmap texel density consistent across meshes.
</member>
- <member name="gi_mode" type="int" setter="set_gi_mode" getter="get_gi_mode" enum="GeometryInstance3D.GIMode">
+ <member name="gi_mode" type="int" setter="set_gi_mode" getter="get_gi_mode" enum="GeometryInstance3D.GIMode" default="1">
The global illumination mode to use for the whole geometry. To avoid inconsistent results, use a mode that matches the purpose of the mesh during gameplay (static/dynamic).
[b]Note:[/b] Lights' bake mode will also affect the global illumination rendering. See [member Light3D.light_bake_mode].
</member>
- <member name="ignore_occlusion_culling" type="bool" setter="set_ignore_occlusion_culling" getter="is_ignoring_occlusion_culling">
+ <member name="ignore_occlusion_culling" type="bool" setter="set_ignore_occlusion_culling" getter="is_ignoring_occlusion_culling" default="false">
</member>
- <member name="lod_bias" type="float" setter="set_lod_bias" getter="get_lod_bias">
+ <member name="lod_bias" type="float" setter="set_lod_bias" getter="get_lod_bias" default="1.0">
</member>
<member name="material_overlay" type="Material" setter="set_material_overlay" getter="get_material_overlay">
The material overlay for the whole geometry.
@@ -56,26 +56,26 @@
The material override for the whole geometry.
If a material is assigned to this property, it will be used instead of any material set in any material slot of the mesh.
</member>
- <member name="transparency" type="float" setter="set_transparency" getter="get_transparency">
+ <member name="transparency" type="float" setter="set_transparency" getter="get_transparency" default="0.0">
The transparency applied to the whole geometry (as a multiplier of the materials' existing transparency). [code]0.0[/code] is fully opaque, while [code]1.0[/code] is fully transparent. Values greater than [code]0.0[/code] (exclusive) will force the geometry's materials to go through the transparent pipeline, which is slower to render and can exhibit rendering issues due to incorrect transparency sorting. However, unlike using a transparent material, setting [member transparency] to a value greater than [code]0.0[/code] (exclusive) will [i]not[/i] disable shadow rendering.
In spatial shaders, [code]1.0 - transparency[/code] is set as the default value of the [code]ALPHA[/code] built-in.
[b]Note:[/b] [member transparency] is clamped between [code]0.0[/code] and [code]1.0[/code], so this property cannot be used to make transparent materials more opaque than they originally are.
</member>
- <member name="visibility_range_begin" type="float" setter="set_visibility_range_begin" getter="get_visibility_range_begin">
+ <member name="visibility_range_begin" type="float" setter="set_visibility_range_begin" getter="get_visibility_range_begin" default="0.0">
Starting distance from which the GeometryInstance3D will be visible, taking [member visibility_range_begin_margin] into account as well. The default value of 0 is used to disable the range check.
</member>
- <member name="visibility_range_begin_margin" type="float" setter="set_visibility_range_begin_margin" getter="get_visibility_range_begin_margin">
+ <member name="visibility_range_begin_margin" type="float" setter="set_visibility_range_begin_margin" getter="get_visibility_range_begin_margin" default="0.0">
Margin for the [member visibility_range_begin] threshold. The GeometryInstance3D will only change its visibility state when it goes over or under the [member visibility_range_begin] threshold by this amount.
If [member visibility_range_fade_mode] is [constant VISIBILITY_RANGE_FADE_DISABLED], this acts as an hysteresis distance. If [member visibility_range_fade_mode] is [constant VISIBILITY_RANGE_FADE_SELF] or [constant VISIBILITY_RANGE_FADE_DEPENDENCIES], this acts as a fade transition distance and must be set to a value greater than [code]0.0[/code] for the effect to be noticeable.
</member>
- <member name="visibility_range_end" type="float" setter="set_visibility_range_end" getter="get_visibility_range_end">
+ <member name="visibility_range_end" type="float" setter="set_visibility_range_end" getter="get_visibility_range_end" default="0.0">
Distance from which the GeometryInstance3D will be hidden, taking [member visibility_range_end_margin] into account as well. The default value of 0 is used to disable the range check.
</member>
- <member name="visibility_range_end_margin" type="float" setter="set_visibility_range_end_margin" getter="get_visibility_range_end_margin">
+ <member name="visibility_range_end_margin" type="float" setter="set_visibility_range_end_margin" getter="get_visibility_range_end_margin" default="0.0">
Margin for the [member visibility_range_end] threshold. The GeometryInstance3D will only change its visibility state when it goes over or under the [member visibility_range_end] threshold by this amount.
If [member visibility_range_fade_mode] is [constant VISIBILITY_RANGE_FADE_DISABLED], this acts as an hysteresis distance. If [member visibility_range_fade_mode] is [constant VISIBILITY_RANGE_FADE_SELF] or [constant VISIBILITY_RANGE_FADE_DEPENDENCIES], this acts as a fade transition distance and must be set to a value greater than [code]0.0[/code] for the effect to be noticeable.
</member>
- <member name="visibility_range_fade_mode" type="int" setter="set_visibility_range_fade_mode" getter="get_visibility_range_fade_mode" enum="GeometryInstance3D.VisibilityRangeFadeMode">
+ <member name="visibility_range_fade_mode" type="int" setter="set_visibility_range_fade_mode" getter="get_visibility_range_fade_mode" enum="GeometryInstance3D.VisibilityRangeFadeMode" default="0">
Controls which instances will be faded when approaching the limits of the visibility range. See [enum VisibilityRangeFadeMode] for possible values.
</member>
</members>
diff --git a/doc/classes/GradientTexture1D.xml b/doc/classes/GradientTexture1D.xml
index 3254754ac1..fa572eeed0 100644
--- a/doc/classes/GradientTexture1D.xml
+++ b/doc/classes/GradientTexture1D.xml
@@ -12,6 +12,7 @@
<member name="gradient" type="Gradient" setter="set_gradient" getter="get_gradient">
The [Gradient] that will be used to fill the texture.
</member>
+ <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
<member name="use_hdr" type="bool" setter="set_use_hdr" getter="is_using_hdr" default="false">
If [code]true[/code], the generated texture will support high dynamic range ([constant Image.FORMAT_RGBAF] format). This allows for glow effects to work if [member Environment.glow_enabled] is [code]true[/code]. If [code]false[/code], the generated texture will use low dynamic range; overbright colors will be clamped ([constant Image.FORMAT_RGBA8] format).
</member>
diff --git a/doc/classes/GradientTexture2D.xml b/doc/classes/GradientTexture2D.xml
index 7561f1b947..87d86e7a59 100644
--- a/doc/classes/GradientTexture2D.xml
+++ b/doc/classes/GradientTexture2D.xml
@@ -27,6 +27,7 @@
<member name="repeat" type="int" setter="set_repeat" getter="get_repeat" enum="GradientTexture2D.Repeat" default="0">
The gradient repeat type, one of the [enum Repeat] values. The texture is filled starting from [member fill_from] to [member fill_to] offsets by default, but the gradient fill can be repeated to cover the entire texture.
</member>
+ <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
<member name="use_hdr" type="bool" setter="set_use_hdr" getter="is_using_hdr" default="false">
If [code]true[/code], the generated texture will support high dynamic range ([constant Image.FORMAT_RGBAF] format). This allows for glow effects to work if [member Environment.glow_enabled] is [code]true[/code]. If [code]false[/code], the generated texture will use low dynamic range; overbright colors will be clamped ([constant Image.FORMAT_RGBA8] format).
</member>
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index bbd633819b..be66b8a7b9 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -118,7 +118,7 @@
<param index="2" name="use_mipmaps" type="bool" />
<param index="3" name="format" type="int" enum="Image.Format" />
<description>
- Creates an empty image of given size and format. See [enum Format] constants. If [param use_mipmaps] is [code]true[/code] then generate mipmaps for this image. See the [method generate_mipmaps].
+ Creates an empty image of given size and format. See [enum Format] constants. If [param use_mipmaps] is [code]true[/code], then generate mipmaps for this image. See the [method generate_mipmaps].
</description>
</method>
<method name="create_from_data" qualifiers="static">
diff --git a/doc/classes/ImageTexture.xml b/doc/classes/ImageTexture.xml
index 45cbd7ac87..03d1947475 100644
--- a/doc/classes/ImageTexture.xml
+++ b/doc/classes/ImageTexture.xml
@@ -67,4 +67,7 @@
</description>
</method>
</methods>
+ <members>
+ <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
+ </members>
</class>
diff --git a/doc/classes/ImageTexture3D.xml b/doc/classes/ImageTexture3D.xml
index 958c5f90f1..ee26a959aa 100644
--- a/doc/classes/ImageTexture3D.xml
+++ b/doc/classes/ImageTexture3D.xml
@@ -1,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="ImageTexture3D" inherits="Texture3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Texture with 3 dimensions.
</brief_description>
<description>
+ [ImageTexture3D] is a 3-dimensional [ImageTexture] that has a width, height, and depth. See also [ImageTextureLayered].
+ 3D textures are typically used to store density maps for [FogMaterial], color correction LUTs for [Environment], vector fields for [GPUParticlesAttractorVectorField3D] and collision maps for [GPUParticlesCollisionSDF3D]. 3D textures can also be used in custom shaders.
</description>
<tutorials>
</tutorials>
@@ -16,12 +19,14 @@
<param index="4" name="use_mipmaps" type="bool" />
<param index="5" name="data" type="Image[]" />
<description>
+ Creates the [ImageTexture3D] with specified [param width], [param height], and [param depth]. See [enum Image.Format] for [param format] options. If [param use_mipmaps] is [code]true[/code], then generate mipmaps for the [ImageTexture3D].
</description>
</method>
<method name="update">
<return type="void" />
<param index="0" name="data" type="Image[]" />
<description>
+ Replaces the texture's existing data with the layers specified in [code]data[/code]. The size of [code]data[/code] must match the parameters that were used for [method create]. In other words, the texture cannot be resized or have its format changed by calling [method update].
</description>
</method>
</methods>
diff --git a/doc/classes/ImageTextureLayered.xml b/doc/classes/ImageTextureLayered.xml
index f5786f070a..0aa1d65d5a 100644
--- a/doc/classes/ImageTextureLayered.xml
+++ b/doc/classes/ImageTextureLayered.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="ImageTextureLayered" inherits="TextureLayered" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Base class for texture types which contain the data of multiple [ImageTexture]s. Each image is of the same size and format.
</brief_description>
<description>
+ Base class for [Texture2DArray], [Cubemap] and [CubemapArray]. Cannot be used directly, but contains all the functions necessary for accessing the derived resource types. See also [Texture3D].
</description>
<tutorials>
</tutorials>
@@ -11,7 +13,7 @@
<return type="int" enum="Error" />
<param index="0" name="images" type="Image[]" />
<description>
- Creates an [ImageTextureLayered] from an array of [Image]s. The first image decides the width, height, image format and mipmapping setting. The other images must have the same width, height, image format and mipmapping setting.
+ Creates an [ImageTextureLayered] from an array of [Image]s. See [method Image.create] for the expected data format. The first image decides the width, height, image format and mipmapping setting. The other images [i]must[/i] have the same width, height, image format and mipmapping setting.
Each [Image] represents one [code]layer[/code].
</description>
</method>
@@ -23,7 +25,7 @@
Replaces the existing [Image] data at the given [code]layer[/code] with this new image.
The given [Image] must have the same width, height, image format and mipmapping setting (a [code]bool[/code] value) as the rest of the referenced images.
If the image format is unsupported, it will be decompressed and converted to a similar and supported [enum Image.Format].
- The update is immediate: synced with the draw.
+ The update is immediate: it's synchronized with drawing.
</description>
</method>
</methods>
diff --git a/doc/classes/Label3D.xml b/doc/classes/Label3D.xml
index b741dc6e64..0cbca2224e 100644
--- a/doc/classes/Label3D.xml
+++ b/doc/classes/Label3D.xml
@@ -44,6 +44,7 @@
<member name="billboard" type="int" setter="set_billboard_mode" getter="get_billboard_mode" enum="BaseMaterial3D.BillboardMode" default="0">
The billboard mode to use for the label. See [enum BaseMaterial3D.BillboardMode] for possible values.
</member>
+ <member name="cast_shadow" type="int" setter="set_cast_shadows_setting" getter="get_cast_shadows_setting" overrides="GeometryInstance3D" enum="GeometryInstance3D.ShadowCastingSetting" default="0" />
<member name="double_sided" type="bool" setter="set_draw_flag" getter="get_draw_flag" default="true">
If [code]true[/code], text can be seen from the back as well, if [code]false[/code], it is invisible when looking at it from behind.
</member>
@@ -57,6 +58,7 @@
Font size of the [Label3D]'s text. To make the font look more detailed when up close, increase [member font_size] while decreasing [member pixel_size] at the same time.
Higher font sizes require more time to render new characters, which can cause stuttering during gameplay.
</member>
+ <member name="gi_mode" type="int" setter="set_gi_mode" getter="get_gi_mode" overrides="GeometryInstance3D" enum="GeometryInstance3D.GIMode" default="0" />
<member name="horizontal_alignment" type="int" setter="set_horizontal_alignment" getter="get_horizontal_alignment" enum="HorizontalAlignment" default="1">
Controls the text's horizontal alignment. Supports left, center, right, and fill, or justify. Set it to one of the [enum HorizontalAlignment] constants.
</member>
diff --git a/doc/classes/LinkButton.xml b/doc/classes/LinkButton.xml
index 7c6ff2d4e1..d7701ea184 100644
--- a/doc/classes/LinkButton.xml
+++ b/doc/classes/LinkButton.xml
@@ -10,9 +10,11 @@
<tutorials>
</tutorials>
<members>
+ <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="0" />
<member name="language" type="String" setter="set_language" getter="get_language" default="&quot;&quot;">
Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead.
</member>
+ <member name="mouse_default_cursor_shape" type="int" setter="set_default_cursor_shape" getter="get_default_cursor_shape" overrides="Control" enum="Control.CursorShape" default="2" />
<member name="structured_text_bidi_override" type="int" setter="set_structured_text_bidi_override" getter="get_structured_text_bidi_override" enum="TextServer.StructuredTextParser" default="0">
Set BiDi algorithm override for the structured text.
</member>
diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml
index facbe5fd0f..640fa9efec 100644
--- a/doc/classes/Mesh.xml
+++ b/doc/classes/Mesh.xml
@@ -176,7 +176,7 @@
</method>
</methods>
<members>
- <member name="lightmap_size_hint" type="Vector2i" setter="set_lightmap_size_hint" getter="get_lightmap_size_hint">
+ <member name="lightmap_size_hint" type="Vector2i" setter="set_lightmap_size_hint" getter="get_lightmap_size_hint" default="Vector2i(0, 0)">
Sets a hint to be used for lightmap resolution.
</member>
</members>
diff --git a/doc/classes/MeshTexture.xml b/doc/classes/MeshTexture.xml
index 8e2bccc79f..d09fa4c898 100644
--- a/doc/classes/MeshTexture.xml
+++ b/doc/classes/MeshTexture.xml
@@ -18,5 +18,6 @@
<member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh">
Sets the mesh used to draw. It must be a mesh using 2D vertices.
</member>
+ <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
</members>
</class>
diff --git a/doc/classes/MissingNode.xml b/doc/classes/MissingNode.xml
index b5aa02cfd6..ac54329313 100644
--- a/doc/classes/MissingNode.xml
+++ b/doc/classes/MissingNode.xml
@@ -4,7 +4,7 @@
This is an internal editor class intended for keeping data of nodes of unknown type.
</brief_description>
<description>
- This is an internal editor class intended for keeping data of nodes of unknown type (most likely this type was supplied by an extension that is no longer loaded). It can´t be manually instantiated or placed in the scene. Ignore it if you don't know what it is.
+ This is an internal editor class intended for keeping data of nodes of unknown type (most likely this type was supplied by an extension that is no longer loaded). It can't be manually instantiated or placed in the scene. Ignore it if you don't know what it is.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/MissingResource.xml b/doc/classes/MissingResource.xml
index eede6350d8..e5a6c4d064 100644
--- a/doc/classes/MissingResource.xml
+++ b/doc/classes/MissingResource.xml
@@ -4,7 +4,7 @@
This is an internal editor class intended for keeping data of resources of unknown type.
</brief_description>
<description>
- This is an internal editor class intended for keeping data of resources of unknown type (most likely this type was supplied by an extension that is no longer loaded). It can´t be manually instantiated or placed in the scene. Ignore it if you don't know what it is.
+ This is an internal editor class intended for keeping data of resources of unknown type (most likely this type was supplied by an extension that is no longer loaded). It can't be manually instantiated or placed in the scene. Ignore it if you don't know what it is.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PhysicsDirectBodyState2D.xml b/doc/classes/PhysicsDirectBodyState2D.xml
index fdc3a44e9d..eca6a1cbc7 100644
--- a/doc/classes/PhysicsDirectBodyState2D.xml
+++ b/doc/classes/PhysicsDirectBodyState2D.xml
@@ -76,6 +76,7 @@
<param index="0" name="torque" type="float" />
<description>
Applies a rotational force without affecting position. A force is time dependent and meant to be applied every physics update.
+ [b]Note:[/b] [member inverse_inertia] is required for this to work. To have [member inverse_inertia], an active [CollisionShape2D] must be a child of the node, or you can manually set [member inverse_inertia].
</description>
</method>
<method name="apply_torque_impulse">
@@ -84,6 +85,7 @@
<description>
Applies a rotational impulse to the body without affecting the position.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
+ [b]Note:[/b] [member inverse_inertia] is required for this to work. To have [member inverse_inertia], an active [CollisionShape2D] must be a child of the node, or you can manually set [member inverse_inertia].
</description>
</method>
<method name="get_constant_force" qualifiers="const">
diff --git a/doc/classes/PhysicsDirectBodyState3D.xml b/doc/classes/PhysicsDirectBodyState3D.xml
index 04087cbfb6..a809384642 100644
--- a/doc/classes/PhysicsDirectBodyState3D.xml
+++ b/doc/classes/PhysicsDirectBodyState3D.xml
@@ -76,6 +76,7 @@
<param index="0" name="torque" type="Vector3" />
<description>
Applies a rotational force without affecting position. A force is time dependent and meant to be applied every physics update.
+ [b]Note:[/b] [member inverse_inertia] is required for this to work. To have [member inverse_inertia], an active [CollisionShape3D] must be a child of the node, or you can manually set [member inverse_inertia].
</description>
</method>
<method name="apply_torque_impulse">
@@ -84,6 +85,7 @@
<description>
Applies a rotational impulse to the body without affecting the position.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
+ [b]Note:[/b] [member inverse_inertia] is required for this to work. To have [member inverse_inertia], an active [CollisionShape3D] must be a child of the node, or you can manually set [member inverse_inertia].
</description>
</method>
<method name="get_constant_force" qualifiers="const">
diff --git a/doc/classes/PlaceholderCubemap.xml b/doc/classes/PlaceholderCubemap.xml
index 3617c6ac2c..0892b023a2 100644
--- a/doc/classes/PlaceholderCubemap.xml
+++ b/doc/classes/PlaceholderCubemap.xml
@@ -1,8 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PlaceholderCubemap" inherits="PlaceholderTextureLayered" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Placeholder class for a cubemap texture.
</brief_description>
<description>
+ This class is used when loading a project that uses a [Cubemap] subclass in 2 conditions:
+ - When running the project exported in dedicated server mode, only the texture's dimensions are kept (as they may be relied upon for gameplay purposes or positioning of other elements). This allows reducing the exported PCK's size significantly.
+ - When this subclass is missing due to using a different engine version or build (e.g. modules disabled).
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PlaceholderCubemapArray.xml b/doc/classes/PlaceholderCubemapArray.xml
index 1fcf1e7795..c7a7e9154c 100644
--- a/doc/classes/PlaceholderCubemapArray.xml
+++ b/doc/classes/PlaceholderCubemapArray.xml
@@ -1,8 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PlaceholderCubemapArray" inherits="PlaceholderTextureLayered" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Placeholder class for a cubemap texture array.
</brief_description>
<description>
+ This class is used when loading a project that uses a [CubemapArray] subclass in 2 conditions:
+ - When running the project exported in dedicated server mode, only the texture's dimensions are kept (as they may be relied upon for gameplay purposes or positioning of other elements). This allows reducing the exported PCK's size significantly.
+ - When this subclass is missing due to using a different engine version or build (e.g. modules disabled).
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PlaceholderMaterial.xml b/doc/classes/PlaceholderMaterial.xml
index c66641d81c..7febdc7a07 100644
--- a/doc/classes/PlaceholderMaterial.xml
+++ b/doc/classes/PlaceholderMaterial.xml
@@ -1,8 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PlaceholderMaterial" inherits="Material" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Placeholder class for a material.
</brief_description>
<description>
+ This class is used when loading a project that uses a [Material] subclass in 2 conditions:
+ - When running the project exported in dedicated server mode, only the texture's dimensions are kept (as they may be relied upon for gameplay purposes or positioning of other elements). This allows reducing the exported PCK's size significantly.
+ - When this subclass is missing due to using a different engine version or build (e.g. modules disabled).
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PlaceholderMesh.xml b/doc/classes/PlaceholderMesh.xml
index cc688816b6..8021a57878 100644
--- a/doc/classes/PlaceholderMesh.xml
+++ b/doc/classes/PlaceholderMesh.xml
@@ -1,13 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PlaceholderMesh" inherits="Mesh" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Placeholder class for a mesh.
</brief_description>
<description>
+ This class is used when loading a project that uses a [Mesh] subclass in 2 conditions:
+ - When running the project exported in dedicated server mode, only the texture's dimensions are kept (as they may be relied upon for gameplay purposes or positioning of other elements). This allows reducing the exported PCK's size significantly.
+ - When this subclass is missing due to using a different engine version or build (e.g. modules disabled).
</description>
<tutorials>
</tutorials>
<members>
<member name="aabb" type="AABB" setter="set_aabb" getter="get_aabb" default="AABB(0, 0, 0, 0, 0, 0)">
+ The smallest [AABB] enclosing this mesh in local space.
</member>
</members>
</class>
diff --git a/doc/classes/PlaceholderTexture2D.xml b/doc/classes/PlaceholderTexture2D.xml
index 76e575265b..c889055e4d 100644
--- a/doc/classes/PlaceholderTexture2D.xml
+++ b/doc/classes/PlaceholderTexture2D.xml
@@ -1,13 +1,19 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PlaceholderTexture2D" inherits="Texture2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Placeholder class for a 2-dimensional texture.
</brief_description>
<description>
+ This class is used when loading a project that uses a [Texture2D] subclass in 2 conditions:
+ - When running the project exported in dedicated server mode, only the texture's dimensions are kept (as they may be relied upon for gameplay purposes or positioning of other elements). This allows reducing the exported PCK's size significantly.
+ - When this subclass is missing due to using a different engine version or build (e.g. modules disabled).
</description>
<tutorials>
</tutorials>
<members>
+ <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
<member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2(1, 1)">
+ The texture's size (in pixels).
</member>
</members>
</class>
diff --git a/doc/classes/PlaceholderTexture2DArray.xml b/doc/classes/PlaceholderTexture2DArray.xml
index a502e5d334..a749e8c039 100644
--- a/doc/classes/PlaceholderTexture2DArray.xml
+++ b/doc/classes/PlaceholderTexture2DArray.xml
@@ -1,8 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PlaceholderTexture2DArray" inherits="PlaceholderTextureLayered" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Placeholder class for a 2-dimensional texture array.
</brief_description>
<description>
+ This class is used when loading a project that uses a [Texture2D] subclass in 2 conditions:
+ - When running the project exported in dedicated server mode, only the texture's dimensions are kept (as they may be relied upon for gameplay purposes or positioning of other elements). This allows reducing the exported PCK's size significantly.
+ - When this subclass is missing due to using a different engine version or build (e.g. modules disabled).
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PlaceholderTexture3D.xml b/doc/classes/PlaceholderTexture3D.xml
index d31e538307..ccd3c94fc2 100644
--- a/doc/classes/PlaceholderTexture3D.xml
+++ b/doc/classes/PlaceholderTexture3D.xml
@@ -1,13 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PlaceholderTexture3D" inherits="Texture3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Placeholder class for a 3-dimensional texture.
</brief_description>
<description>
+ This class is used when loading a project that uses a [Texture3D] subclass in 2 conditions:
+ - When running the project exported in dedicated server mode, only the texture's dimensions are kept (as they may be relied upon for gameplay purposes or positioning of other elements). This allows reducing the exported PCK's size significantly.
+ - When this subclass is missing due to using a different engine version or build (e.g. modules disabled).
</description>
<tutorials>
</tutorials>
<members>
<member name="size" type="Vector3i" setter="set_size" getter="get_size" default="Vector3i(1, 1, 1)">
+ The texture's size (in pixels).
</member>
</members>
</class>
diff --git a/doc/classes/PlaceholderTextureLayered.xml b/doc/classes/PlaceholderTextureLayered.xml
index 39af08473a..8cc6dd606a 100644
--- a/doc/classes/PlaceholderTextureLayered.xml
+++ b/doc/classes/PlaceholderTextureLayered.xml
@@ -1,15 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PlaceholderTextureLayered" inherits="TextureLayered" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Placeholder class for a 2-dimensional texture array.
</brief_description>
<description>
+ This class is used when loading a project that uses a [TextureLayered] subclass in 2 conditions:
+ - When running the project exported in dedicated server mode, only the texture's dimensions are kept (as they may be relied upon for gameplay purposes or positioning of other elements). This allows reducing the exported PCK's size significantly.
+ - When this subclass is missing due to using a different engine version or build (e.g. modules disabled).
</description>
<tutorials>
</tutorials>
<members>
<member name="layers" type="int" setter="set_layers" getter="get_layers" default="1">
+ The number of layers in the texture array.
</member>
<member name="size" type="Vector2i" setter="set_size" getter="get_size" default="Vector2i(1, 1)">
+ The size of each texture layer (in pixels).
</member>
</members>
</class>
diff --git a/doc/classes/PortableCompressedTexture2D.xml b/doc/classes/PortableCompressedTexture2D.xml
index a0492f2c07..b64cda6df5 100644
--- a/doc/classes/PortableCompressedTexture2D.xml
+++ b/doc/classes/PortableCompressedTexture2D.xml
@@ -58,6 +58,7 @@
When running on the editor, this class will keep the source compressed data in memory. Otherwise, the source compressed data is lost after loading and the resource can't be re saved.
This flag allows to keep the compressed data in memory if you intend it to persist after loading.
</member>
+ <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
<member name="size_override" type="Vector2" setter="set_size_override" getter="get_size_override" default="Vector2(0, 0)">
Allow overriding the texture size (for 2D only).
</member>
diff --git a/doc/classes/PrimitiveMesh.xml b/doc/classes/PrimitiveMesh.xml
index 1b9ecdbfa0..b1c8907d8e 100644
--- a/doc/classes/PrimitiveMesh.xml
+++ b/doc/classes/PrimitiveMesh.xml
@@ -34,15 +34,21 @@
</method>
</methods>
<members>
- <member name="custom_aabb" type="AABB" setter="set_custom_aabb" getter="get_custom_aabb">
+ <member name="add_uv2" type="bool" setter="set_add_uv2" getter="get_add_uv2" default="false">
+ If set, generates UV2 UV coordinates applying a padding using the [member uv2_padding] setting. UV2 is needed for lightmapping.
+ </member>
+ <member name="custom_aabb" type="AABB" setter="set_custom_aabb" getter="get_custom_aabb" default="AABB(0, 0, 0, 0, 0, 0)">
Overrides the [AABB] with one defined by user for use with frustum culling. Especially useful to avoid unexpected culling when using a shader to offset vertices.
</member>
- <member name="flip_faces" type="bool" setter="set_flip_faces" getter="get_flip_faces">
+ <member name="flip_faces" type="bool" setter="set_flip_faces" getter="get_flip_faces" default="false">
If set, the order of the vertices in each triangle are reversed resulting in the backside of the mesh being drawn.
This gives the same result as using [constant BaseMaterial3D.CULL_FRONT] in [member BaseMaterial3D.cull_mode].
</member>
<member name="material" type="Material" setter="set_material" getter="get_material">
The current [Material] of the primitive mesh.
</member>
+ <member name="uv2_padding" type="float" setter="set_uv2_padding" getter="get_uv2_padding" default="2.0">
+ If [member add_uv2] is set, specifies the padding in pixels applied along seams of the mesh. If at generation the size of the lightmap texture can't be determined, the UVs are calculated assuming a texture size of 1024x1024.
+ </member>
</members>
</class>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index fae88a401b..015de62ec1 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -341,6 +341,9 @@
<member name="compression/formats/zstd/window_log_size" type="int" setter="" getter="" default="27">
Largest size limit (in power of 2) allowed when compressing using long-distance matching with Zstandard. Higher values can result in better compression, but will require more memory when compressing and decompressing.
</member>
+ <member name="debug/disable_touch" type="bool" setter="" getter="" default="false">
+ Disable touch input. Only has effect on iOS.
+ </member>
<member name="debug/file_logging/enable_file_logging" type="bool" setter="" getter="" default="false">
If [code]true[/code], logs all output to files.
</member>
@@ -2013,6 +2016,9 @@
<member name="rendering/lightmapping/bake_quality/ultra_quality_ray_count" type="int" setter="" getter="" default="1024">
The number of rays to use for baking lightmaps with [LightmapGI] when [member LightmapGI.quality] is [constant LightmapGI.BAKE_QUALITY_ULTRA].
</member>
+ <member name="rendering/lightmapping/primitive_meshes/texel_size" type="float" setter="" getter="" default="0.2">
+ The texel_size that is used to calculate the [member Mesh.lightmap_size_hint] on [PrimitiveMesh] resources if [member PrimitiveMesh.add_uv2] is enabled.
+ </member>
<member name="rendering/lightmapping/probe_capture/update_speed" type="float" setter="" getter="" default="15">
The framerate-independent update speed when representing dynamic object lighting from [LightmapProbe]s. Higher values make dynamic object lighting update faster. Higher values can prevent fast-moving objects from having "outdated" indirect lighting displayed on them, at the cost of possible flickering when an object moves from a bright area to a shaded area.
</member>
diff --git a/doc/classes/Range.xml b/doc/classes/Range.xml
index 9764318ee4..2dcfc90955 100644
--- a/doc/classes/Range.xml
+++ b/doc/classes/Range.xml
@@ -38,34 +38,35 @@
</method>
</methods>
<members>
- <member name="allow_greater" type="bool" setter="set_allow_greater" getter="is_greater_allowed">
+ <member name="allow_greater" type="bool" setter="set_allow_greater" getter="is_greater_allowed" default="false">
If [code]true[/code], [member value] may be greater than [member max_value].
</member>
- <member name="allow_lesser" type="bool" setter="set_allow_lesser" getter="is_lesser_allowed">
+ <member name="allow_lesser" type="bool" setter="set_allow_lesser" getter="is_lesser_allowed" default="false">
If [code]true[/code], [member value] may be less than [member min_value].
</member>
- <member name="exp_edit" type="bool" setter="set_exp_ratio" getter="is_ratio_exp">
+ <member name="exp_edit" type="bool" setter="set_exp_ratio" getter="is_ratio_exp" default="false">
If [code]true[/code], and [code]min_value[/code] is greater than 0, [code]value[/code] will be represented exponentially rather than linearly.
</member>
- <member name="max_value" type="float" setter="set_max" getter="get_max">
+ <member name="max_value" type="float" setter="set_max" getter="get_max" default="100.0">
Maximum value. Range is clamped if [code]value[/code] is greater than [code]max_value[/code].
</member>
- <member name="min_value" type="float" setter="set_min" getter="get_min">
+ <member name="min_value" type="float" setter="set_min" getter="get_min" default="0.0">
Minimum value. Range is clamped if [code]value[/code] is less than [code]min_value[/code].
</member>
- <member name="page" type="float" setter="set_page" getter="get_page">
+ <member name="page" type="float" setter="set_page" getter="get_page" default="0.0">
Page size. Used mainly for [ScrollBar]. ScrollBar's length is its size multiplied by [code]page[/code] over the difference between [code]min_value[/code] and [code]max_value[/code].
</member>
<member name="ratio" type="float" setter="set_as_ratio" getter="get_as_ratio">
The value mapped between 0 and 1.
</member>
- <member name="rounded" type="bool" setter="set_use_rounded_values" getter="is_using_rounded_values">
+ <member name="rounded" type="bool" setter="set_use_rounded_values" getter="is_using_rounded_values" default="false">
If [code]true[/code], [code]value[/code] will always be rounded to the nearest integer.
</member>
- <member name="step" type="float" setter="set_step" getter="get_step">
+ <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" default="0" />
+ <member name="step" type="float" setter="set_step" getter="get_step" default="0.01">
If greater than 0, [code]value[/code] will always be rounded to a multiple of [code]step[/code]. If [code]rounded[/code] is also [code]true[/code], [code]value[/code] will first be rounded to a multiple of [code]step[/code] then rounded to the nearest integer.
</member>
- <member name="value" type="float" setter="set_value" getter="get_value">
+ <member name="value" type="float" setter="set_value" getter="get_value" default="0.0">
Range's current value. Changing this property (even via code) will trigger [signal value_changed] signal. Use [method set_value_no_signal] if you want to avoid it.
</member>
</members>
diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml
index cb13697cc2..2de812f5fc 100644
--- a/doc/classes/RenderingDevice.xml
+++ b/doc/classes/RenderingDevice.xml
@@ -643,6 +643,15 @@
<description>
</description>
</method>
+ <method name="vertex_array_create">
+ <return type="RID" />
+ <param index="0" name="vertex_count" type="int" />
+ <param index="1" name="vertex_format" type="int" />
+ <param index="2" name="src_buffers" type="RID[]" />
+ <description>
+ Creates a vertex array based on the specified buffers.
+ </description>
+ </method>
<method name="vertex_buffer_create">
<return type="RID" />
<param index="0" name="size_bytes" type="int" />
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 1c02d58299..13e5470a56 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -3024,6 +3024,14 @@
<description>
</description>
</method>
+ <method name="texture_get_rd_texture" qualifiers="const">
+ <return type="RID" />
+ <param index="0" name="texture" type="RID" />
+ <param index="1" name="srgb" type="bool" default="false" />
+ <description>
+ Returns a texture [RID] that can be used with [RenderingDevice].
+ </description>
+ </method>
<method name="texture_proxy_create">
<return type="RID" />
<param index="0" name="base" type="RID" />
diff --git a/doc/classes/RigidBody2D.xml b/doc/classes/RigidBody2D.xml
index 9eedc3a24c..6e3535f14a 100644
--- a/doc/classes/RigidBody2D.xml
+++ b/doc/classes/RigidBody2D.xml
@@ -87,6 +87,7 @@
<param index="0" name="torque" type="float" />
<description>
Applies a rotational force without affecting position. A force is time dependent and meant to be applied every physics update.
+ [b]Note:[/b] [member inertia] is required for this to work. To have [member inertia], an active [CollisionShape2D] must be a child of the node, or you can manually set [member inertia].
</description>
</method>
<method name="apply_torque_impulse">
@@ -95,6 +96,7 @@
<description>
Applies a rotational impulse to the body without affecting the position.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
+ [b]Note:[/b] [member inertia] is required for this to work. To have [member inertia], an active [CollisionShape2D] must be a child of the node, or you can manually set [member inertia].
</description>
</method>
<method name="get_colliding_bodies" qualifiers="const">
diff --git a/doc/classes/RigidBody3D.xml b/doc/classes/RigidBody3D.xml
index 3ee3f25df1..8380d56de3 100644
--- a/doc/classes/RigidBody3D.xml
+++ b/doc/classes/RigidBody3D.xml
@@ -87,6 +87,7 @@
<param index="0" name="torque" type="Vector3" />
<description>
Applies a rotational force without affecting position. A force is time dependent and meant to be applied every physics update.
+ [b]Note:[/b] [member inertia] is required for this to work. To have [member inertia], an active [CollisionShape3D] must be a child of the node, or you can manually set [member inertia].
</description>
</method>
<method name="apply_torque_impulse">
@@ -95,6 +96,7 @@
<description>
Applies a rotational impulse to the body without affecting the position.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
+ [b]Note:[/b] [member inertia] is required for this to work. To have [member inertia], an active [CollisionShape3D] must be a child of the node, or you can manually set [member inertia].
</description>
</method>
<method name="get_colliding_bodies" qualifiers="const">
diff --git a/doc/classes/ScrollBar.xml b/doc/classes/ScrollBar.xml
index d0dd69408e..247e892c24 100644
--- a/doc/classes/ScrollBar.xml
+++ b/doc/classes/ScrollBar.xml
@@ -12,6 +12,7 @@
<member name="custom_step" type="float" setter="set_custom_step" getter="get_custom_step" default="-1.0">
Overrides the step used when clicking increment and decrement buttons or when using arrow keys when the [ScrollBar] is focused.
</member>
+ <member name="step" type="float" setter="set_step" getter="get_step" overrides="Range" default="0.0" />
</members>
<signals>
<signal name="scrolling">
diff --git a/doc/classes/Slider.xml b/doc/classes/Slider.xml
index c3dbd69e59..cecca0a5fb 100644
--- a/doc/classes/Slider.xml
+++ b/doc/classes/Slider.xml
@@ -13,9 +13,11 @@
<member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true">
If [code]true[/code], the slider can be interacted with. If [code]false[/code], the value can be changed only by code.
</member>
+ <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" />
<member name="scrollable" type="bool" setter="set_scrollable" getter="is_scrollable" default="true">
If [code]true[/code], the value can be changed using the mouse wheel.
</member>
+ <member name="step" type="float" setter="set_step" getter="get_step" overrides="Range" default="1.0" />
<member name="tick_count" type="int" setter="set_ticks" getter="get_ticks" default="0">
Number of ticks displayed on the slider, including border ticks. Ticks are uniformly-distributed value markers.
</member>
diff --git a/doc/classes/SpinBox.xml b/doc/classes/SpinBox.xml
index 93799b58f0..e214867890 100644
--- a/doc/classes/SpinBox.xml
+++ b/doc/classes/SpinBox.xml
@@ -59,6 +59,8 @@
<member name="select_all_on_focus" type="bool" setter="set_select_all_on_focus" getter="is_select_all_on_focus" default="false">
If [code]true[/code], the [SpinBox] will select the whole text when the [LineEdit] gains focus. Clicking the up and down arrows won't trigger this behavior.
</member>
+ <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" default="1" />
+ <member name="step" type="float" setter="set_step" getter="get_step" overrides="Range" default="1.0" />
<member name="suffix" type="String" setter="set_suffix" getter="get_suffix" default="&quot;&quot;">
Adds the specified [code]suffix[/code] string after the numerical value of the [SpinBox].
</member>
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 1ee91b91d2..b0b4f74b46 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -634,11 +634,11 @@
</method>
<method name="rsplit" qualifiers="const">
<return type="PackedStringArray" />
- <param index="0" name="delimiter" type="String" />
+ <param index="0" name="delimiter" type="String" default="&quot;&quot;" />
<param index="1" name="allow_empty" type="bool" default="true" />
<param index="2" name="maxsplit" type="int" default="0" />
<description>
- Splits the string by a [param delimiter] string and returns an array of the substrings, starting from right.
+ Splits the string by a [param delimiter] string and returns an array of the substrings, starting from right. If [param delimiter] is an empty string, each substring will be a single character.
The splits in the returned array are sorted in the same order as the original string, from left to right.
If [param allow_empty] is [code]true[/code], and there are two adjacent delimiters in the string, it will add an empty string to the array of substrings at this position.
If [param maxsplit] is specified, it defines the number of splits to do from the right up to [param maxsplit]. The default value of 0 means that all items are split, thus giving the same result as [method split].
@@ -710,11 +710,11 @@
</method>
<method name="split" qualifiers="const">
<return type="PackedStringArray" />
- <param index="0" name="delimiter" type="String" />
+ <param index="0" name="delimiter" type="String" default="&quot;&quot;" />
<param index="1" name="allow_empty" type="bool" default="true" />
<param index="2" name="maxsplit" type="int" default="0" />
<description>
- Splits the string by a [param delimiter] string and returns an array of the substrings. The [param delimiter] can be of any length.
+ Splits the string by a [param delimiter] string and returns an array of the substrings. The [param delimiter] can be of any length. If [param delimiter] is an empty string, each substring will be a single character.
If [param allow_empty] is [code]true[/code], and there are two adjacent delimiters in the string, it will add an empty string to the array of substrings at this position.
If [param maxsplit] is specified, it defines the number of splits to do from the left up to [param maxsplit]. The default value of [code]0[/code] means that all items are split.
If you need only one element from the array at a specific index, [method get_slice] is a more performant option.
diff --git a/doc/classes/StyleBox.xml b/doc/classes/StyleBox.xml
index 8656cde4a0..ff6d4d8821 100644
--- a/doc/classes/StyleBox.xml
+++ b/doc/classes/StyleBox.xml
@@ -114,21 +114,21 @@
</method>
</methods>
<members>
- <member name="content_margin_bottom" type="float" setter="set_default_margin" getter="get_default_margin">
+ <member name="content_margin_bottom" type="float" setter="set_default_margin" getter="get_default_margin" default="-1.0">
The bottom margin for the contents of this style box. Increasing this value reduces the space available to the contents from the bottom.
If this value is negative, it is ignored and a child-specific margin is used instead. For example for [StyleBoxFlat] the border thickness (if any) is used instead.
It is up to the code using this style box to decide what these contents are: for example, a [Button] respects this content margin for the textual contents of the button.
[method get_margin] should be used to fetch this value as consumer instead of reading these properties directly. This is because it correctly respects negative values and the fallback mentioned above.
</member>
- <member name="content_margin_left" type="float" setter="set_default_margin" getter="get_default_margin">
+ <member name="content_margin_left" type="float" setter="set_default_margin" getter="get_default_margin" default="-1.0">
The left margin for the contents of this style box. Increasing this value reduces the space available to the contents from the left.
Refer to [member content_margin_bottom] for extra considerations.
</member>
- <member name="content_margin_right" type="float" setter="set_default_margin" getter="get_default_margin">
+ <member name="content_margin_right" type="float" setter="set_default_margin" getter="get_default_margin" default="-1.0">
The right margin for the contents of this style box. Increasing this value reduces the space available to the contents from the right.
Refer to [member content_margin_bottom] for extra considerations.
</member>
- <member name="content_margin_top" type="float" setter="set_default_margin" getter="get_default_margin">
+ <member name="content_margin_top" type="float" setter="set_default_margin" getter="get_default_margin" default="-1.0">
The top margin for the contents of this style box. Increasing this value reduces the space available to the contents from the top.
Refer to [member content_margin_bottom] for extra considerations.
</member>
diff --git a/doc/classes/Texture.xml b/doc/classes/Texture.xml
index df6e0433dc..86c9026fd1 100644
--- a/doc/classes/Texture.xml
+++ b/doc/classes/Texture.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Texture" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Base class for all texture types.
</brief_description>
<description>
+ [Texture] is the base class for all texture types. Common texture types are [Texture2D] and [ImageTexture]. See also [Image].
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Texture2D.xml b/doc/classes/Texture2D.xml
index 3dd8c339b2..aac197090a 100644
--- a/doc/classes/Texture2D.xml
+++ b/doc/classes/Texture2D.xml
@@ -19,6 +19,8 @@
<param index="2" name="modulate" type="Color" />
<param index="3" name="transpose" type="bool" />
<description>
+ Called when the entire [Texture2D] is requested to be drawn over a [CanvasItem], with the top-left offset specified in [param pos]. [param modulate] specifies a multiplier for the colors being drawn, while [param transpose] specifies whether drawing should be performed in column-major order instead of row-major order (resulting in 90-degree clockwise rotation).
+ [b]Note:[/b] This is only used in 2D rendering, not 3D.
</description>
</method>
<method name="_draw_rect" qualifiers="virtual const">
@@ -29,6 +31,8 @@
<param index="3" name="modulate" type="Color" />
<param index="4" name="transpose" type="bool" />
<description>
+ Called when the [Texture2D] is requested to be drawn onto [CanvasItem]'s specified [param rect]. [param modulate] specifies a multiplier for the colors being drawn, while [param transpose] specifies whether drawing should be performed in column-major order instead of row-major order (resulting in 90-degree clockwise rotation).
+ [b]Note:[/b] This is only used in 2D rendering, not 3D.
</description>
</method>
<method name="_draw_rect_region" qualifiers="virtual const">
@@ -40,21 +44,26 @@
<param index="4" name="transpose" type="bool" />
<param index="5" name="clip_uv" type="bool" />
<description>
+ Called when a part of the [Texture2D] specified by [param src_rect]'s coordinates is requested to be drawn onto [CanvasItem]'s specified [param rect]. [param modulate] specifies a multiplier for the colors being drawn, while [param transpose] specifies whether drawing should be performed in column-major order instead of row-major order (resulting in 90-degree clockwise rotation).
+ [b]Note:[/b] This is only used in 2D rendering, not 3D.
</description>
</method>
<method name="_get_height" qualifiers="virtual const">
<return type="int" />
<description>
+ Called when the [Texture2D]'s height is queried.
</description>
</method>
<method name="_get_width" qualifiers="virtual const">
<return type="int" />
<description>
+ Called when the [Texture2D]'s width is queried.
</description>
</method>
<method name="_has_alpha" qualifiers="virtual const">
<return type="bool" />
<description>
+ Called when the presence of an alpha channel in the [Texture2D] is queried.
</description>
</method>
<method name="_is_pixel_opaque" qualifiers="virtual const">
@@ -62,6 +71,7 @@
<param index="0" name="x" type="int" />
<param index="1" name="y" type="int" />
<description>
+ Called when a pixel's opaque state in the [Texture2D] is queried at the specified [code](x, y)[/code] position.
</description>
</method>
<method name="draw" qualifiers="const">
@@ -100,7 +110,7 @@
<method name="get_height" qualifiers="const">
<return type="int" />
<description>
- Returns the texture height.
+ Returns the texture height in pixels.
</description>
</method>
<method name="get_image" qualifiers="const">
@@ -113,13 +123,13 @@
<method name="get_size" qualifiers="const">
<return type="Vector2" />
<description>
- Returns the texture size.
+ Returns the texture size in pixels.
</description>
</method>
<method name="get_width" qualifiers="const">
<return type="int" />
<description>
- Returns the texture width.
+ Returns the texture width in pixels.
</description>
</method>
<method name="has_alpha" qualifiers="const">
diff --git a/doc/classes/Texture2DArray.xml b/doc/classes/Texture2DArray.xml
index 113f37f974..ec00198db1 100644
--- a/doc/classes/Texture2DArray.xml
+++ b/doc/classes/Texture2DArray.xml
@@ -4,8 +4,9 @@
A single texture resource which consists of multiple, separate images. Each image has the same dimensions and number of mipmap levels.
</brief_description>
<description>
- A Texture2DArray is different from a Texture3D: The Texture2DArray does not support trilinear interpolation between the [Image]s, i.e. no blending.
+ A Texture2DArray is different from a Texture3D: The Texture2DArray does not support trilinear interpolation between the [Image]s, i.e. no blending. See also [Cubemap] and [CubemapArray], which are texture arrays with specialized cubemap functions.
A Texture2DArray is also different from an [AtlasTexture]: In a Texture2DArray, all images are treated separately. In an atlas, the regions (i.e. the single images) can be of different sizes. Furthermore, you usually need to add a padding around the regions, to prevent accidental UV mapping to more than one region. The same goes for mipmapping: Mipmap chains are handled separately for each layer. In an atlas, the slicing has to be done manually in the fragment shader.
+ To create such a texture file yourself, reimport your image files using the Godot Editor import presets.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Texture3D.xml b/doc/classes/Texture3D.xml
index 4968f46fe8..1a66932d62 100644
--- a/doc/classes/Texture3D.xml
+++ b/doc/classes/Texture3D.xml
@@ -1,8 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Texture3D" inherits="Texture" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Base class for 3-dimensionnal textures.
</brief_description>
<description>
+ Base class for [ImageTexture3D] and [CompressedTexture3D]. Cannot be used directly, but contains all the functions necessary for accessing the derived resource types. [Texture3D] is the base class for all 3-dimensional texture types. See also [TextureLayered].
+ All images need to have the same width, height and number of mipmap levels.
+ To create such a texture file yourself, reimport your image files using the Godot Editor import presets.
</description>
<tutorials>
</tutorials>
@@ -10,61 +14,73 @@
<method name="_get_data" qualifiers="virtual const">
<return type="Image[]" />
<description>
+ Called when the [Texture3D]'s data is queried.
</description>
</method>
<method name="_get_depth" qualifiers="virtual const">
<return type="int" />
<description>
+ Called when the [Texture3D]'s depth is queried.
</description>
</method>
<method name="_get_format" qualifiers="virtual const">
<return type="int" enum="Image.Format" />
<description>
+ Called when the [Texture3D]'s format is queried.
</description>
</method>
<method name="_get_height" qualifiers="virtual const">
<return type="int" />
<description>
+ Called when the [Texture3D]'s height is queried.
</description>
</method>
<method name="_get_width" qualifiers="virtual const">
<return type="int" />
<description>
+ Called when the [Texture3D]'s width is queried.
</description>
</method>
<method name="_has_mipmaps" qualifiers="virtual const">
<return type="bool" />
<description>
+ Called when the presence of mipmaps in the [Texture3D] is queried.
</description>
</method>
<method name="get_data" qualifiers="const">
<return type="Image[]" />
<description>
+ Returns the [Texture3D]'s data as an array of [Image]s. Each [Image] represents a [i]slice[/i] of the [Texture3D], with different slices mapping to different depth (Z axis) levels.
</description>
</method>
<method name="get_depth" qualifiers="const">
<return type="int" />
<description>
+ Returns the [Texture3D]'s depth in pixels. Depth is typically represented by the Z axis (a dimension not present in [Texture2D]).
</description>
</method>
<method name="get_format" qualifiers="const">
<return type="int" enum="Image.Format" />
<description>
+ Returns the current format being used by this texture. See [enum Image.Format] for details.
</description>
</method>
<method name="get_height" qualifiers="const">
<return type="int" />
<description>
+ Returns the [Texture3D]'s height in pixels. Width is typically represented by the Y axis.
</description>
</method>
<method name="get_width" qualifiers="const">
<return type="int" />
<description>
+ Returns the [Texture3D]'s width in pixels. Width is typically represented by the X axis.
</description>
</method>
<method name="has_mipmaps" qualifiers="const">
<return type="bool" />
<description>
+ Returns [code]true[/code] if the [Texture3D] has generated mipmaps.
</description>
</method>
</methods>
diff --git a/doc/classes/TextureLayered.xml b/doc/classes/TextureLayered.xml
index 5e6afcbc5c..8f6dff7acf 100644
--- a/doc/classes/TextureLayered.xml
+++ b/doc/classes/TextureLayered.xml
@@ -4,12 +4,11 @@
Base class for texture types which contain the data of multiple [Image]s. Each image is of the same size and format.
</brief_description>
<description>
- Base class for [Texture2DArray], [Cubemap] and [CubemapArray]. Cannot be used directly, but contains all the functions necessary for accessing the derived resource types.
+ Base class for [ImageTextureLayered]. Cannot be used directly, but contains all the functions necessary for accessing the derived resource types. See also [Texture3D].
Data is set on a per-layer basis. For [Texture2DArray]s, the layer specifies the array layer.
All images need to have the same width, height and number of mipmap levels.
- A [TextureLayered] can be loaded with [code]method ResourceFormatLoader.load[/code].
- To create such a texture file yourself, re-import your image files using the Godot Editor import presets.
- Internally, Godot maps these files to their respective counterparts in the target rendering driver (GLES3, Vulkan).
+ A [TextureLayered] can be loaded with [method ResourceLoader.load].
+ Internally, Godot maps these files to their respective counterparts in the target rendering driver (Vulkan, GLES3).
</description>
<tutorials>
</tutorials>
@@ -17,37 +16,44 @@
<method name="_get_format" qualifiers="virtual const">
<return type="int" enum="Image.Format" />
<description>
+ Called when the [TextureLayered]'s format is queried.
</description>
</method>
<method name="_get_height" qualifiers="virtual const">
<return type="int" />
<description>
+ Called when the the [TextureLayered]'s height is queried.
</description>
</method>
<method name="_get_layer_data" qualifiers="virtual const">
<return type="Image" />
<param index="0" name="layer_index" type="int" />
<description>
+ Called when the data for a layer in the [TextureLayered] is queried.
</description>
</method>
<method name="_get_layered_type" qualifiers="virtual const">
<return type="int" />
<description>
+ Called when the layers' type in the [TextureLayered] is queried.
</description>
</method>
<method name="_get_layers" qualifiers="virtual const">
<return type="int" />
<description>
+ Called when the number of layers in the [TextureLayered] is queried.
</description>
</method>
<method name="_get_width" qualifiers="virtual const">
<return type="int" />
<description>
+ Called when the [TextureLayered]'s width queried.
</description>
</method>
<method name="_has_mipmaps" qualifiers="virtual const">
<return type="bool" />
<description>
+ Called when the presence of mipmaps in the [TextureLayered] is queried.
</description>
</method>
<method name="get_format" qualifiers="const">
@@ -59,7 +65,7 @@
<method name="get_height" qualifiers="const">
<return type="int" />
<description>
- Returns the height of the texture. Height is typically represented by the Y-axis.
+ Returns the height of the texture in pixels. Height is typically represented by the Y axis.
</description>
</method>
<method name="get_layer_data" qualifiers="const">
@@ -72,6 +78,7 @@
<method name="get_layered_type" qualifiers="const">
<return type="int" enum="TextureLayered.LayeredType" />
<description>
+ Returns the [TextureLayered]'s type. The type determines how the data is accessed, with cubemaps having special types.
</description>
</method>
<method name="get_layers" qualifiers="const">
@@ -83,7 +90,7 @@
<method name="get_width" qualifiers="const">
<return type="int" />
<description>
- Returns the width of the texture. Width is typically represented by the X-axis.
+ Returns the width of the texture in pixels. Width is typically represented by the X axis.
</description>
</method>
<method name="has_mipmaps" qualifiers="const">
@@ -95,10 +102,13 @@
</methods>
<constants>
<constant name="LAYERED_TYPE_2D_ARRAY" value="0" enum="LayeredType">
+ Texture is a generic [Texture2DArray].
</constant>
<constant name="LAYERED_TYPE_CUBEMAP" value="1" enum="LayeredType">
+ Texture is a [Cubemap], with each side in its own layer (6 in total).
</constant>
<constant name="LAYERED_TYPE_CUBEMAP_ARRAY" value="2" enum="LayeredType">
+ Texture is a [CubemapArray], with each cubemap being made of 6 layers.
</constant>
</constants>
</class>
diff --git a/doc/classes/TextureProgressBar.xml b/doc/classes/TextureProgressBar.xml
index fcdb18e10d..54b77bf5eb 100644
--- a/doc/classes/TextureProgressBar.xml
+++ b/doc/classes/TextureProgressBar.xml
@@ -27,6 +27,7 @@
<member name="fill_mode" type="int" setter="set_fill_mode" getter="get_fill_mode" default="0">
The fill direction. See [enum FillMode] for possible values.
</member>
+ <member name="mouse_filter" type="int" setter="set_mouse_filter" getter="get_mouse_filter" overrides="Control" enum="Control.MouseFilter" default="1" />
<member name="nine_patch_stretch" type="bool" setter="set_nine_patch_stretch" getter="get_nine_patch_stretch" default="false">
If [code]true[/code], Godot treats the bar's textures like in [NinePatchRect]. Use the [code]stretch_margin_*[/code] properties like [member stretch_margin_bottom] to set up the nine patch's 3×3 grid. When using a radial [member fill_mode], this setting will enable stretching.
</member>
@@ -40,6 +41,8 @@
<member name="radial_initial_angle" type="float" setter="set_radial_initial_angle" getter="get_radial_initial_angle" default="0.0">
Starting angle for the fill of [member texture_progress] if [member fill_mode] is [constant FILL_CLOCKWISE] or [constant FILL_COUNTER_CLOCKWISE]. When the node's [code]value[/code] is equal to its [code]min_value[/code], the texture doesn't show up at all. When the [code]value[/code] increases, the texture fills and tends towards [member radial_fill_degrees].
</member>
+ <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" default="1" />
+ <member name="step" type="float" setter="set_step" getter="get_step" overrides="Range" default="1.0" />
<member name="stretch_margin_bottom" type="int" setter="set_stretch_margin" getter="get_stretch_margin" default="0">
The height of the 9-patch's bottom row. A margin of 16 means the 9-slice's bottom corners and side will have a height of 16 pixels. You can set all 4 margin values individually to create panels with non-uniform borders.
</member>
diff --git a/doc/classes/Translation.xml b/doc/classes/Translation.xml
index 314be9adf8..ae2f8d8dff 100644
--- a/doc/classes/Translation.xml
+++ b/doc/classes/Translation.xml
@@ -88,6 +88,12 @@
The number [param n] is the number or quantity of the plural object. It will be used to guide the translation system to fetch the correct plural form for the selected language.
</description>
</method>
+ <method name="get_translated_message_list" qualifiers="const">
+ <return type="PackedStringArray" />
+ <description>
+ Returns all the messages (translated text).
+ </description>
+ </method>
</methods>
<members>
<member name="locale" type="String" setter="set_locale" getter="get_locale" default="&quot;en&quot;">
diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml
index 532f6703b2..bf79821e2d 100644
--- a/doc/classes/Tree.xml
+++ b/doc/classes/Tree.xml
@@ -293,6 +293,14 @@
Sets language code of column title used for line-breaking and text shaping algorithms, if left empty current locale is used instead.
</description>
</method>
+ <method name="set_selected">
+ <return type="void" />
+ <param index="0" name="item" type="TreeItem" />
+ <param index="1" name="column" type="int" />
+ <description>
+ Selects the specified [TreeItem] and column.
+ </description>
+ </method>
</methods>
<members>
<member name="allow_reselect" type="bool" setter="set_allow_reselect" getter="get_allow_reselect" default="false">
diff --git a/doc/classes/VisualInstance3D.xml b/doc/classes/VisualInstance3D.xml
index 94e8c25660..31811f817b 100644
--- a/doc/classes/VisualInstance3D.xml
+++ b/doc/classes/VisualInstance3D.xml
@@ -56,7 +56,7 @@
</method>
</methods>
<members>
- <member name="layers" type="int" setter="set_layer_mask" getter="get_layer_mask">
+ <member name="layers" type="int" setter="set_layer_mask" getter="get_layer_mask" default="1">
The render layer(s) this [VisualInstance3D] is drawn on.
This object will only be visible for [Camera3D]s whose cull mask includes the render object this [VisualInstance3D] is set to.
For [Light3D]s, this can be used to control which [VisualInstance3D]s are affected by a specific light. For [GPUParticles3D], this can be used to control which particles are effected by a specific attractor. For [Decal]s, this can be used to control which [VisualInstance3D]s are affected by a specific decal.
diff --git a/doc/classes/XRInterface.xml b/doc/classes/XRInterface.xml
index cc483dbd02..05d5eb6673 100644
--- a/doc/classes/XRInterface.xml
+++ b/doc/classes/XRInterface.xml
@@ -35,6 +35,16 @@
Returns an array of vectors that denotes the physical play area mapped to the virtual space around the [XROrigin3D] point. The points form a convex polygon that can be used to react to or visualize the play area. This returns an empty array if this feature is not supported or if the information is not yet available.
</description>
</method>
+ <method name="get_projection_for_view">
+ <return type="Projection" />
+ <param index="0" name="view" type="int" />
+ <param index="1" name="aspect" type="float" />
+ <param index="2" name="near" type="float" />
+ <param index="3" name="far" type="float" />
+ <description>
+ Returns the projection matrix for a view/eye.
+ </description>
+ </method>
<method name="get_render_target_size">
<return type="Vector2" />
<description>
@@ -47,6 +57,16 @@
If supported, returns the status of our tracking. This will allow you to provide feedback to the user whether there are issues with positional tracking.
</description>
</method>
+ <method name="get_transform_for_view">
+ <return type="Transform3D" />
+ <param index="0" name="view" type="int" />
+ <param index="1" name="cam_transform" type="Transform3D" />
+ <description>
+ Returns the transform for a view/eye.
+ [param view] is the view/eye index.
+ [param cam_transform] is the transform that maps device coordinates to scene coordinates, typically the global_transform of the current XROrigin3D.
+ </description>
+ </method>
<method name="get_view_count">
<return type="int" />
<description>
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 29252c8677..0a64cda787 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -581,7 +581,7 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
_record_item_commands(ci, p_canvas_transform_inverse, current_clip, blend_mode, p_lights, index, batch_broken);
}
- if (r_last_index >= index) {
+ if (index == 0) {
// Nothing to render, just return.
state.current_batch_index = 0;
state.canvas_instance_batches.clear();
@@ -1006,13 +1006,15 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, const Tran
if (primitive->point_count != state.canvas_instance_batches[state.current_batch_index].primitive_points || state.canvas_instance_batches[state.current_batch_index].command_type != Item::Command::TYPE_PRIMITIVE) {
_new_batch(r_batch_broken, r_index);
- state.canvas_instance_batches[state.current_batch_index].tex = RID();
+ state.canvas_instance_batches[state.current_batch_index].tex = primitive->texture;
state.canvas_instance_batches[state.current_batch_index].primitive_points = primitive->point_count;
state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_PRIMITIVE;
state.canvas_instance_batches[state.current_batch_index].command = c;
state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_PRIMITIVE;
}
+ _prepare_canvas_texture(state.canvas_instance_batches[state.current_batch_index].tex, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
+
for (uint32_t j = 0; j < MIN(3u, primitive->point_count); j++) {
state.instance_data_array[r_index].points[j * 2 + 0] = primitive->points[j].x;
state.instance_data_array[r_index].points[j * 2 + 1] = primitive->points[j].y;
@@ -1325,7 +1327,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
void RasterizerCanvasGLES3::_add_to_batch(uint32_t &r_index, bool &r_batch_broken) {
if (r_index >= data.max_instances_per_ubo - 1) {
- WARN_PRINT_ONCE("Trying to draw too many items. Please increase maximum number of items in the project settings 'rendering/gl_compatibility/item_buffer_size'");
+ ERR_PRINT_ONCE("Trying to draw too many items. Please increase maximum number of items in the project settings 'rendering/gl_compatibility/item_buffer_size'");
return;
}
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 2e8c95fe61..734911ccdb 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1642,6 +1642,9 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
ERR_FAIL_COND(rb.is_null());
}
+ GLES3::RenderTarget *rt = texture_storage->get_render_target(rb->render_target);
+ ERR_FAIL_COND(!rt);
+
// Assign render data
// Use the format from rendererRD
RenderDataGLES3 render_data;
@@ -1729,8 +1732,20 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
scene_state.ubo.emissive_exposure_normalization = -1.0; // Use default exposure normalization.
+ bool flip_y = !render_data.reflection_probe.is_valid();
+
+ if (rt->overridden.color.is_valid()) {
+ // If we've overridden the render target's color texture, then don't render upside down.
+ // We're probably rendering directly to an XR device.
+ flip_y = false;
+ }
+ if (!flip_y) {
+ // If we're rendering right-side up, then we need to change the winding order.
+ glFrontFace(GL_CW);
+ }
+
_setup_lights(&render_data, false, render_data.directional_light_count, render_data.omni_light_count, render_data.spot_light_count);
- _setup_environment(&render_data, render_data.reflection_probe.is_valid(), screen_size, !render_data.reflection_probe.is_valid(), clear_color, false);
+ _setup_environment(&render_data, render_data.reflection_probe.is_valid(), screen_size, flip_y, clear_color, false);
_fill_render_list(RENDER_LIST_OPAQUE, &render_data, PASS_MODE_COLOR);
render_list[RENDER_LIST_OPAQUE].sort_by_key();
@@ -1811,7 +1826,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
}
}
- glBindFramebuffer(GL_FRAMEBUFFER, rb->framebuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
glViewport(0, 0, rb->width, rb->height);
// Do depth prepass if it's explicitly enabled
@@ -1917,6 +1932,11 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
_render_list_template<PASS_MODE_COLOR_TRANSPARENT>(&render_list_params_alpha, &render_data, 0, render_list[RENDER_LIST_ALPHA].elements.size(), true);
+ if (!flip_y) {
+ // Restore the default winding order.
+ glFrontFace(GL_CCW);
+ }
+
if (rb.is_valid()) {
_render_buffers_debug_draw(rb, p_shadow_atlas, p_occluder_debug_tex);
}
@@ -1973,6 +1993,8 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
}
+ bool should_request_redraw = false;
+
for (uint32_t i = p_from_element; i < p_to_element; i++) {
const GeometryInstanceSurface *surf = p_params->elements[i];
GeometryInstanceGLES3 *inst = surf->owner;
@@ -2003,6 +2025,11 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
continue;
}
+ //request a redraw if one of the shaders uses TIME
+ if (shader->uses_time) {
+ should_request_redraw = true;
+ }
+
if constexpr (p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) {
if (scene_state.current_depth_test != shader->depth_test) {
if (shader->depth_test == GLES3::SceneShaderData::DEPTH_TEST_DISABLED) {
@@ -2227,6 +2254,11 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
glDisableVertexAttribArray(15);
}
}
+
+ // Make the actual redraw request
+ if (should_request_redraw) {
+ RenderingServerDefault::redraw_request();
+ }
}
void RasterizerSceneGLES3::render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index 6748eb3676..2d6a793c9e 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -3358,6 +3358,9 @@ void SceneShaderData::set_code(const String &p_code) {
actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
actions.usage_flag_pointers["ALPHA_SCISSOR_THRESHOLD"] = &uses_alpha_clip;
+ // Use alpha clip pipeline for alpha hash/dither.
+ // This prevents sorting issues inherent to alpha blending and allows such materials to cast shadows.
+ actions.usage_flag_pointers["ALPHA_HASH_SCALE"] = &uses_alpha_clip;
actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass;
actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
index b8e4530f56..e0e78de728 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
@@ -33,17 +33,12 @@
#include "render_scene_buffers_gles3.h"
#include "texture_storage.h"
-#ifdef ANDROID_ENABLED
-#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
-#endif
-
RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() {
free_render_buffer_data();
}
void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
- GLES3::Config *config = GLES3::Config::get_singleton();
//internal_size.x = p_internal_size.x; // ignore for now
//internal_size.y = p_internal_size.y;
@@ -62,66 +57,9 @@ void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_inte
GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
is_transparent = rt->is_transparent;
-
- // framebuffer
- glGenFramebuffers(1, &framebuffer);
- glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
-
- if (view_count > 1 && config->multiview_supported) {
- glBindTexture(GL_TEXTURE_2D_ARRAY, rt->color);
- glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, view_count);
- } else {
- glBindTexture(GL_TEXTURE_2D, rt->color);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
- }
-
- glGenTextures(1, &depth_texture);
- if (view_count > 1 && config->multiview_supported) {
- glBindTexture(GL_TEXTURE_2D_ARRAY, depth_texture);
- glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
-
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- } else {
- glBindTexture(GL_TEXTURE_2D, depth_texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- }
-
- if (view_count > 1 && config->multiview_supported) {
- glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_texture, 0, 0, view_count);
- } else {
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0);
- }
-
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-
- glBindTexture(GL_TEXTURE_2D, 0);
- glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
- glBindFramebuffer(GL_FRAMEBUFFER, texture_storage->system_fbo);
-
- if (status != GL_FRAMEBUFFER_COMPLETE) {
- free_render_buffer_data();
- WARN_PRINT("Could not create 3D renderbuffer, status: " + texture_storage->get_framebuffer_error(status));
- return;
- }
}
void RenderSceneBuffersGLES3::free_render_buffer_data() {
- if (depth_texture) {
- glDeleteTextures(1, &depth_texture);
- depth_texture = 0;
- }
- if (framebuffer) {
- glDeleteFramebuffers(1, &framebuffer);
- framebuffer = 0;
- }
}
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.h b/drivers/gles3/storage/render_scene_buffers_gles3.h
index dbedbd22c3..092c14e1b8 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.h
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.h
@@ -61,9 +61,6 @@ public:
bool is_transparent = false;
RID render_target;
- GLuint internal_texture = 0; // Used for rendering when post effects are enabled
- GLuint depth_texture = 0; // Main depth texture
- GLuint framebuffer = 0; // Main framebuffer, contains internal_texture and depth_texture or render_target->color and depth_texture
//built-in textures used for ping pong image processing and blurring
struct Blur {
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index 11151c4100..51e22fe779 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -614,7 +614,9 @@ void TextureStorage::texture_free(RID p_texture) {
}
if (t->tex_id != 0) {
- glDeleteTextures(1, &t->tex_id);
+ if (!t->is_external) {
+ glDeleteTextures(1, &t->tex_id);
+ }
t->tex_id = 0;
}
@@ -680,6 +682,35 @@ void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) {
texture_owner.initialize_rid(p_texture, proxy_tex);
}
+RID TextureStorage::texture_create_external(Texture::Type p_type, Image::Format p_format, unsigned int p_image, int p_width, int p_height, int p_depth, int p_layers, RS::TextureLayeredType p_layered_type) {
+ Texture texture;
+ texture.active = true;
+ texture.is_external = true;
+ texture.type = p_type;
+
+ switch (p_type) {
+ case Texture::TYPE_2D: {
+ texture.target = GL_TEXTURE_2D;
+ } break;
+ case Texture::TYPE_3D: {
+ texture.target = GL_TEXTURE_3D;
+ } break;
+ case Texture::TYPE_LAYERED: {
+ texture.target = GL_TEXTURE_2D_ARRAY;
+ } break;
+ }
+
+ texture.real_format = texture.format = p_format;
+ texture.tex_id = p_image;
+ texture.alloc_width = texture.width = p_width;
+ texture.alloc_height = texture.height = p_height;
+ texture.depth = p_depth;
+ texture.layers = p_layers;
+ texture.layered_type = p_layered_type;
+
+ return texture_owner.make_rid(texture);
+}
+
void TextureStorage::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) {
texture_set_data(p_texture, p_image, p_layer);
#ifdef TOOLS_ENABLED
@@ -690,6 +721,26 @@ void TextureStorage::texture_2d_update(RID p_texture, const Ref<Image> &p_image,
}
void TextureStorage::texture_proxy_update(RID p_texture, RID p_proxy_to) {
+ Texture *tex = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND(!tex);
+ ERR_FAIL_COND(!tex->is_proxy);
+ Texture *proxy_to = texture_owner.get_or_null(p_proxy_to);
+ ERR_FAIL_COND(!proxy_to);
+ ERR_FAIL_COND(proxy_to->is_proxy);
+
+ if (tex->proxy_to.is_valid()) {
+ Texture *prev_tex = texture_owner.get_or_null(tex->proxy_to);
+ ERR_FAIL_COND(!prev_tex);
+ prev_tex->proxies.erase(p_texture);
+ }
+
+ *tex = *proxy_to;
+
+ tex->proxy_to = p_proxy_to;
+ tex->is_render_target = false;
+ tex->is_proxy = true;
+ tex->proxies.clear();
+ proxy_to->proxies.push_back(p_texture);
}
void TextureStorage::texture_2d_placeholder_initialize(RID p_texture) {
@@ -991,6 +1042,10 @@ Size2 TextureStorage::texture_size_with_proxy(RID p_texture) {
}
}
+RID TextureStorage::texture_get_rd_texture_rid(RID p_texture, bool p_srgb) const {
+ return RID();
+}
+
void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer) {
Texture *texture = texture_owner.get_or_null(p_texture);
@@ -1459,43 +1514,74 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
glDepthMask(GL_FALSE);
{
- /* Front FBO */
+ Texture *texture;
+ bool use_multiview = rt->view_count > 1 && config->multiview_supported;
+ GLenum texture_target = use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
- Texture *texture = get_texture(rt->texture);
- ERR_FAIL_COND(!texture);
+ /* Front FBO */
- // framebuffer
glGenFramebuffers(1, &rt->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
// color
- glGenTextures(1, &rt->color);
- if (rt->view_count > 1 && config->multiview_supported) {
- glBindTexture(GL_TEXTURE_2D_ARRAY, rt->color);
- glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, rt->color_internal_format, rt->size.x, rt->size.y, rt->view_count, 0, rt->color_format, rt->color_type, nullptr);
-
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ if (rt->overridden.color.is_valid()) {
+ texture = get_texture(rt->overridden.color);
+ ERR_FAIL_COND(!texture);
+
+ rt->color = texture->tex_id;
+ rt->size = Size2i(texture->width, texture->height);
} else {
- glBindTexture(GL_TEXTURE_2D, rt->color);
- glTexImage2D(GL_TEXTURE_2D, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr);
+ texture = get_texture(rt->texture);
+ ERR_FAIL_COND(!texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- }
+ glGenTextures(1, &rt->color);
+ glBindTexture(texture_target, rt->color);
- if (rt->view_count > 1 && config->multiview_supported) {
+ if (use_multiview) {
+ glTexImage3D(texture_target, 0, rt->color_internal_format, rt->size.x, rt->size.y, rt->view_count, 0, rt->color_format, rt->color_type, nullptr);
+ } else {
+ glTexImage2D(texture_target, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr);
+ }
+
+ glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+ if (use_multiview) {
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, rt->view_count);
} else {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
}
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ // depth
+ if (rt->overridden.depth.is_valid()) {
+ texture = get_texture(rt->overridden.depth);
+ ERR_FAIL_COND(!texture);
+ rt->depth = texture->tex_id;
+ } else {
+ glGenTextures(1, &rt->depth);
+ glBindTexture(texture_target, rt->depth);
+
+ if (use_multiview) {
+ glTexImage3D(texture_target, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, rt->view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+ } else {
+ glTexImage2D(texture_target, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+ }
+
+ glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+ if (use_multiview) {
+ glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, rt->depth, 0, 0, rt->view_count);
+ } else {
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0);
+ }
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
glDeleteFramebuffers(1, &rt->fbo);
glDeleteTextures(1, &rt->color);
@@ -1503,32 +1589,38 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
rt->size.x = 0;
rt->size.y = 0;
rt->color = 0;
- texture->tex_id = 0;
- texture->active = false;
+ rt->depth = 0;
+ if (rt->overridden.color.is_null()) {
+ texture->tex_id = 0;
+ texture->active = false;
+ }
WARN_PRINT("Could not create render target, status: " + get_framebuffer_error(status));
return;
}
- texture->format = rt->image_format;
- texture->real_format = rt->image_format;
- if (rt->view_count > 1 && config->multiview_supported) {
- texture->type = Texture::TYPE_LAYERED;
- texture->target = GL_TEXTURE_2D_ARRAY;
- texture->layers = rt->view_count;
+ if (rt->overridden.color.is_valid()) {
+ texture->is_render_target = true;
} else {
- texture->type = Texture::TYPE_2D;
- texture->target = GL_TEXTURE_2D;
- texture->layers = 1;
+ texture->format = rt->image_format;
+ texture->real_format = rt->image_format;
+ texture->target = texture_target;
+ if (rt->view_count > 1 && config->multiview_supported) {
+ texture->type = Texture::TYPE_LAYERED;
+ texture->layers = rt->view_count;
+ } else {
+ texture->type = Texture::TYPE_2D;
+ texture->layers = 1;
+ }
+ texture->gl_format_cache = rt->color_format;
+ texture->gl_type_cache = GL_UNSIGNED_BYTE;
+ texture->gl_internal_format_cache = rt->color_internal_format;
+ texture->tex_id = rt->color;
+ texture->width = rt->size.x;
+ texture->alloc_width = rt->size.x;
+ texture->height = rt->size.y;
+ texture->alloc_height = rt->size.y;
+ texture->active = true;
}
- texture->gl_format_cache = rt->color_format;
- texture->gl_type_cache = GL_UNSIGNED_BYTE;
- texture->gl_internal_format_cache = rt->color_internal_format;
- texture->tex_id = rt->color;
- texture->width = rt->size.x;
- texture->alloc_width = rt->size.x;
- texture->height = rt->size.y;
- texture->alloc_height = rt->size.y;
- texture->active = true;
}
glClearColor(0, 0, 0, 0);
@@ -1596,17 +1688,32 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
if (rt->fbo) {
glDeleteFramebuffers(1, &rt->fbo);
- glDeleteTextures(1, &rt->color);
rt->fbo = 0;
+ }
+
+ if (rt->overridden.color.is_null()) {
+ glDeleteTextures(1, &rt->color);
rt->color = 0;
}
- Texture *tex = get_texture(rt->texture);
- tex->alloc_height = 0;
- tex->alloc_width = 0;
- tex->width = 0;
- tex->height = 0;
- tex->active = false;
+ if (rt->overridden.depth.is_null()) {
+ glDeleteTextures(1, &rt->depth);
+ rt->depth = 0;
+ }
+
+ if (rt->texture.is_valid()) {
+ Texture *tex = get_texture(rt->texture);
+ tex->alloc_height = 0;
+ tex->alloc_width = 0;
+ tex->width = 0;
+ tex->height = 0;
+ tex->active = false;
+ }
+
+ if (rt->overridden.color.is_valid()) {
+ Texture *tex = get_texture(rt->overridden.color);
+ tex->is_render_target = false;
+ }
if (rt->backbuffer_fbo != 0) {
glDeleteFramebuffers(1, &rt->backbuffer_fbo);
@@ -1617,6 +1724,15 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
_render_target_clear_sdf(rt);
}
+void TextureStorage::_clear_render_target_overridden_fbo_cache(RenderTarget *rt) {
+ // Dispose of the cached fbo's and the allocated textures
+ for (KeyValue<uint32_t, RenderTarget::RTOverridden::FBOCacheEntry> &E : rt->overridden.fbo_cache) {
+ glDeleteTextures(E.value.allocated_textures.size(), E.value.allocated_textures.ptr());
+ glDeleteFramebuffers(1, &E.value.fbo);
+ }
+ rt->overridden.fbo_cache.clear();
+}
+
RID TextureStorage::render_target_create() {
RenderTarget render_target;
//render_target.was_used = false;
@@ -1635,11 +1751,14 @@ RID TextureStorage::render_target_create() {
void TextureStorage::render_target_free(RID p_rid) {
RenderTarget *rt = render_target_owner.get_or_null(p_rid);
_clear_render_target(rt);
+ _clear_render_target_overridden_fbo_cache(rt);
Texture *t = get_texture(rt->texture);
if (t) {
t->is_render_target = false;
- texture_free(rt->texture);
+ if (rt->overridden.color.is_null()) {
+ texture_free(rt->texture);
+ }
//memdelete(t);
}
render_target_owner.free(p_rid);
@@ -1666,6 +1785,9 @@ void TextureStorage::render_target_set_size(RID p_render_target, int p_width, in
if (p_width == rt->size.x && p_height == rt->size.y && p_view_count == rt->view_count) {
return;
}
+ if (rt->overridden.color.is_valid()) {
+ return;
+ }
_clear_render_target(rt);
@@ -1683,10 +1805,91 @@ Size2i TextureStorage::render_target_get_size(RID p_render_target) const {
return rt->size;
}
+void TextureStorage::render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+ ERR_FAIL_COND(rt->direct_to_screen);
+
+ rt->overridden.velocity = p_velocity_texture;
+
+ if (rt->overridden.color == p_color_texture && rt->overridden.depth == p_depth_texture) {
+ return;
+ }
+
+ if (p_color_texture.is_null() && p_depth_texture.is_null()) {
+ _clear_render_target(rt);
+ rt->overridden.is_overridden = false;
+ rt->overridden.color = RID();
+ rt->overridden.depth = RID();
+ rt->size = Size2i();
+ _clear_render_target_overridden_fbo_cache(rt);
+ return;
+ }
+
+ if (!rt->overridden.is_overridden) {
+ _clear_render_target(rt);
+ }
+
+ rt->overridden.color = p_color_texture;
+ rt->overridden.depth = p_depth_texture;
+ rt->overridden.is_overridden = true;
+
+ uint32_t hash_key = hash_murmur3_one_64(p_color_texture.get_id());
+ hash_key = hash_murmur3_one_64(p_depth_texture.get_id(), hash_key);
+ hash_key = hash_fmix32(hash_key);
+
+ RBMap<uint32_t, RenderTarget::RTOverridden::FBOCacheEntry>::Element *cache;
+ if ((cache = rt->overridden.fbo_cache.find(hash_key)) != nullptr) {
+ rt->fbo = cache->get().fbo;
+ rt->size = cache->get().size;
+ rt->texture = p_color_texture;
+ return;
+ }
+
+ _update_render_target(rt);
+
+ RenderTarget::RTOverridden::FBOCacheEntry new_entry;
+ new_entry.fbo = rt->fbo;
+ new_entry.size = rt->size;
+ // Keep track of any textures we had to allocate because they weren't overridden.
+ if (p_color_texture.is_null()) {
+ new_entry.allocated_textures.push_back(rt->color);
+ }
+ if (p_depth_texture.is_null()) {
+ new_entry.allocated_textures.push_back(rt->depth);
+ }
+ rt->overridden.fbo_cache.insert(hash_key, new_entry);
+}
+
+RID TextureStorage::render_target_get_override_color(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
+
+ return rt->overridden.color;
+}
+
+RID TextureStorage::render_target_get_override_depth(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
+
+ return rt->overridden.depth;
+}
+
+RID TextureStorage::render_target_get_override_velocity(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
+
+ return rt->overridden.velocity;
+}
+
RID TextureStorage::render_target_get_texture(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
+ if (rt->overridden.color.is_valid()) {
+ return rt->overridden.color;
+ }
+
return rt->texture;
}
@@ -1696,8 +1899,10 @@ void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_t
rt->is_transparent = p_transparent;
- _clear_render_target(rt);
- _update_render_target(rt);
+ if (rt->overridden.color.is_null()) {
+ _clear_render_target(rt);
+ _update_render_target(rt);
+ }
}
bool TextureStorage::render_target_get_transparent(RID p_render_target) const {
@@ -1718,6 +1923,11 @@ void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, boo
// those functions change how they operate depending on the value of DIRECT_TO_SCREEN
_clear_render_target(rt);
rt->direct_to_screen = p_direct_to_screen;
+ if (rt->direct_to_screen) {
+ rt->overridden.color = RID();
+ rt->overridden.depth = RID();
+ rt->overridden.velocity = RID();
+ }
_update_render_target(rt);
}
@@ -1750,6 +1960,7 @@ void TextureStorage::render_target_set_msaa(RID p_render_target, RS::ViewportMSA
}
WARN_PRINT("2D MSAA is not yet supported for GLES3.");
+
_clear_render_target(rt);
rt->msaa = p_msaa;
_update_render_target(rt);
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index 35fa16c894..7714e72f62 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -126,6 +126,7 @@ struct Texture {
RID self;
bool is_proxy = false;
+ bool is_external = false;
bool is_render_target = false;
RID proxy_to = RID();
@@ -187,6 +188,7 @@ struct Texture {
void copy_from(const Texture &o) {
proxy_to = o.proxy_to;
is_proxy = o.is_proxy;
+ is_external = o.is_external;
width = o.width;
height = o.height;
alloc_width = o.alloc_width;
@@ -310,6 +312,7 @@ struct RenderTarget {
RID self;
GLuint fbo = 0;
GLuint color = 0;
+ GLuint depth = 0;
GLuint backbuffer_fbo = 0;
GLuint backbuffer = 0;
@@ -333,6 +336,20 @@ struct RenderTarget {
bool used_in_frame = false;
RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
+ struct RTOverridden {
+ bool is_overridden = false;
+ RID color;
+ RID depth;
+ RID velocity;
+
+ struct FBOCacheEntry {
+ GLuint fbo;
+ Size2i size;
+ Vector<GLuint> allocated_textures;
+ };
+ RBMap<uint32_t, FBOCacheEntry> fbo_cache;
+ } overridden;
+
RID texture;
Color clear_color = Color(1, 1, 1, 1);
@@ -395,6 +412,7 @@ private:
mutable RID_Owner<RenderTarget> render_target_owner;
void _clear_render_target(RenderTarget *rt);
+ void _clear_render_target_overridden_fbo_cache(RenderTarget *rt);
void _update_render_target(RenderTarget *rt);
void _create_render_target_backbuffer(RenderTarget *rt);
void _render_target_allocate_sdf(RenderTarget *rt);
@@ -454,6 +472,8 @@ public:
virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) override;
virtual void texture_proxy_initialize(RID p_texture, RID p_base) override; //all slices, then all the mipmaps, must be coherent
+ RID texture_create_external(Texture::Type p_type, Image::Format p_format, unsigned int p_image, int p_width, int p_height, int p_depth, int p_layers, RS::TextureLayeredType p_layered_type = RS::TEXTURE_LAYERED_2D_ARRAY);
+
virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override;
virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override{};
virtual void texture_proxy_update(RID p_proxy, RID p_base) override;
@@ -484,6 +504,8 @@ public:
virtual Size2 texture_size_with_proxy(RID p_proxy) override;
+ virtual RID texture_get_rd_texture_rid(RID p_texture, bool p_srgb = false) const override;
+
void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0);
void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer = 0);
//Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const;
@@ -593,10 +615,10 @@ public:
virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override {}
virtual RID render_target_get_vrs_texture(RID p_render_target) const override { return RID(); }
- virtual void render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) override {}
- virtual RID render_target_get_override_color(RID p_render_target) const override { return RID(); }
- virtual RID render_target_get_override_depth(RID p_render_target) const override { return RID(); }
- virtual RID render_target_get_override_velocity(RID p_render_target) const override { return RID(); }
+ virtual void render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) override;
+ virtual RID render_target_get_override_color(RID p_render_target) const override;
+ virtual RID render_target_get_override_depth(RID p_render_target) const override;
+ virtual RID render_target_get_override_velocity(RID p_render_target) const override;
virtual RID render_target_get_texture(RID p_render_target) override;
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 1fe31a3c47..0ff4ca31e6 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -7751,7 +7751,7 @@ void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_
dl->validation.index_array_size = index_array->indices;
dl->validation.index_array_offset = index_array->offset;
- vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, index_array->offset, index_array->index_type);
+ vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, 0, index_array->index_type);
}
void RenderingDeviceVulkan::draw_list_set_line_width(DrawListID p_list, float p_width) {
@@ -9387,12 +9387,10 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
}
}
- // NOTE: If adding new project settings here, also duplicate their definition in
- // rendering_server.cpp for headless doctool.
- staging_buffer_block_size = GLOBAL_DEF("rendering/rendering_device/staging_buffer/block_size_kb", 256);
+ staging_buffer_block_size = GLOBAL_GET("rendering/rendering_device/staging_buffer/block_size_kb");
staging_buffer_block_size = MAX(4u, staging_buffer_block_size);
staging_buffer_block_size *= 1024; // Kb -> bytes.
- staging_buffer_max_size = GLOBAL_DEF("rendering/rendering_device/staging_buffer/max_size_mb", 128);
+ staging_buffer_max_size = GLOBAL_GET("rendering/rendering_device/staging_buffer/max_size_mb");
staging_buffer_max_size = MAX(1u, staging_buffer_max_size);
staging_buffer_max_size *= 1024 * 1024;
@@ -9400,7 +9398,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
// Validate enough blocks.
staging_buffer_max_size = staging_buffer_block_size * 4;
}
- texture_upload_region_size_px = GLOBAL_DEF("rendering/rendering_device/staging_buffer/texture_upload_region_size_px", 64);
+ texture_upload_region_size_px = GLOBAL_GET("rendering/rendering_device/staging_buffer/texture_upload_region_size_px");
texture_upload_region_size_px = nearest_power_of_2_templated(texture_upload_region_size_px);
frames_drawn = frame_count; // Start from frame count, so everything else is immediately old.
@@ -9415,7 +9413,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
ERR_CONTINUE(err != OK);
}
- max_descriptors_per_pool = GLOBAL_DEF("rendering/rendering_device/vulkan/max_descriptors_per_pool", 64);
+ max_descriptors_per_pool = GLOBAL_GET("rendering/rendering_device/vulkan/max_descriptors_per_pool");
// Check to make sure DescriptorPoolKey is good.
static_assert(sizeof(uint64_t) * 3 >= UNIFORM_TYPE_MAX * sizeof(uint16_t));
diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp
index d6636606d2..f196530e51 100644
--- a/drivers/wasapi/audio_driver_wasapi.cpp
+++ b/drivers/wasapi/audio_driver_wasapi.cpp
@@ -127,11 +127,6 @@ static bool default_capture_device_changed = false;
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#endif
-#if defined(__GNUC__)
-// Workaround GCC warning from -Wcast-function-type.
-#define GetProcAddress (void *)GetProcAddress
-#endif
-
class CMMNotificationClient : public IMMNotificationClient {
LONG _cRef = 1;
IMMDeviceEnumerator *_pEnumerator = nullptr;
@@ -206,21 +201,7 @@ public:
static CMMNotificationClient notif_client;
-typedef const char *(CDECL *PWineGetVersionPtr)(void);
-
-bool AudioDriverWASAPI::is_running_on_wine() {
- HMODULE nt_lib = LoadLibraryW(L"ntdll.dll");
- if (!nt_lib) {
- return false;
- }
-
- PWineGetVersionPtr wine_get_version = (PWineGetVersionPtr)GetProcAddress(nt_lib, "wine_get_version");
- FreeLibrary(nt_lib);
-
- return (bool)wine_get_version;
-}
-
-Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool reinit) {
+Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool p_reinit, bool p_no_audio_client_3) {
WAVEFORMATEX *pwfex;
IMMDeviceEnumerator *enumerator = nullptr;
IMMDevice *device = nullptr;
@@ -286,7 +267,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
}
}
- if (reinit) {
+ if (p_reinit) {
// In case we're trying to re-initialize the device prevent throwing this error on the console,
// otherwise if there is currently no device available this will spam the console.
if (hr != S_OK) {
@@ -304,10 +285,11 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
}
using_audio_client_3 = !p_capture; // IID_IAudioClient3 is only used for adjustable output latency (not input)
- if (using_audio_client_3 && is_running_on_wine()) {
+
+ if (p_no_audio_client_3) {
using_audio_client_3 = false;
- print_verbose("WASAPI: Wine detected, falling back to IAudioClient interface");
}
+
if (using_audio_client_3) {
hr = device->Activate(IID_IAudioClient3, CLSCTX_ALL, nullptr, (void **)&p_device->audio_client);
if (hr != S_OK) {
@@ -325,7 +307,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
SAFE_RELEASE(device)
- if (reinit) {
+ if (p_reinit) {
if (hr != S_OK) {
return ERR_CANT_OPEN;
}
@@ -436,7 +418,12 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
&fundamental_period_frames,
&min_period_frames,
&max_period_frames);
- ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_CANT_OPEN, "WASAPI: GetSharedModeEnginePeriod failed with error 0x" + String::num_uint64(hr, 16) + ".");
+ if (hr != S_OK) {
+ print_verbose("WASAPI: GetSharedModeEnginePeriod failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient.");
+ CoTaskMemFree(pwfex);
+ SAFE_RELEASE(device)
+ return audio_device_init(p_device, p_capture, p_reinit, true);
+ }
// Period frames must be an integral multiple of fundamental_period_frames or IAudioClient3 initialization will fail,
// so we need to select the closest multiple to the user-specified latency.
@@ -453,12 +440,25 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
buffer_frames = period_frames;
hr = device_audio_client_3->InitializeSharedAudioStream(0, period_frames, pwfex, nullptr);
- ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_CANT_OPEN, "WASAPI: InitializeSharedAudioStream failed with error 0x" + String::num_uint64(hr, 16) + ".");
- uint32_t output_latency_in_frames;
- WAVEFORMATEX *current_pwfex;
- device_audio_client_3->GetCurrentSharedModeEnginePeriod(&current_pwfex, &output_latency_in_frames);
- real_latency = (float)output_latency_in_frames / (float)current_pwfex->nSamplesPerSec;
- CoTaskMemFree(current_pwfex);
+ if (hr != S_OK) {
+ print_verbose("WASAPI: InitializeSharedAudioStream failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient.");
+ CoTaskMemFree(pwfex);
+ SAFE_RELEASE(device);
+ return audio_device_init(p_device, p_capture, p_reinit, true);
+ } else {
+ uint32_t output_latency_in_frames;
+ WAVEFORMATEX *current_pwfex;
+ hr = device_audio_client_3->GetCurrentSharedModeEnginePeriod(&current_pwfex, &output_latency_in_frames);
+ if (hr == OK) {
+ real_latency = (float)output_latency_in_frames / (float)current_pwfex->nSamplesPerSec;
+ CoTaskMemFree(current_pwfex);
+ } else {
+ print_verbose("WASAPI: GetCurrentSharedModeEnginePeriod failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient.");
+ CoTaskMemFree(pwfex);
+ SAFE_RELEASE(device);
+ return audio_device_init(p_device, p_capture, p_reinit, true);
+ }
+ }
}
if (p_capture) {
@@ -475,8 +475,8 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
return OK;
}
-Error AudioDriverWASAPI::init_render_device(bool reinit) {
- Error err = audio_device_init(&audio_output, false, reinit);
+Error AudioDriverWASAPI::init_render_device(bool p_reinit) {
+ Error err = audio_device_init(&audio_output, false, p_reinit);
if (err != OK) {
return err;
}
@@ -507,8 +507,8 @@ Error AudioDriverWASAPI::init_render_device(bool reinit) {
return OK;
}
-Error AudioDriverWASAPI::init_capture_device(bool reinit) {
- Error err = audio_device_init(&audio_input, true, reinit);
+Error AudioDriverWASAPI::init_capture_device(bool p_reinit) {
+ Error err = audio_device_init(&audio_input, true, p_reinit);
if (err != OK) {
return err;
}
diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h
index e9f2794e97..fb6a55734d 100644
--- a/drivers/wasapi/audio_driver_wasapi.h
+++ b/drivers/wasapi/audio_driver_wasapi.h
@@ -79,19 +79,17 @@ class AudioDriverWASAPI : public AudioDriver {
SafeFlag exit_thread;
- static bool is_running_on_wine();
-
static _FORCE_INLINE_ void write_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i, int32_t sample);
static _FORCE_INLINE_ int32_t read_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i);
static void thread_func(void *p_udata);
- Error init_render_device(bool reinit = false);
- Error init_capture_device(bool reinit = false);
+ Error init_render_device(bool p_reinit = false);
+ Error init_capture_device(bool p_reinit = false);
Error finish_render_device();
Error finish_capture_device();
- Error audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool reinit);
+ Error audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool p_reinit, bool p_no_audio_client_3 = false);
Error audio_device_finish(AudioDeviceWASAPI *p_device);
PackedStringArray audio_device_get_list(bool p_capture);
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index 9b1ff78727..3b9d6c18eb 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "editor/action_map_editor.h"
+
#include "editor/editor_scale.h"
#include "editor/event_listener_line_edit.h"
#include "editor/input_event_configuration_dialog.h"
@@ -395,15 +396,9 @@ void ActionMapEditor::update_action_list(const Vector<ActionInfo> &p_action_info
action_tree->clear();
TreeItem *root = action_tree->create_item();
- int uneditable_count = 0;
-
for (int i = 0; i < actions_cache.size(); i++) {
ActionInfo action_info = actions_cache[i];
- if (!action_info.editable) {
- uneditable_count++;
- }
-
const Array events = action_info.action["events"];
if (!_should_display_action(action_info.name, events)) {
continue;
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 212a46cb62..510dc345bf 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -1872,7 +1872,7 @@ void CodeTextEditor::_apply_settings_change() {
}
fc->set_opentype_features(ftrs);
} break;
- default: { // Default.
+ default: { // Enabled.
Dictionary ftrs;
ftrs[TS->name_to_tag("calt")] = 1;
fc->set_opentype_features(ftrs);
@@ -2106,7 +2106,7 @@ CodeTextEditor::CodeTextEditor() {
}
fc->set_opentype_features(ftrs);
} break;
- default: { // Default.
+ default: { // Enabled.
Dictionary ftrs;
ftrs[TS->name_to_tag("calt")] = 1;
fc->set_opentype_features(ftrs);
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 6142856f75..545b0895b0 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -284,12 +284,12 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String
bool can_instantiate = (p_type_category == TypeCategory::CPP_TYPE && ClassDB::can_instantiate(p_type)) ||
p_type_category == TypeCategory::OTHER_TYPE;
- if (!can_instantiate) {
- r_item->set_custom_color(0, search_options->get_theme_color(SNAME("disabled_font_color"), SNAME("Editor")));
+ if (can_instantiate && !ClassDB::is_virtual(p_type)) {
+ r_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, icon_fallback));
+ } else {
r_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, "NodeDisabled"));
+ r_item->set_custom_color(0, search_options->get_theme_color(SNAME("disabled_font_color"), SNAME("Editor")));
r_item->set_selectable(0, false);
- } else {
- r_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, icon_fallback));
}
bool is_deprecated = EditorHelp::get_doc_data()->class_list[p_type].is_deprecated;
diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp
index e2fd462f3a..071eb583c0 100644
--- a/editor/debugger/editor_performance_profiler.cpp
+++ b/editor/debugger/editor_performance_profiler.cpp
@@ -234,6 +234,7 @@ TreeItem *EditorPerformanceProfiler::_get_monitor_base(const StringName &p_base_
base->set_editable(0, false);
base->set_selectable(0, false);
base->set_expand_right(0, true);
+ base->set_custom_font(0, get_theme_font(SNAME("bold"), SNAME("EditorFonts")));
base_map.insert(p_base_name, base);
return base;
}
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index 7d6eb186dc..14a2640e63 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -335,7 +335,7 @@ static Variant get_documentation_default_value(const StringName &p_class_name, c
Variant default_value = Variant();
r_default_value_valid = false;
- if (ClassDB::can_instantiate(p_class_name)) {
+ if (ClassDB::can_instantiate(p_class_name) && !ClassDB::is_virtual(p_class_name)) { // Keep this condition in sync with ClassDB::class_get_default_property_value.
default_value = ClassDB::class_get_default_property_value(p_class_name, p_property_name, &r_default_value_valid);
} else {
// Cannot get default value of classes that can't be instantiated
diff --git a/editor/editor_audio_buses.h b/editor/editor_audio_buses.h
index 436b391ccd..97e94089cc 100644
--- a/editor/editor_audio_buses.h
+++ b/editor/editor_audio_buses.h
@@ -47,6 +47,7 @@
#include "scene/gui/tree.h"
class EditorAudioBuses;
+class EditorFileDialog;
class EditorAudioBus : public PanelContainer {
GDCLASS(EditorAudioBus, PanelContainer);
diff --git a/editor/editor_build_profile.h b/editor/editor_build_profile.h
index 606c415429..9624f7e44b 100644
--- a/editor/editor_build_profile.h
+++ b/editor/editor_build_profile.h
@@ -117,6 +117,7 @@ public:
VARIANT_ENUM_CAST(EditorBuildProfile::BuildOption)
VARIANT_ENUM_CAST(EditorBuildProfile::BuildOptionCategory)
+class EditorFileDialog;
class EditorFileSystemDirectory;
class EditorBuildProfileManager : public AcceptDialog {
diff --git a/editor/editor_command_palette.cpp b/editor/editor_command_palette.cpp
index a0913265eb..3f93fa1f41 100644
--- a/editor/editor_command_palette.cpp
+++ b/editor/editor_command_palette.cpp
@@ -226,7 +226,7 @@ void EditorCommandPalette::_add_command(String p_command_name, String p_key_name
void EditorCommandPalette::execute_command(String &p_command_key) {
ERR_FAIL_COND_MSG(!commands.has(p_command_key), p_command_key + " not found.");
commands[p_command_key].last_used = OS::get_singleton()->get_unix_time();
- commands[p_command_key].callable.call_deferredp(nullptr, 0);
+ commands[p_command_key].callable.call_deferred();
_save_history();
}
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index 9549ffb09b..49fb16a095 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -47,6 +47,7 @@ const char *EditorFeatureProfile::feature_names[FEATURE_MAX] = {
TTRC("Node Dock"),
TTRC("FileSystem Dock"),
TTRC("Import Dock"),
+ TTRC("History Dock"),
};
const char *EditorFeatureProfile::feature_descriptions[FEATURE_MAX] = {
@@ -57,6 +58,7 @@ const char *EditorFeatureProfile::feature_descriptions[FEATURE_MAX] = {
TTRC("Allows to work with signals and groups of the node selected in the Scene dock."),
TTRC("Allows to browse the local file system via a dedicated dock."),
TTRC("Allows to configure import settings for individual assets. Requires the FileSystem dock to function."),
+ TTRC("Provides an overview of the editor's and each scene's undo history."),
};
const char *EditorFeatureProfile::feature_identifiers[FEATURE_MAX] = {
@@ -67,6 +69,7 @@ const char *EditorFeatureProfile::feature_identifiers[FEATURE_MAX] = {
"node_dock",
"filesystem_dock",
"import_dock",
+ "history_dock",
};
void EditorFeatureProfile::set_disable_class(const StringName &p_class, bool p_disabled) {
@@ -302,6 +305,7 @@ void EditorFeatureProfile::_bind_methods() {
BIND_ENUM_CONSTANT(FEATURE_NODE_DOCK);
BIND_ENUM_CONSTANT(FEATURE_FILESYSTEM_DOCK);
BIND_ENUM_CONSTANT(FEATURE_IMPORT_DOCK);
+ BIND_ENUM_CONSTANT(FEATURE_HISTORY_DOCK);
BIND_ENUM_CONSTANT(FEATURE_MAX);
}
diff --git a/editor/editor_feature_profile.h b/editor/editor_feature_profile.h
index dab6c951e4..1d79844913 100644
--- a/editor/editor_feature_profile.h
+++ b/editor/editor_feature_profile.h
@@ -40,6 +40,8 @@
#include "scene/gui/split_container.h"
#include "scene/gui/tree.h"
+class EditorFileDialog;
+
class EditorFeatureProfile : public RefCounted {
GDCLASS(EditorFeatureProfile, RefCounted);
@@ -52,6 +54,7 @@ public:
FEATURE_NODE_DOCK,
FEATURE_FILESYSTEM_DOCK,
FEATURE_IMPORT_DOCK,
+ FEATURE_HISTORY_DOCK,
FEATURE_MAX
};
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index 51ebc31df3..e7d4636ad9 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -335,7 +335,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
}
mono_fc->set_opentype_features(ftrs);
} break;
- default: { // Default.
+ default: { // Enabled.
Dictionary ftrs;
ftrs[TS->name_to_tag("calt")] = 1;
mono_fc->set_opentype_features(ftrs);
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 89398409a2..973e4acbcb 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -54,10 +54,14 @@ void EditorHelp::_update_theme() {
qualifier_color = get_theme_color(SNAME("qualifier_color"), SNAME("EditorHelp"));
type_color = get_theme_color(SNAME("type_color"), SNAME("EditorHelp"));
+ class_desc->add_theme_style_override("normal", get_theme_stylebox(SNAME("background"), SNAME("EditorHelp")));
+ class_desc->add_theme_style_override("focus", get_theme_stylebox(SNAME("background"), SNAME("EditorHelp")));
class_desc->add_theme_color_override("selection_color", get_theme_color(SNAME("selection_color"), SNAME("EditorHelp")));
class_desc->add_theme_constant_override("line_separation", get_theme_constant(SNAME("line_separation"), SNAME("EditorHelp")));
class_desc->add_theme_constant_override("table_h_separation", get_theme_constant(SNAME("table_h_separation"), SNAME("EditorHelp")));
class_desc->add_theme_constant_override("table_v_separation", get_theme_constant(SNAME("table_v_separation"), SNAME("EditorHelp")));
+ class_desc->add_theme_constant_override("text_highlight_h_padding", get_theme_constant(SNAME("text_highlight_h_padding"), SNAME("EditorHelp")));
+ class_desc->add_theme_constant_override("text_highlight_v_padding", get_theme_constant(SNAME("text_highlight_v_padding"), SNAME("EditorHelp")));
doc_font = get_theme_font(SNAME("doc"), SNAME("EditorFonts"));
doc_bold_font = get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts"));
@@ -1786,9 +1790,19 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, Control
Ref<Font> doc_code_font = p_owner_node->get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
Ref<Font> doc_kbd_font = p_owner_node->get_theme_font(SNAME("doc_keyboard"), SNAME("EditorFonts"));
- Color link_color = p_owner_node->get_theme_color(SNAME("link_color"), SNAME("EditorHelp"));
- Color code_color = p_owner_node->get_theme_color(SNAME("code_color"), SNAME("EditorHelp"));
- Color kbd_color = p_owner_node->get_theme_color(SNAME("kbd_color"), SNAME("EditorHelp"));
+ const Color type_color = p_owner_node->get_theme_color(SNAME("type_color"), SNAME("EditorHelp"));
+ const Color code_color = p_owner_node->get_theme_color(SNAME("code_color"), SNAME("EditorHelp"));
+ const Color kbd_color = p_owner_node->get_theme_color(SNAME("kbd_color"), SNAME("EditorHelp"));
+ const Color code_dark_color = Color(code_color, 0.8);
+
+ const Color link_color = p_owner_node->get_theme_color(SNAME("link_color"), SNAME("EditorHelp"));
+ const Color link_method_color = p_owner_node->get_theme_color(SNAME("accent_color"), SNAME("Editor"));
+ const Color link_property_color = link_color.lerp(p_owner_node->get_theme_color(SNAME("accent_color"), SNAME("Editor")), 0.25);
+ const Color link_annotation_color = link_color.lerp(p_owner_node->get_theme_color(SNAME("accent_color"), SNAME("Editor")), 0.5);
+
+ const Color code_bg_color = p_owner_node->get_theme_color(SNAME("code_bg_color"), SNAME("EditorHelp"));
+ const Color kbd_bg_color = p_owner_node->get_theme_color(SNAME("kbd_bg_color"), SNAME("EditorHelp"));
+ const Color param_bg_color = p_owner_node->get_theme_color(SNAME("param_bg_color"), SNAME("EditorHelp"));
String bbcode = p_bbcode.dedent().replace("\t", "").replace("\r", "").strip_edges();
@@ -1921,14 +1935,21 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, Control
const String link_tag = tag.substr(0, tag_end);
const String link_target = tag.substr(tag_end + 1, tag.length()).lstrip(" ");
- // Use monospace font with translucent colored background color to make clickable references
+ // Use monospace font to make clickable references
// easier to distinguish from inline code and other text.
p_rt->push_font(doc_code_font);
- p_rt->push_color(link_color);
- p_rt->push_bgcolor(code_color * Color(1, 1, 1, 0.15));
+
+ Color target_color = link_color;
+ if (link_tag == "method") {
+ target_color = link_method_color;
+ } else if (link_tag == "member" || link_tag == "signal" || link_tag == "theme property") {
+ target_color = link_property_color;
+ } else if (link_tag == "annotation") {
+ target_color = link_annotation_color;
+ }
+ p_rt->push_color(target_color);
p_rt->push_meta("@" + link_tag + " " + link_target);
- p_rt->add_text(link_target + (tag.begins_with("method ") ? "()" : ""));
- p_rt->pop();
+ p_rt->add_text(link_target + (link_tag == "method" ? "()" : ""));
p_rt->pop();
p_rt->pop();
p_rt->pop();
@@ -1940,7 +1961,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, Control
// Use monospace font with translucent background color to make code easier to distinguish from other text.
p_rt->push_font(doc_code_font);
- p_rt->push_bgcolor(Color(0.5, 0.5, 0.5, 0.15));
+ p_rt->push_bgcolor(param_bg_color);
p_rt->push_color(code_color);
p_rt->add_text(param_name);
p_rt->pop();
@@ -1951,17 +1972,15 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, Control
} else if (doc->class_list.has(tag)) {
// Class reference tag such as [Node2D] or [SceneTree].
- // Use monospace font with translucent colored background color to make clickable references
+ // Use monospace font to make clickable references
// easier to distinguish from inline code and other text.
p_rt->push_font(doc_code_font);
- p_rt->push_color(link_color);
- p_rt->push_bgcolor(code_color * Color(1, 1, 1, 0.15));
+ p_rt->push_color(type_color);
p_rt->push_meta("#" + tag);
p_rt->add_text(tag);
p_rt->pop();
p_rt->pop();
p_rt->pop();
- p_rt->pop();
pos = brk_end + 1;
} else if (tag == "b") {
@@ -1975,30 +1994,30 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, Control
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "code") {
- // Use monospace font with translucent background color to make code easier to distinguish from other text.
+ // Use monospace font with darkened background color to make code easier to distinguish from other text.
p_rt->push_font(doc_code_font);
- p_rt->push_bgcolor(Color(0.5, 0.5, 0.5, 0.15));
- p_rt->push_color(code_color);
+ p_rt->push_bgcolor(code_bg_color);
+ p_rt->push_color(code_color.lerp(p_owner_node->get_theme_color(SNAME("error_color"), SNAME("Editor")), 0.6));
code_tag = true;
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "codeblock") {
- // Use monospace font with translucent background color to make code easier to distinguish from other text.
+ // Use monospace font with darkened background color to make code easier to distinguish from other text.
// Use a single-column table with cell row background color instead of `[bgcolor]`.
// This makes the background color highlight cover the entire block, rather than individual lines.
p_rt->push_font(doc_code_font);
p_rt->push_table(1);
p_rt->push_cell();
- p_rt->set_cell_row_background_color(Color(0.5, 0.5, 0.5, 0.15), Color(0.5, 0.5, 0.5, 0.15));
+ p_rt->set_cell_row_background_color(code_bg_color, Color(code_bg_color, 0.99));
p_rt->set_cell_padding(Rect2(10 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE));
- p_rt->push_color(code_color);
+ p_rt->push_color(code_dark_color);
codeblock_tag = true;
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "kbd") {
// Use keyboard font with custom color and background color.
p_rt->push_font(doc_kbd_font);
- p_rt->push_bgcolor(Color(0.5, 0.5, 0.5, 0.15));
+ p_rt->push_bgcolor(kbd_bg_color);
p_rt->push_color(kbd_color);
code_tag = true; // Though not strictly a code tag, logic is similar.
pos = brk_end + 1;
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 716e0b454f..227f35597c 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -114,6 +114,7 @@
#include "editor/import/audio_stream_import_settings.h"
#include "editor/import/dynamic_font_import_settings.h"
#include "editor/import/editor_import_collada.h"
+#include "editor/import/editor_import_plugin.h"
#include "editor/import/resource_importer_bitmask.h"
#include "editor/import/resource_importer_bmfont.h"
#include "editor/import/resource_importer_csv_translation.h"
@@ -244,15 +245,11 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto
String full_path = p_full_paths[set_idx];
// Get rid of file extensions and res:// prefixes.
- if (scene_name.rfind(".") >= 0) {
- scene_name = scene_name.substr(0, scene_name.rfind("."));
- }
+ scene_name = scene_name.get_basename();
if (full_path.begins_with("res://")) {
full_path = full_path.substr(6);
}
- if (full_path.rfind(".") >= 0) {
- full_path = full_path.substr(0, full_path.rfind("."));
- }
+ full_path = full_path.get_basename();
// Normalize trailing slashes when normalizing directory names.
scene_name = scene_name.trim_suffix("/");
@@ -270,7 +267,7 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto
String parent = full_path.substr(0, difference);
int slash_idx = parent.rfind("/");
slash_idx = parent.rfind("/", slash_idx - 1);
- parent = slash_idx >= 0 ? parent.substr(slash_idx + 1) : parent;
+ parent = (slash_idx >= 0 && parent.length() > 1) ? parent.substr(slash_idx + 1) : parent;
r_filenames.write[set_idx] = parent + r_filenames[set_idx];
}
}
@@ -302,15 +299,11 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto
String path = p_full_paths[E->get()];
// Get rid of file extensions and res:// prefixes.
- if (scene_name.rfind(".") >= 0) {
- scene_name = scene_name.substr(0, scene_name.rfind("."));
- }
+ scene_name = scene_name.get_basename();
if (path.begins_with("res://")) {
path = path.substr(6);
}
- if (path.rfind(".") >= 0) {
- path = path.substr(0, path.rfind("."));
- }
+ path = path.get_basename();
// Normalize trailing slashes when normalizing directory names.
scene_name = scene_name.trim_suffix("/");
@@ -544,7 +537,7 @@ void EditorNode::_update_from_settings() {
RS::get_singleton()->environment_set_volumetric_fog_filter_active(bool(GLOBAL_GET("rendering/environment/volumetric_fog/use_filter")));
RS::get_singleton()->canvas_set_shadow_texture_size(GLOBAL_GET("rendering/2d/shadow_atlas/size"));
- bool use_half_res_gi = GLOBAL_DEF("rendering/global_illumination/gi/use_half_resolution", false);
+ bool use_half_res_gi = GLOBAL_GET("rendering/global_illumination/gi/use_half_resolution");
RS::get_singleton()->gi_set_use_half_resolution(use_half_res_gi);
bool snap_2d_transforms = GLOBAL_GET("rendering/2d/snap/snap_2d_transforms_to_pixel");
@@ -5142,7 +5135,7 @@ bool EditorNode::has_scenes_in_session() {
bool EditorNode::ensure_main_scene(bool p_from_native) {
pick_main_scene->set_meta("from_native", p_from_native); // Whether from play button or native run.
- String main_scene = GLOBAL_DEF_BASIC("application/run/main_scene", "");
+ String main_scene = GLOBAL_GET("application/run/main_scene");
if (main_scene.is_empty()) {
current_menu_option = -1;
@@ -5209,7 +5202,7 @@ bool EditorNode::is_run_playing() const {
String EditorNode::get_run_playing_scene() const {
String run_filename = editor_run.get_running_scene();
if (run_filename.is_empty() && is_run_playing()) {
- run_filename = GLOBAL_DEF_BASIC("application/run/main_scene", ""); // Must be the main scene then.
+ run_filename = GLOBAL_GET("application/run/main_scene"); // Must be the main scene then.
}
return run_filename;
@@ -5976,12 +5969,14 @@ void EditorNode::_feature_profile_changed() {
TabContainer *import_tabs = cast_to<TabContainer>(ImportDock::get_singleton()->get_parent());
TabContainer *node_tabs = cast_to<TabContainer>(NodeDock::get_singleton()->get_parent());
TabContainer *fs_tabs = cast_to<TabContainer>(FileSystemDock::get_singleton()->get_parent());
+ TabContainer *history_tabs = cast_to<TabContainer>(history_dock->get_parent());
if (profile.is_valid()) {
node_tabs->set_tab_hidden(node_tabs->get_tab_idx_from_control(NodeDock::get_singleton()), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_NODE_DOCK));
// The Import dock is useless without the FileSystem dock. Ensure the configuration is valid.
bool fs_dock_disabled = profile->is_feature_disabled(EditorFeatureProfile::FEATURE_FILESYSTEM_DOCK);
fs_tabs->set_tab_hidden(fs_tabs->get_tab_idx_from_control(FileSystemDock::get_singleton()), fs_dock_disabled);
import_tabs->set_tab_hidden(import_tabs->get_tab_idx_from_control(ImportDock::get_singleton()), fs_dock_disabled || profile->is_feature_disabled(EditorFeatureProfile::FEATURE_IMPORT_DOCK));
+ history_tabs->set_tab_hidden(history_tabs->get_tab_idx_from_control(history_dock), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_HISTORY_DOCK));
main_editor_buttons[EDITOR_3D]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D));
main_editor_buttons[EDITOR_SCRIPT]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCRIPT));
@@ -5997,6 +5992,8 @@ void EditorNode::_feature_profile_changed() {
import_tabs->set_tab_hidden(import_tabs->get_tab_idx_from_control(ImportDock::get_singleton()), false);
node_tabs->set_tab_hidden(node_tabs->get_tab_idx_from_control(NodeDock::get_singleton()), false);
fs_tabs->set_tab_hidden(fs_tabs->get_tab_idx_from_control(FileSystemDock::get_singleton()), false);
+ history_tabs->set_tab_hidden(history_tabs->get_tab_idx_from_control(history_dock), false);
+ history_dock->set_visible(true);
ImportDock::get_singleton()->set_visible(true);
NodeDock::get_singleton()->set_visible(true);
FileSystemDock::get_singleton()->set_visible(true);
@@ -7108,7 +7105,7 @@ EditorNode::EditorNode() {
filesystem_dock->connect("display_mode_changed", callable_mp(this, &EditorNode::_save_docks));
get_project_settings()->connect_filesystem_dock_signals(filesystem_dock);
- HistoryDock *hd = memnew(HistoryDock);
+ history_dock = memnew(HistoryDock);
// Scene: Top left.
dock_slot[DOCK_SLOT_LEFT_UR]->add_child(SceneTreeDock::get_singleton());
@@ -7131,8 +7128,8 @@ EditorNode::EditorNode() {
dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(dock_slot[DOCK_SLOT_RIGHT_UL]->get_tab_idx_from_control(NodeDock::get_singleton()), TTR("Node"));
// History: Full height right, behind Node.
- dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(hd);
- dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(dock_slot[DOCK_SLOT_RIGHT_UL]->get_tab_idx_from_control(hd), TTR("History"));
+ dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(history_dock);
+ dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(dock_slot[DOCK_SLOT_RIGHT_UL]->get_tab_idx_from_control(history_dock), TTR("History"));
// Hide unused dock slots and vsplits.
dock_slot[DOCK_SLOT_LEFT_UL]->hide();
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 9c8d564057..f27fe429b9 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -77,6 +77,7 @@ class EditorUndoRedoManager;
class ExportTemplateManager;
class FileDialog;
class FileSystemDock;
+class HistoryDock;
class HSplitContainer;
class ImportDock;
class LinkButton;
@@ -274,6 +275,7 @@ private:
EditorRunNative *run_native = nullptr;
EditorSelection *editor_selection = nullptr;
EditorSettingsDialog *editor_settings_dialog = nullptr;
+ HistoryDock *history_dock = nullptr;
ProjectExportDialog *project_export = nullptr;
ProjectSettingsEditor *project_settings_editor = nullptr;
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 8fca21ae7b..683731f982 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -30,14 +30,18 @@
#include "editor_plugin.h"
+#include "editor/debugger/editor_debugger_node.h"
#include "editor/editor_command_palette.h"
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_settings.h"
+#include "editor/editor_translation_parser.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/export/editor_export.h"
#include "editor/filesystem_dock.h"
+#include "editor/import/editor_import_plugin.h"
+#include "editor/import/resource_importer_scene.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "editor/plugins/script_editor_plugin.h"
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 753ccedf70..2d8f0c47cb 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -32,32 +32,33 @@
#define EDITOR_PLUGIN_H
#include "core/io/config_file.h"
-#include "editor/debugger/editor_debugger_node.h"
-#include "editor/editor_inspector.h"
-#include "editor/editor_translation_parser.h"
-#include "editor/import/editor_import_plugin.h"
-#include "editor/import/resource_importer_scene.h"
-#include "editor/script_create_dialog.h"
#include "scene/3d/camera_3d.h"
-#include "scene/main/node.h"
-#include "scene/resources/texture.h"
+#include "scene/gui/control.h"
class Node3D;
-class Camera3D;
+class Button;
+class PopupMenu;
class EditorCommandPalette;
-class EditorSelection;
class EditorExport;
-class EditorSettings;
-class EditorImportPlugin;
class EditorExportPlugin;
+class EditorFileSystem;
+class EditorImportPlugin;
+class EditorInspector;
+class EditorInspectorPlugin;
class EditorNode3DGizmoPlugin;
+class EditorPaths;
class EditorResourcePreview;
-class EditorUndoRedoManager;
-class EditorFileSystem;
+class EditorSceneFormatImporter;
+class EditorScenePostImportPlugin;
+class EditorSelection;
+class EditorSettings;
class EditorToolAddons;
-class EditorPaths;
+class EditorTranslationParserPlugin;
+class EditorUndoRedoManager;
class FileSystemDock;
+class ScriptCreateDialog;
class ScriptEditor;
+class VBoxContainer;
class EditorInterface : public Node {
GDCLASS(EditorInterface, Node);
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index d76dce0c1d..d71976a1af 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -1045,7 +1045,6 @@ void EditorPropertyLayersGrid::_notification(int p_what) {
const int vofs = (grid_size.height - h) / 2;
int layer_index = 0;
- int block_index = 0;
Point2 arrow_pos;
@@ -1112,8 +1111,6 @@ void EditorPropertyLayersGrid::_notification(int p_what) {
break;
}
}
-
- ++block_index;
}
if ((expansion_rows != prev_expansion_rows) && expanded) {
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index 7c1e3e63ef..0b38996b2d 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -570,13 +570,17 @@ void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<Strin
for (int i = 0; i < size; i++) {
String base = allowed_types[i].strip_edges();
- p_vector->insert(base);
+ if (!ClassDB::is_virtual(base)) {
+ p_vector->insert(base);
+ }
// If we hit a familiar base type, take all the data from cache.
if (allowed_types_cache.has(base)) {
List<StringName> allowed_subtypes = allowed_types_cache[base];
for (const StringName &subtype_name : allowed_subtypes) {
- p_vector->insert(subtype_name);
+ if (!ClassDB::is_virtual(subtype_name)) {
+ p_vector->insert(subtype_name);
+ }
}
} else {
List<StringName> allowed_subtypes;
@@ -586,13 +590,17 @@ void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<Strin
ClassDB::get_inheriters_from_class(base, &inheriters);
}
for (const StringName &subtype_name : inheriters) {
- p_vector->insert(subtype_name);
+ if (!ClassDB::is_virtual(subtype_name)) {
+ p_vector->insert(subtype_name);
+ }
allowed_subtypes.push_back(subtype_name);
}
for (const StringName &subtype_name : global_classes) {
if (EditorNode::get_editor_data().script_class_is_parent(subtype_name, base)) {
- p_vector->insert(subtype_name);
+ if (!ClassDB::is_virtual(subtype_name)) {
+ p_vector->insert(subtype_name);
+ }
allowed_subtypes.push_back(subtype_name);
}
}
diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp
index 599df12bd3..913a0ba104 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -31,6 +31,7 @@
#include "editor_run.h"
#include "core/config/project_settings.h"
+#include "editor/debugger/editor_debugger_node.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "main/main.h"
@@ -57,8 +58,11 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
args.push_back(resource_path.replace(" ", "%20"));
}
- args.push_back("--remote-debug");
- args.push_back(EditorDebuggerNode::get_singleton()->get_server_uri());
+ const String debug_uri = EditorDebuggerNode::get_singleton()->get_server_uri();
+ if (debug_uri.size()) {
+ args.push_back("--remote-debug");
+ args.push_back(debug_uri);
+ }
args.push_back("--editor-pid");
args.push_back(itos(OS::get_singleton()->get_process_id()));
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index a4e907b46f..bc186c7a16 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -412,7 +412,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/editor/custom_display_scale", 1.0, "0.5,3,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/editor/main_font_size", 14, "8,48,1")
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/editor/code_font_size", 14, "8,48,1")
- EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/code_font_contextual_ligatures", 0, "Default,Disable Contextual Alternates (Coding Ligatures),Use Custom OpenType Feature Set")
+ EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/code_font_contextual_ligatures", 1, "Enabled,Disable Contextual Alternates (Coding Ligatures),Use Custom OpenType Feature Set")
_initial_set("interface/editor/code_font_custom_opentype_features", "");
_initial_set("interface/editor/code_font_custom_variations", "");
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/font_antialiasing", 1, "None,Grayscale,LCD Subpixel")
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index a72c545b2f..77a0d9f85c 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -487,6 +487,7 @@ void EditorSettingsDialog::_update_shortcuts() {
TreeItem *section = E.value;
if (section->get_first_child() == nullptr) {
root->remove_child(section);
+ memdelete(section);
}
}
}
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 17b5eb3314..692deb3beb 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -1491,6 +1491,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("normal", "RichTextLabel", style_tree_bg);
// Editor help.
+ Ref<StyleBoxFlat> style_editor_help = style_default->duplicate();
+ style_editor_help->set_bg_color(dark_color_2);
+ style_editor_help->set_border_color(dark_color_3);
+ theme->set_stylebox("background", "EditorHelp", style_editor_help);
+
theme->set_color("title_color", "EditorHelp", accent_color);
theme->set_color("headline_color", "EditorHelp", mono_color);
theme->set_color("text_color", "EditorHelp", font_color);
@@ -1503,9 +1508,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("link_color", "EditorHelp", accent_color.lerp(mono_color, 0.8));
theme->set_color("code_color", "EditorHelp", accent_color.lerp(mono_color, 0.6));
theme->set_color("kbd_color", "EditorHelp", accent_color.lerp(property_color, 0.6));
+ theme->set_color("code_bg_color", "EditorHelp", dark_color_3);
+ theme->set_color("kbd_bg_color", "EditorHelp", dark_color_1);
+ theme->set_color("param_bg_color", "EditorHelp", dark_color_1);
theme->set_constant("line_separation", "EditorHelp", Math::round(6 * EDSCALE));
theme->set_constant("table_h_separation", "EditorHelp", 16 * EDSCALE);
theme->set_constant("table_v_separation", "EditorHelp", 6 * EDSCALE);
+ theme->set_constant("text_highlight_h_padding", "EditorHelp", 1 * EDSCALE);
+ theme->set_constant("text_highlight_v_padding", "EditorHelp", 2 * EDSCALE);
// Panel
theme->set_stylebox("panel", "Panel", make_flat_stylebox(dark_color_1, 6, 4, 6, 4, corner_width));
diff --git a/editor/editor_undo_redo_manager.cpp b/editor/editor_undo_redo_manager.cpp
index 09b567fc68..8dfd8e0528 100644
--- a/editor/editor_undo_redo_manager.cpp
+++ b/editor/editor_undo_redo_manager.cpp
@@ -33,6 +33,7 @@
#include "core/io/resource.h"
#include "core/os/os.h"
#include "core/templates/local_vector.h"
+#include "editor/debugger/editor_debugger_node.h"
#include "editor/editor_log.h"
#include "editor/editor_node.h"
#include "scene/main/node.h"
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 62bcf0b193..30fa1e8a0d 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -42,6 +42,7 @@
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/import/resource_importer_scene.h"
#include "editor/import_dock.h"
#include "editor/scene_create_dialog.h"
#include "editor/scene_tree_dock.h"
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index a2bd1223a9..b7605d8e2b 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -422,8 +422,7 @@ void FindInFilesDialog::set_find_in_files_mode(FindInFilesMode p_mode) {
}
String FindInFilesDialog::get_search_text() const {
- String text = _search_text_line_edit->get_text();
- return text.strip_edges();
+ return _search_text_line_edit->get_text();
}
String FindInFilesDialog::get_replace_text() const {
diff --git a/editor/import/audio_stream_import_settings.cpp b/editor/import/audio_stream_import_settings.cpp
index d94b517003..a8cd4c3e49 100644
--- a/editor/import/audio_stream_import_settings.cpp
+++ b/editor/import/audio_stream_import_settings.cpp
@@ -32,6 +32,7 @@
#include "editor/audio_stream_preview.h"
#include "editor/editor_file_system.h"
#include "editor/editor_scale.h"
+#include "scene/gui/check_box.h"
AudioStreamImportSettings *AudioStreamImportSettings::singleton = nullptr;
diff --git a/editor/import/audio_stream_import_settings.h b/editor/import/audio_stream_import_settings.h
index 5e399237ca..fc756c6524 100644
--- a/editor/import/audio_stream_import_settings.h
+++ b/editor/import/audio_stream_import_settings.h
@@ -34,9 +34,12 @@
#include "editor/editor_plugin.h"
#include "scene/audio/audio_stream_player.h"
#include "scene/gui/color_rect.h"
+#include "scene/gui/dialogs.h"
#include "scene/gui/spin_box.h"
#include "scene/resources/texture.h"
+class CheckBox;
+
class AudioStreamImportSettings : public ConfirmationDialog {
GDCLASS(AudioStreamImportSettings, ConfirmationDialog);
diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp
index f61ff5182d..8f15becd95 100644
--- a/editor/import/dynamic_font_import_settings.cpp
+++ b/editor/import/dynamic_font_import_settings.cpp
@@ -30,6 +30,7 @@
#include "dynamic_font_import_settings.h"
+#include "core/config/project_settings.h"
#include "editor/editor_file_dialog.h"
#include "editor/editor_file_system.h"
#include "editor/editor_inspector.h"
@@ -528,6 +529,12 @@ void DynamicFontImportSettings::_variation_selected() {
label_glyphs->set_text(TTR("Preloaded glyphs: ") + itos(import_variation_data->selected_glyphs.size()));
_range_selected();
_change_text_opts();
+
+ btn_fill->set_disabled(false);
+ btn_fill_locales->set_disabled(false);
+ } else {
+ btn_fill->set_disabled(true);
+ btn_fill_locales->set_disabled(true);
}
}
@@ -551,6 +558,15 @@ void DynamicFontImportSettings::_variation_remove(Object *p_item, int p_column,
}
_variations_validate();
+
+ vars_item = vars_list->get_selected();
+ if (vars_item) {
+ btn_fill->set_disabled(false);
+ btn_fill_locales->set_disabled(false);
+ } else {
+ btn_fill->set_disabled(true);
+ btn_fill_locales->set_disabled(true);
+ }
}
void DynamicFontImportSettings::_variation_changed(const String &p_edited_property) {
@@ -623,6 +639,27 @@ void DynamicFontImportSettings::_change_text_opts() {
text_edit->add_theme_font_override("font", font_main_text);
}
+void DynamicFontImportSettings::_glyph_update_lbl() {
+ Ref<DynamicFontImportSettingsData> import_variation_data;
+
+ TreeItem *vars_item = vars_list->get_selected();
+ if (vars_item) {
+ import_variation_data = vars_item->get_metadata(0);
+ }
+ if (import_variation_data.is_null()) {
+ return;
+ }
+
+ int linked_glyphs = 0;
+ for (const char32_t &c : import_variation_data->selected_chars) {
+ if (import_variation_data->selected_glyphs.has(font_main->get_glyph_index(16, c))) {
+ linked_glyphs++;
+ }
+ }
+ int unlinked_glyphs = import_variation_data->selected_glyphs.size() - linked_glyphs;
+ label_glyphs->set_text(TTR("Preloaded glyphs:") + " " + itos(unlinked_glyphs + import_variation_data->selected_chars.size()));
+}
+
void DynamicFontImportSettings::_glyph_clear() {
Ref<DynamicFontImportSettingsData> import_variation_data;
@@ -635,7 +672,7 @@ void DynamicFontImportSettings::_glyph_clear() {
}
import_variation_data->selected_glyphs.clear();
- label_glyphs->set_text(TTR("Preloaded glyphs:") + " " + itos(import_variation_data->selected_glyphs.size()));
+ _glyph_update_lbl();
_range_selected();
}
@@ -662,7 +699,7 @@ void DynamicFontImportSettings::_glyph_text_selected() {
}
}
TS->free_rid(text_rid);
- label_glyphs->set_text(TTR("Preloaded glyphs:") + " " + itos(import_variation_data->selected_glyphs.size()));
+ _glyph_update_lbl();
}
_range_selected();
}
@@ -699,7 +736,7 @@ void DynamicFontImportSettings::_glyph_selected() {
item->clear_custom_bg_color(glyph_table->get_selected_column());
}
}
- label_glyphs->set_text(TTR("Preloaded glyphs:") + " " + itos(import_variation_data->selected_glyphs.size()));
+ _glyph_update_lbl();
item = glyph_tree->get_selected();
ERR_FAIL_NULL(item);
@@ -800,7 +837,7 @@ void DynamicFontImportSettings::_edit_range(int32_t p_start, int32_t p_end) {
col = 0;
}
}
- label_glyphs->set_text(TTR("Preloaded glyphs:") + " " + itos(import_variation_data->selected_glyphs.size()));
+ _glyph_update_lbl();
}
bool DynamicFontImportSettings::_char_update(int32_t p_char) {
@@ -947,10 +984,73 @@ void DynamicFontImportSettings::_re_import() {
EditorFileSystem::get_singleton()->reimport_file_with_custom_parameters(base_path, "font_data_dynamic", main_settings);
}
+void DynamicFontImportSettings::_locale_edited() {
+ TreeItem *item = locale_tree->get_selected();
+ ERR_FAIL_NULL(item);
+ item->set_checked(0, !item->is_checked(0));
+}
+
+void DynamicFontImportSettings::_process_locales() {
+ Ref<DynamicFontImportSettingsData> import_variation_data;
+
+ TreeItem *vars_item = vars_list->get_selected();
+ if (vars_item) {
+ import_variation_data = vars_item->get_metadata(0);
+ }
+ if (import_variation_data.is_null()) {
+ return;
+ }
+
+ for (int i = 0; i < locale_root->get_child_count(); i++) {
+ TreeItem *item = locale_root->get_child(i);
+ if (item) {
+ if (item->is_checked(0)) {
+ String locale = item->get_text(0);
+ Ref<Translation> tr = ResourceLoader::load(locale);
+ if (tr.is_valid()) {
+ Vector<String> messages = tr->get_translated_message_list();
+ for (const String &E : messages) {
+ RID text_rid = TS->create_shaped_text();
+ if (text_rid.is_valid()) {
+ TS->shaped_text_add_string(text_rid, E, font_main->get_rids(), 16, Dictionary(), tr->get_locale());
+ TS->shaped_text_shape(text_rid);
+ const Glyph *gl = TS->shaped_text_get_glyphs(text_rid);
+ const int gl_size = TS->shaped_text_get_glyph_count(text_rid);
+
+ for (int j = 0; j < gl_size; j++) {
+ if (gl[j].font_rid.is_valid() && gl[j].index != 0) {
+ import_variation_data->selected_glyphs.insert(gl[j].index);
+ }
+ }
+ TS->free_rid(text_rid);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ _glyph_update_lbl();
+ _range_selected();
+}
+
void DynamicFontImportSettings::open_settings(const String &p_path) {
// Load base font data.
Vector<uint8_t> font_data = FileAccess::get_file_as_array(p_path);
+ // Load project locale list.
+ locale_tree->clear();
+ locale_root = locale_tree->create_item();
+ ERR_FAIL_NULL(locale_root);
+
+ Vector<String> translations = GLOBAL_GET("internationalization/locale/translations");
+ for (const String &E : translations) {
+ TreeItem *item = locale_tree->create_item(locale_root);
+ ERR_FAIL_NULL(item);
+ item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ item->set_text(0, E);
+ }
+
// Load font for preview.
font_preview.instantiate();
font_preview->set_data(font_data);
@@ -1003,10 +1103,11 @@ void DynamicFontImportSettings::open_settings(const String &p_path) {
int gww = get_theme_font(SNAME("font"))->get_string_size("00000").x + 50;
glyph_table->set_column_custom_minimum_width(0, gww);
-
glyph_table->clear();
vars_list->clear();
+ glyph_tree->set_selected(glyph_root->get_child(0));
+
vars_list_root = vars_list->create_item();
import_settings_data->settings.clear();
@@ -1080,6 +1181,10 @@ void DynamicFontImportSettings::open_settings(const String &p_path) {
import_variation_data_custom->selected_glyphs.insert(c);
}
}
+ if (preload_configurations.is_empty()) {
+ _variation_add(); // Add default variation.
+ }
+ vars_list->set_selected(vars_list_root->get_child(0));
} else {
Variant value = config->get_value("params", key);
import_settings_data->defaults[key] = value;
@@ -1269,11 +1374,57 @@ DynamicFontImportSettings::DynamicFontImportSettings() {
inspector_vars->connect("property_edited", callable_mp(this, &DynamicFontImportSettings::_variation_changed));
page2_side_vb->add_child(inspector_vars);
+ VBoxContainer *preload_pages_vb = memnew(VBoxContainer);
+ page2_hb->add_child(preload_pages_vb);
+
preload_pages = memnew(TabContainer);
preload_pages->set_tab_alignment(TabBar::ALIGNMENT_CENTER);
preload_pages->set_v_size_flags(Control::SIZE_EXPAND_FILL);
preload_pages->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- page2_hb->add_child(preload_pages);
+ preload_pages_vb->add_child(preload_pages);
+
+ HBoxContainer *gl_hb = memnew(HBoxContainer);
+ preload_pages_vb->add_child(gl_hb);
+ gl_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+
+ label_glyphs = memnew(Label);
+ gl_hb->add_child(label_glyphs);
+ label_glyphs->set_text(TTR("Preloaded glyphs:") + " " + itos(0));
+ label_glyphs->set_custom_minimum_size(Size2(50 * EDSCALE, 0));
+
+ Button *btn_clear = memnew(Button);
+ gl_hb->add_child(btn_clear);
+ btn_clear->set_text(TTR("Clear Glyph List"));
+ btn_clear->connect("pressed", callable_mp(this, &DynamicFontImportSettings::_glyph_clear));
+
+ VBoxContainer *page2_0_vb = memnew(VBoxContainer);
+ page2_0_vb->set_name(TTR("Glyphs from the Translations"));
+ preload_pages->add_child(page2_0_vb);
+
+ page2_0_description = memnew(Label);
+ page2_0_description->set_text(TTR("Select translations to add all required glyphs to pre-render list:"));
+ page2_0_description->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ page2_0_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
+ page2_0_vb->add_child(page2_0_description);
+
+ locale_tree = memnew(Tree);
+ page2_0_vb->add_child(locale_tree);
+ locale_tree->set_columns(1);
+ locale_tree->set_hide_root(true);
+ locale_tree->set_column_expand(0, true);
+ locale_tree->connect("item_activated", callable_mp(this, &DynamicFontImportSettings::_locale_edited));
+ locale_tree->set_column_custom_minimum_width(0, 120 * EDSCALE);
+ locale_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ locale_root = locale_tree->create_item();
+
+ HBoxContainer *locale_hb = memnew(HBoxContainer);
+ page2_0_vb->add_child(locale_hb);
+ locale_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+
+ btn_fill_locales = memnew(Button);
+ locale_hb->add_child(btn_fill_locales);
+ btn_fill_locales->set_text(TTR("Shape all Strings in the Translations and Add Glyphs"));
+ btn_fill_locales->connect("pressed", callable_mp(this, &DynamicFontImportSettings::_process_locales));
// Page 2.1 layout: Text to select glyphs
VBoxContainer *page2_1_vb = memnew(VBoxContainer);
@@ -1281,7 +1432,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() {
preload_pages->add_child(page2_1_vb);
page2_1_description = memnew(Label);
- page2_1_description->set_text(TTR("Enter a text to shape and add all required glyphs to pre-render list:"));
+ page2_1_description->set_text(TTR("Enter a text and select OpenType features to shape and add all required glyphs to pre-render list:"));
page2_1_description->set_h_size_flags(Control::SIZE_EXPAND_FILL);
page2_1_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
page2_1_vb->add_child(page2_1_description);
@@ -1307,21 +1458,11 @@ DynamicFontImportSettings::DynamicFontImportSettings() {
page2_1_vb->add_child(text_hb);
text_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- label_glyphs = memnew(Label);
- text_hb->add_child(label_glyphs);
- label_glyphs->set_text(TTR("Preloaded glyphs:") + " " + itos(0));
- label_glyphs->set_custom_minimum_size(Size2(50 * EDSCALE, 0));
-
- Button *btn_fill = memnew(Button);
+ btn_fill = memnew(Button);
text_hb->add_child(btn_fill);
btn_fill->set_text(TTR("Shape Text and Add Glyphs"));
btn_fill->connect("pressed", callable_mp(this, &DynamicFontImportSettings::_glyph_text_selected));
- Button *btn_clear = memnew(Button);
- text_hb->add_child(btn_clear);
- btn_clear->set_text(TTR("Clear Glyph List"));
- btn_clear->connect("pressed", callable_mp(this, &DynamicFontImportSettings::_glyph_clear));
-
// Page 2.2 layout: Character map
VBoxContainer *page2_2_vb = memnew(VBoxContainer);
page2_2_vb->set_name(TTR("Glyphs from the Character Map"));
diff --git a/editor/import/dynamic_font_import_settings.h b/editor/import/dynamic_font_import_settings.h
index a1f763b445..386e9896dc 100644
--- a/editor/import/dynamic_font_import_settings.h
+++ b/editor/import/dynamic_font_import_settings.h
@@ -118,18 +118,30 @@ class DynamicFontImportSettings : public ConfirmationDialog {
TabContainer *preload_pages = nullptr;
+ Label *label_glyphs = nullptr;
+ void _glyph_clear();
+ void _glyph_update_lbl();
+
+ // Page 2.0 layout: Translations
+ Label *page2_0_description = nullptr;
+ Tree *locale_tree = nullptr;
+ TreeItem *locale_root = nullptr;
+ Button *btn_fill_locales = nullptr;
+
+ void _locale_edited();
+ void _process_locales();
+
// Page 2.1 layout: Text to select glyphs
Label *page2_1_description = nullptr;
- Label *label_glyphs = nullptr;
TextEdit *text_edit = nullptr;
EditorInspector *inspector_text = nullptr;
+ Button *btn_fill = nullptr;
List<ResourceImporter::ImportOption> options_text;
Ref<DynamicFontImportSettingsData> text_settings_data;
void _change_text_opts();
void _glyph_text_selected();
- void _glyph_clear();
// Page 2.2 layout: Character map
Label *page2_2_description = nullptr;
diff --git a/editor/import/resource_importer_imagefont.cpp b/editor/import/resource_importer_imagefont.cpp
index 58c2061051..9d15854707 100644
--- a/editor/import/resource_importer_imagefont.cpp
+++ b/editor/import/resource_importer_imagefont.cpp
@@ -63,7 +63,8 @@ void ResourceImporterImageFont::get_import_options(const String &p_path, List<Im
r_options->push_back(ImportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "character_ranges"), Vector<String>()));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "columns"), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "rows"), 1));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "font_size"), 14));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::RECT2I, "image_margin"), Rect2i()));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::RECT2I, "character_margin"), Rect2i()));
r_options->push_back(ImportOption(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font")), Array()));
@@ -93,33 +94,39 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin
int columns = p_options["columns"];
int rows = p_options["rows"];
- int base_size = p_options["font_size"];
Vector<String> ranges = p_options["character_ranges"];
Array fallbacks = p_options["fallbacks"];
+ Rect2i img_margin = p_options["image_margin"];
+ Rect2i char_margin = p_options["character_margin"];
+
+ Ref<Image> img;
+ img.instantiate();
+ Error err = ImageLoader::load_image(p_source_file, img);
+ ERR_FAIL_COND_V_MSG(err != OK, ERR_FILE_CANT_READ, TTR("Can't load font texture:") + " \"" + p_source_file + "\".");
+
+ int count = columns * rows;
+ int chr_cell_width = (img->get_width() - img_margin.position.x - img_margin.size.x) / columns;
+ int chr_cell_height = (img->get_height() - img_margin.position.y - img_margin.size.y) / rows;
+ ERR_FAIL_COND_V_MSG(chr_cell_width <= 0 || chr_cell_height <= 0, ERR_FILE_CANT_READ, TTR("Image margin too big."));
+
+ int chr_width = chr_cell_width - char_margin.position.x - char_margin.size.x;
+ int chr_height = chr_cell_height - char_margin.position.y - char_margin.size.y;
+ ERR_FAIL_COND_V_MSG(chr_width <= 0 || chr_height <= 0, ERR_FILE_CANT_READ, TTR("Character margin too bit."));
Ref<FontFile> font;
font.instantiate();
font->set_antialiasing(TextServer::FONT_ANTIALIASING_NONE);
font->set_generate_mipmaps(false);
font->set_multichannel_signed_distance_field(false);
- font->set_fixed_size(base_size);
+ font->set_fixed_size(chr_height);
font->set_subpixel_positioning(TextServer::SUBPIXEL_POSITIONING_DISABLED);
font->set_force_autohinter(false);
font->set_hinting(TextServer::HINTING_NONE);
font->set_oversampling(1.0f);
font->set_fallbacks(fallbacks);
+ font->set_texture_image(0, Vector2i(chr_height, 0), 0, img);
- Ref<Image> img;
- img.instantiate();
- Error err = ImageLoader::load_image(p_source_file, img);
- ERR_FAIL_COND_V_MSG(err != OK, ERR_FILE_CANT_READ, TTR("Can't load font texture:") + " \"" + p_source_file + "\".");
- font->set_texture_image(0, Vector2i(base_size, 0), 0, img);
-
- int count = columns * rows;
- int chr_width = img->get_width() / columns;
- int chr_height = img->get_height() / rows;
int pos = 0;
-
for (int i = 0; i < ranges.size(); i++) {
int32_t start, end;
Vector<String> tokens = ranges[i].split("-");
@@ -141,17 +148,17 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin
for (int32_t idx = start; idx <= end; idx++) {
int x = pos % columns;
int y = pos / columns;
- font->set_glyph_advance(0, base_size, idx, Vector2(chr_width, 0));
- font->set_glyph_offset(0, Vector2i(base_size, 0), idx, Vector2(0, -0.5 * chr_height));
- font->set_glyph_size(0, Vector2i(base_size, 0), idx, Vector2(chr_width, chr_height));
- font->set_glyph_uv_rect(0, Vector2i(base_size, 0), idx, Rect2(chr_width * x, chr_height * y, chr_width, chr_height));
- font->set_glyph_texture_idx(0, Vector2i(base_size, 0), idx, 0);
+ font->set_glyph_advance(0, chr_height, idx, Vector2(chr_width, 0));
+ font->set_glyph_offset(0, Vector2i(chr_height, 0), idx, Vector2(0, -0.5 * chr_height));
+ font->set_glyph_size(0, Vector2i(chr_height, 0), idx, Vector2(chr_width, chr_height));
+ font->set_glyph_uv_rect(0, Vector2i(chr_height, 0), idx, Rect2(img_margin.position.x + chr_cell_width * x + char_margin.position.x, img_margin.position.y + chr_cell_height * y + char_margin.position.y, chr_width, chr_height));
+ font->set_glyph_texture_idx(0, Vector2i(chr_height, 0), idx, 0);
pos++;
- ERR_FAIL_COND_V_MSG(pos >= count, ERR_CANT_CREATE, "Too many characters in range.");
+ ERR_FAIL_COND_V_MSG(pos >= count, ERR_CANT_CREATE, "Too many characters in range, should be " + itos(columns * rows));
}
}
- font->set_cache_ascent(0, base_size, 0.5 * chr_height);
- font->set_cache_descent(0, base_size, 0.5 * chr_height);
+ font->set_cache_ascent(0, chr_height, 0.5 * chr_height);
+ font->set_cache_descent(0, chr_height, 0.5 * chr_height);
int flg = 0;
if ((bool)p_options["compress"]) {
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 8ede88a888..a6a0eef11b 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -1276,14 +1276,12 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
} break;
}
- int idx = 0;
for (const Ref<Shape3D> &E : shapes) {
CollisionShape3D *cshape = memnew(CollisionShape3D);
cshape->set_shape(E);
base->add_child(cshape, true);
cshape->set_owner(base->get_owner());
- idx++;
}
}
}
diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp
index a7ebf21cd2..affb31945d 100644
--- a/editor/plugin_config_dialog.cpp
+++ b/editor/plugin_config_dialog.cpp
@@ -36,6 +36,7 @@
#include "editor/editor_plugin.h"
#include "editor/editor_scale.h"
#include "editor/project_settings_editor.h"
+#include "scene/gui/grid_container.h"
void PluginConfigDialog::_clear_fields() {
name_edit->set_text("");
diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h
index 8a3db9d837..8414945223 100644
--- a/editor/plugins/abstract_polygon_2d_editor.h
+++ b/editor/plugins/abstract_polygon_2d_editor.h
@@ -36,6 +36,7 @@
#include "scene/gui/box_container.h"
class CanvasItemEditor;
+class ConfirmationDialog;
class AbstractPolygon2DEditor : public HBoxContainer {
GDCLASS(AbstractPolygon2DEditor, HBoxContainer);
diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h
index c8b01cb54b..54aa227c96 100644
--- a/editor/plugins/animation_blend_space_1d_editor.h
+++ b/editor/plugins/animation_blend_space_1d_editor.h
@@ -40,7 +40,8 @@
#include "scene/gui/separator.h"
#include "scene/gui/tree.h"
-class EditorUndoRedoManager;
+class CheckBox;
+class PanelContainer;
class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendSpace1DEditor, AnimationTreeNodeEditorPlugin);
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index 6f206ff445..3ec8324e1d 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -42,6 +42,7 @@
#include "editor/editor_undo_redo_manager.h"
#include "scene/animation/animation_blend_tree.h"
#include "scene/animation/animation_player.h"
+#include "scene/gui/grid_container.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
#include "scene/main/window.h"
diff --git a/editor/plugins/animation_blend_space_2d_editor.h b/editor/plugins/animation_blend_space_2d_editor.h
index 1f015a1804..e4512b78a3 100644
--- a/editor/plugins/animation_blend_space_2d_editor.h
+++ b/editor/plugins/animation_blend_space_2d_editor.h
@@ -40,6 +40,10 @@
#include "scene/gui/separator.h"
#include "scene/gui/tree.h"
+class CheckBox;
+class OptionButton;
+class PanelContainer;
+
class EditorUndoRedoManager;
class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index b55fc3b617..112c824d8e 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -31,17 +31,22 @@
#ifndef ANIMATION_BLEND_TREE_EDITOR_PLUGIN_H
#define ANIMATION_BLEND_TREE_EDITOR_PLUGIN_H
-#include "editor/editor_plugin.h"
#include "editor/plugins/animation_tree_editor_plugin.h"
#include "scene/animation/animation_blend_tree.h"
#include "scene/gui/button.h"
#include "scene/gui/graph_edit.h"
+#include "scene/gui/panel_container.h"
#include "scene/gui/popup.h"
#include "scene/gui/tree.h"
+class AcceptDialog;
+class CheckBox;
class ProgressBar;
class EditorFileDialog;
+class EditorProperty;
class EditorUndoRedoManager;
+class MenuButton;
+class PanelContainer;
class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendTreeEditor, AnimationTreeNodeEditorPlugin);
diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h
index d0828a5f52..180f238834 100644
--- a/editor/plugins/animation_state_machine_editor.h
+++ b/editor/plugins/animation_state_machine_editor.h
@@ -31,16 +31,17 @@
#ifndef ANIMATION_STATE_MACHINE_EDITOR_H
#define ANIMATION_STATE_MACHINE_EDITOR_H
-#include "editor/editor_plugin.h"
#include "editor/plugins/animation_tree_editor_plugin.h"
#include "scene/animation/animation_node_state_machine.h"
-#include "scene/gui/button.h"
#include "scene/gui/graph_edit.h"
#include "scene/gui/popup.h"
#include "scene/gui/tree.h"
+class ConfirmationDialog;
class EditorFileDialog;
class EditorUndoRedoManager;
+class OptionButton;
+class PanelContainer;
class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeStateMachineEditor, AnimationTreeNodeEditorPlugin);
diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h
index 070d25e29f..2795892c2e 100644
--- a/editor/plugins/asset_library_editor_plugin.h
+++ b/editor/plugins/asset_library_editor_plugin.h
@@ -50,6 +50,9 @@
#include "scene/gui/texture_button.h"
#include "scene/main/http_request.h"
+class EditorFileDialog;
+class MenuButton;
+
class EditorAssetLibraryItem : public PanelContainer {
GDCLASS(EditorAssetLibraryItem, PanelContainer);
diff --git a/editor/plugins/bit_map_editor_plugin.h b/editor/plugins/bit_map_editor_plugin.h
index b045f8c751..8c65b1b6f1 100644
--- a/editor/plugins/bit_map_editor_plugin.h
+++ b/editor/plugins/bit_map_editor_plugin.h
@@ -31,9 +31,12 @@
#ifndef BIT_MAP_EDITOR_PLUGIN_H
#define BIT_MAP_EDITOR_PLUGIN_H
+#include "editor/editor_inspector.h"
#include "editor/editor_plugin.h"
#include "scene/resources/bit_map.h"
+class TextureRect;
+
class BitMapEditor : public VBoxContainer {
GDCLASS(BitMapEditor, VBoxContainer);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 1d6f41d4c4..baf335f5b4 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -928,9 +928,7 @@ void CanvasItemEditor::_add_node_pressed(int p_result) {
[[fallthrough]];
}
case ADD_MOVE: {
- if (p_result == ADD_MOVE) {
- nodes_to_move = EditorNode::get_singleton()->get_editor_selection()->get_selected_node_list();
- }
+ nodes_to_move = EditorNode::get_singleton()->get_editor_selection()->get_selected_node_list();
if (nodes_to_move.is_empty()) {
return;
}
@@ -1731,22 +1729,16 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
drag_to = transform.affine_inverse().xform(m->get_position());
- Transform2D xform = ci->get_global_transform_with_canvas().affine_inverse();
+ Transform2D xform = ci->get_global_transform_with_canvas();
Point2 drag_to_snapped_begin;
Point2 drag_to_snapped_end;
- // last call decides which snapping lines are drawn
- if (drag_type == DRAG_LEFT || drag_type == DRAG_TOP || drag_type == DRAG_TOP_LEFT) {
- drag_to_snapped_end = snap_point(xform.affine_inverse().xform(current_end) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, ci);
- drag_to_snapped_begin = snap_point(xform.affine_inverse().xform(current_begin) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, ci);
- } else {
- drag_to_snapped_begin = snap_point(xform.affine_inverse().xform(current_begin) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, ci);
- drag_to_snapped_end = snap_point(xform.affine_inverse().xform(current_end) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, ci);
- }
+ drag_to_snapped_end = snap_point(xform.xform(current_end) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, ci);
+ drag_to_snapped_begin = snap_point(xform.xform(current_begin) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, ci);
- Point2 drag_begin = xform.xform(drag_to_snapped_begin);
- Point2 drag_end = xform.xform(drag_to_snapped_end);
+ Point2 drag_begin = xform.affine_inverse().xform(drag_to_snapped_begin);
+ Point2 drag_end = xform.affine_inverse().xform(drag_to_snapped_end);
// Horizontal resize
if (drag_type == DRAG_LEFT || drag_type == DRAG_TOP_LEFT || drag_type == DRAG_BOTTOM_LEFT) {
@@ -2068,12 +2060,9 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
}
- int index = 0;
for (CanvasItem *ci : drag_selection) {
Transform2D xform = ci->get_global_transform_with_canvas().affine_inverse() * ci->get_transform();
-
ci->_edit_set_position(ci->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
- index++;
}
return true;
}
@@ -2191,12 +2180,9 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
new_pos = previous_pos + (drag_to - drag_from);
}
- int index = 0;
for (CanvasItem *ci : drag_selection) {
Transform2D xform = ci->get_global_transform_with_canvas().affine_inverse() * ci->get_transform();
-
ci->_edit_set_position(ci->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
- index++;
}
}
return true;
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index ba193a67b8..74d4af9a13 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -42,8 +42,11 @@
#include "scene/gui/texture_rect.h"
#include "scene/main/canvas_item.h"
+class AcceptDialog;
+class ConfirmationDialog;
class EditorData;
class CanvasItemEditorViewport;
+class MenuButton;
class ViewPanner;
class CanvasItemEditorSelectedItem : public Object {
diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp
index bb6092755e..6af9b85657 100644
--- a/editor/plugins/control_editor_plugin.cpp
+++ b/editor/plugins/control_editor_plugin.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
+#include "scene/gui/grid_container.h"
#include "scene/gui/separator.h"
// Inspector controls.
@@ -810,19 +811,6 @@ void ControlEditorToolbar::_container_flags_selected(int p_flags, bool p_vertica
undo_redo->commit_action();
}
-Vector2 ControlEditorToolbar::_anchor_to_position(const Control *p_control, Vector2 anchor) {
- ERR_FAIL_COND_V(!p_control, Vector2());
-
- Transform2D parent_transform = p_control->get_transform().affine_inverse();
- Rect2 parent_rect = p_control->get_parent_anchorable_rect();
-
- if (p_control->is_layout_rtl()) {
- return parent_transform.xform(parent_rect.position + Vector2(parent_rect.size.x - parent_rect.size.x * anchor.x, parent_rect.size.y * anchor.y));
- } else {
- return parent_transform.xform(parent_rect.position + Vector2(parent_rect.size.x * anchor.x, parent_rect.size.y * anchor.y));
- }
-}
-
Vector2 ControlEditorToolbar::_position_to_anchor(const Control *p_control, Vector2 position) {
ERR_FAIL_COND_V(!p_control, Vector2());
diff --git a/editor/plugins/control_editor_plugin.h b/editor/plugins/control_editor_plugin.h
index 22267cbc04..14886e77a4 100644
--- a/editor/plugins/control_editor_plugin.h
+++ b/editor/plugins/control_editor_plugin.h
@@ -31,6 +31,7 @@
#ifndef CONTROL_EDITOR_PLUGIN_H
#define CONTROL_EDITOR_PLUGIN_H
+#include "editor/editor_inspector.h"
#include "editor/editor_plugin.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
@@ -45,6 +46,7 @@
#include "scene/gui/texture_rect.h"
class EditorUndoRedoManager;
+class GridContainer;
// Inspector controls.
class ControlPositioningWarning : public MarginContainer {
@@ -222,7 +224,6 @@ class ControlEditorToolbar : public HBoxContainer {
void _anchor_mode_toggled(bool p_status);
void _container_flags_selected(int p_flags, bool p_vertical);
- Vector2 _anchor_to_position(const Control *p_control, Vector2 anchor);
Vector2 _position_to_anchor(const Control *p_control, Vector2 position);
bool _is_node_locked(const Node *p_node);
List<Control *> _get_edited_controls();
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.h b/editor/plugins/cpu_particles_2d_editor_plugin.h
index 06ca208463..694162588b 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.h
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.h
@@ -36,10 +36,13 @@
#include "scene/2d/cpu_particles_2d.h"
#include "scene/gui/box_container.h"
-class EditorPlugin;
+class CheckBox;
+class ConfirmationDialog;
class SpinBox;
class EditorFileDialog;
class EditorUndoRedoManager;
+class MenuButton;
+class OptionButton;
class CPUParticles2DEditorPlugin : public EditorPlugin {
GDCLASS(CPUParticles2DEditorPlugin, EditorPlugin);
diff --git a/editor/plugins/curve_editor_plugin.h b/editor/plugins/curve_editor_plugin.h
index 5cf3b16a06..5503ce96ff 100644
--- a/editor/plugins/curve_editor_plugin.h
+++ b/editor/plugins/curve_editor_plugin.h
@@ -31,6 +31,7 @@
#ifndef CURVE_EDITOR_PLUGIN_H
#define CURVE_EDITOR_PLUGIN_H
+#include "editor/editor_inspector.h"
#include "editor/editor_plugin.h"
#include "editor/editor_resource_preview.h"
#include "scene/resources/curve.h"
diff --git a/editor/plugins/gdextension_export_plugin.h b/editor/plugins/gdextension_export_plugin.h
index e1d68d97b5..c5f7d2a047 100644
--- a/editor/plugins/gdextension_export_plugin.h
+++ b/editor/plugins/gdextension_export_plugin.h
@@ -107,7 +107,7 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p
for (const String &E : p_features) {
tags.append(E);
}
- ERR_FAIL_MSG(vformat("Couldn't export extension: %s. No suitable library found for export flags: %s", p_path, String(", ").join(tags)));
+ ERR_FAIL_MSG(vformat("No suitable library found. The libraries' tags referred to an invalid feature flag. Possible feature flags for your platform: %s", p_path, String(", ").join(tags)));
}
List<String> dependencies;
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.h b/editor/plugins/gpu_particles_2d_editor_plugin.h
index 0229b57c10..0a0ea21c1f 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.h
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.h
@@ -37,8 +37,12 @@
#include "scene/gui/box_container.h"
#include "scene/gui/spin_box.h"
+class CheckBox;
+class ConfirmationDialog;
class EditorFileDialog;
class EditorUndoRedoManager;
+class MenuButton;
+class OptionButton;
class GPUParticles2DEditorPlugin : public EditorPlugin {
GDCLASS(GPUParticles2DEditorPlugin, EditorPlugin);
diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.h b/editor/plugins/gpu_particles_3d_editor_plugin.h
index 17bdfa6e3f..e5b264cfe4 100644
--- a/editor/plugins/gpu_particles_3d_editor_plugin.h
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.h
@@ -35,6 +35,10 @@
#include "scene/3d/gpu_particles_3d.h"
#include "scene/gui/spin_box.h"
+class ConfirmationDialog;
+class HBoxContainer;
+class MenuButton;
+class OptionButton;
class SceneTreeDialog;
class GPUParticles3DEditorBase : public Control {
diff --git a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.h b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.h
index 684279039a..2c1f49df29 100644
--- a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.h
+++ b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.h
@@ -37,6 +37,7 @@
struct EditorProgress;
class EditorFileDialog;
+class HBoxContainer;
class GPUParticlesCollisionSDF3DEditorPlugin : public EditorPlugin {
GDCLASS(GPUParticlesCollisionSDF3DEditorPlugin, EditorPlugin);
diff --git a/editor/plugins/gradient_editor_plugin.h b/editor/plugins/gradient_editor_plugin.h
index ab191d83e2..f3859e74d3 100644
--- a/editor/plugins/gradient_editor_plugin.h
+++ b/editor/plugins/gradient_editor_plugin.h
@@ -31,6 +31,7 @@
#ifndef GRADIENT_EDITOR_PLUGIN_H
#define GRADIENT_EDITOR_PLUGIN_H
+#include "editor/editor_inspector.h"
#include "editor/editor_plugin.h"
#include "gradient_editor.h"
diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.cpp b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
index dc01a52bb3..561dca4fc6 100644
--- a/editor/plugins/gradient_texture_2d_editor_plugin.cpp
+++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
@@ -121,13 +121,12 @@ void GradientTexture2DEditorRect::_notification(int p_what) {
Size2 rect_size = get_size();
// Get the size and position to draw the texture and handles at.
- size = Size2(texture->get_width() * rect_size.height / texture->get_height(), rect_size.height);
- if (size.width > rect_size.width) {
- size.width = rect_size.width;
- size.height = texture->get_height() * size.width / texture->get_width();
- }
- offset = ((rect_size - size + handle_size) / 2).round();
- size -= handle_size;
+ // Subtract handle sizes so they stay inside the preview, but keep the texture's aspect ratio.
+ Size2 available_size = rect_size - handle_size;
+ Size2 ratio = available_size / texture->get_size();
+ size = MIN(ratio.x, ratio.y) * texture->get_size();
+ offset = ((rect_size - size) / 2).round();
+
checkerboard->set_rect(Rect2(offset, size));
draw_set_transform(offset);
@@ -180,8 +179,9 @@ GradientTexture2DEditorRect::GradientTexture2DEditorRect() {
checkerboard = memnew(TextureRect);
checkerboard->set_stretch_mode(TextureRect::STRETCH_TILE);
+ checkerboard->set_ignore_texture_size(true);
checkerboard->set_draw_behind_parent(true);
- add_child(checkerboard);
+ add_child(checkerboard, false, INTERNAL_MODE_FRONT);
set_custom_minimum_size(Size2(0, 250 * EDSCALE));
}
diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.h b/editor/plugins/gradient_texture_2d_editor_plugin.h
index 9faf33152a..0737300498 100644
--- a/editor/plugins/gradient_texture_2d_editor_plugin.h
+++ b/editor/plugins/gradient_texture_2d_editor_plugin.h
@@ -31,6 +31,7 @@
#ifndef GRADIENT_TEXTURE_2D_EDITOR_PLUGIN_H
#define GRADIENT_TEXTURE_2D_EDITOR_PLUGIN_H
+#include "editor/editor_inspector.h"
#include "editor/editor_plugin.h"
#include "editor/editor_spin_slider.h"
diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h
index 8e64434d8b..a6321dcf34 100644
--- a/editor/plugins/material_editor_plugin.h
+++ b/editor/plugins/material_editor_plugin.h
@@ -31,6 +31,7 @@
#ifndef MATERIAL_EDITOR_PLUGIN_H
#define MATERIAL_EDITOR_PLUGIN_H
+#include "editor/editor_inspector.h"
#include "editor/editor_plugin.h"
#include "editor/plugins/editor_resource_conversion_plugin.h"
#include "scene/3d/camera_3d.h"
diff --git a/editor/plugins/mesh_editor_plugin.h b/editor/plugins/mesh_editor_plugin.h
index 6394cb1171..b8d6562c5c 100644
--- a/editor/plugins/mesh_editor_plugin.h
+++ b/editor/plugins/mesh_editor_plugin.h
@@ -31,6 +31,7 @@
#ifndef MESH_EDITOR_PLUGIN_H
#define MESH_EDITOR_PLUGIN_H
+#include "editor/editor_inspector.h"
#include "editor/editor_plugin.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/light_3d.h"
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.h b/editor/plugins/mesh_instance_3d_editor_plugin.h
index 88800227d1..81ba263be0 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.h
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.h
@@ -35,6 +35,10 @@
#include "scene/3d/mesh_instance_3d.h"
#include "scene/gui/spin_box.h"
+class AcceptDialog;
+class ConfirmationDialog;
+class MenuButton;
+
class MeshInstance3DEditor : public Control {
GDCLASS(MeshInstance3DEditor, Control);
diff --git a/editor/plugins/multimesh_editor_plugin.h b/editor/plugins/multimesh_editor_plugin.h
index 5773989d0d..76f86cfa5d 100644
--- a/editor/plugins/multimesh_editor_plugin.h
+++ b/editor/plugins/multimesh_editor_plugin.h
@@ -36,6 +36,10 @@
#include "scene/gui/slider.h"
#include "scene/gui/spin_box.h"
+class AcceptDialog;
+class ConfirmationDialog;
+class MenuButton;
+class OptionButton;
class SceneTreeDialog;
class MultiMeshEditor : public Control {
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 5ea1bf6dc1..5c5034a916 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -39,6 +39,7 @@
#include "scene/3d/light_3d.h"
#include "scene/3d/visual_instance_3d.h"
#include "scene/3d/world_environment.h"
+#include "scene/gui/box_container.h"
#include "scene/gui/color_picker.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/spin_box.h"
@@ -47,9 +48,14 @@
#include "scene/resources/fog_material.h"
#include "scene/resources/sky_material.h"
+class AcceptDialog;
+class CheckBox;
+class ConfirmationDialog;
class EditorData;
+class MenuButton;
class Node3DEditor;
class Node3DEditorViewport;
+class OptionButton;
class SubViewportContainer;
class DirectionalLight3D;
class WorldEnvironment;
diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h
index 13eca79010..d2015b2bb8 100644
--- a/editor/plugins/path_2d_editor_plugin.h
+++ b/editor/plugins/path_2d_editor_plugin.h
@@ -33,10 +33,12 @@
#include "editor/editor_plugin.h"
#include "scene/2d/path_2d.h"
+#include "scene/gui/box_container.h"
#include "scene/gui/separator.h"
class CanvasItemEditor;
class EditorUndoRedoManager;
+class MenuButton;
class Path2DEditor : public HBoxContainer {
GDCLASS(Path2DEditor, HBoxContainer);
diff --git a/editor/plugins/path_3d_editor_plugin.h b/editor/plugins/path_3d_editor_plugin.h
index 11a640b79f..a2816c89ae 100644
--- a/editor/plugins/path_3d_editor_plugin.h
+++ b/editor/plugins/path_3d_editor_plugin.h
@@ -37,6 +37,8 @@
#include "scene/3d/path_3d.h"
#include "scene/gui/separator.h"
+class MenuButton;
+
class Path3DGizmo : public EditorNode3DGizmo {
GDCLASS(Path3DGizmo, EditorNode3DGizmo);
diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h
index d878d3f9af..6021401e4f 100644
--- a/editor/plugins/polygon_2d_editor_plugin.h
+++ b/editor/plugins/polygon_2d_editor_plugin.h
@@ -33,11 +33,17 @@
#include "editor/plugins/abstract_polygon_2d_editor.h"
+class AcceptDialog;
+class ButtonGroup;
+class HScrollBar;
class HSlider;
+class MenuButton;
class Panel;
class ScrollContainer;
class SpinBox;
+class TextureRect;
class ViewPanner;
+class VScrollBar;
class Polygon2DEditor : public AbstractPolygon2DEditor {
GDCLASS(Polygon2DEditor, AbstractPolygon2DEditor);
diff --git a/editor/plugins/polygon_3d_editor_plugin.h b/editor/plugins/polygon_3d_editor_plugin.h
index 918072b429..fe8e2ce36d 100644
--- a/editor/plugins/polygon_3d_editor_plugin.h
+++ b/editor/plugins/polygon_3d_editor_plugin.h
@@ -34,10 +34,12 @@
#include "editor/editor_plugin.h"
#include "scene/3d/collision_polygon_3d.h"
#include "scene/3d/mesh_instance_3d.h"
+#include "scene/gui/box_container.h"
#include "scene/resources/immediate_mesh.h"
class CanvasItemEditor;
class EditorUndoRedoManager;
+class MenuButton;
class Polygon3DEditor : public HBoxContainer {
GDCLASS(Polygon3DEditor, HBoxContainer);
diff --git a/editor/plugins/resource_preloader_editor_plugin.h b/editor/plugins/resource_preloader_editor_plugin.h
index ef80283dae..59641e2561 100644
--- a/editor/plugins/resource_preloader_editor_plugin.h
+++ b/editor/plugins/resource_preloader_editor_plugin.h
@@ -33,6 +33,7 @@
#include "editor/editor_plugin.h"
#include "scene/gui/dialogs.h"
+#include "scene/gui/panel_container.h"
#include "scene/gui/tree.h"
#include "scene/main/resource_preloader.h"
diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp
index de30c4100d..a38a040814 100644
--- a/editor/plugins/root_motion_editor_plugin.cpp
+++ b/editor/plugins/root_motion_editor_plugin.cpp
@@ -30,6 +30,8 @@
#include "root_motion_editor_plugin.h"
#include "editor/editor_node.h"
+#include "scene/animation/animation_player.h"
+#include "scene/animation/animation_tree.h"
#include "scene/main/window.h"
void EditorPropertyRootMotion::_confirmed() {
diff --git a/editor/plugins/root_motion_editor_plugin.h b/editor/plugins/root_motion_editor_plugin.h
index 5b8c1d77b3..7134b48c36 100644
--- a/editor/plugins/root_motion_editor_plugin.h
+++ b/editor/plugins/root_motion_editor_plugin.h
@@ -32,9 +32,8 @@
#define ROOT_MOTION_EDITOR_PLUGIN_H
#include "editor/editor_inspector.h"
-#include "editor/editor_spin_slider.h"
-#include "editor/property_selector.h"
-#include "scene/animation/animation_tree.h"
+
+class Tree;
class EditorPropertyRootMotion : public EditorProperty {
GDCLASS(EditorPropertyRootMotion, EditorProperty);
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index a45ce4cc22..3f84ded0a2 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -48,6 +48,7 @@
#include "scene/resources/text_file.h"
class EditorFileDialog;
+class TextureRect;
class EditorSyntaxHighlighter : public SyntaxHighlighter {
GDCLASS(EditorSyntaxHighlighter, SyntaxHighlighter)
diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h
index 7638778af7..1ae419053e 100644
--- a/editor/plugins/shader_editor_plugin.h
+++ b/editor/plugins/shader_editor_plugin.h
@@ -35,6 +35,7 @@
class HSplitContainer;
class ItemList;
+class MenuButton;
class ShaderCreateDialog;
class TabContainer;
class TextShaderEditor;
diff --git a/editor/plugins/skeleton_2d_editor_plugin.h b/editor/plugins/skeleton_2d_editor_plugin.h
index 295725b751..6794f72955 100644
--- a/editor/plugins/skeleton_2d_editor_plugin.h
+++ b/editor/plugins/skeleton_2d_editor_plugin.h
@@ -35,6 +35,9 @@
#include "scene/2d/skeleton_2d.h"
#include "scene/gui/spin_box.h"
+class AcceptDialog;
+class MenuButton;
+
class Skeleton2DEditor : public Control {
GDCLASS(Skeleton2DEditor, Control);
diff --git a/editor/plugins/sprite_2d_editor_plugin.h b/editor/plugins/sprite_2d_editor_plugin.h
index b87f108bd2..ae1083ed41 100644
--- a/editor/plugins/sprite_2d_editor_plugin.h
+++ b/editor/plugins/sprite_2d_editor_plugin.h
@@ -35,6 +35,10 @@
#include "scene/2d/sprite_2d.h"
#include "scene/gui/spin_box.h"
+class AcceptDialog;
+class ConfirmationDialog;
+class MenuButton;
+
class Sprite2DEditor : public Control {
GDCLASS(Sprite2DEditor, Control);
diff --git a/editor/plugins/texture_3d_editor_plugin.h b/editor/plugins/texture_3d_editor_plugin.h
index 7795c83c8a..6790f6f2d5 100644
--- a/editor/plugins/texture_3d_editor_plugin.h
+++ b/editor/plugins/texture_3d_editor_plugin.h
@@ -31,6 +31,7 @@
#ifndef TEXTURE_3D_EDITOR_PLUGIN_H
#define TEXTURE_3D_EDITOR_PLUGIN_H
+#include "editor/editor_inspector.h"
#include "editor/editor_plugin.h"
#include "scene/gui/spin_box.h"
#include "scene/resources/shader.h"
diff --git a/editor/plugins/texture_editor_plugin.h b/editor/plugins/texture_editor_plugin.h
index 9beada556c..d7312bfcb4 100644
--- a/editor/plugins/texture_editor_plugin.h
+++ b/editor/plugins/texture_editor_plugin.h
@@ -31,9 +31,13 @@
#ifndef TEXTURE_EDITOR_PLUGIN_H
#define TEXTURE_EDITOR_PLUGIN_H
+#include "editor/editor_inspector.h"
#include "editor/editor_plugin.h"
+#include "scene/gui/margin_container.h"
#include "scene/resources/texture.h"
+class TextureRect;
+
class TexturePreview : public MarginContainer {
GDCLASS(TexturePreview, MarginContainer);
diff --git a/editor/plugins/texture_layered_editor_plugin.h b/editor/plugins/texture_layered_editor_plugin.h
index f4dbc104c8..16a2f65386 100644
--- a/editor/plugins/texture_layered_editor_plugin.h
+++ b/editor/plugins/texture_layered_editor_plugin.h
@@ -31,6 +31,7 @@
#ifndef TEXTURE_LAYERED_EDITOR_PLUGIN_H
#define TEXTURE_LAYERED_EDITOR_PLUGIN_H
+#include "editor/editor_inspector.h"
#include "editor/editor_plugin.h"
#include "scene/gui/spin_box.h"
#include "scene/resources/shader.h"
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index a7a8d526d0..b0c8597adf 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -242,7 +242,7 @@ void TextureRegionEditor::_region_draw() {
hscroll->set_value((hscroll->get_min() + hscroll->get_max() - hscroll->get_page()) / 2);
vscroll->set_value((vscroll->get_min() + vscroll->get_max() - vscroll->get_page()) / 2);
// This ensures that the view is updated correctly.
- callable_mp(this, &TextureRegionEditor::_pan_callback).bind(Vector2(1, 0)).call_deferredp(nullptr, 0);
+ callable_mp(this, &TextureRegionEditor::_pan_callback).bind(Vector2(1, 0)).call_deferred();
request_center = false;
}
diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h
index 7eda4f469f..48cbb6b70e 100644
--- a/editor/plugins/texture_region_editor_plugin.h
+++ b/editor/plugins/texture_region_editor_plugin.h
@@ -32,6 +32,7 @@
#define TEXTURE_REGION_EDITOR_PLUGIN_H
#include "canvas_item_editor_plugin.h"
+#include "editor/editor_inspector.h"
#include "editor/editor_plugin.h"
#include "scene/2d/sprite_2d.h"
#include "scene/3d/sprite_3d.h"
@@ -41,6 +42,7 @@
class ViewPanner;
class EditorUndoRedoManager;
+class OptionButton;
class TextureRegionEditor : public AcceptDialog {
GDCLASS(TextureRegionEditor, AcceptDialog);
diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h
index 9f89a047cb..b54aa5de6c 100644
--- a/editor/plugins/theme_editor_plugin.h
+++ b/editor/plugins/theme_editor_plugin.h
@@ -45,6 +45,8 @@
#include "scene/resources/theme.h"
class EditorFileDialog;
+class PanelContainer;
+class TabContainer;
class ThemeItemImportTree : public VBoxContainer {
GDCLASS(ThemeItemImportTree, VBoxContainer);
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index 69104cadec..4fe7178e7e 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -192,6 +192,19 @@ void TileAtlasView::_draw_base_tiles() {
rect = rect.intersection(Rect2i(Vector2(), texture->get_size()));
if (rect.size.x > 0 && rect.size.y > 0) {
base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
+ }
+ }
+ }
+ }
+
+ // Draw dark overlay after for performance reasons.
+ for (int x = 0; x < grid_size.x; x++) {
+ for (int y = 0; y < grid_size.y; y++) {
+ Vector2i coords = Vector2i(x, y);
+ if (tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
+ Rect2i rect = Rect2i((texture_region_size + separation) * coords + margins, texture_region_size + separation);
+ rect = rect.intersection(Rect2i(Vector2(), texture->get_size()));
+ if (rect.size.x > 0 && rect.size.y > 0) {
base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5));
}
}
@@ -242,23 +255,34 @@ void TileAtlasView::_draw_base_tiles() {
// Draw the tile.
TileMap::draw_tile(base_tiles_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, 0, frame);
+ }
+ }
- // Draw, the texture in the separation areas
- if (separation.x > 0) {
- Rect2i right_sep_rect = Rect2i(base_frame_rect.get_position() + Vector2i(base_frame_rect.size.x, 0), Vector2i(separation.x, base_frame_rect.size.y));
- right_sep_rect = right_sep_rect.intersection(Rect2i(Vector2(), texture->get_size()));
- if (right_sep_rect.size.x > 0 && right_sep_rect.size.y > 0) {
- base_tiles_draw->draw_texture_rect_region(texture, right_sep_rect, right_sep_rect);
- base_tiles_draw->draw_rect(right_sep_rect, Color(0.0, 0.0, 0.0, 0.5));
+ // Draw Dark overlay on separation in its own pass.
+ if (separation.x > 0 || separation.y > 0) {
+ for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
+ Vector2i atlas_coords = tile_set_atlas_source->get_tile_id(i);
+
+ for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(atlas_coords); frame++) {
+ // Update the y to max value.
+ Rect2i base_frame_rect = tile_set_atlas_source->get_tile_texture_region(atlas_coords, frame);
+
+ if (separation.x > 0) {
+ Rect2i right_sep_rect = Rect2i(base_frame_rect.get_position() + Vector2i(base_frame_rect.size.x, 0), Vector2i(separation.x, base_frame_rect.size.y));
+ right_sep_rect = right_sep_rect.intersection(Rect2i(Vector2(), texture->get_size()));
+ if (right_sep_rect.size.x > 0 && right_sep_rect.size.y > 0) {
+ //base_tiles_draw->draw_texture_rect_region(texture, right_sep_rect, right_sep_rect);
+ base_tiles_draw->draw_rect(right_sep_rect, Color(0.0, 0.0, 0.0, 0.5));
+ }
}
- }
- if (separation.y > 0) {
- Rect2i bottom_sep_rect = Rect2i(base_frame_rect.get_position() + Vector2i(0, base_frame_rect.size.y), Vector2i(base_frame_rect.size.x + separation.x, separation.y));
- bottom_sep_rect = bottom_sep_rect.intersection(Rect2i(Vector2(), texture->get_size()));
- if (bottom_sep_rect.size.x > 0 && bottom_sep_rect.size.y > 0) {
- base_tiles_draw->draw_texture_rect_region(texture, bottom_sep_rect, bottom_sep_rect);
- base_tiles_draw->draw_rect(bottom_sep_rect, Color(0.0, 0.0, 0.0, 0.5));
+ if (separation.y > 0) {
+ Rect2i bottom_sep_rect = Rect2i(base_frame_rect.get_position() + Vector2i(0, base_frame_rect.size.y), Vector2i(base_frame_rect.size.x + separation.x, separation.y));
+ bottom_sep_rect = bottom_sep_rect.intersection(Rect2i(Vector2(), texture->get_size()));
+ if (bottom_sep_rect.size.x > 0 && bottom_sep_rect.size.y > 0) {
+ //base_tiles_draw->draw_texture_rect_region(texture, bottom_sep_rect, bottom_sep_rect);
+ base_tiles_draw->draw_rect(bottom_sep_rect, Color(0.0, 0.0, 0.0, 0.5));
+ }
}
}
}
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index f7e033d753..5e21215738 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -32,20 +32,13 @@
#define VISUAL_SHADER_EDITOR_PLUGIN_H
#include "editor/editor_plugin.h"
+#include "editor/editor_properties.h"
#include "editor/plugins/editor_resource_conversion_plugin.h"
#include "scene/resources/visual_shader.h"
-class Button;
-class CodeEdit;
-class CodeHighlighter;
class CurveEditor;
class GraphEdit;
class GraphNode;
-class PopupMenu;
-class PopupPanel;
-class RichTextLabel;
-class TextEdit;
-class Tree;
class VisualShaderEditor;
class EditorUndoRedoManager;
diff --git a/editor/plugins/voxel_gi_editor_plugin.h b/editor/plugins/voxel_gi_editor_plugin.h
index 43d6f71e26..feff3b4f35 100644
--- a/editor/plugins/voxel_gi_editor_plugin.h
+++ b/editor/plugins/voxel_gi_editor_plugin.h
@@ -37,6 +37,7 @@
class EditorFileDialog;
struct EditorProgress;
+class HBoxContainer;
class VoxelGIEditorPlugin : public EditorPlugin {
GDCLASS(VoxelGIEditorPlugin, EditorPlugin);
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 588746bf64..b2a2566ad4 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -546,7 +546,6 @@ private:
Vector<String> failed_files;
- int idx = 0;
while (ret == UNZ_OK) {
//get filename
unz_file_info info;
@@ -585,7 +584,6 @@ private:
}
}
- idx++;
ret = unzGoToNextFile(pkg);
}
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index 04bb4d93e7..6ec9d31ca8 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -46,6 +46,8 @@
#include "scene/gui/tree.h"
#include "scene_tree_editor.h"
+class TextureRect;
+
#include "modules/modules_enabled.gen.h" // For regex.
#ifdef MODULE_REGEX_ENABLED
class RenameDialog;
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index cc09c3a432..08c0f0f708 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -275,7 +275,6 @@ String ScriptCreateDialog::_validate_path(const String &p_path, bool p_file_must
bool found = false;
bool match = false;
- int index = 0;
for (const String &E : extensions) {
if (E.nocasecmp_to(extension) == 0) {
found = true;
@@ -284,7 +283,6 @@ String ScriptCreateDialog::_validate_path(const String &p_path, bool p_file_must
}
break;
}
- index++;
}
if (!found) {
@@ -373,7 +371,7 @@ void ScriptCreateDialog::_create_new() {
const ScriptLanguage::ScriptTemplate sinfo = _get_current_template();
String parent_class = parent_name->get_text();
- if (!ClassDB::class_exists(parent_class) && !ScriptServer::is_global_class(parent_class)) {
+ if (!parent_name->get_text().is_quoted() && !ClassDB::class_exists(parent_class) && !ScriptServer::is_global_class(parent_class)) {
// If base is a custom type, replace with script path instead.
const EditorData::CustomType *type = EditorNode::get_editor_data().get_custom_type_by_name(parent_class);
ERR_FAIL_NULL(type);
diff --git a/main/main.cpp b/main/main.cpp
index 5b998d98ce..0a8de56e01 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -85,6 +85,7 @@
#endif
#ifdef TOOLS_ENABLED
+#include "editor/debugger/editor_debugger_node.h"
#include "editor/doc_data_class_path.gen.h"
#include "editor/doc_tools.h"
#include "editor/editor_node.h"
@@ -443,11 +444,7 @@ Error Main::test_setup() {
globals = memnew(ProjectSettings);
- GLOBAL_DEF("debug/settings/crash_handler/message",
- String("Please include this when reporting the bug on https://github.com/godotengine/godot/issues"));
- GLOBAL_DEF_RST("rendering/occlusion_culling/bvh_build_quality", 2);
-
- register_core_settings(); //here globals are present
+ register_core_settings(); // Here globals are present.
translation_server = memnew(TranslationServer);
tsman = memnew(TextServerManager);
@@ -665,11 +662,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF_RST("application/run/flush_stdout_on_print", false);
GLOBAL_DEF_RST("application/run/flush_stdout_on_print.debug", true);
- GLOBAL_DEF("debug/settings/crash_handler/message",
- String("Please include this when reporting the bug to the project developer."));
- GLOBAL_DEF("debug/settings/crash_handler/message.editor",
- String("Please include this when reporting the bug on: https://github.com/godotengine/godot/issues"));
-
MAIN_PRINT("Main: Parse CMDLine");
/* argument parsing and main creation */
@@ -1358,7 +1350,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
ResourceUID::get_singleton()->load_from_cache(); // load UUIDs from cache.
- GLOBAL_DEF("memory/limits/multithreaded_server/rid_pool_prealloc", 60);
ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/multithreaded_server/rid_pool_prealloc",
PropertyInfo(Variant::INT,
"memory/limits/multithreaded_server/rid_pool_prealloc",
@@ -1715,7 +1706,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
window_mode = (DisplayServer::WindowMode)(GLOBAL_GET("display/window/size/mode").operator int());
}
- GLOBAL_DEF_RST("internationalization/rendering/force_right_to_left_layout_direction", false);
GLOBAL_DEF("internationalization/locale/include_text_server_data", false);
OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", true);
@@ -2165,12 +2155,12 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
boot_logo->set_pixel(0, 0, Color(0, 0, 0, 0));
}
+ Color boot_bg_color = GLOBAL_DEF_BASIC("application/boot_splash/bg_color", boot_splash_bg_color);
+
#if defined(TOOLS_ENABLED) && !defined(NO_EDITOR_SPLASH)
- const Color boot_bg_color =
+ boot_bg_color =
GLOBAL_DEF_BASIC("application/boot_splash/bg_color",
(editor || project_manager) ? boot_splash_editor_bg_color : boot_splash_bg_color);
-#else
- const Color boot_bg_color = GLOBAL_DEF_BASIC("application/boot_splash/bg_color", boot_splash_bg_color);
#endif
if (boot_logo.is_valid()) {
RenderingServer::get_singleton()->set_boot_image(boot_logo, boot_bg_color, boot_logo_scale,
@@ -2202,7 +2192,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
MAIN_PRINT("Main: DCC");
RenderingServer::get_singleton()->set_default_clear_color(
- GLOBAL_DEF_BASIC("rendering/environment/defaults/default_clear_color", Color(0.3, 0.3, 0.3)));
+ GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
GLOBAL_DEF("application/config/icon", String());
ProjectSettings::get_singleton()->set_custom_property_info("application/config/icon",
@@ -2805,15 +2795,48 @@ bool Main::start() {
startup_benchmark_file = String();
}
#endif
+ GLOBAL_DEF_BASIC("display/window/stretch/mode", "disabled");
+ ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/mode",
+ PropertyInfo(Variant::STRING,
+ "display/window/stretch/mode",
+ PROPERTY_HINT_ENUM,
+ "disabled,canvas_items,viewport"));
+ GLOBAL_DEF_BASIC("display/window/stretch/aspect", "keep");
+ ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/aspect",
+ PropertyInfo(Variant::STRING,
+ "display/window/stretch/aspect",
+ PROPERTY_HINT_ENUM,
+ "ignore,keep,keep_width,keep_height,expand"));
+ GLOBAL_DEF_BASIC("display/window/stretch/scale", 1.0);
+ ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/scale",
+ PropertyInfo(Variant::FLOAT,
+ "display/window/stretch/scale",
+ PROPERTY_HINT_RANGE,
+ "0.5,8.0,0.01"));
+ sml->set_auto_accept_quit(GLOBAL_DEF("application/config/auto_accept_quit", true));
+ sml->set_quit_on_go_back(GLOBAL_DEF("application/config/quit_on_go_back", true));
+ GLOBAL_DEF_BASIC("gui/common/snap_controls_to_pixels", true);
+ GLOBAL_DEF_BASIC("gui/fonts/dynamic_fonts/use_oversampling", true);
+
+ GLOBAL_DEF_BASIC("rendering/textures/canvas_textures/default_texture_filter", 1);
+ ProjectSettings::get_singleton()->set_custom_property_info(
+ "rendering/textures/canvas_textures/default_texture_filter",
+ PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM,
+ "Nearest,Linear,Linear Mipmap,Nearest Mipmap"));
+ GLOBAL_DEF_BASIC("rendering/textures/canvas_textures/default_texture_repeat", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info(
+ "rendering/textures/canvas_textures/default_texture_repeat",
+ PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM,
+ "Disable,Enable,Mirror"));
if (!editor && !project_manager) {
//standard helpers that can be changed from main config
- String stretch_mode = GLOBAL_DEF_BASIC("display/window/stretch/mode", "disabled");
- String stretch_aspect = GLOBAL_DEF_BASIC("display/window/stretch/aspect", "keep");
- Size2i stretch_size = Size2i(GLOBAL_DEF_BASIC("display/window/size/viewport_width", 0),
- GLOBAL_DEF_BASIC("display/window/size/viewport_height", 0));
- real_t stretch_scale = GLOBAL_DEF_BASIC("display/window/stretch/scale", 1.0);
+ String stretch_mode = GLOBAL_GET("display/window/stretch/mode");
+ String stretch_aspect = GLOBAL_GET("display/window/stretch/aspect");
+ Size2i stretch_size = Size2i(GLOBAL_GET("display/window/size/viewport_width"),
+ GLOBAL_GET("display/window/size/viewport_height"));
+ real_t stretch_scale = GLOBAL_GET("display/window/stretch/scale");
Window::ContentScaleMode cs_sm = Window::CONTENT_SCALE_MODE_DISABLED;
if (stretch_mode == "canvas_items") {
@@ -2838,8 +2861,8 @@ bool Main::start() {
sml->get_root()->set_content_scale_size(stretch_size);
sml->get_root()->set_content_scale_factor(stretch_scale);
- sml->set_auto_accept_quit(GLOBAL_DEF("application/config/auto_accept_quit", true));
- sml->set_quit_on_go_back(GLOBAL_DEF("application/config/quit_on_go_back", true));
+ sml->set_auto_accept_quit(GLOBAL_GET("application/config/auto_accept_quit"));
+ sml->set_quit_on_go_back(GLOBAL_GET("application/config/quit_on_go_back"));
String appname = GLOBAL_GET("application/config/name");
appname = TranslationServer::get_singleton()->translate(appname);
#ifdef DEBUG_ENABLED
@@ -2855,53 +2878,18 @@ bool Main::start() {
// It can still be overridden by the user in a script.
DisplayServer::get_singleton()->window_set_min_size(Size2i(64, 64));
- bool snap_controls = GLOBAL_DEF("gui/common/snap_controls_to_pixels", true);
+ bool snap_controls = GLOBAL_GET("gui/common/snap_controls_to_pixels");
sml->get_root()->set_snap_controls_to_pixels(snap_controls);
- bool font_oversampling = GLOBAL_DEF("gui/fonts/dynamic_fonts/use_oversampling", true);
+ bool font_oversampling = GLOBAL_GET("gui/fonts/dynamic_fonts/use_oversampling");
sml->get_root()->set_use_font_oversampling(font_oversampling);
- int texture_filter = GLOBAL_DEF("rendering/textures/canvas_textures/default_texture_filter", 1);
- int texture_repeat = GLOBAL_DEF("rendering/textures/canvas_textures/default_texture_repeat", 0);
+ int texture_filter = GLOBAL_GET("rendering/textures/canvas_textures/default_texture_filter");
+ int texture_repeat = GLOBAL_GET("rendering/textures/canvas_textures/default_texture_repeat");
sml->get_root()->set_default_canvas_item_texture_filter(
Viewport::DefaultCanvasItemTextureFilter(texture_filter));
sml->get_root()->set_default_canvas_item_texture_repeat(
Viewport::DefaultCanvasItemTextureRepeat(texture_repeat));
-
- } else {
- GLOBAL_DEF_BASIC("display/window/stretch/mode", "disabled");
- ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/mode",
- PropertyInfo(Variant::STRING,
- "display/window/stretch/mode",
- PROPERTY_HINT_ENUM,
- "disabled,canvas_items,viewport"));
- GLOBAL_DEF_BASIC("display/window/stretch/aspect", "keep");
- ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/aspect",
- PropertyInfo(Variant::STRING,
- "display/window/stretch/aspect",
- PROPERTY_HINT_ENUM,
- "ignore,keep,keep_width,keep_height,expand"));
- GLOBAL_DEF_BASIC("display/window/stretch/scale", 1.0);
- ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/scale",
- PropertyInfo(Variant::FLOAT,
- "display/window/stretch/scale",
- PROPERTY_HINT_RANGE,
- "0.5,8.0,0.01"));
- sml->set_auto_accept_quit(GLOBAL_DEF("application/config/auto_accept_quit", true));
- sml->set_quit_on_go_back(GLOBAL_DEF("application/config/quit_on_go_back", true));
- GLOBAL_DEF_BASIC("gui/common/snap_controls_to_pixels", true);
- GLOBAL_DEF_BASIC("gui/fonts/dynamic_fonts/use_oversampling", true);
-
- GLOBAL_DEF_BASIC("rendering/textures/canvas_textures/default_texture_filter", 1);
- ProjectSettings::get_singleton()->set_custom_property_info(
- "rendering/textures/canvas_textures/default_texture_filter",
- PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM,
- "Nearest,Linear,Linear Mipmap,Nearest Mipmap"));
- GLOBAL_DEF_BASIC("rendering/textures/canvas_textures/default_texture_repeat", 0);
- ProjectSettings::get_singleton()->set_custom_property_info(
- "rendering/textures/canvas_textures/default_texture_repeat",
- PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM,
- "Disable,Enable,Mirror"));
}
#ifdef TOOLS_ENABLED
@@ -2970,7 +2958,7 @@ bool Main::start() {
Engine::get_singleton()->startup_benchmark_begin_measure("game_load");
// Load SSL Certificates from Project Settings (or builtin).
- Crypto::load_default_certificates(GLOBAL_DEF("network/tls/certificate_bundle_override", ""));
+ Crypto::load_default_certificates(GLOBAL_GET("network/tls/certificate_bundle_override"));
if (!game_path.is_empty()) {
Node *scene = nullptr;
@@ -2983,7 +2971,7 @@ bool Main::start() {
sml->add_current_scene(scene);
#ifdef MACOS_ENABLED
- String mac_iconpath = GLOBAL_DEF("application/config/macos_native_icon", "Variant()");
+ String mac_iconpath = GLOBAL_GET("application/config/macos_native_icon");
if (!mac_iconpath.is_empty()) {
DisplayServer::get_singleton()->set_native_icon(mac_iconpath);
hasicon = true;
@@ -2991,14 +2979,14 @@ bool Main::start() {
#endif
#ifdef WINDOWS_ENABLED
- String win_iconpath = GLOBAL_DEF("application/config/windows_native_icon", "Variant()");
+ String win_iconpath = GLOBAL_GET("application/config/windows_native_icon");
if (!win_iconpath.is_empty()) {
DisplayServer::get_singleton()->set_native_icon(win_iconpath);
hasicon = true;
}
#endif
- String iconpath = GLOBAL_DEF("application/config/icon", "Variant()");
+ String iconpath = GLOBAL_GET("application/config/icon");
if ((!iconpath.is_empty()) && (!hasicon)) {
Ref<Image> icon;
icon.instantiate();
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 7acd1cdb96..fd13edc4cf 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -2432,9 +2432,8 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
// TODO: Make enums not be just a dictionary?
Dictionary new_enum;
for (int j = 0; j < enum_n->values.size(); j++) {
- int value = enum_n->values[j].value;
// Needs to be string because Variant::get will convert to String.
- new_enum[String(enum_n->values[j].identifier->name)] = value;
+ new_enum[String(enum_n->values[j].identifier->name)] = enum_n->values[j].value;
}
p_script->constants.insert(enum_n->identifier->name, new_enum);
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 4279edf394..6842a1ff49 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -3802,7 +3802,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
String enum_hint_string;
bool first = true;
- for (const KeyValue<StringName, int> &E : export_type.enum_values) {
+ for (const KeyValue<StringName, int64_t> &E : export_type.enum_values) {
if (!first) {
enum_hint_string += ",";
} else {
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index f40887ddb8..d8f5b866aa 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -131,7 +131,7 @@ public:
ClassNode *class_type = nullptr;
MethodInfo method_info; // For callable/signals.
- HashMap<StringName, int> enum_values; // For enums.
+ HashMap<StringName, int64_t> enum_values; // For enums.
_FORCE_INLINE_ bool is_set() const { return kind != UNRESOLVED; }
_FORCE_INLINE_ bool has_no_type() const { return type_source == UNDETECTED; }
diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h
index 5af46bc752..66fd27b449 100644
--- a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h
+++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.h
@@ -36,6 +36,8 @@
#include "editor/editor_plugin.h"
#include "editor_scene_importer_gltf.h"
+class EditorFileDialog;
+
class SceneExporterGLTFPlugin : public EditorPlugin {
GDCLASS(SceneExporterGLTFPlugin, EditorPlugin);
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.h b/modules/gridmap/editor/grid_map_editor_plugin.h
index 6fd38d9445..91f14690ca 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.h
+++ b/modules/gridmap/editor/grid_map_editor_plugin.h
@@ -35,11 +35,14 @@
#include "../grid_map.h"
#include "editor/editor_plugin.h"
+#include "scene/gui/box_container.h"
#include "scene/gui/item_list.h"
#include "scene/gui/slider.h"
#include "scene/gui/spin_box.h"
+class ConfirmationDialog;
class EditorUndoRedoManager;
+class MenuButton;
class Node3DEditorPlugin;
class GridMapEditor : public VBoxContainer {
diff --git a/modules/lightmapper_rd/register_types.cpp b/modules/lightmapper_rd/register_types.cpp
index 0e0330c1a1..ed223e1faa 100644
--- a/modules/lightmapper_rd/register_types.cpp
+++ b/modules/lightmapper_rd/register_types.cpp
@@ -57,6 +57,7 @@ void initialize_lightmapper_rd_module(ModuleInitializationLevel p_level) {
GLOBAL_DEF("rendering/lightmapping/bake_quality/high_quality_probe_ray_count", 512);
GLOBAL_DEF("rendering/lightmapping/bake_quality/ultra_quality_probe_ray_count", 2048);
GLOBAL_DEF("rendering/lightmapping/bake_performance/max_rays_per_probe_pass", 64);
+ GLOBAL_DEF("rendering/lightmapping/primitive_meshes/texel_size", 0.2);
#ifndef _3D_DISABLED
GDREGISTER_CLASS(LightmapperRD);
Lightmapper::create_gpu = create_lightmapper_rd;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
index 088f4e7ecf..b30b6a0752 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
@@ -374,7 +374,7 @@ namespace Godot.NativeInterop
public static partial Error godotsharp_array_resize(ref godot_array p_self, int p_new_size);
- public static partial Error godotsharp_array_shuffle(ref godot_array p_self);
+ public static partial void godotsharp_array_shuffle(ref godot_array p_self);
public static partial void godotsharp_array_to_string(ref godot_array p_self, out godot_string r_str);
diff --git a/modules/multiplayer/editor/replication_editor_plugin.cpp b/modules/multiplayer/editor/replication_editor_plugin.cpp
index aee5f5b483..de10420652 100644
--- a/modules/multiplayer/editor/replication_editor_plugin.cpp
+++ b/modules/multiplayer/editor/replication_editor_plugin.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/inspector_dock.h"
+#include "editor/property_selector.h"
#include "editor/scene_tree_editor.h"
#include "modules/multiplayer/multiplayer_synchronizer.h"
#include "scene/gui/dialogs.h"
diff --git a/modules/multiplayer/editor/replication_editor_plugin.h b/modules/multiplayer/editor/replication_editor_plugin.h
index e60e49cc25..6c40a99293 100644
--- a/modules/multiplayer/editor/replication_editor_plugin.h
+++ b/modules/multiplayer/editor/replication_editor_plugin.h
@@ -32,17 +32,17 @@
#define REPLICATION_EDITOR_PLUGIN_H
#include "editor/editor_plugin.h"
-
-#include "editor/editor_spin_slider.h"
-#include "editor/property_selector.h"
-
-#include "../scene_replication_config.h"
+#include "modules/multiplayer/scene_replication_config.h"
+#include "scene/gui/box_container.h"
class ConfirmationDialog;
class MultiplayerSynchronizer;
-class SceneTreeDialog;
+class AcceptDialog;
+class LineEdit;
class Tree;
class TreeItem;
+class PropertySelector;
+class SceneTreeDialog;
class ReplicationEditor : public VBoxContainer {
GDCLASS(ReplicationEditor, VBoxContainer);
diff --git a/modules/navigation/editor/navigation_mesh_editor_plugin.h b/modules/navigation/editor/navigation_mesh_editor_plugin.h
index bc9e4185b7..b7bde98131 100644
--- a/modules/navigation/editor/navigation_mesh_editor_plugin.h
+++ b/modules/navigation/editor/navigation_mesh_editor_plugin.h
@@ -35,6 +35,8 @@
#include "editor/editor_plugin.h"
+class AcceptDialog;
+class HBoxContainer;
class NavigationRegion3D;
class NavigationMeshEditor : public Control {
diff --git a/modules/noise/doc_classes/NoiseTexture2D.xml b/modules/noise/doc_classes/NoiseTexture2D.xml
index 9eea2738c5..0a800a143b 100644
--- a/modules/noise/doc_classes/NoiseTexture2D.xml
+++ b/modules/noise/doc_classes/NoiseTexture2D.xml
@@ -44,6 +44,7 @@
<member name="noise" type="Noise" setter="set_noise" getter="get_noise">
The instance of the [Noise] object.
</member>
+ <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
<member name="seamless" type="bool" setter="set_seamless" getter="get_seamless" default="false">
If [code]true[/code], a seamless texture is requested from the [Noise] resource.
[b]Note:[/b] Seamless noise textures may take longer to generate and/or can have a lower contrast compared to non-seamless noise depending on the used [Noise] resource. This is because some implementations use higher dimensions for generating seamless noise.
diff --git a/modules/noise/editor/noise_editor_plugin.cpp b/modules/noise/editor/noise_editor_plugin.cpp
index e8e73e4fd9..47f5f8f819 100644
--- a/modules/noise/editor/noise_editor_plugin.cpp
+++ b/modules/noise/editor/noise_editor_plugin.cpp
@@ -32,7 +32,9 @@
#ifdef TOOLS_ENABLED
+#include "editor/editor_inspector.h"
#include "editor/editor_scale.h"
+#include "scene/gui/texture_rect.h"
#include "modules/noise/noise.h"
#include "modules/noise/noise_texture_2d.h"
diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub
index b5978ab134..84542be3b9 100644
--- a/modules/openxr/SCsub
+++ b/modules/openxr/SCsub
@@ -90,6 +90,8 @@ if env["platform"] == "android":
env_openxr.add_source_files(module_obj, "extensions/openxr_android_extension.cpp")
if env["vulkan"]:
env_openxr.add_source_files(module_obj, "extensions/openxr_vulkan_extension.cpp")
+if env["opengl3"]:
+ env_openxr.add_source_files(module_obj, "extensions/openxr_opengl_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_palm_pose_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_composition_layer_depth_extension.cpp")
diff --git a/modules/openxr/extensions/openxr_opengl_extension.cpp b/modules/openxr/extensions/openxr_opengl_extension.cpp
new file mode 100644
index 0000000000..ee69144123
--- /dev/null
+++ b/modules/openxr/extensions/openxr_opengl_extension.cpp
@@ -0,0 +1,466 @@
+/*************************************************************************/
+/* openxr_opengl_extension.cpp */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+
+#ifdef GLES3_ENABLED
+
+#include "../extensions/openxr_opengl_extension.h"
+#include "../openxr_util.h"
+#include "drivers/gles3/effects/copy_effects.h"
+#include "drivers/gles3/storage/texture_storage.h"
+#include "servers/rendering/rendering_server_globals.h"
+#include "servers/rendering_server.h"
+
+OpenXROpenGLExtension::OpenXROpenGLExtension(OpenXRAPI *p_openxr_api) :
+ OpenXRGraphicsExtensionWrapper(p_openxr_api) {
+#ifdef ANDROID_ENABLED
+ request_extensions[XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME] = nullptr;
+#else
+ request_extensions[XR_KHR_OPENGL_ENABLE_EXTENSION_NAME] = nullptr;
+#endif
+
+ ERR_FAIL_NULL(openxr_api);
+}
+
+OpenXROpenGLExtension::~OpenXROpenGLExtension() {
+}
+
+void OpenXROpenGLExtension::on_instance_created(const XrInstance p_instance) {
+ ERR_FAIL_NULL(openxr_api);
+
+ // Obtain pointers to functions we're accessing here.
+
+#ifdef ANDROID_ENABLED
+ EXT_INIT_XR_FUNC(xrGetOpenGLESGraphicsRequirementsKHR);
+#else
+ EXT_INIT_XR_FUNC(xrGetOpenGLGraphicsRequirementsKHR);
+#endif
+ EXT_INIT_XR_FUNC(xrEnumerateSwapchainImages);
+}
+
+bool OpenXROpenGLExtension::check_graphics_api_support(XrVersion p_desired_version) {
+ ERR_FAIL_NULL_V(openxr_api, false);
+
+ XrSystemId system_id = openxr_api->get_system_id();
+ XrInstance instance = openxr_api->get_instance();
+
+#ifdef ANDROID_ENABLED
+ XrGraphicsRequirementsOpenGLESKHR opengl_requirements;
+ opengl_requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR;
+ opengl_requirements.next = nullptr;
+
+ XrResult result = xrGetOpenGLESGraphicsRequirementsKHR(instance, system_id, &opengl_requirements);
+ if (!openxr_api->xr_result(result, "Failed to get OpenGL graphics requirements!")) {
+ return false;
+ }
+#else
+ XrGraphicsRequirementsOpenGLKHR opengl_requirements;
+ opengl_requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR;
+ opengl_requirements.next = nullptr;
+
+ XrResult result = xrGetOpenGLGraphicsRequirementsKHR(instance, system_id, &opengl_requirements);
+ if (!openxr_api->xr_result(result, "Failed to get OpenGL graphics requirements!")) {
+ return false;
+ }
+#endif
+
+ if (p_desired_version < opengl_requirements.minApiVersionSupported) {
+ print_line("OpenXR: Requested OpenGL version does not meet the minimum version this runtime supports.");
+ print_line("- desired_version ", OpenXRUtil::make_xr_version_string(p_desired_version));
+ print_line("- minApiVersionSupported ", OpenXRUtil::make_xr_version_string(opengl_requirements.minApiVersionSupported));
+ print_line("- maxApiVersionSupported ", OpenXRUtil::make_xr_version_string(opengl_requirements.maxApiVersionSupported));
+ return false;
+ }
+
+ if (p_desired_version > opengl_requirements.maxApiVersionSupported) {
+ print_line("OpenXR: Requested OpenGL version exceeds the maximum version this runtime has been tested on and is known to support.");
+ print_line("- desired_version ", OpenXRUtil::make_xr_version_string(p_desired_version));
+ print_line("- minApiVersionSupported ", OpenXRUtil::make_xr_version_string(opengl_requirements.minApiVersionSupported));
+ print_line("- maxApiVersionSupported ", OpenXRUtil::make_xr_version_string(opengl_requirements.maxApiVersionSupported));
+ }
+
+ return true;
+}
+
+#ifdef WIN32
+XrGraphicsBindingOpenGLWin32KHR OpenXROpenGLExtension::graphics_binding_gl;
+#elif ANDROID_ENABLED
+XrGraphicsBindingOpenGLESAndroidKHR OpenXROpenGLExtension::graphics_binding_gl;
+#else
+XrGraphicsBindingOpenGLXlibKHR OpenXROpenGLExtension::graphics_binding_gl;
+#endif
+
+void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_next_pointer) {
+ XrVersion desired_version = XR_MAKE_VERSION(3, 3, 0);
+
+ if (!check_graphics_api_support(desired_version)) {
+ print_line("OpenXR: Trying to initialize with OpenGL anyway...");
+ //return p_next_pointer;
+ }
+
+ DisplayServer *display_server = DisplayServer::get_singleton();
+
+#ifdef WIN32
+ graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR,
+ graphics_binding_gl.next = p_next_pointer;
+
+ graphics_binding_gl.hDC = (HDC)display_server->window_get_native_handle(DisplayServer::WINDOW_VIEW);
+ graphics_binding_gl.hGLRC = (HGLRC)display_server->window_get_native_handle(DisplayServer::OPENGL_CONTEXT);
+#elif ANDROID_ENABLED
+ graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR;
+ graphics_binding_gl.next = p_next_pointer;
+
+ graphics_binding_gl.display = eglGetCurrentDisplay();
+ graphics_binding_gl.config = (EGLConfig)0; // https://github.com/KhronosGroup/OpenXR-SDK-Source/blob/master/src/tests/hello_xr/graphicsplugin_opengles.cpp#L122
+ graphics_binding_gl.context = eglGetCurrentContext();
+#else
+ graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR;
+ graphics_binding_gl.next = p_next_pointer;
+
+ void *display_handle = (void *)display_server->window_get_native_handle(DisplayServer::DISPLAY_HANDLE);
+ void *glxcontext_handle = (void *)display_server->window_get_native_handle(DisplayServer::OPENGL_CONTEXT);
+ void *glxdrawable_handle = (void *)display_server->window_get_native_handle(DisplayServer::WINDOW_HANDLE);
+
+ graphics_binding_gl.xDisplay = (Display *)display_handle;
+ graphics_binding_gl.glxContext = (GLXContext)glxcontext_handle;
+ graphics_binding_gl.glxDrawable = (GLXDrawable)glxdrawable_handle;
+
+ // spec says to use proper values but runtimes don't care
+ graphics_binding_gl.visualid = 0;
+ graphics_binding_gl.glxFBConfig = 0;
+#endif
+
+ return &graphics_binding_gl;
+}
+
+void OpenXROpenGLExtension::get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) {
+#ifdef WIN32
+ p_usable_swap_chains.push_back(GL_SRGB8_ALPHA8);
+ p_usable_swap_chains.push_back(GL_RGBA8);
+#elif ANDROID_ENABLED
+ p_usable_swap_chains.push_back(GL_SRGB8_ALPHA8);
+ p_usable_swap_chains.push_back(GL_RGBA8);
+#else
+ p_usable_swap_chains.push_back(GL_SRGB8_ALPHA8_EXT);
+ p_usable_swap_chains.push_back(GL_RGBA8_EXT);
+#endif
+}
+
+void OpenXROpenGLExtension::get_usable_depth_formats(Vector<int64_t> &p_usable_depth_formats) {
+ p_usable_depth_formats.push_back(GL_DEPTH_COMPONENT32F);
+ p_usable_depth_formats.push_back(GL_DEPTH24_STENCIL8);
+ p_usable_depth_formats.push_back(GL_DEPTH32F_STENCIL8);
+}
+
+bool OpenXROpenGLExtension::get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ ERR_FAIL_NULL_V(texture_storage, false);
+
+ uint32_t swapchain_length;
+ XrResult result = xrEnumerateSwapchainImages(p_swapchain, 0, &swapchain_length, nullptr);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to get swapchaim image count [", openxr_api->get_error_string(result), "]");
+ return false;
+ }
+
+#ifdef ANDROID_ENABLED
+ XrSwapchainImageOpenGLESKHR *images = (XrSwapchainImageOpenGLESKHR *)memalloc(sizeof(XrSwapchainImageOpenGLESKHR) * swapchain_length);
+#else
+ XrSwapchainImageOpenGLKHR *images = (XrSwapchainImageOpenGLKHR *)memalloc(sizeof(XrSwapchainImageOpenGLKHR) * swapchain_length);
+#endif
+ ERR_FAIL_NULL_V_MSG(images, false, "OpenXR Couldn't allocate memory for swap chain image");
+
+ for (uint64_t i = 0; i < swapchain_length; i++) {
+#ifdef ANDROID_ENABLED
+ images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR;
+#else
+ images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR;
+#endif
+ images[i].next = nullptr;
+ images[i].image = 0;
+ }
+
+ result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to get swapchaim images [", openxr_api->get_error_string(result), "]");
+ memfree(images);
+ return false;
+ }
+
+ SwapchainGraphicsData *data = memnew(SwapchainGraphicsData);
+ if (data == nullptr) {
+ print_line("OpenXR: Failed to allocate memory for swapchain data");
+ memfree(images);
+ return false;
+ }
+ *r_swapchain_graphics_data = data;
+ data->is_multiview = (p_array_size > 1);
+
+ Image::Format format = Image::FORMAT_RGBA8;
+
+ Vector<RID> texture_rids;
+
+ for (uint64_t i = 0; i < swapchain_length; i++) {
+ RID texture_rid = texture_storage->texture_create_external(
+ p_array_size == 1 ? GLES3::Texture::TYPE_2D : GLES3::Texture::TYPE_LAYERED,
+ format,
+ images[i].image,
+ p_width,
+ p_height,
+ 1,
+ p_array_size);
+
+ texture_rids.push_back(texture_rid);
+ }
+
+ data->texture_rids = texture_rids;
+
+ memfree(images);
+
+ return true;
+}
+
+bool OpenXROpenGLExtension::create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) {
+ XrMatrix4x4f matrix;
+ XrMatrix4x4f_CreateProjectionFov(&matrix, GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far);
+
+ for (int j = 0; j < 4; j++) {
+ for (int i = 0; i < 4; i++) {
+ r_camera_matrix.columns[j][i] = matrix.m[j * 4 + i];
+ }
+ }
+
+ return true;
+}
+
+RID OpenXROpenGLExtension::get_texture(void *p_swapchain_graphics_data, int p_image_index) {
+ SwapchainGraphicsData *data = (SwapchainGraphicsData *)p_swapchain_graphics_data;
+ ERR_FAIL_NULL_V(data, RID());
+
+ ERR_FAIL_INDEX_V(p_image_index, data->texture_rids.size(), RID());
+ return data->texture_rids[p_image_index];
+}
+
+void OpenXROpenGLExtension::cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) {
+ if (*p_swapchain_graphics_data == nullptr) {
+ return;
+ }
+
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ ERR_FAIL_NULL(texture_storage);
+
+ SwapchainGraphicsData *data = (SwapchainGraphicsData *)*p_swapchain_graphics_data;
+
+ for (int i = 0; i < data->texture_rids.size(); i++) {
+ texture_storage->texture_free(data->texture_rids[i]);
+ }
+ data->texture_rids.clear();
+
+ memdelete(data);
+ *p_swapchain_graphics_data = nullptr;
+}
+
+#define ENUM_TO_STRING_CASE(e) \
+ case e: { \
+ return String(#e); \
+ } break;
+
+String OpenXROpenGLExtension::get_swapchain_format_name(int64_t p_swapchain_format) const {
+ // These are somewhat different per platform, will need to weed some stuff out...
+ switch (p_swapchain_format) {
+#ifdef WIN32
+ // using definitions from GLAD
+ ENUM_TO_STRING_CASE(GL_R8_SNORM)
+ ENUM_TO_STRING_CASE(GL_RG8_SNORM)
+ ENUM_TO_STRING_CASE(GL_RGB8_SNORM)
+ ENUM_TO_STRING_CASE(GL_RGBA8_SNORM)
+ ENUM_TO_STRING_CASE(GL_R16_SNORM)
+ ENUM_TO_STRING_CASE(GL_RG16_SNORM)
+ ENUM_TO_STRING_CASE(GL_RGB16_SNORM)
+ ENUM_TO_STRING_CASE(GL_RGBA16_SNORM)
+ ENUM_TO_STRING_CASE(GL_RGB4)
+ ENUM_TO_STRING_CASE(GL_RGB5)
+ ENUM_TO_STRING_CASE(GL_RGB8)
+ ENUM_TO_STRING_CASE(GL_RGB10)
+ ENUM_TO_STRING_CASE(GL_RGB12)
+ ENUM_TO_STRING_CASE(GL_RGB16)
+ ENUM_TO_STRING_CASE(GL_RGBA2)
+ ENUM_TO_STRING_CASE(GL_RGBA4)
+ ENUM_TO_STRING_CASE(GL_RGB5_A1)
+ ENUM_TO_STRING_CASE(GL_RGBA8)
+ ENUM_TO_STRING_CASE(GL_RGB10_A2)
+ ENUM_TO_STRING_CASE(GL_RGBA12)
+ ENUM_TO_STRING_CASE(GL_RGBA16)
+ ENUM_TO_STRING_CASE(GL_RGBA32F)
+ ENUM_TO_STRING_CASE(GL_RGB32F)
+ ENUM_TO_STRING_CASE(GL_RGBA16F)
+ ENUM_TO_STRING_CASE(GL_RGB16F)
+ ENUM_TO_STRING_CASE(GL_RGBA32UI)
+ ENUM_TO_STRING_CASE(GL_RGB32UI)
+ ENUM_TO_STRING_CASE(GL_RGBA16UI)
+ ENUM_TO_STRING_CASE(GL_RGB16UI)
+ ENUM_TO_STRING_CASE(GL_RGBA8UI)
+ ENUM_TO_STRING_CASE(GL_RGB8UI)
+ ENUM_TO_STRING_CASE(GL_RGBA32I)
+ ENUM_TO_STRING_CASE(GL_RGB32I)
+ ENUM_TO_STRING_CASE(GL_RGBA16I)
+ ENUM_TO_STRING_CASE(GL_RGB16I)
+ ENUM_TO_STRING_CASE(GL_RGBA8I)
+ ENUM_TO_STRING_CASE(GL_RGB8I)
+ ENUM_TO_STRING_CASE(GL_RGB10_A2UI)
+ ENUM_TO_STRING_CASE(GL_SRGB)
+ ENUM_TO_STRING_CASE(GL_SRGB8)
+ ENUM_TO_STRING_CASE(GL_SRGB_ALPHA)
+ ENUM_TO_STRING_CASE(GL_SRGB8_ALPHA8)
+ ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT16)
+ ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT24)
+ ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT32)
+ ENUM_TO_STRING_CASE(GL_DEPTH24_STENCIL8)
+ ENUM_TO_STRING_CASE(GL_R11F_G11F_B10F)
+ ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT32F)
+ ENUM_TO_STRING_CASE(GL_DEPTH32F_STENCIL8)
+
+#elif ANDROID_ENABLED
+ // using definitions from GLES3/gl3.h
+
+ ENUM_TO_STRING_CASE(GL_RGBA4)
+ ENUM_TO_STRING_CASE(GL_RGB5_A1)
+ ENUM_TO_STRING_CASE(GL_RGB565)
+ ENUM_TO_STRING_CASE(GL_RGB8)
+ ENUM_TO_STRING_CASE(GL_RGBA8)
+ ENUM_TO_STRING_CASE(GL_RGB10_A2)
+ ENUM_TO_STRING_CASE(GL_RGBA32F)
+ ENUM_TO_STRING_CASE(GL_RGB32F)
+ ENUM_TO_STRING_CASE(GL_RGBA16F)
+ ENUM_TO_STRING_CASE(GL_RGB16F)
+ ENUM_TO_STRING_CASE(GL_R11F_G11F_B10F)
+ ENUM_TO_STRING_CASE(GL_UNSIGNED_INT_10F_11F_11F_REV)
+ ENUM_TO_STRING_CASE(GL_RGB9_E5)
+ ENUM_TO_STRING_CASE(GL_UNSIGNED_INT_5_9_9_9_REV)
+ ENUM_TO_STRING_CASE(GL_RGBA32UI)
+ ENUM_TO_STRING_CASE(GL_RGB32UI)
+ ENUM_TO_STRING_CASE(GL_RGBA16UI)
+ ENUM_TO_STRING_CASE(GL_RGB16UI)
+ ENUM_TO_STRING_CASE(GL_RGBA8UI)
+ ENUM_TO_STRING_CASE(GL_RGB8UI)
+ ENUM_TO_STRING_CASE(GL_RGBA32I)
+ ENUM_TO_STRING_CASE(GL_RGB32I)
+ ENUM_TO_STRING_CASE(GL_RGBA16I)
+ ENUM_TO_STRING_CASE(GL_RGB16I)
+ ENUM_TO_STRING_CASE(GL_RGBA8I)
+ ENUM_TO_STRING_CASE(GL_RGB8I)
+ ENUM_TO_STRING_CASE(GL_RG)
+ ENUM_TO_STRING_CASE(GL_RG_INTEGER)
+ ENUM_TO_STRING_CASE(GL_R8)
+ ENUM_TO_STRING_CASE(GL_RG8)
+ ENUM_TO_STRING_CASE(GL_R16F)
+ ENUM_TO_STRING_CASE(GL_R32F)
+ ENUM_TO_STRING_CASE(GL_RG16F)
+ ENUM_TO_STRING_CASE(GL_RG32F)
+ ENUM_TO_STRING_CASE(GL_R8I)
+ ENUM_TO_STRING_CASE(GL_R8UI)
+ ENUM_TO_STRING_CASE(GL_R16I)
+ ENUM_TO_STRING_CASE(GL_R16UI)
+ ENUM_TO_STRING_CASE(GL_R32I)
+ ENUM_TO_STRING_CASE(GL_R32UI)
+ ENUM_TO_STRING_CASE(GL_RG8I)
+ ENUM_TO_STRING_CASE(GL_RG8UI)
+ ENUM_TO_STRING_CASE(GL_RG16I)
+ ENUM_TO_STRING_CASE(GL_RG16UI)
+ ENUM_TO_STRING_CASE(GL_RG32I)
+ ENUM_TO_STRING_CASE(GL_RG32UI)
+ ENUM_TO_STRING_CASE(GL_R8_SNORM)
+ ENUM_TO_STRING_CASE(GL_RG8_SNORM)
+ ENUM_TO_STRING_CASE(GL_RGB8_SNORM)
+ ENUM_TO_STRING_CASE(GL_RGBA8_SNORM)
+ ENUM_TO_STRING_CASE(GL_RGB10_A2UI)
+ ENUM_TO_STRING_CASE(GL_SRGB)
+ ENUM_TO_STRING_CASE(GL_SRGB8)
+ ENUM_TO_STRING_CASE(GL_SRGB8_ALPHA8)
+ ENUM_TO_STRING_CASE(GL_COMPRESSED_R11_EAC)
+ ENUM_TO_STRING_CASE(GL_COMPRESSED_SIGNED_R11_EAC)
+ ENUM_TO_STRING_CASE(GL_COMPRESSED_RG11_EAC)
+ ENUM_TO_STRING_CASE(GL_COMPRESSED_SIGNED_RG11_EAC)
+ ENUM_TO_STRING_CASE(GL_COMPRESSED_RGB8_ETC2)
+ ENUM_TO_STRING_CASE(GL_COMPRESSED_SRGB8_ETC2)
+ ENUM_TO_STRING_CASE(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2)
+ ENUM_TO_STRING_CASE(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2)
+ ENUM_TO_STRING_CASE(GL_COMPRESSED_RGBA8_ETC2_EAC)
+ ENUM_TO_STRING_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC)
+ ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT16)
+ ENUM_TO_STRING_CASE(GL_DEPTH_COMPONENT24)
+ ENUM_TO_STRING_CASE(GL_DEPTH24_STENCIL8)
+
+#else
+ // using definitions from GL/gl.h
+ ENUM_TO_STRING_CASE(GL_ALPHA4_EXT)
+ ENUM_TO_STRING_CASE(GL_ALPHA8_EXT)
+ ENUM_TO_STRING_CASE(GL_ALPHA12_EXT)
+ ENUM_TO_STRING_CASE(GL_ALPHA16_EXT)
+ ENUM_TO_STRING_CASE(GL_LUMINANCE4_EXT)
+ ENUM_TO_STRING_CASE(GL_LUMINANCE8_EXT)
+ ENUM_TO_STRING_CASE(GL_LUMINANCE12_EXT)
+ ENUM_TO_STRING_CASE(GL_LUMINANCE16_EXT)
+ ENUM_TO_STRING_CASE(GL_LUMINANCE4_ALPHA4_EXT)
+ ENUM_TO_STRING_CASE(GL_LUMINANCE6_ALPHA2_EXT)
+ ENUM_TO_STRING_CASE(GL_LUMINANCE8_ALPHA8_EXT)
+ ENUM_TO_STRING_CASE(GL_LUMINANCE12_ALPHA4_EXT)
+ ENUM_TO_STRING_CASE(GL_LUMINANCE12_ALPHA12_EXT)
+ ENUM_TO_STRING_CASE(GL_LUMINANCE16_ALPHA16_EXT)
+ ENUM_TO_STRING_CASE(GL_INTENSITY_EXT)
+ ENUM_TO_STRING_CASE(GL_INTENSITY4_EXT)
+ ENUM_TO_STRING_CASE(GL_INTENSITY8_EXT)
+ ENUM_TO_STRING_CASE(GL_INTENSITY12_EXT)
+ ENUM_TO_STRING_CASE(GL_INTENSITY16_EXT)
+ ENUM_TO_STRING_CASE(GL_RGB2_EXT)
+ ENUM_TO_STRING_CASE(GL_RGB4_EXT)
+ ENUM_TO_STRING_CASE(GL_RGB5_EXT)
+ ENUM_TO_STRING_CASE(GL_RGB8_EXT)
+ ENUM_TO_STRING_CASE(GL_RGB10_EXT)
+ ENUM_TO_STRING_CASE(GL_RGB12_EXT)
+ ENUM_TO_STRING_CASE(GL_RGB16_EXT)
+ ENUM_TO_STRING_CASE(GL_RGBA2_EXT)
+ ENUM_TO_STRING_CASE(GL_RGBA4_EXT)
+ ENUM_TO_STRING_CASE(GL_RGB5_A1_EXT)
+ ENUM_TO_STRING_CASE(GL_RGBA8_EXT)
+ ENUM_TO_STRING_CASE(GL_RGB10_A2_EXT)
+ ENUM_TO_STRING_CASE(GL_RGBA12_EXT)
+ ENUM_TO_STRING_CASE(GL_RGBA16_EXT)
+ ENUM_TO_STRING_CASE(GL_SRGB_EXT)
+ ENUM_TO_STRING_CASE(GL_SRGB8_EXT)
+ ENUM_TO_STRING_CASE(GL_SRGB_ALPHA_EXT)
+ ENUM_TO_STRING_CASE(GL_SRGB8_ALPHA8_EXT)
+#endif
+ default: {
+ return String("Swapchain format 0x") + String::num_int64(p_swapchain_format, 16);
+ } break;
+ }
+}
+
+#endif // GLES3_ENABLED
diff --git a/modules/openxr/extensions/openxr_opengl_extension.h b/modules/openxr/extensions/openxr_opengl_extension.h
new file mode 100644
index 0000000000..b666653c8e
--- /dev/null
+++ b/modules/openxr/extensions/openxr_opengl_extension.h
@@ -0,0 +1,120 @@
+/*************************************************************************/
+/* openxr_opengl_extension.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 OPENXR_OPENGL_EXTENSION_H
+#define OPENXR_OPENGL_EXTENSION_H
+
+#ifdef GLES3_ENABLED
+
+#include "core/templates/vector.h"
+#include "openxr_extension_wrapper.h"
+
+#include "../openxr_api.h"
+#include "../util.h"
+
+#ifdef ANDROID_ENABLED
+#define XR_USE_GRAPHICS_API_OPENGL_ES
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#else
+#define XR_USE_GRAPHICS_API_OPENGL
+#endif
+
+#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 X11_ENABLED
+#include OPENGL_INCLUDE_H
+#define GL_GLEXT_PROTOTYPES 1
+#define GL3_PROTOTYPES 1
+#include <GL/gl.h>
+#include <GL/glext.h>
+#include <GL/glx.h>
+#include <X11/Xlib.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 OpenXROpenGLExtension : public OpenXRGraphicsExtensionWrapper {
+public:
+ OpenXROpenGLExtension(OpenXRAPI *p_openxr_api);
+ virtual ~OpenXROpenGLExtension() override;
+
+ virtual void on_instance_created(const XrInstance p_instance) override;
+ virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override;
+
+ virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) override;
+ virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) override;
+ virtual String get_swapchain_format_name(int64_t p_swapchain_format) const override;
+ virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) override;
+ virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) override;
+ virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) override;
+ virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) override;
+
+private:
+ static OpenXROpenGLExtension *singleton;
+
+#ifdef WIN32
+ static XrGraphicsBindingOpenGLWin32KHR graphics_binding_gl;
+#elif ANDROID_ENABLED
+ static XrGraphicsBindingOpenGLESAndroidKHR graphics_binding_gl;
+#else
+ static XrGraphicsBindingOpenGLXlibKHR graphics_binding_gl;
+#endif
+
+ struct SwapchainGraphicsData {
+ bool is_multiview;
+ Vector<RID> texture_rids;
+ };
+
+ bool check_graphics_api_support(XrVersion p_desired_version);
+
+#ifdef ANDROID_ENABLED
+ EXT_PROTO_XRRESULT_FUNC3(xrGetOpenGLESGraphicsRequirementsKHR, (XrInstance), p_instance, (XrSystemId), p_system_id, (XrGraphicsRequirementsOpenGLESKHR *), p_graphics_requirements)
+#else
+ EXT_PROTO_XRRESULT_FUNC3(xrGetOpenGLGraphicsRequirementsKHR, (XrInstance), p_instance, (XrSystemId), p_system_id, (XrGraphicsRequirementsOpenGLKHR *), p_graphics_requirements)
+#endif
+ EXT_PROTO_XRRESULT_FUNC4(xrEnumerateSwapchainImages, (XrSwapchain), p_swapchain, (uint32_t), p_image_capacity_input, (uint32_t *), p_image_count_output, (XrSwapchainImageBaseHeader *), p_images)
+};
+
+#endif // GLES3_ENABLED
+
+#endif // OPENXR_OPENGL_EXTENSION_H
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 8b189cf027..88111afede 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -45,10 +45,40 @@
#include "extensions/openxr_android_extension.h"
#endif
+// We need to have all the graphics API defines before the Vulkan or OpenGL
+// extensions are included, otherwise we'll only get one graphics API.
+#ifdef VULKAN_ENABLED
+#define XR_USE_GRAPHICS_API_VULKAN
+#endif
+#ifdef GLES3_ENABLED
+#ifdef ANDROID
+#define XR_USE_GRAPHICS_API_OPENGL_ES
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#else
+#define XR_USE_GRAPHICS_API_OPENGL
+#endif // ANDROID
+#ifdef X11_ENABLED
+#include OPENGL_INCLUDE_H
+#define GL_GLEXT_PROTOTYPES 1
+#define GL3_PROTOTYPES 1
+#include <GL/gl.h>
+#include <GL/glext.h>
+#include <GL/glx.h>
+#include <X11/Xlib.h>
+#endif // X11_ENABLED
+#endif // GLES_ENABLED
+
#ifdef VULKAN_ENABLED
#include "extensions/openxr_vulkan_extension.h"
#endif
+#ifdef GLES3_ENABLED
+#include "extensions/openxr_opengl_extension.h"
+#endif
+
#include "extensions/openxr_composition_layer_depth_extension.h"
#include "extensions/openxr_fb_display_refresh_rate_extension.h"
#include "extensions/openxr_fb_passthrough_extension_wrapper.h"
@@ -1142,9 +1172,8 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) {
#endif
} else if (p_rendering_driver == "opengl3") {
#ifdef GLES3_ENABLED
- // graphics_extension = memnew(OpenXROpenGLExtension(this));
- // register_extension_wrapper(graphics_extension);
- ERR_FAIL_V_MSG(false, "OpenXR: OpenGL is not supported at this time.");
+ graphics_extension = memnew(OpenXROpenGLExtension(this));
+ register_extension_wrapper(graphics_extension);
#else
// shouldn't be possible...
ERR_FAIL_V(false);
diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp
index be6b7e4411..77660eb6f0 100644
--- a/modules/openxr/openxr_interface.cpp
+++ b/modules/openxr/openxr_interface.cpp
@@ -666,6 +666,7 @@ Transform3D OpenXRInterface::get_camera_transform() {
Transform3D OpenXRInterface::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, Transform3D());
+ ERR_FAIL_UNSIGNED_INDEX_V_MSG(p_view, get_view_count(), Transform3D(), "View index outside bounds.");
Transform3D t;
if (openxr_api && openxr_api->get_view_transform(p_view, t)) {
@@ -685,6 +686,7 @@ Transform3D OpenXRInterface::get_transform_for_view(uint32_t p_view, const Trans
Projection OpenXRInterface::get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) {
Projection cm;
+ ERR_FAIL_UNSIGNED_INDEX_V_MSG(p_view, get_view_count(), cm, "View index outside bounds.");
if (openxr_api) {
if (openxr_api->get_view_projection(p_view, p_z_near, p_z_far, cm)) {
diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp
index 3bd132bc73..eea015e486 100644
--- a/modules/websocket/emws_peer.cpp
+++ b/modules/websocket/emws_peer.cpp
@@ -95,6 +95,10 @@ Error EMWSPeer::connect_to_url(const String &p_url, bool p_verify_tls, Ref<X509C
requested_url += ":" + String::num(port);
}
+ if (!path.is_empty()) {
+ requested_url += path;
+ }
+
peer_sock = godot_js_websocket_create(this, requested_url.utf8().get_data(), proto_string.utf8().get_data(), &_esws_on_connect, &_esws_on_message, &_esws_on_error, &_esws_on_close);
if (peer_sock == -1) {
return FAILED;
diff --git a/modules/zip/zip_packer.cpp b/modules/zip/zip_packer.cpp
index e62700f191..5566848087 100644
--- a/modules/zip/zip_packer.cpp
+++ b/modules/zip/zip_packer.cpp
@@ -46,7 +46,11 @@ Error ZIPPacker::open(String p_path, ZipAppend p_append) {
Error ZIPPacker::close() {
ERR_FAIL_COND_V_MSG(fa.is_null(), FAILED, "ZIPPacker cannot be closed because it is not open.");
- return zipClose(zf, NULL) == ZIP_OK ? OK : FAILED;
+ Error err = zipClose(zf, NULL) == ZIP_OK ? OK : FAILED;
+ if (err == OK) {
+ zf = NULL;
+ }
+ return err;
}
Error ZIPPacker::start_file(String p_path) {
@@ -79,11 +83,7 @@ Error ZIPPacker::write_file(Vector<uint8_t> p_data) {
Error ZIPPacker::close_file() {
ERR_FAIL_COND_V_MSG(fa.is_null(), FAILED, "ZIPPacker must be opened before use.");
- Error err = zipCloseFileInZip(zf) == ZIP_OK ? OK : FAILED;
- if (err == OK) {
- zf = NULL;
- }
- return err;
+ return zipCloseFileInZip(zf) == ZIP_OK ? OK : FAILED;
}
void ZIPPacker::_bind_methods() {
diff --git a/platform/android/android_keys_utils.h b/platform/android/android_keys_utils.h
index 5ec3ee17aa..bc633aeade 100644
--- a/platform/android/android_keys_utils.h
+++ b/platform/android/android_keys_utils.h
@@ -43,7 +43,6 @@ struct AndroidGodotCodePair {
static AndroidGodotCodePair android_godot_code_pairs[] = {
{ AKEYCODE_UNKNOWN, Key::UNKNOWN }, // (0) Unknown key code.
- { AKEYCODE_HOME, Key::HOME }, // (3) Home key.
{ AKEYCODE_BACK, Key::BACK }, // (4) Back key.
{ AKEYCODE_0, Key::KEY_0 }, // (7) '0' key.
{ AKEYCODE_1, Key::KEY_1 }, // (8) '1' key.
@@ -63,6 +62,7 @@ static AndroidGodotCodePair android_godot_code_pairs[] = {
{ AKEYCODE_DPAD_RIGHT, Key::RIGHT }, // (22) Directional Pad Right key.
{ AKEYCODE_VOLUME_UP, Key::VOLUMEUP }, // (24) Volume Up key.
{ AKEYCODE_VOLUME_DOWN, Key::VOLUMEDOWN }, // (25) Volume Down key.
+ { AKEYCODE_POWER, Key::STANDBY }, // (26) Power key.
{ AKEYCODE_CLEAR, Key::CLEAR }, // (28) Clear key.
{ AKEYCODE_A, Key::A }, // (29) 'A' key.
{ AKEYCODE_B, Key::B }, // (30) 'B' key.
@@ -98,6 +98,7 @@ static AndroidGodotCodePair android_godot_code_pairs[] = {
{ AKEYCODE_SHIFT_RIGHT, Key::SHIFT }, // (60) Right Shift modifier key.
{ AKEYCODE_TAB, Key::TAB }, // (61) Tab key.
{ AKEYCODE_SPACE, Key::SPACE }, // (62) Space key.
+ { AKEYCODE_ENVELOPE, Key::LAUNCHMAIL }, // (65) Envelope special function key.
{ AKEYCODE_ENTER, Key::ENTER }, // (66) Enter key.
{ AKEYCODE_DEL, Key::BACKSPACE }, // (67) Backspace key.
{ AKEYCODE_GRAVE, Key::QUOTELEFT }, // (68) '`' (backtick) key.
@@ -114,6 +115,7 @@ static AndroidGodotCodePair android_godot_code_pairs[] = {
{ AKEYCODE_MENU, Key::MENU }, // (82) Menu key.
{ AKEYCODE_SEARCH, Key::SEARCH }, // (84) Search key.
{ AKEYCODE_MEDIA_STOP, Key::MEDIASTOP }, // (86) Stop media key.
+ { AKEYCODE_MEDIA_NEXT, Key::MEDIANEXT }, // (87) Play Next media key.
{ AKEYCODE_MEDIA_PREVIOUS, Key::MEDIAPREVIOUS }, // (88) Play Previous media key.
{ AKEYCODE_PAGE_UP, Key::PAGEUP }, // (92) Page Up key.
{ AKEYCODE_PAGE_DOWN, Key::PAGEDOWN }, // (93) Page Down key.
@@ -127,6 +129,8 @@ static AndroidGodotCodePair android_godot_code_pairs[] = {
{ AKEYCODE_META_RIGHT, Key::META }, // (118) Right Meta modifier key.
{ AKEYCODE_SYSRQ, Key::PRINT }, // (120) System Request / Print Screen key.
{ AKEYCODE_BREAK, Key::PAUSE }, // (121) Break / Pause key.
+ { AKEYCODE_MOVE_HOME, Key::HOME }, // (122) Home Movement key.
+ { AKEYCODE_MOVE_END, Key::END }, // (123) End Movement key.
{ AKEYCODE_INSERT, Key::INSERT }, // (124) Insert key.
{ AKEYCODE_FORWARD, Key::FORWARD }, // (125) Forward key.
{ AKEYCODE_MEDIA_PLAY, Key::MEDIAPLAY }, // (126) Play media key.
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index 08369e735d..967f5c7dae 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -321,6 +321,11 @@ int64_t DisplayServerAndroid::window_get_native_handle(HandleType p_handle_type,
case WINDOW_VIEW: {
return 0; // Not supported.
}
+#ifdef GLES3_ENABLED
+ case OPENGL_CONTEXT: {
+ return eglGetCurrentContext();
+ }
+#endif
default: {
return 0;
}
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 3bfdd3b881..9919268375 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -585,12 +585,13 @@ zip_fileinfo EditorExportPlatformAndroid::get_zip_fileinfo() {
return zipfi;
}
-Vector<String> EditorExportPlatformAndroid::get_abis() {
- Vector<String> abis;
- abis.push_back("armeabi-v7a");
- abis.push_back("arm64-v8a");
- abis.push_back("x86");
- abis.push_back("x86_64");
+Vector<EditorExportPlatformAndroid::ABI> EditorExportPlatformAndroid::get_abis() {
+ // Should have the same order and size as get_archs.
+ Vector<ABI> abis;
+ abis.push_back(ABI("armeabi-v7a", "arm32"));
+ abis.push_back(ABI("arm64-v8a", "arm64"));
+ abis.push_back(ABI("x86", "x86_32"));
+ abis.push_back(ABI("x86_64", "x86_64"));
return abis;
}
@@ -687,14 +688,20 @@ Error EditorExportPlatformAndroid::save_apk_so(void *p_userdata, const SharedObj
return FAILED;
}
APKExportData *ed = static_cast<APKExportData *>(p_userdata);
- Vector<String> abis = get_abis();
+ Vector<ABI> abis = get_abis();
bool exported = false;
for (int i = 0; i < p_so.tags.size(); ++i) {
// shared objects can be fat (compatible with multiple ABIs)
- int abi_index = abis.find(p_so.tags[i]);
+ int abi_index = -1;
+ for (int j = 0; j < abis.size(); ++j) {
+ if (abis[j].abi == p_so.tags[i] || abis[j].arch == p_so.tags[i]) {
+ abi_index = j;
+ break;
+ }
+ }
if (abi_index != -1) {
exported = true;
- String abi = abis[abi_index];
+ String abi = abis[abi_index].abi;
String dst_path = String("lib").path_join(abi).path_join(p_so.path.get_file());
Vector<uint8_t> array = FileAccess::get_file_as_array(p_so.path);
Error store_err = store_in_apk(ed, dst_path, array);
@@ -702,9 +709,7 @@ Error EditorExportPlatformAndroid::save_apk_so(void *p_userdata, const SharedObj
}
}
if (!exported) {
- String abis_string = String(" ").join(abis);
- String err = "Cannot determine ABI for library \"" + p_so.path + "\". One of the supported ABIs must be used as a tag: " + abis_string;
- ERR_PRINT(err);
+ ERR_PRINT("Cannot determine architecture for library \"" + p_so.path + "\". One of the supported architectures must be used as a tag: " + join_abis(abis, " ", true));
return FAILED;
}
return OK;
@@ -725,16 +730,22 @@ Error EditorExportPlatformAndroid::ignore_apk_file(void *p_userdata, const Strin
Error EditorExportPlatformAndroid::copy_gradle_so(void *p_userdata, const SharedObject &p_so) {
ERR_FAIL_COND_V_MSG(!p_so.path.get_file().begins_with("lib"), FAILED,
"Android .so file names must start with \"lib\", but got: " + p_so.path);
- Vector<String> abis = get_abis();
+ Vector<ABI> abis = get_abis();
CustomExportData *export_data = static_cast<CustomExportData *>(p_userdata);
bool exported = false;
for (int i = 0; i < p_so.tags.size(); ++i) {
- int abi_index = abis.find(p_so.tags[i]);
+ int abi_index = -1;
+ for (int j = 0; j < abis.size(); ++j) {
+ if (abis[j].abi == p_so.tags[i] || abis[j].arch == p_so.tags[i]) {
+ abi_index = j;
+ break;
+ }
+ }
if (abi_index != -1) {
exported = true;
String base = "res://android/build/libs";
String type = export_data->debug ? "debug" : "release";
- String abi = abis[abi_index];
+ String abi = abis[abi_index].abi;
String filename = p_so.path.get_file();
String dst_path = base.path_join(type).path_join(abi).path_join(filename);
Vector<uint8_t> data = FileAccess::get_file_as_array(p_so.path);
@@ -745,7 +756,7 @@ Error EditorExportPlatformAndroid::copy_gradle_so(void *p_userdata, const Shared
}
}
ERR_FAIL_COND_V_MSG(!exported, FAILED,
- "Cannot determine ABI for library \"" + p_so.path + "\". One of the supported ABIs must be used as a tag: " + String(" ").join(abis));
+ "Cannot determine architecture for library \"" + p_so.path + "\". One of the supported architectures must be used as a tag:" + join_abis(abis, " ", true));
return OK;
}
@@ -1656,11 +1667,11 @@ void EditorExportPlatformAndroid::_copy_icons_to_gradle_project(const Ref<Editor
}
}
-Vector<String> EditorExportPlatformAndroid::get_enabled_abis(const Ref<EditorExportPreset> &p_preset) {
- Vector<String> abis = get_abis();
- Vector<String> enabled_abis;
+Vector<EditorExportPlatformAndroid::ABI> EditorExportPlatformAndroid::get_enabled_abis(const Ref<EditorExportPreset> &p_preset) {
+ Vector<ABI> abis = get_abis();
+ Vector<ABI> enabled_abis;
for (int i = 0; i < abis.size(); ++i) {
- bool is_enabled = p_preset->get("architectures/" + abis[i]);
+ bool is_enabled = p_preset->get("architectures/" + abis[i].abi);
if (is_enabled) {
enabled_abis.push_back(abis[i]);
}
@@ -1671,9 +1682,10 @@ Vector<String> EditorExportPlatformAndroid::get_enabled_abis(const Ref<EditorExp
void EditorExportPlatformAndroid::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const {
r_features->push_back("etc2");
- Vector<String> abis = get_enabled_abis(p_preset);
+ Vector<ABI> abis = get_enabled_abis(p_preset);
for (int i = 0; i < abis.size(); ++i) {
- r_features->push_back(abis[i]);
+ r_features->push_back(abis[i].arch);
+ r_features->push_back(abis[i].abi);
}
}
@@ -1697,9 +1709,9 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
// Android supports multiple architectures in an app bundle, so
// we expose each option as a checkbox in the export dialog.
- const Vector<String> abis = get_abis();
+ const Vector<ABI> abis = get_abis();
for (int i = 0; i < abis.size(); ++i) {
- const String abi = abis[i];
+ const String abi = abis[i].abi;
// All Android devices supporting Vulkan run 64-bit Android,
// so there is usually no point in exporting for 32-bit Android.
const bool is_default = abi == "arm64-v8a";
@@ -2516,13 +2528,24 @@ void EditorExportPlatformAndroid::_remove_copied_libs() {
da->remove(GDNATIVE_LIBS_PATH);
}
-String EditorExportPlatformAndroid::join_list(List<String> parts, const String &separator) const {
+String EditorExportPlatformAndroid::join_list(const List<String> &p_parts, const String &p_separator) {
+ String ret;
+ for (int i = 0; i < p_parts.size(); ++i) {
+ if (i > 0) {
+ ret += p_separator;
+ }
+ ret += p_parts[i];
+ }
+ return ret;
+}
+
+String EditorExportPlatformAndroid::join_abis(const Vector<EditorExportPlatformAndroid::ABI> &p_parts, const String &p_separator, bool p_use_arch) {
String ret;
- for (int i = 0; i < parts.size(); ++i) {
+ for (int i = 0; i < p_parts.size(); ++i) {
if (i > 0) {
- ret += separator;
+ ret += p_separator;
}
- ret += parts[i];
+ ret += (p_use_arch) ? p_parts[i].arch : p_parts[i].abi;
}
return ret;
}
@@ -2544,7 +2567,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
bool use_custom_build = bool(p_preset->get("custom_build/use_custom_build"));
bool p_give_internet = p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG);
bool apk_expansion = p_preset->get("apk_expansion/enable");
- Vector<String> enabled_abis = get_enabled_abis(p_preset);
+ Vector<ABI> enabled_abis = get_enabled_abis(p_preset);
print_verbose("Exporting for Android...");
print_verbose("- debug build: " + bool_to_string(p_debug));
@@ -2553,7 +2576,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
print_verbose("- sign build: " + bool_to_string(should_sign));
print_verbose("- custom build enabled: " + bool_to_string(use_custom_build));
print_verbose("- apk expansion enabled: " + bool_to_string(apk_expansion));
- print_verbose("- enabled abis: " + String(",").join(enabled_abis));
+ print_verbose("- enabled abis: " + join_abis(enabled_abis, ",", false));
print_verbose("- export filter: " + itos(p_preset->get_export_filter()));
print_verbose("- include filter: " + p_preset->get_include_filter());
print_verbose("- exclude filter: " + p_preset->get_exclude_filter());
@@ -2676,7 +2699,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
if (!target_sdk_version.is_valid_int()) {
target_sdk_version = itos(DEFAULT_TARGET_SDK_VERSION);
}
- String enabled_abi_string = String("|").join(enabled_abis);
+ String enabled_abi_string = join_abis(enabled_abis, "|", false);
String sign_flag = should_sign ? "true" : "false";
String zipalign_flag = "true";
@@ -2861,7 +2884,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
String apk_expansion_pkey = p_preset->get("apk_expansion/public_key");
- Vector<String> invalid_abis(enabled_abis);
+ Vector<ABI> invalid_abis(enabled_abis);
while (ret == UNZ_OK) {
//get filename
unz_file_info info;
@@ -2924,7 +2947,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
if (file.ends_with(".so")) {
bool enabled = false;
for (int i = 0; i < enabled_abis.size(); ++i) {
- if (file.begins_with("lib/" + enabled_abis[i] + "/")) {
+ if (file.begins_with("lib/" + enabled_abis[i].abi + "/")) {
invalid_abis.erase(enabled_abis[i]);
enabled = true;
break;
@@ -2966,8 +2989,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
}
if (!invalid_abis.is_empty()) {
- String unsupported_arch = String(", ").join(invalid_abis);
- add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Missing libraries in the export template for the selected architectures: %s. Please build a template with all required libraries, or uncheck the missing architectures in the export preset."), unsupported_arch));
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Missing libraries in the export template for the selected architectures: %s. Please build a template with all required libraries, or uncheck the missing architectures in the export preset."), join_abis(invalid_abis, ", ", false)));
CLEANUP_AND_RETURN(ERR_FILE_NOT_FOUND);
}
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
index 46012bd46c..c8fcb761fe 100644
--- a/platform/android/export/export_plugin.h
+++ b/platform/android/export/export_plugin.h
@@ -99,7 +99,22 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
static zip_fileinfo get_zip_fileinfo();
- static Vector<String> get_abis();
+ struct ABI {
+ String abi;
+ String arch;
+
+ bool operator==(const ABI &p_a) const {
+ return p_a.abi == abi;
+ }
+
+ ABI(const String &p_abi, const String &p_arch) {
+ abi = p_abi;
+ arch = p_arch;
+ }
+ ABI() {}
+ };
+
+ static Vector<ABI> get_abis();
/// List the gdap files in the directory specified by the p_path parameter.
static Vector<String> list_gdap_files(const String &p_path);
@@ -152,7 +167,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
const Ref<Image> &foreground,
const Ref<Image> &background);
- static Vector<String> get_enabled_abis(const Ref<EditorExportPreset> &p_preset);
+ static Vector<ABI> get_enabled_abis(const Ref<EditorExportPreset> &p_preset);
public:
typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
@@ -228,7 +243,8 @@ public:
void _remove_copied_libs();
- String join_list(List<String> parts, const String &separator) const;
+ static String join_list(const List<String> &p_parts, const String &p_separator);
+ static String join_abis(const Vector<ABI> &p_parts, const String &p_separator, bool p_use_arch);
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle
index 0346625e4b..e1d9dc4cde 100644
--- a/platform/android/java/app/config.gradle
+++ b/platform/android/java/app/config.gradle
@@ -1,10 +1,10 @@
ext.versions = [
- androidGradlePlugin: '7.0.3',
+ androidGradlePlugin: '7.2.1',
compileSdk : 32,
- minSdk : 19, // Also update 'platform/android/java/lib/AndroidManifest.xml#minSdkVersion' & 'platform/android/export/export_plugin.cpp#DEFAULT_MIN_SDK_VERSION'
- targetSdk : 32, // Also update 'platform/android/java/lib/AndroidManifest.xml#targetSdkVersion' & 'platform/android/export/export_plugin.cpp#DEFAULT_TARGET_SDK_VERSION'
+ minSdk : 19, // Also update 'platform/android/export/export_plugin.cpp#DEFAULT_MIN_SDK_VERSION'
+ targetSdk : 32, // Also update 'platform/android/export/export_plugin.cpp#DEFAULT_TARGET_SDK_VERSION'
buildTools : '32.0.0',
- kotlinVersion : '1.6.21',
+ kotlinVersion : '1.7.0',
fragmentVersion : '1.3.6',
nexusPublishVersion: '1.1.0',
javaVersion : 11,
diff --git a/platform/android/java/gradle/wrapper/gradle-wrapper.properties b/platform/android/java/gradle/wrapper/gradle-wrapper.properties
index ffed3a254e..41dfb87909 100644
--- a/platform/android/java/gradle/wrapper/gradle-wrapper.properties
+++ b/platform/android/java/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/platform/android/java/lib/AndroidManifest.xml b/platform/android/java/lib/AndroidManifest.xml
index 79b5aadf2a..1f77e2fc34 100644
--- a/platform/android/java/lib/AndroidManifest.xml
+++ b/platform/android/java/lib/AndroidManifest.xml
@@ -4,9 +4,6 @@
android:versionCode="1"
android:versionName="1.0">
- <!-- Should match the mindSdk and targetSdk values in platform/android/java/app/config.gradle -->
- <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="32" />
-
<application>
<!-- Records the version of the Godot library -->
diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle
index c9e2a5d7d2..841656a240 100644
--- a/platform/android/java/lib/build.gradle
+++ b/platform/android/java/lib/build.gradle
@@ -176,11 +176,10 @@ android {
}
}
- // TODO: Enable when issues with AGP 7.1+ are resolved (https://github.com/GodotVR/godot_openxr/issues/187).
-// publishing {
-// singleVariant("templateRelease") {
-// withSourcesJar()
-// withJavadocJar()
-// }
-// }
+ publishing {
+ singleVariant("templateRelease") {
+ withSourcesJar()
+ withJavadocJar()
+ }
+ }
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
index 7925b54fc4..804dbaf165 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
@@ -127,7 +127,9 @@ public class GodotEditText extends EditText {
edit.setText("");
edit.append(text);
if (msg.arg2 != -1) {
- edit.setSelection(msg.arg1, msg.arg2);
+ int selectionStart = Math.min(msg.arg1, edit.length());
+ int selectionEnd = Math.min(msg.arg2, edit.length());
+ edit.setSelection(selectionStart, selectionEnd);
edit.mInputWrapper.setSelection(true);
} else {
edit.mInputWrapper.setSelection(false);
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
index a7a57621de..cde8d7cdae 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
@@ -77,7 +77,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
}
private fun contextClickRouter(event: MotionEvent) {
- if (scaleInProgress) {
+ if (scaleInProgress || nextDownIsDoubleTap) {
return
}
@@ -134,40 +134,24 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
}
private fun onActionUp(event: MotionEvent): Boolean {
+ if (event.actionMasked == MotionEvent.ACTION_CANCEL && pointerCaptureInProgress) {
+ // Don't dispatch the ACTION_CANCEL while a capture is in progress
+ return true
+ }
+
val sourceMouseRelative = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)
} else {
false
}
- when {
- pointerCaptureInProgress -> {
- return if (event.actionMasked == MotionEvent.ACTION_CANCEL) {
- // Don't dispatch the ACTION_CANCEL while a capture is in progress
- true
- } else {
- GodotInputHandler.handleMouseEvent(
- MotionEvent.ACTION_UP,
- event.buttonState,
- event.x,
- event.y,
- 0f,
- 0f,
- false,
- sourceMouseRelative
- )
- pointerCaptureInProgress = false
- true
- }
- }
- dragInProgress -> {
- GodotInputHandler.handleMotionEvent(event)
- dragInProgress = false
- return true
- }
- contextClickInProgress -> {
+
+ if (pointerCaptureInProgress || dragInProgress || contextClickInProgress) {
+ if (contextClickInProgress || GodotInputHandler.isMouseEvent(event)) {
+ // This may be an ACTION_BUTTON_RELEASE event which we don't handle,
+ // so we convert it to an ACTION_UP event.
GodotInputHandler.handleMouseEvent(
- event.actionMasked,
- 0,
+ MotionEvent.ACTION_UP,
+ event.buttonState,
event.x,
event.y,
0f,
@@ -175,11 +159,16 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
false,
sourceMouseRelative
)
- contextClickInProgress = false
- return true
+ } else {
+ GodotInputHandler.handleTouchEvent(event)
}
- else -> return false
+ pointerCaptureInProgress = false
+ dragInProgress = false
+ contextClickInProgress = false
+ return true
}
+
+ return false
}
private fun onActionMove(event: MotionEvent): Boolean {
@@ -242,7 +231,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
val x = terminusEvent.x
val y = terminusEvent.y
- if (terminusEvent.pointerCount >= 2 && panningAndScalingEnabled) {
+ if (terminusEvent.pointerCount >= 2 && panningAndScalingEnabled && !pointerCaptureInProgress) {
GodotLib.pan(x, y, distanceX / 5f, distanceY / 5f)
} else {
GodotInputHandler.handleMotionEvent(terminusEvent)
@@ -251,7 +240,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
}
override fun onScale(detector: ScaleGestureDetector?): Boolean {
- if (detector == null || !panningAndScalingEnabled) {
+ if (detector == null || !panningAndScalingEnabled || pointerCaptureInProgress) {
return false
}
GodotLib.magnify(
@@ -263,7 +252,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
}
override fun onScaleBegin(detector: ScaleGestureDetector?): Boolean {
- if (detector == null || !panningAndScalingEnabled) {
+ if (detector == null || !panningAndScalingEnabled || pointerCaptureInProgress) {
return false
}
scaleInProgress = true
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index d2f3c5aed2..2f26497cc8 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
@@ -245,7 +245,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
return true;
}
- } else if (isMouseEvent(event)) {
+ } else {
return handleMouseEvent(event);
}
@@ -473,6 +473,9 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative) {
+ // We don't handle ACTION_BUTTON_PRESS and ACTION_BUTTON_RELEASE events as they typically
+ // follow ACTION_DOWN and ACTION_UP events. As such, handling them would result in duplicate
+ // stream of events to the engine.
switch (eventAction) {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
diff --git a/platform/android/java_godot_view_wrapper.cpp b/platform/android/java_godot_view_wrapper.cpp
index 762840a4b1..378a467772 100644
--- a/platform/android/java_godot_view_wrapper.cpp
+++ b/platform/android/java_godot_view_wrapper.cpp
@@ -68,7 +68,7 @@ void GodotJavaViewWrapper::request_pointer_capture() {
}
void GodotJavaViewWrapper::release_pointer_capture() {
- if (_request_pointer_capture != nullptr) {
+ if (_release_pointer_capture != nullptr) {
JNIEnv *env = get_jni_env();
ERR_FAIL_NULL(env);
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 4469c7a0f7..97fa90b1d2 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -162,11 +162,16 @@ Vector<String> OS_Android::get_granted_permissions() const {
}
Error OS_Android::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
- p_library_handle = dlopen(p_path.utf8().get_data(), RTLD_NOW);
+ String path = p_path;
+ if (!FileAccess::exists(path)) {
+ path = p_path.get_file();
+ }
+
+ p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + dlerror() + ".");
if (r_resolved_path != nullptr) {
- *r_resolved_path = p_path;
+ *r_resolved_path = path;
}
return OK;
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index 8808d8e842..6793b40dd4 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -227,7 +227,7 @@ void DisplayServerIOS::_window_callback(const Callable &p_callable, const Varian
// MARK: Touches
void DisplayServerIOS::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click) {
- if (!GLOBAL_DEF("debug/disable_touch", false)) {
+ if (!GLOBAL_GET("debug/disable_touch")) {
Ref<InputEventScreenTouch> ev;
ev.instantiate();
@@ -240,7 +240,7 @@ void DisplayServerIOS::touch_press(int p_idx, int p_x, int p_y, bool p_pressed,
}
void DisplayServerIOS::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y) {
- if (!GLOBAL_DEF("debug/disable_touch", false)) {
+ if (!GLOBAL_GET("debug/disable_touch")) {
Ref<InputEventScreenDrag> ev;
ev.instantiate();
ev->set_index(p_idx);
diff --git a/platform/linuxbsd/x11/detect_prime_x11.cpp b/platform/linuxbsd/x11/detect_prime_x11.cpp
index fb833ab5e6..78a10fa2b0 100644
--- a/platform/linuxbsd/x11/detect_prime_x11.cpp
+++ b/platform/linuxbsd/x11/detect_prime_x11.cpp
@@ -208,7 +208,10 @@ int detect_prime() {
print_verbose("Couldn't write vendor/renderer string.");
}
close(fdset[1]);
- exit(0);
+
+ // The function quick_exit() is used because exit() will call destructors on static objects copied by fork().
+ // These objects will be freed anyway when the process finishes execution.
+ quick_exit(0);
}
}
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index f477787771..b86bc10643 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -376,10 +376,18 @@ void DisplayServerX11::mouse_set_mode(MouseMode p_mode) {
}
// The only modes that show a cursor are VISIBLE and CONFINED
- bool showCursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED);
+ bool show_cursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED);
+ bool previously_shown = (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED);
+
+ if (show_cursor && !previously_shown) {
+ WindowID window_id = get_window_at_screen_position(mouse_get_position());
+ if (window_id != INVALID_WINDOW_ID) {
+ _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
+ }
+ }
for (const KeyValue<WindowID, WindowData> &E : windows) {
- if (showCursor) {
+ if (show_cursor) {
XDefineCursor(x11_display, E.value.x11_window, cursors[current_cursor]); // show cursor
} else {
XDefineCursor(x11_display, E.value.x11_window, null_cursor); // hide cursor
@@ -1309,6 +1317,14 @@ int64_t DisplayServerX11::window_get_native_handle(HandleType p_handle_type, Win
case WINDOW_VIEW: {
return 0; // Not supported.
}
+#ifdef GLES3_ENABLED
+ case OPENGL_CONTEXT: {
+ if (gl_manager) {
+ return (int64_t)gl_manager->get_glx_context(p_window);
+ }
+ return 0;
+ }
+#endif
default: {
return 0;
}
diff --git a/platform/linuxbsd/x11/gl_manager_x11.cpp b/platform/linuxbsd/x11/gl_manager_x11.cpp
index f586c57dda..893a22e75e 100644
--- a/platform/linuxbsd/x11/gl_manager_x11.cpp
+++ b/platform/linuxbsd/x11/gl_manager_x11.cpp
@@ -376,6 +376,17 @@ bool GLManager_X11::is_using_vsync() const {
return use_vsync;
}
+void *GLManager_X11::get_glx_context(DisplayServer::WindowID p_window_id) {
+ if (p_window_id == -1) {
+ return nullptr;
+ }
+
+ const GLWindow &win = _windows[p_window_id];
+ const GLDisplay &disp = get_display(win.gldisplay_id);
+
+ return (void *)disp.context->glx_context;
+}
+
GLManager_X11::GLManager_X11(const Vector2i &p_size, ContextType p_context_type) {
context_type = p_context_type;
diff --git a/platform/linuxbsd/x11/gl_manager_x11.h b/platform/linuxbsd/x11/gl_manager_x11.h
index 4f78c45c88..1594c82801 100644
--- a/platform/linuxbsd/x11/gl_manager_x11.h
+++ b/platform/linuxbsd/x11/gl_manager_x11.h
@@ -116,6 +116,8 @@ public:
void set_use_vsync(bool p_use);
bool is_using_vsync() const;
+ void *get_glx_context(DisplayServer::WindowID p_window_id);
+
GLManager_X11(const Vector2i &p_size, ContextType p_context_type);
~GLManager_X11();
};
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index 618da6b388..8e75b98302 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -106,6 +106,7 @@ public:
bool layered_window = false;
bool fullscreen = false;
+ bool exclusive_fullscreen = false;
bool on_top = false;
bool borderless = false;
bool resize_disabled = false;
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 4478a635a8..42a984a4eb 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -1843,11 +1843,22 @@ void DisplayServerMacOS::mouse_set_mode(MouseMode p_mode) {
window_id = MAIN_WINDOW_ID;
}
WindowData &wd = windows[window_id];
+
+ bool show_cursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED);
+ bool previously_shown = (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED);
+
+ if (show_cursor && !previously_shown) {
+ WindowID window_id = get_window_at_screen_position(mouse_get_position());
+ if (window_id != INVALID_WINDOW_ID) {
+ send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
+ }
+ }
+
if (p_mode == MOUSE_MODE_CAPTURED) {
// Apple Docs state that the display parameter is not used.
// "This parameter is not used. By default, you may pass kCGDirectMainDisplay."
// https://developer.apple.com/library/mac/documentation/graphicsimaging/reference/Quartz_Services_Ref/Reference/reference.html
- if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
+ if (previously_shown) {
CGDisplayHideCursor(kCGDirectMainDisplay);
}
CGAssociateMouseAndMouseCursorPosition(false);
@@ -1858,7 +1869,7 @@ void DisplayServerMacOS::mouse_set_mode(MouseMode p_mode) {
CGPoint lMouseWarpPos = { pointOnScreen.x, CGDisplayBounds(CGMainDisplayID()).size.height - pointOnScreen.y };
CGWarpMouseCursorPosition(lMouseWarpPos);
} else if (p_mode == MOUSE_MODE_HIDDEN) {
- if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
+ if (previously_shown) {
CGDisplayHideCursor(kCGDirectMainDisplay);
}
[wd.window_object setMovable:YES];
@@ -1868,7 +1879,7 @@ void DisplayServerMacOS::mouse_set_mode(MouseMode p_mode) {
[wd.window_object setMovable:NO];
CGAssociateMouseAndMouseCursorPosition(false);
} else if (p_mode == MOUSE_MODE_CONFINED_HIDDEN) {
- if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
+ if (previously_shown) {
CGDisplayHideCursor(kCGDirectMainDisplay);
}
[wd.window_object setMovable:NO];
@@ -1884,7 +1895,7 @@ void DisplayServerMacOS::mouse_set_mode(MouseMode p_mode) {
warp_events.clear();
mouse_mode = p_mode;
- if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
+ if (show_cursor) {
cursor_update_shape();
}
}
@@ -2573,7 +2584,13 @@ void DisplayServerMacOS::window_set_mode(WindowMode p_mode, WindowID p_window) {
[wd.window_object setContentMaxSize:NSMakeSize(size.x, size.y)];
}
[wd.window_object toggleFullScreen:nil];
+
+ if (old_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
+ [NSApp setPresentationOptions:NSApplicationPresentationDefault];
+ }
+
wd.fullscreen = false;
+ wd.exclusive_fullscreen = false;
} break;
case WINDOW_MODE_MAXIMIZED: {
if ([wd.window_object isZoomed]) {
@@ -2598,7 +2615,15 @@ void DisplayServerMacOS::window_set_mode(WindowMode p_mode, WindowID p_window) {
[wd.window_object setContentMinSize:NSMakeSize(0, 0)];
[wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
[wd.window_object toggleFullScreen:nil];
+
wd.fullscreen = true;
+ if (p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
+ const NSUInteger presentationOptions = NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar;
+ [NSApp setPresentationOptions:presentationOptions];
+ wd.exclusive_fullscreen = true;
+ } else {
+ wd.exclusive_fullscreen = false;
+ }
} break;
case WINDOW_MODE_MAXIMIZED: {
if (![wd.window_object isZoomed]) {
@@ -2615,7 +2640,11 @@ DisplayServer::WindowMode DisplayServerMacOS::window_get_mode(WindowID p_window)
const WindowData &wd = windows[p_window];
if (wd.fullscreen) { // If fullscreen, it's not in another mode.
- return WINDOW_MODE_FULLSCREEN;
+ if (wd.exclusive_fullscreen) {
+ return WINDOW_MODE_EXCLUSIVE_FULLSCREEN;
+ } else {
+ return WINDOW_MODE_FULLSCREEN;
+ }
}
if ([wd.window_object isZoomed] && !wd.resize_disabled) {
return WINDOW_MODE_MAXIMIZED;
@@ -2932,6 +2961,14 @@ int64_t DisplayServerMacOS::window_get_native_handle(HandleType p_handle_type, W
case WINDOW_VIEW: {
return (int64_t)windows[p_window].window_view;
}
+#ifdef GLES3_ENABLED
+ case OPENGL_CONTEXT: {
+ if (gl_manager) {
+ return (int64_t)gl_manager->get_context(p_window);
+ }
+ return 0;
+ }
+#endif
default: {
return 0;
}
diff --git a/platform/macos/gl_manager_macos_legacy.h b/platform/macos/gl_manager_macos_legacy.h
index 8752086551..d7ad5b1197 100644
--- a/platform/macos/gl_manager_macos_legacy.h
+++ b/platform/macos/gl_manager_macos_legacy.h
@@ -89,6 +89,8 @@ public:
void set_use_vsync(bool p_use);
bool is_using_vsync() const;
+ NSOpenGLContext *get_context(DisplayServer::WindowID p_window_id);
+
GLManager_MacOS(ContextType p_context_type);
~GLManager_MacOS();
};
diff --git a/platform/macos/gl_manager_macos_legacy.mm b/platform/macos/gl_manager_macos_legacy.mm
index dec4821b86..ea5c36da6c 100644
--- a/platform/macos/gl_manager_macos_legacy.mm
+++ b/platform/macos/gl_manager_macos_legacy.mm
@@ -215,6 +215,15 @@ bool GLManager_MacOS::is_using_vsync() const {
return use_vsync;
}
+NSOpenGLContext *GLManager_MacOS::get_context(DisplayServer::WindowID p_window_id) {
+ if (!windows.has(p_window_id)) {
+ return nullptr;
+ }
+
+ GLWindow &win = windows[p_window_id];
+ return win.context;
+}
+
GLManager_MacOS::GLManager_MacOS(ContextType p_context_type) {
context_type = p_context_type;
}
diff --git a/platform/macos/godot_window_delegate.mm b/platform/macos/godot_window_delegate.mm
index 279fd2a359..3bdbc8c5ec 100644
--- a/platform/macos/godot_window_delegate.mm
+++ b/platform/macos/godot_window_delegate.mm
@@ -147,7 +147,12 @@
}
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
+ if (wd.exclusive_fullscreen) {
+ [NSApp setPresentationOptions:NSApplicationPresentationDefault];
+ }
+
wd.fullscreen = false;
+ wd.exclusive_fullscreen = false;
[(GodotWindow *)wd.window_object setAnimDuration:-1.0f];
diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp
index 2c1e87e663..f704124704 100644
--- a/platform/web/display_server_web.cpp
+++ b/platform/web/display_server_web.cpp
@@ -54,7 +54,15 @@ DisplayServerWeb *DisplayServerWeb::get_singleton() {
// Window (canvas)
bool DisplayServerWeb::check_size_force_redraw() {
- return godot_js_display_size_update() != 0;
+ bool size_changed = godot_js_display_size_update() != 0;
+ if (size_changed && !rect_changed_callback.is_null()) {
+ Variant size = Rect2i(Point2i(), window_get_size()); // TODO use window_get_position if implemented.
+ Variant *vp = &size;
+ Variant ret;
+ Callable::CallError ce;
+ rect_changed_callback.callp((const Variant **)&vp, 1, ret, ce);
+ }
+ return size_changed;
}
void DisplayServerWeb::fullscreen_change_callback(int p_fullscreen) {
@@ -758,10 +766,8 @@ DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode
godot_js_os_request_quit_cb(request_quit_callback);
#ifdef GLES3_ENABLED
- // TODO "vulkan" defaults to webgl2 for now.
- bool wants_webgl2 = p_rendering_driver == "opengl3" || p_rendering_driver == "vulkan";
- bool webgl2_init_failed = wants_webgl2 && !godot_js_display_has_webgl(2);
- if (wants_webgl2 && !webgl2_init_failed) {
+ bool webgl2_inited = false;
+ if (godot_js_display_has_webgl(2)) {
EmscriptenWebGLContextAttributes attributes;
emscripten_webgl_init_context_attributes(&attributes);
attributes.alpha = OS::get_singleton()->is_layered_allowed();
@@ -770,20 +776,17 @@ DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode
attributes.explicitSwapControl = true;
webgl_ctx = emscripten_webgl_create_context(canvas_id, &attributes);
- if (emscripten_webgl_make_context_current(webgl_ctx) != EMSCRIPTEN_RESULT_SUCCESS) {
- webgl2_init_failed = true;
- } else {
- if (!emscripten_webgl_enable_extension(webgl_ctx, "OVR_multiview2")) {
- // @todo Should we log this?
- }
- RasterizerGLES3::make_current();
- }
+ webgl2_inited = webgl_ctx && emscripten_webgl_make_context_current(webgl_ctx) == EMSCRIPTEN_RESULT_SUCCESS;
}
- if (webgl2_init_failed) {
+ if (webgl2_inited) {
+ if (!emscripten_webgl_enable_extension(webgl_ctx, "OVR_multiview2")) {
+ print_verbose("Failed to enable WebXR extension.");
+ }
+ RasterizerGLES3::make_current();
+
+ } else {
OS::get_singleton()->alert("Your browser does not seem to support WebGL2. Please update your browser version.",
"Unable to initialize video driver");
- }
- if (!wants_webgl2 || webgl2_init_failed) {
RasterizerDummy::make_current();
}
#else
@@ -908,7 +911,7 @@ ObjectID DisplayServerWeb::window_get_attached_instance_id(WindowID p_window) co
}
void DisplayServerWeb::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
- // Not supported.
+ rect_changed_callback = p_callable;
}
void DisplayServerWeb::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) {
diff --git a/platform/web/display_server_web.h b/platform/web/display_server_web.h
index 3222e2483e..1919736802 100644
--- a/platform/web/display_server_web.h
+++ b/platform/web/display_server_web.h
@@ -60,6 +60,7 @@ private:
WindowMode window_mode = WINDOW_MODE_WINDOWED;
ObjectID window_attached_instance_id = {};
+ Callable rect_changed_callback;
Callable window_event_callback;
Callable input_event_callback;
Callable input_text_callback;
diff --git a/platform/web/js/engine/config.js b/platform/web/js/engine/config.js
index 41be7b2512..4560f12b49 100644
--- a/platform/web/js/engine/config.js
+++ b/platform/web/js/engine/config.js
@@ -275,7 +275,7 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused-
'print': this.onPrint,
'printErr': this.onPrintError,
'thisProgram': this.executable,
- 'noExitRuntime': true,
+ 'noExitRuntime': false,
'dynamicLibraries': [`${loadPath}.side.wasm`],
'instantiateWasm': function (imports, onSuccess) {
function done(result) {
diff --git a/platform/web/web_main.cpp b/platform/web/web_main.cpp
index a76b98f4e9..fce782b546 100644
--- a/platform/web/web_main.cpp
+++ b/platform/web/web_main.cpp
@@ -41,30 +41,25 @@
static OS_Web *os = nullptr;
static uint64_t target_ticks = 0;
+static bool main_started = false;
+static bool shutdown_complete = false;
void exit_callback() {
- emscripten_cancel_main_loop(); // After this, we can exit!
- Main::cleanup();
+ if (!shutdown_complete) {
+ return; // Still waiting.
+ }
+ if (main_started) {
+ Main::cleanup();
+ main_started = false;
+ }
int exit_code = OS_Web::get_singleton()->get_exit_code();
memdelete(os);
os = nullptr;
- emscripten_force_exit(exit_code); // No matter that we call cancel_main_loop, regular "exit" will not work, forcing.
+ emscripten_force_exit(exit_code); // Exit runtime.
}
void cleanup_after_sync() {
- emscripten_set_main_loop(exit_callback, -1, false);
-}
-
-void early_cleanup() {
- emscripten_cancel_main_loop(); // After this, we can exit!
- int exit_code = OS_Web::get_singleton()->get_exit_code();
- memdelete(os);
- os = nullptr;
- emscripten_force_exit(exit_code); // No matter that we call cancel_main_loop, regular "exit" will not work, forcing.
-}
-
-void early_cleanup_sync() {
- emscripten_set_main_loop(early_cleanup, -1, false);
+ shutdown_complete = true;
}
void main_loop_callback() {
@@ -87,7 +82,8 @@ void main_loop_callback() {
target_ticks += (uint64_t)(1000000 / max_fps);
}
if (os->main_loop_iterate()) {
- emscripten_cancel_main_loop(); // Cancel current loop and wait for cleanup_after_sync.
+ emscripten_cancel_main_loop(); // Cancel current loop and set the cleanup one.
+ emscripten_set_main_loop(exit_callback, -1, false);
godot_js_os_finish_async(cleanup_after_sync);
}
}
@@ -109,10 +105,14 @@ extern EMSCRIPTEN_KEEPALIVE int godot_web_main(int argc, char *argv[]) {
}
os->set_exit_code(exit_code);
// Will only exit after sync.
- godot_js_os_finish_async(early_cleanup_sync);
+ emscripten_set_main_loop(exit_callback, -1, false);
+ godot_js_os_finish_async(cleanup_after_sync);
return exit_code;
}
+ os->set_exit_code(0);
+ main_started = true;
+
// Ease up compatibility.
ResourceLoader::set_abort_on_missing_resources(false);
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index d6ee712a31..af80a07da9 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -741,9 +741,20 @@ int64_t DisplayServerWindows::window_get_native_handle(HandleType p_handle_type,
case WINDOW_HANDLE: {
return (int64_t)windows[p_window].hWnd;
}
+#if defined(GLES3_ENABLED)
case WINDOW_VIEW: {
- return 0; // Not supported.
+ if (gl_manager) {
+ return (int64_t)gl_manager->get_hdc(p_window);
+ }
+ return 0;
}
+ case OPENGL_CONTEXT: {
+ if (gl_manager) {
+ return (int64_t)gl_manager->get_hglrc(p_window);
+ }
+ return 0;
+ }
+#endif
default: {
return 0;
}
@@ -1881,7 +1892,7 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) {
pos += sizeof(WORD);
f->seek(pos);
- icon_dir = (ICONDIR *)memrealloc(icon_dir, 3 * sizeof(WORD) + icon_dir->idCount * sizeof(ICONDIRENTRY));
+ icon_dir = (ICONDIR *)memrealloc(icon_dir, sizeof(ICONDIR) - sizeof(ICONDIRENTRY) + icon_dir->idCount * sizeof(ICONDIRENTRY));
f->get_buffer((uint8_t *)&icon_dir->idEntries[0], icon_dir->idCount * sizeof(ICONDIRENTRY));
int small_icon_index = -1; // Select 16x16 with largest color count.
diff --git a/platform/windows/gl_manager_windows.cpp b/platform/windows/gl_manager_windows.cpp
index 7689751f1b..900bca8258 100644
--- a/platform/windows/gl_manager_windows.cpp
+++ b/platform/windows/gl_manager_windows.cpp
@@ -339,6 +339,16 @@ bool GLManager_Windows::is_using_vsync() const {
return use_vsync;
}
+HDC GLManager_Windows::get_hdc(DisplayServer::WindowID p_window_id) {
+ return get_window(p_window_id).hDC;
+}
+
+HGLRC GLManager_Windows::get_hglrc(DisplayServer::WindowID p_window_id) {
+ const GLWindow &win = get_window(p_window_id);
+ const GLDisplay &disp = get_display(win.gldisplay_id);
+ return disp.hRC;
+}
+
GLManager_Windows::GLManager_Windows(ContextType p_context_type) {
context_type = p_context_type;
diff --git a/platform/windows/gl_manager_windows.h b/platform/windows/gl_manager_windows.h
index 5e43a3de2a..c6d5f9f855 100644
--- a/platform/windows/gl_manager_windows.h
+++ b/platform/windows/gl_manager_windows.h
@@ -113,6 +113,9 @@ public:
void set_use_vsync(bool p_use);
bool is_using_vsync() const;
+ HDC get_hdc(DisplayServer::WindowID p_window_id);
+ HGLRC get_hglrc(DisplayServer::WindowID p_window_id);
+
GLManager_Windows(ContextType p_context_type);
~GLManager_Windows();
};
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index 9786b01058..e18f2bd1a1 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -141,16 +141,16 @@ void GPUParticles2D::set_process_material(const Ref<Material> &p_material) {
void GPUParticles2D::set_trail_enabled(bool p_enabled) {
trail_enabled = p_enabled;
- RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_lifetime);
queue_redraw();
RS::get_singleton()->particles_set_transform_align(particles, p_enabled ? RS::PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY : RS::PARTICLES_TRANSFORM_ALIGN_DISABLED);
}
-void GPUParticles2D::set_trail_length(double p_seconds) {
+void GPUParticles2D::set_trail_lifetime(double p_seconds) {
ERR_FAIL_COND(p_seconds < 0.001);
- trail_length = p_seconds;
- RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+ trail_lifetime = p_seconds;
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_lifetime);
queue_redraw();
}
@@ -181,8 +181,8 @@ bool GPUParticles2D::is_trail_enabled() const {
return trail_enabled;
}
-double GPUParticles2D::get_trail_length() const {
- return trail_length;
+double GPUParticles2D::get_trail_lifetime() const {
+ return trail_lifetime;
}
void GPUParticles2D::_update_collision_size() {
@@ -614,10 +614,10 @@ void GPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("emit_particle", "xform", "velocity", "color", "custom", "flags"), &GPUParticles2D::emit_particle);
ClassDB::bind_method(D_METHOD("set_trail_enabled", "enabled"), &GPUParticles2D::set_trail_enabled);
- ClassDB::bind_method(D_METHOD("set_trail_length", "secs"), &GPUParticles2D::set_trail_length);
+ ClassDB::bind_method(D_METHOD("set_trail_lifetime", "secs"), &GPUParticles2D::set_trail_lifetime);
ClassDB::bind_method(D_METHOD("is_trail_enabled"), &GPUParticles2D::is_trail_enabled);
- ClassDB::bind_method(D_METHOD("get_trail_length"), &GPUParticles2D::get_trail_length);
+ ClassDB::bind_method(D_METHOD("get_trail_lifetime"), &GPUParticles2D::get_trail_lifetime);
ClassDB::bind_method(D_METHOD("set_trail_sections", "sections"), &GPUParticles2D::set_trail_sections);
ClassDB::bind_method(D_METHOD("get_trail_sections"), &GPUParticles2D::get_trail_sections);
@@ -647,7 +647,7 @@ void GPUParticles2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,Reverse Lifetime"), "set_draw_order", "get_draw_order");
ADD_GROUP("Trails", "trail_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_trail_enabled", "is_trail_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,10,0.01,suffix:s"), "set_trail_length", "get_trail_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_lifetime", PROPERTY_HINT_RANGE, "0.01,10,0.01,or_greater,suffix:s"), "set_trail_lifetime", "get_trail_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_sections", PROPERTY_HINT_RANGE, "2,128,1"), "set_trail_sections", "get_trail_sections");
ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_section_subdivisions", PROPERTY_HINT_RANGE, "1,1024,1"), "set_trail_section_subdivisions", "get_trail_section_subdivisions");
ADD_GROUP("Process Material", "process_");
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
index d613b4ef51..7fba174357 100644
--- a/scene/2d/gpu_particles_2d.h
+++ b/scene/2d/gpu_particles_2d.h
@@ -74,7 +74,7 @@ private:
real_t collision_base_size = 1.0;
bool trail_enabled = false;
- double trail_length = 0.3;
+ double trail_lifetime = 0.3;
int trail_sections = 8;
int trail_section_subdivisions = 4;
@@ -104,7 +104,7 @@ public:
void set_speed_scale(double p_scale);
void set_collision_base_size(real_t p_ratio);
void set_trail_enabled(bool p_enabled);
- void set_trail_length(double p_seconds);
+ void set_trail_lifetime(double p_seconds);
void set_trail_sections(int p_sections);
void set_trail_section_subdivisions(int p_subdivisions);
@@ -126,7 +126,7 @@ public:
real_t get_collision_base_size() const;
bool is_trail_enabled() const;
- double get_trail_length() const;
+ double get_trail_lifetime() const;
int get_trail_sections() const;
int get_trail_section_subdivisions() const;
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index a98be62dfa..ca23fe03a2 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -330,7 +330,7 @@ bool CollisionObject3D::_are_collision_shapes_visible() {
void CollisionObject3D::_update_shape_data(uint32_t p_owner) {
if (_are_collision_shapes_visible()) {
if (debug_shapes_to_update.is_empty()) {
- callable_mp(this, &CollisionObject3D::_update_debug_shapes).call_deferredp({}, 0);
+ callable_mp(this, &CollisionObject3D::_update_debug_shapes).call_deferred();
}
debug_shapes_to_update.insert(p_owner);
}
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index dbbf196f7a..9d04202c2d 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -176,22 +176,22 @@ void GPUParticles3D::set_draw_order(DrawOrder p_order) {
void GPUParticles3D::set_trail_enabled(bool p_enabled) {
trail_enabled = p_enabled;
- RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_lifetime);
update_configuration_warnings();
}
-void GPUParticles3D::set_trail_length(double p_seconds) {
+void GPUParticles3D::set_trail_lifetime(double p_seconds) {
ERR_FAIL_COND(p_seconds < 0.001);
- trail_length = p_seconds;
- RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+ trail_lifetime = p_seconds;
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_lifetime);
}
bool GPUParticles3D::is_trail_enabled() const {
return trail_enabled;
}
-double GPUParticles3D::get_trail_length() const {
- return trail_length;
+double GPUParticles3D::get_trail_lifetime() const {
+ return trail_lifetime;
}
GPUParticles3D::DrawOrder GPUParticles3D::get_draw_order() const {
@@ -552,10 +552,10 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("emit_particle", "xform", "velocity", "color", "custom", "flags"), &GPUParticles3D::emit_particle);
ClassDB::bind_method(D_METHOD("set_trail_enabled", "enabled"), &GPUParticles3D::set_trail_enabled);
- ClassDB::bind_method(D_METHOD("set_trail_length", "secs"), &GPUParticles3D::set_trail_length);
+ ClassDB::bind_method(D_METHOD("set_trail_lifetime", "secs"), &GPUParticles3D::set_trail_lifetime);
ClassDB::bind_method(D_METHOD("is_trail_enabled"), &GPUParticles3D::is_trail_enabled);
- ClassDB::bind_method(D_METHOD("get_trail_length"), &GPUParticles3D::get_trail_length);
+ ClassDB::bind_method(D_METHOD("get_trail_lifetime"), &GPUParticles3D::get_trail_lifetime);
ClassDB::bind_method(D_METHOD("set_transform_align", "align"), &GPUParticles3D::set_transform_align);
ClassDB::bind_method(D_METHOD("get_transform_align"), &GPUParticles3D::get_transform_align);
@@ -583,7 +583,7 @@ void GPUParticles3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_align", PROPERTY_HINT_ENUM, "Disabled,Z-Billboard,Y to Velocity,Z-Billboard + Y to Velocity"), "set_transform_align", "get_transform_align");
ADD_GROUP("Trails", "trail_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_trail_enabled", "is_trail_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,10,0.01,suffix:s"), "set_trail_length", "get_trail_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_lifetime", PROPERTY_HINT_RANGE, "0.01,10,0.01,or_greater,suffix:s"), "set_trail_lifetime", "get_trail_lifetime");
ADD_GROUP("Process Material", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticleProcessMaterial"), "set_process_material", "get_process_material");
ADD_GROUP("Draw Passes", "draw_");
@@ -627,7 +627,7 @@ GPUParticles3D::GPUParticles3D() {
set_pre_process_time(0);
set_explosiveness_ratio(0);
set_randomness_ratio(0);
- set_trail_length(0.3);
+ set_trail_lifetime(0.3);
set_visibility_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8)));
set_use_local_coordinates(false);
set_draw_passes(1);
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index ef92218e4d..835d71862a 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -76,7 +76,7 @@ private:
real_t collision_base_size = 0.01;
bool trail_enabled = false;
- double trail_length = 0.3;
+ double trail_lifetime = 0.3;
TransformAlign transform_align = TRANSFORM_ALIGN_DISABLED;
@@ -112,7 +112,7 @@ public:
void set_speed_scale(double p_scale);
void set_collision_base_size(real_t p_ratio);
void set_trail_enabled(bool p_enabled);
- void set_trail_length(double p_seconds);
+ void set_trail_lifetime(double p_seconds);
bool is_emitting() const;
int get_amount() const;
@@ -127,7 +127,7 @@ public:
double get_speed_scale() const;
real_t get_collision_base_size() const;
bool is_trail_enabled() const;
- double get_trail_length() const;
+ double get_trail_lifetime() const;
void set_fixed_fps(int p_count);
int get_fixed_fps() const;
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index 09d31b1ca0..b5b37bf837 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -74,10 +74,6 @@ RID VisualInstance3D::get_instance() const {
return instance;
}
-RID VisualInstance3D::_get_visual_instance_rid() const {
- return instance;
-}
-
void VisualInstance3D::set_layer_mask(uint32_t p_mask) {
layers = p_mask;
RenderingServer::get_singleton()->instance_set_layer_mask(instance, p_mask);
@@ -106,7 +102,6 @@ bool VisualInstance3D::get_layer_mask_value(int p_layer_number) const {
}
void VisualInstance3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_get_visual_instance_rid"), &VisualInstance3D::_get_visual_instance_rid);
ClassDB::bind_method(D_METHOD("set_base", "base"), &VisualInstance3D::set_base);
ClassDB::bind_method(D_METHOD("get_base"), &VisualInstance3D::get_base);
ClassDB::bind_method(D_METHOD("get_instance"), &VisualInstance3D::get_instance);
@@ -216,15 +211,20 @@ GeometryInstance3D::VisibilityRangeFadeMode GeometryInstance3D::get_visibility_r
}
const StringName *GeometryInstance3D::_instance_uniform_get_remap(const StringName p_name) const {
- StringName *r = instance_uniform_property_remap.getptr(p_name);
+ StringName *r = instance_shader_parameter_property_remap.getptr(p_name);
if (!r) {
String s = p_name;
+#ifndef DISABLE_DEPRECATED
if (s.begins_with("shader_uniforms/")) {
- StringName name = s.replace("shader_uniforms/", "");
- instance_uniform_property_remap[p_name] = name;
- return instance_uniform_property_remap.getptr(p_name);
+ s = s.replace("shader_uniforms/", "instance_shader_parameters/");
+ }
+#endif // DISABLE_DEPRECATED
+ if (s.begins_with("instance_shader_parameters/")) {
+ StringName pname = StringName(s);
+ StringName name = s.replace("instance_shader_parameters/", "");
+ instance_shader_parameter_property_remap[pname] = name;
+ return instance_shader_parameter_property_remap.getptr(pname);
}
-
return nullptr;
}
@@ -247,7 +247,7 @@ bool GeometryInstance3D::_set(const StringName &p_name, const Variant &p_value)
set_gi_mode(GI_MODE_DYNAMIC);
return true;
}
-#endif
+#endif // DISABLE_DEPRECATED
return false;
}
@@ -270,13 +270,13 @@ void GeometryInstance3D::_get_property_list(List<PropertyInfo> *p_list) const {
if (def_value.get_type() != Variant::NIL) {
has_def_value = true;
}
- if (instance_uniforms.has(pi.name)) {
+ if (instance_shader_parameters.has(pi.name)) {
pi.usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE | (has_def_value ? (PROPERTY_USAGE_CHECKABLE | PROPERTY_USAGE_CHECKED) : PROPERTY_USAGE_NONE);
} else {
pi.usage = PROPERTY_USAGE_EDITOR | (has_def_value ? PROPERTY_USAGE_CHECKABLE : PROPERTY_USAGE_NONE); //do not save if not changed
}
- pi.name = "shader_uniforms/" + pi.name;
+ pi.name = "instance_shader_parameters/" + pi.name;
p_list->push_back(pi);
}
}
@@ -315,9 +315,9 @@ void GeometryInstance3D::set_instance_shader_parameter(const StringName &p_name,
if (p_value.get_type() == Variant::NIL) {
Variant def_value = RS::get_singleton()->instance_geometry_get_shader_parameter_default_value(get_instance(), p_name);
RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_name, def_value);
- instance_uniforms.erase(p_value);
+ instance_shader_parameters.erase(p_value);
} else {
- instance_uniforms[p_name] = p_value;
+ instance_shader_parameters[p_name] = p_value;
if (p_value.get_type() == Variant::OBJECT) {
RID tex_id = p_value;
RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_name, tex_id);
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index c9a25d9705..f18bff2ddc 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -40,8 +40,6 @@ class VisualInstance3D : public Node3D {
RID instance;
uint32_t layers = 1;
- RID _get_visual_instance_rid() const;
-
protected:
void _update_visibility();
@@ -119,8 +117,8 @@ private:
float lod_bias = 1.0;
- mutable HashMap<StringName, Variant> instance_uniforms;
- mutable HashMap<StringName, StringName> instance_uniform_property_remap;
+ mutable HashMap<StringName, Variant> instance_shader_parameters;
+ mutable HashMap<StringName, StringName> instance_shader_parameter_property_remap;
float extra_cull_margin = 0.0;
LightmapScale lightmap_scale = LIGHTMAP_SCALE_1X;
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index f5d30c584f..ca7d1dfc1d 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -644,6 +644,12 @@ void XROrigin3D::set_current(bool p_enabled) {
origin_nodes[i]->set_current(false);
}
}
+
+ // update XRServer with our current position
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ xr_server->set_world_origin(get_global_transform());
} else {
bool found = false;
// We no longer have a current origin so find the first one we can make current
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 5f8f25154c..ea310f5a12 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -694,8 +694,8 @@ void CodeEdit::_backspace_internal(int p_caret) {
return;
}
- if (has_selection()) {
- delete_selection();
+ if (has_selection(p_caret)) {
+ delete_selection(p_caret);
return;
}
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index d6b5557a3f..82f089735d 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -896,7 +896,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
if (k.is_valid() && k->get_unicode()) {
uint64_t now = OS::get_singleton()->get_ticks_msec();
uint64_t diff = now - search_time_msec;
- uint64_t max_interval = uint64_t(GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000));
+ uint64_t max_interval = uint64_t(GLOBAL_GET("gui/timers/incremental_search_max_interval_msec"));
search_time_msec = now;
if (diff > max_interval) {
@@ -1831,9 +1831,6 @@ void ItemList::_bind_methods() {
ADD_SIGNAL(MethodInfo("item_clicked", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::VECTOR2, "at_position"), PropertyInfo(Variant::INT, "mouse_button_index")));
ADD_SIGNAL(MethodInfo("multi_selected", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "selected")));
ADD_SIGNAL(MethodInfo("item_activated", PropertyInfo(Variant::INT, "index")));
-
- GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000);
- ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/incremental_search_max_interval_msec", PropertyInfo(Variant::INT, "gui/timers/incremental_search_max_interval_msec", PROPERTY_HINT_RANGE, "0,10000,1,or_greater")); // No negative numbers
}
ItemList::ItemList() {
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index fb5ab9f923..8a77c39487 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -960,17 +960,30 @@ void LineEdit::_notification(int p_what) {
if (ime_text.length() == 0) {
// Normal caret.
CaretInfo caret = TS->shaped_text_get_carets(text_rid, caret_column);
-
- if (caret.l_caret == Rect2() && caret.t_caret == Rect2()) {
+ if (using_placeholder || (caret.l_caret == Rect2() && caret.t_caret == Rect2())) {
// No carets, add one at the start.
int h = theme_cache.font->get_height(theme_cache.font_size);
int y = style->get_offset().y + (y_area - h) / 2;
- if (rtl) {
- caret.l_dir = TextServer::DIRECTION_RTL;
- caret.l_caret = Rect2(Vector2(ofs_max, y), Size2(caret_width, h));
- } else {
- caret.l_dir = TextServer::DIRECTION_LTR;
- caret.l_caret = Rect2(Vector2(x_ofs, y), Size2(caret_width, h));
+ caret.l_dir = (rtl) ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR;
+ switch (alignment) {
+ case HORIZONTAL_ALIGNMENT_FILL:
+ case HORIZONTAL_ALIGNMENT_LEFT: {
+ if (rtl) {
+ caret.l_caret = Rect2(Vector2(ofs_max, y), Size2(caret_width, h));
+ } else {
+ caret.l_caret = Rect2(Vector2(style->get_offset().x, y), Size2(caret_width, h));
+ }
+ } break;
+ case HORIZONTAL_ALIGNMENT_CENTER: {
+ caret.l_caret = Rect2(Vector2(size.x / 2, y), Size2(caret_width, h));
+ } break;
+ case HORIZONTAL_ALIGNMENT_RIGHT: {
+ if (rtl) {
+ caret.l_caret = Rect2(Vector2(style->get_offset().x, y), Size2(caret_width, h));
+ } else {
+ caret.l_caret = Rect2(Vector2(ofs_max, y), Size2(caret_width, h));
+ }
+ } break;
}
RenderingServer::get_singleton()->canvas_item_add_rect(ci, caret.l_caret, caret_color);
} else {
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index 2cbece69f2..0940b4c07b 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -451,7 +451,7 @@ void OptionButton::_queue_refresh_cache() {
}
cache_refresh_pending = true;
- callable_mp(this, &OptionButton::_refresh_size_cache).call_deferredp(nullptr, 0);
+ callable_mp(this, &OptionButton::_refresh_size_cache).call_deferred();
}
void OptionButton::select(int p_idx) {
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 9a411ef7ed..82f56a56c9 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -472,7 +472,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
if (allow_search && k.is_valid() && k->get_unicode() && k->is_pressed()) {
uint64_t now = OS::get_singleton()->get_ticks_msec();
uint64_t diff = now - search_time_msec;
- uint64_t max_interval = uint64_t(GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000));
+ uint64_t max_interval = uint64_t(GLOBAL_GET("gui/timers/incremental_search_max_interval_msec"));
search_time_msec = now;
if (diff > max_interval) {
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index ec34a8d26d..531226f938 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -182,14 +182,12 @@ void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) {
drag_accum = Vector2();
last_drag_accum = Vector2();
drag_from = Vector2(prev_h_scroll, prev_v_scroll);
- drag_touching = screen_is_touchscreen;
+ drag_touching = true;
drag_touching_deaccel = false;
beyond_deadzone = false;
time_since_motion = 0;
- if (drag_touching) {
- set_physics_process_internal(true);
- time_since_motion = 0;
- }
+ set_physics_process_internal(true);
+ time_since_motion = 0;
} else {
if (drag_touching) {
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 1b8444abf4..56f7281721 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1854,6 +1854,12 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
} else {
if (mb->get_button_index() == MouseButton::LEFT) {
if (selection_drag_attempt && is_mouse_over_selection()) {
+ remove_secondary_carets();
+
+ Point2i pos = get_line_column_at_pos(get_local_mouse_pos());
+ set_caret_line(pos.y, false, true, 0, 0);
+ set_caret_column(pos.x, true, 0);
+
deselect();
}
dragging_minimap = false;
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 6f9a9a5141..25df4e7932 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -4338,6 +4338,12 @@ TreeItem *Tree::get_selected() const {
return selected_item;
}
+void Tree::set_selected(TreeItem *p_item, int p_column) {
+ ERR_FAIL_INDEX(p_column, columns.size());
+ ERR_FAIL_COND(!p_item);
+ select_single_item(p_item, get_root(), p_column);
+}
+
int Tree::get_selected_column() const {
return selected_col;
}
@@ -4818,7 +4824,7 @@ TreeItem *Tree::get_item_with_text(const String &p_find) const {
void Tree::_do_incr_search(const String &p_add) {
uint64_t time = OS::get_singleton()->get_ticks_usec() / 1000; // convert to msec
uint64_t diff = time - last_keypress;
- if (diff > uint64_t(GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000))) {
+ if (diff > uint64_t(GLOBAL_GET("gui/timers/incremental_search_max_interval_msec"))) {
incr_search = p_add;
} else if (incr_search != p_add) {
incr_search += p_add;
@@ -5156,6 +5162,7 @@ void Tree::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_root_hidden"), &Tree::is_root_hidden);
ClassDB::bind_method(D_METHOD("get_next_selected", "from"), &Tree::get_next_selected);
ClassDB::bind_method(D_METHOD("get_selected"), &Tree::get_selected);
+ ClassDB::bind_method(D_METHOD("set_selected", "item", "column"), &Tree::set_selected);
ClassDB::bind_method(D_METHOD("get_selected_column"), &Tree::get_selected_column);
ClassDB::bind_method(D_METHOD("get_pressed_button"), &Tree::get_pressed_button);
ClassDB::bind_method(D_METHOD("set_select_mode", "mode"), &Tree::set_select_mode);
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index f994a5cec1..77a62e1d6a 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -666,6 +666,7 @@ public:
bool is_root_hidden() const;
TreeItem *get_next_selected(TreeItem *p_item);
TreeItem *get_selected() const;
+ void set_selected(TreeItem *p_item, int p_column = 0);
int get_selected_column() const;
int get_pressed_button() const;
void set_select_mode(SelectMode p_mode);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index f8b0a66a71..43a2c9473e 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1561,44 +1561,15 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
set_input_as_handled();
}
- if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == MouseButton::LEFT) {
+ if (gui.dragging && mb->get_button_index() == MouseButton::LEFT) {
// Alternate drop use (when using force_drag(), as proposed by #5342).
- gui.drag_successful = false;
- if (gui.mouse_focus) {
- gui.drag_successful = _gui_drop(gui.mouse_focus, pos, false);
- }
-
- gui.drag_data = Variant();
- gui.dragging = false;
-
- Control *drag_preview = _gui_get_drag_preview();
- if (drag_preview) {
- memdelete(drag_preview);
- gui.drag_preview_id = ObjectID();
- }
- _propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
- get_base_window()->update_mouse_cursor_shape();
+ _perform_drop(gui.mouse_focus, pos);
}
_gui_cancel_tooltip();
} else {
- if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == MouseButton::LEFT) {
- gui.drag_successful = false;
- if (gui.drag_mouse_over) {
- gui.drag_successful = _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, false);
- }
-
- Control *drag_preview = _gui_get_drag_preview();
- if (drag_preview) {
- memdelete(drag_preview);
- gui.drag_preview_id = ObjectID();
- }
-
- gui.drag_data = Variant();
- gui.dragging = false;
- gui.drag_mouse_over = nullptr;
- _propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
- get_base_window()->update_mouse_cursor_shape();
+ if (gui.dragging && mb->get_button_index() == MouseButton::LEFT) {
+ _perform_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos);
}
gui.mouse_focus_mask &= ~mouse_button_to_mask(mb->get_button_index()); // Remove from mask.
@@ -1682,7 +1653,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
gui.drag_attempted = true;
- if (gui.drag_data.get_type() != Variant::NIL) {
+ if (gui.dragging) {
_propagate_viewport_notification(this, NOTIFICATION_DRAG_BEGIN);
}
}
@@ -1795,7 +1766,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
}
- if (gui.drag_data.get_type() != Variant::NIL) {
+ if (gui.dragging) {
// Handle drag & drop.
Control *drag_preview = _gui_get_drag_preview();
@@ -1997,6 +1968,12 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
if (mm.is_null() && mb.is_null() && p_event->is_action_type()) {
+ if (gui.dragging && p_event->is_action_pressed("ui_cancel") && Input::get_singleton()->is_action_just_pressed("ui_cancel")) {
+ _perform_drop();
+ set_input_as_handled();
+ return;
+ }
+
if (gui.key_focus && !gui.key_focus->is_visible_in_tree()) {
gui.key_focus->release_focus();
}
@@ -2078,6 +2055,27 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
}
+void Viewport::_perform_drop(Control *p_control, Point2 p_pos) {
+ // Without any arguments, simply cancel Drag and Drop.
+ if (p_control) {
+ gui.drag_successful = _gui_drop(p_control, p_pos, false);
+ } else {
+ gui.drag_successful = false;
+ }
+
+ Control *drag_preview = _gui_get_drag_preview();
+ if (drag_preview) {
+ memdelete(drag_preview);
+ gui.drag_preview_id = ObjectID();
+ }
+
+ gui.drag_data = Variant();
+ gui.dragging = false;
+ gui.drag_mouse_over = nullptr;
+ _propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
+ get_base_window()->update_mouse_cursor_shape();
+}
+
void Viewport::_gui_cleanup_internal_state(Ref<InputEvent> p_event) {
ERR_FAIL_COND(p_event.is_null());
@@ -4231,6 +4229,8 @@ void SubViewport::_bind_methods() {
BIND_ENUM_CONSTANT(UPDATE_ALWAYS);
}
-SubViewport::SubViewport() {}
+SubViewport::SubViewport() {
+ RS::get_singleton()->viewport_set_size(get_viewport_rid(), get_size().width, get_size().height);
+}
SubViewport::~SubViewport() {}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 8911aea335..dc69ec24d8 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -405,6 +405,7 @@ private:
Control *_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform);
void _gui_input_event(Ref<InputEvent> p_event);
+ void _perform_drop(Control *p_control = nullptr, Point2 p_pos = Point2());
void _gui_cleanup_internal_state(Ref<InputEvent> p_event);
_FORCE_INLINE_ Transform2D _get_input_pre_xform() const;
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index dfd9c6eb2f..1eb78f0160 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -5851,18 +5851,18 @@ Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float
return dst;
}
case Variant::PACKED_INT32_ARRAY: {
- const Vector<int32_t> *arr_a = Object::cast_to<Vector<int32_t>>(a);
- const Vector<int32_t> *arr_b = Object::cast_to<Vector<int32_t>>(b);
- int32_t sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
+ const Vector<int32_t> arr_a = a;
+ const Vector<int32_t> arr_b = b;
+ int32_t sz = arr_a.size();
+ if (sz == 0 || arr_b.size() != sz) {
return a;
} else {
Vector<int32_t> v;
v.resize(sz);
{
int32_t *vw = v.ptrw();
- const int32_t *ar = arr_a->ptr();
- const int32_t *br = arr_b->ptr();
+ const int32_t *ar = arr_a.ptr();
+ const int32_t *br = arr_b.ptr();
Variant va;
for (int32_t i = 0; i < sz; i++) {
@@ -5874,18 +5874,18 @@ Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float
}
}
case Variant::PACKED_INT64_ARRAY: {
- const Vector<int64_t> *arr_a = Object::cast_to<Vector<int64_t>>(a);
- const Vector<int64_t> *arr_b = Object::cast_to<Vector<int64_t>>(b);
- int64_t sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
+ const Vector<int64_t> arr_a = a;
+ const Vector<int64_t> arr_b = b;
+ int64_t sz = arr_a.size();
+ if (sz == 0 || arr_b.size() != sz) {
return a;
} else {
Vector<int64_t> v;
v.resize(sz);
{
int64_t *vw = v.ptrw();
- const int64_t *ar = arr_a->ptr();
- const int64_t *br = arr_b->ptr();
+ const int64_t *ar = arr_a.ptr();
+ const int64_t *br = arr_b.ptr();
Variant va;
for (int64_t i = 0; i < sz; i++) {
@@ -5897,18 +5897,18 @@ Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float
}
}
case Variant::PACKED_FLOAT32_ARRAY: {
- const Vector<float> *arr_a = Object::cast_to<Vector<float>>(a);
- const Vector<float> *arr_b = Object::cast_to<Vector<float>>(b);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
+ const Vector<float> arr_a = a;
+ const Vector<float> arr_b = b;
+ int sz = arr_a.size();
+ if (sz == 0 || arr_b.size() != sz) {
return a;
} else {
Vector<float> v;
v.resize(sz);
{
float *vw = v.ptrw();
- const float *ar = arr_a->ptr();
- const float *br = arr_b->ptr();
+ const float *ar = arr_a.ptr();
+ const float *br = arr_b.ptr();
Variant va;
for (int i = 0; i < sz; i++) {
@@ -5920,18 +5920,18 @@ Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float
}
}
case Variant::PACKED_FLOAT64_ARRAY: {
- const Vector<double> *arr_a = Object::cast_to<Vector<double>>(a);
- const Vector<double> *arr_b = Object::cast_to<Vector<double>>(b);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
+ const Vector<double> arr_a = a;
+ const Vector<double> arr_b = b;
+ int sz = arr_a.size();
+ if (sz == 0 || arr_b.size() != sz) {
return a;
} else {
Vector<double> v;
v.resize(sz);
{
double *vw = v.ptrw();
- const double *ar = arr_a->ptr();
- const double *br = arr_b->ptr();
+ const double *ar = arr_a.ptr();
+ const double *br = arr_b.ptr();
Variant va;
for (int i = 0; i < sz; i++) {
@@ -5943,18 +5943,18 @@ Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float
}
}
case Variant::PACKED_VECTOR2_ARRAY: {
- const Vector<Vector2> *arr_a = Object::cast_to<Vector<Vector2>>(a);
- const Vector<Vector2> *arr_b = Object::cast_to<Vector<Vector2>>(b);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
+ const Vector<Vector2> arr_a = a;
+ const Vector<Vector2> arr_b = b;
+ int sz = arr_a.size();
+ if (sz == 0 || arr_b.size() != sz) {
return a;
} else {
Vector<Vector2> v;
v.resize(sz);
{
Vector2 *vw = v.ptrw();
- const Vector2 *ar = arr_a->ptr();
- const Vector2 *br = arr_b->ptr();
+ const Vector2 *ar = arr_a.ptr();
+ const Vector2 *br = arr_b.ptr();
for (int i = 0; i < sz; i++) {
vw[i] = ar[i].lerp(br[i], c);
@@ -5964,18 +5964,18 @@ Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float
}
}
case Variant::PACKED_VECTOR3_ARRAY: {
- const Vector<Vector3> *arr_a = Object::cast_to<Vector<Vector3>>(a);
- const Vector<Vector3> *arr_b = Object::cast_to<Vector<Vector3>>(b);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
+ const Vector<Vector3> arr_a = a;
+ const Vector<Vector3> arr_b = b;
+ int sz = arr_a.size();
+ if (sz == 0 || arr_b.size() != sz) {
return a;
} else {
Vector<Vector3> v;
v.resize(sz);
{
Vector3 *vw = v.ptrw();
- const Vector3 *ar = arr_a->ptr();
- const Vector3 *br = arr_b->ptr();
+ const Vector3 *ar = arr_a.ptr();
+ const Vector3 *br = arr_b.ptr();
for (int i = 0; i < sz; i++) {
vw[i] = ar[i].lerp(br[i], c);
@@ -5985,18 +5985,18 @@ Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float
}
}
case Variant::PACKED_COLOR_ARRAY: {
- const Vector<Color> *arr_a = Object::cast_to<Vector<Color>>(a);
- const Vector<Color> *arr_b = Object::cast_to<Vector<Color>>(b);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
+ const Vector<Color> arr_a = a;
+ const Vector<Color> arr_b = b;
+ int sz = arr_a.size();
+ if (sz == 0 || arr_b.size() != sz) {
return a;
} else {
Vector<Color> v;
v.resize(sz);
{
Color *vw = v.ptrw();
- const Color *ar = arr_a->ptr();
- const Color *br = arr_b->ptr();
+ const Color *ar = arr_a.ptr();
+ const Color *br = arr_b.ptr();
for (int i = 0; i < sz; i++) {
vw[i] = ar[i].lerp(br[i], c);
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 185b6f4bdc..79ca87e9d6 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -1788,7 +1788,10 @@ Error FontFile::load_bitmap_font(const String &p_path) {
ERR_FAIL_V_MSG(ERR_CANT_CREATE, RTR("Unsupported BMFont texture format."));
}
} else {
- if ((ch[0] == 0) && (ch[1] == 0) && (ch[2] == 0) && (ch[3] == 0)) { // RGBA8 color, no outline
+ if ((ch[3] == 0) && (ch[0] == 4) && (ch[1] == 4) && (ch[2] == 4) && img->get_format() == Image::FORMAT_RGBA8) { // might be RGBA8 color, no outline (color part of the image should be sold white, but some apps designed for Godot 3 generate color fonts with this config)
+ outline = 0;
+ set_texture_image(0, Vector2i(base_size, 0), page, img);
+ } else if ((ch[0] == 0) && (ch[1] == 0) && (ch[2] == 0) && (ch[3] == 0)) { // RGBA8 color, no outline
outline = 0;
ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, RTR("Unsupported BMFont texture format."));
set_texture_image(0, Vector2i(base_size, 0), page, img);
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 706db3af16..d1e300e057 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -940,7 +940,7 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma
dst[0] = (int16_t)CLAMP(src[0] / 127.0f * 32767, -32768, 32767);
dst[1] = (int16_t)CLAMP(src[1] / 127.0f * 32767, -32768, 32767);
}
- src_offset += sizeof(int16_t) * 2;
+ src_offset += sizeof(int8_t) * 2;
} else {
for (uint32_t i = 0; i < p_elements; i++) {
const int16_t *src = (const int16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
@@ -962,7 +962,7 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma
dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(uint16_t) * 2;
+ src_offset += sizeof(uint8_t) * 4; // 1 byte padding
} else {
for (uint32_t i = 0; i < p_elements; i++) {
const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
@@ -973,7 +973,7 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma
dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(uint16_t) * 2;
+ src_offset += sizeof(float) * 3;
}
}
@@ -988,7 +988,7 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma
dst[0] = (uint16_t)CLAMP((src[0] / 127.0f * .5f + .5f) * 65535, 0, 65535);
dst[1] = (uint16_t)CLAMP((src[1] / 127.0f * .5f + .5f) * 65535, 0, 65535);
}
- src_offset += sizeof(uint16_t) * 2;
+ src_offset += sizeof(uint8_t) * 2;
} else { // int16 SNORM -> uint16 UNORM
for (uint32_t i = 0; i < p_elements; i++) {
const int16_t *src = (const int16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
@@ -1010,7 +1010,7 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma
dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(uint16_t) * 2;
+ src_offset += sizeof(uint8_t) * 4;
} else {
for (uint32_t i = 0; i < p_elements; i++) {
const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
@@ -1021,7 +1021,7 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma
dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(uint16_t) * 2;
+ src_offset += sizeof(float) * 4;
}
}
} break;
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index eb83a37c7b..e5ad590c0a 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -30,6 +30,7 @@
#include "primitive_meshes.h"
+#include "core/config/project_settings.h"
#include "core/core_string_names.h"
#include "scene/resources/theme.h"
#include "scene/theme/theme_db.h"
@@ -37,6 +38,8 @@
#include "thirdparty/misc/clipper.hpp"
#include "thirdparty/misc/polypartition.h"
+#define PADDING_REF_SIZE 1024.0
+
/**
PrimitiveMesh
*/
@@ -94,6 +97,26 @@ void PrimitiveMesh::_update() const {
}
}
+ if (add_uv2) {
+ // _create_mesh_array should populate our UV2, this is a fallback in case it doesn't.
+ // As we don't know anything about the geometry we only pad the right and bottom edge
+ // of our texture.
+ Vector<Vector2> uv = arr[RS::ARRAY_TEX_UV];
+ Vector<Vector2> uv2 = arr[RS::ARRAY_TEX_UV2];
+
+ if (uv.size() > 0 && uv2.size() == 0) {
+ Vector2 uv2_scale = get_uv2_scale();
+ uv2.resize(uv.size());
+
+ Vector2 *uv2w = uv2.ptrw();
+ for (int i = 0; i < uv.size(); i++) {
+ uv2w[i] = uv[i] * uv2_scale;
+ }
+ }
+
+ arr[RS::ARRAY_TEX_UV2] = uv2;
+ }
+
array_len = pc;
index_array_len = indices.size();
// in with the new
@@ -160,7 +183,12 @@ TypedArray<Array> PrimitiveMesh::surface_get_blend_shape_arrays(int p_surface) c
uint32_t PrimitiveMesh::surface_get_format(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, 1, 0);
- return RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_TANGENT | RS::ARRAY_FORMAT_TEX_UV | RS::ARRAY_FORMAT_INDEX;
+ uint32_t mesh_format = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_TANGENT | RS::ARRAY_FORMAT_TEX_UV | RS::ARRAY_FORMAT_INDEX;
+ if (add_uv2) {
+ mesh_format |= RS::ARRAY_FORMAT_TEX_UV2;
+ }
+
+ return mesh_format;
}
Mesh::PrimitiveType PrimitiveMesh::surface_get_primitive_type(int p_idx) const {
@@ -219,9 +247,17 @@ void PrimitiveMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flip_faces", "flip_faces"), &PrimitiveMesh::set_flip_faces);
ClassDB::bind_method(D_METHOD("get_flip_faces"), &PrimitiveMesh::get_flip_faces);
+ ClassDB::bind_method(D_METHOD("set_add_uv2", "add_uv2"), &PrimitiveMesh::set_add_uv2);
+ ClassDB::bind_method(D_METHOD("get_add_uv2"), &PrimitiveMesh::get_add_uv2);
+
+ ClassDB::bind_method(D_METHOD("set_uv2_padding", "uv2_padding"), &PrimitiveMesh::set_uv2_padding);
+ ClassDB::bind_method(D_METHOD("get_uv2_padding"), &PrimitiveMesh::get_uv2_padding);
+
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material");
ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, "suffix:m"), "set_custom_aabb", "get_custom_aabb");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_faces"), "set_flip_faces", "get_flip_faces");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "add_uv2"), "set_add_uv2", "get_add_uv2");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "uv2_padding"), "set_uv2_padding", "get_uv2_padding");
GDVIRTUAL_BIND(_create_mesh_array);
}
@@ -263,6 +299,42 @@ bool PrimitiveMesh::get_flip_faces() const {
return flip_faces;
}
+void PrimitiveMesh::set_add_uv2(bool p_enable) {
+ add_uv2 = p_enable;
+ _update_lightmap_size();
+ _request_update();
+}
+
+void PrimitiveMesh::set_uv2_padding(float p_padding) {
+ uv2_padding = p_padding;
+ _update_lightmap_size();
+ _request_update();
+}
+
+Vector2 PrimitiveMesh::get_uv2_scale(Vector2 p_margin_scale) const {
+ Vector2 uv2_scale;
+ Vector2 lightmap_size = get_lightmap_size_hint();
+
+ // Calculate it as a margin, if no lightmap size hint is given we assume "PADDING_REF_SIZE" as our texture size.
+ uv2_scale.x = p_margin_scale.x * uv2_padding / (lightmap_size.x == 0.0 ? PADDING_REF_SIZE : lightmap_size.x);
+ uv2_scale.y = p_margin_scale.y * uv2_padding / (lightmap_size.y == 0.0 ? PADDING_REF_SIZE : lightmap_size.y);
+
+ // Inverse it to turn our margin into a scale
+ uv2_scale = Vector2(1.0, 1.0) - uv2_scale;
+
+ return uv2_scale;
+}
+
+float PrimitiveMesh::get_lightmap_texel_size() const {
+ float texel_size = GLOBAL_GET("rendering/lightmapping/primitive_meshes/texel_size");
+
+ if (texel_size <= 0.0) {
+ texel_size = 0.2;
+ }
+
+ return texel_size;
+}
+
PrimitiveMesh::PrimitiveMesh() {
mesh = RenderingServer::get_singleton()->mesh_create();
}
@@ -275,22 +347,52 @@ PrimitiveMesh::~PrimitiveMesh() {
CapsuleMesh
*/
+void CapsuleMesh::_update_lightmap_size() {
+ if (get_add_uv2()) {
+ // size must have changed, update lightmap size hint
+ Size2i _lightmap_size_hint;
+ float texel_size = get_lightmap_texel_size();
+ float padding = get_uv2_padding();
+
+ float radial_length = radius * Math_PI * 0.5; // circumference of 90 degree bend
+ float vertical_length = radial_length * 2 + (height - 2.0 * radius); // total vertical length
+
+ _lightmap_size_hint.x = MAX(1.0, 4.0 * radial_length / texel_size) + padding;
+ _lightmap_size_hint.y = MAX(1.0, vertical_length / texel_size) + padding;
+
+ set_lightmap_size_hint(_lightmap_size_hint);
+ }
+}
+
void CapsuleMesh::_create_mesh_array(Array &p_arr) const {
- create_mesh_array(p_arr, radius, height, radial_segments, rings);
+ bool _add_uv2 = get_add_uv2();
+ float texel_size = get_lightmap_texel_size();
+ float _uv2_padding = get_uv2_padding() * texel_size;
+
+ create_mesh_array(p_arr, radius, height, radial_segments, rings, _add_uv2, _uv2_padding);
}
-void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const float height, const int radial_segments, const int rings) {
+void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const float height, const int radial_segments, const int rings, bool p_add_uv2, const float p_uv2_padding) {
int i, j, prevrow, thisrow, point;
float x, y, z, u, v, w;
float onethird = 1.0 / 3.0;
float twothirds = 2.0 / 3.0;
+ // Only used if we calculate UV2
+ float radial_width = 2.0 * radius * Math_PI;
+ float radial_h = radial_width / (radial_width + p_uv2_padding);
+ float radial_length = radius * Math_PI * 0.5; // circumference of 90 degree bend
+ float vertical_length = radial_length * 2 + (height - 2.0 * radius) + p_uv2_padding; // total vertical length
+ float radial_v = radial_length / vertical_length; // v size of top and bottom section
+ float height_v = (height - 2.0 * radius) / vertical_length; // v size of height section
+
// note, this has been aligned with our collision shape but I've left the descriptions as top/middle/bottom
Vector<Vector3> points;
Vector<Vector3> normals;
Vector<float> tangents;
Vector<Vector2> uvs;
+ Vector<Vector2> uv2s;
Vector<int> indices;
point = 0;
@@ -322,6 +424,9 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa
normals.push_back(p.normalized());
ADD_TANGENT(-z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u, v * onethird));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(u * radial_h, v * radial_v));
+ }
point++;
if (i > 0 && j > 0) {
@@ -361,6 +466,9 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa
normals.push_back(Vector3(x, 0.0, -z));
ADD_TANGENT(-z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u, onethird + (v * onethird)));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(u * radial_h, radial_v + (v * height_v)));
+ }
point++;
if (i > 0 && j > 0) {
@@ -390,17 +498,20 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa
y = radius * cos(0.5 * Math_PI * v);
for (i = 0; i <= radial_segments; i++) {
- float u2 = i;
- u2 /= radial_segments;
+ u = i;
+ u /= radial_segments;
- x = -sin(u2 * Math_TAU);
- z = cos(u2 * Math_TAU);
+ x = -sin(u * Math_TAU);
+ z = cos(u * Math_TAU);
Vector3 p = Vector3(x * radius * w, y, -z * radius * w);
points.push_back(p + Vector3(0.0, -0.5 * height + radius, 0.0));
normals.push_back(p.normalized());
ADD_TANGENT(-z, 0.0, -x, 1.0)
- uvs.push_back(Vector2(u2, twothirds + ((v - 1.0) * onethird)));
+ uvs.push_back(Vector2(u, twothirds + ((v - 1.0) * onethird)));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(u * radial_h, radial_v + height_v + ((v - 1.0) * radial_v)));
+ }
point++;
if (i > 0 && j > 0) {
@@ -422,6 +533,9 @@ void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const floa
p_arr[RS::ARRAY_NORMAL] = normals;
p_arr[RS::ARRAY_TANGENT] = tangents;
p_arr[RS::ARRAY_TEX_UV] = uvs;
+ if (p_add_uv2) {
+ p_arr[RS::ARRAY_TEX_UV2] = uv2s;
+ }
p_arr[RS::ARRAY_INDEX] = indices;
}
@@ -450,6 +564,7 @@ void CapsuleMesh::set_radius(const float p_radius) {
if (radius > height * 0.5) {
height = radius * 2.0;
}
+ _update_lightmap_size();
_request_update();
}
@@ -462,6 +577,7 @@ void CapsuleMesh::set_height(const float p_height) {
if (radius > height * 0.5) {
radius = height * 0.5;
}
+ _update_lightmap_size();
_request_update();
}
@@ -493,16 +609,53 @@ CapsuleMesh::CapsuleMesh() {}
BoxMesh
*/
+void BoxMesh::_update_lightmap_size() {
+ if (get_add_uv2()) {
+ // size must have changed, update lightmap size hint
+ Size2i _lightmap_size_hint;
+ float texel_size = get_lightmap_texel_size();
+ float padding = get_uv2_padding();
+
+ float width = (size.x + size.z) / texel_size;
+ float length = (size.y + size.y + MAX(size.x, size.z)) / texel_size;
+
+ _lightmap_size_hint.x = MAX(1.0, width) + 2.0 * padding;
+ _lightmap_size_hint.y = MAX(1.0, length) + 3.0 * padding;
+
+ set_lightmap_size_hint(_lightmap_size_hint);
+ }
+}
+
void BoxMesh::_create_mesh_array(Array &p_arr) const {
- BoxMesh::create_mesh_array(p_arr, size, subdivide_w, subdivide_h, subdivide_d);
+ // Note about padding, with our box each face of the box faces a different direction so we want a seam
+ // around every face. We thus add our padding to the right and bottom of each face.
+ // With 3 faces along the width and 2 along the height of the texture we need to adjust our scale
+ // accordingly.
+ bool _add_uv2 = get_add_uv2();
+ float texel_size = get_lightmap_texel_size();
+ float _uv2_padding = get_uv2_padding() * texel_size;
+
+ BoxMesh::create_mesh_array(p_arr, size, subdivide_w, subdivide_h, subdivide_d, _add_uv2, _uv2_padding);
}
-void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int subdivide_h, int subdivide_d) {
+void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int subdivide_h, int subdivide_d, bool p_add_uv2, const float p_uv2_padding) {
int i, j, prevrow, thisrow, point;
float x, y, z;
float onethird = 1.0 / 3.0;
float twothirds = 2.0 / 3.0;
+ // Only used if we calculate UV2
+ // TODO this could be improved by changing the order depending on which side is the longest (basically the below works best if size.y is the longest)
+ float total_h = (size.x + size.z + (2.0 * p_uv2_padding));
+ float padding_h = p_uv2_padding / total_h;
+ float width_h = size.x / total_h;
+ float depth_h = size.z / total_h;
+ float total_v = (size.y + size.y + MAX(size.x, size.z) + (3.0 * p_uv2_padding));
+ float padding_v = p_uv2_padding / total_v;
+ float width_v = size.x / total_v;
+ float height_v = size.y / total_v;
+ float depth_v = size.z / total_v;
+
Vector3 start_pos = size * -0.5;
// set our bounding box
@@ -511,6 +664,7 @@ void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int
Vector<Vector3> normals;
Vector<float> tangents;
Vector<Vector2> uvs;
+ Vector<Vector2> uv2s;
Vector<int> indices;
point = 0;
@@ -525,18 +679,24 @@ void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int
thisrow = point;
prevrow = 0;
for (j = 0; j <= subdivide_h + 1; j++) {
+ float v = j;
+ float v2 = v / (subdivide_w + 1.0);
+ v /= (2.0 * (subdivide_h + 1.0));
+
x = start_pos.x;
for (i = 0; i <= subdivide_w + 1; i++) {
float u = i;
- float v = j;
+ float u2 = u / (subdivide_w + 1.0);
u /= (3.0 * (subdivide_w + 1.0));
- v /= (2.0 * (subdivide_h + 1.0));
// front
points.push_back(Vector3(x, -y, -start_pos.z)); // double negative on the Z!
normals.push_back(Vector3(0.0, 0.0, 1.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
uvs.push_back(Vector2(u, v));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(u2 * width_h, v2 * height_v));
+ }
point++;
// back
@@ -544,6 +704,9 @@ void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int
normals.push_back(Vector3(0.0, 0.0, -1.0));
ADD_TANGENT(-1.0, 0.0, 0.0, 1.0);
uvs.push_back(Vector2(twothirds + u, v));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(u2 * width_h, height_v + padding_v + (v2 * height_v)));
+ }
point++;
if (i > 0 && j > 0) {
@@ -579,18 +742,24 @@ void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int
thisrow = point;
prevrow = 0;
for (j = 0; j <= (subdivide_h + 1); j++) {
+ float v = j;
+ float v2 = v / (subdivide_h + 1.0);
+ v /= (2.0 * (subdivide_h + 1.0));
+
z = start_pos.z;
for (i = 0; i <= (subdivide_d + 1); i++) {
float u = i;
- float v = j;
+ float u2 = u / (subdivide_d + 1.0);
u /= (3.0 * (subdivide_d + 1.0));
- v /= (2.0 * (subdivide_h + 1.0));
// right
points.push_back(Vector3(-start_pos.x, -y, -z));
normals.push_back(Vector3(1.0, 0.0, 0.0));
ADD_TANGENT(0.0, 0.0, -1.0, 1.0);
uvs.push_back(Vector2(onethird + u, v));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(width_h + padding_h + (u2 * depth_h), v2 * height_v));
+ }
point++;
// left
@@ -598,6 +767,9 @@ void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int
normals.push_back(Vector3(-1.0, 0.0, 0.0));
ADD_TANGENT(0.0, 0.0, 1.0, 1.0);
uvs.push_back(Vector2(u, 0.5 + v));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(width_h + padding_h + (u2 * depth_h), height_v + padding_v + (v2 * height_v)));
+ }
point++;
if (i > 0 && j > 0) {
@@ -633,18 +805,24 @@ void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int
thisrow = point;
prevrow = 0;
for (j = 0; j <= (subdivide_d + 1); j++) {
+ float v = j;
+ float v2 = v / (subdivide_d + 1.0);
+ v /= (2.0 * (subdivide_d + 1.0));
+
x = start_pos.x;
for (i = 0; i <= (subdivide_w + 1); i++) {
float u = i;
- float v = j;
+ float u2 = u / (subdivide_w + 1.0);
u /= (3.0 * (subdivide_w + 1.0));
- v /= (2.0 * (subdivide_d + 1.0));
// top
points.push_back(Vector3(-x, -start_pos.y, -z));
normals.push_back(Vector3(0.0, 1.0, 0.0));
ADD_TANGENT(-1.0, 0.0, 0.0, 1.0);
uvs.push_back(Vector2(onethird + u, 0.5 + v));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(u2 * width_h, ((height_v + padding_v) * 2.0) + (v2 * depth_v)));
+ }
point++;
// bottom
@@ -652,6 +830,9 @@ void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int
normals.push_back(Vector3(0.0, -1.0, 0.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
uvs.push_back(Vector2(twothirds + u, 0.5 + v));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(width_h + padding_h + (u2 * depth_h), ((height_v + padding_v) * 2.0) + (v2 * width_v)));
+ }
point++;
if (i > 0 && j > 0) {
@@ -686,6 +867,9 @@ void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int
p_arr[RS::ARRAY_NORMAL] = normals;
p_arr[RS::ARRAY_TANGENT] = tangents;
p_arr[RS::ARRAY_TEX_UV] = uvs;
+ if (p_add_uv2) {
+ p_arr[RS::ARRAY_TEX_UV2] = uv2s;
+ }
p_arr[RS::ARRAY_INDEX] = indices;
}
@@ -708,6 +892,7 @@ void BoxMesh::_bind_methods() {
void BoxMesh::set_size(const Vector3 &p_size) {
size = p_size;
+ _update_lightmap_size();
_request_update();
}
@@ -748,18 +933,58 @@ BoxMesh::BoxMesh() {}
CylinderMesh
*/
+void CylinderMesh::_update_lightmap_size() {
+ if (get_add_uv2()) {
+ // size must have changed, update lightmap size hint
+ Size2i _lightmap_size_hint;
+ float texel_size = get_lightmap_texel_size();
+ float padding = get_uv2_padding();
+
+ float top_circumference = top_radius * Math_PI * 2.0;
+ float bottom_circumference = bottom_radius * Math_PI * 2.0;
+
+ float _width = MAX(top_circumference, bottom_circumference) / texel_size + padding;
+ _width = MAX(_width, (((top_radius + bottom_radius) / texel_size) + padding) * 2.0); // this is extremely unlikely to be larger, will only happen if padding is larger then our diameter.
+ _lightmap_size_hint.x = MAX(1.0, _width);
+
+ float _height = ((height + (MAX(top_radius, bottom_radius) * 2.0)) / texel_size) + (2.0 * padding);
+
+ _lightmap_size_hint.y = MAX(1.0, _height);
+
+ set_lightmap_size_hint(_lightmap_size_hint);
+ }
+}
+
void CylinderMesh::_create_mesh_array(Array &p_arr) const {
- create_mesh_array(p_arr, top_radius, bottom_radius, height, radial_segments, rings, cap_top, cap_bottom);
+ bool _add_uv2 = get_add_uv2();
+ float texel_size = get_lightmap_texel_size();
+ float _uv2_padding = get_uv2_padding() * texel_size;
+
+ create_mesh_array(p_arr, top_radius, bottom_radius, height, radial_segments, rings, cap_top, cap_bottom, _add_uv2, _uv2_padding);
}
-void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments, int rings, bool cap_top, bool cap_bottom) {
+void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments, int rings, bool cap_top, bool cap_bottom, bool p_add_uv2, const float p_uv2_padding) {
int i, j, prevrow, thisrow, point;
- float x, y, z, u, v, radius;
+ float x, y, z, u, v, radius, radius_h;
+
+ // Only used if we calculate UV2
+ float top_circumference = top_radius * Math_PI * 2.0;
+ float bottom_circumference = bottom_radius * Math_PI * 2.0;
+ float vertical_length = height + MAX(2.0 * top_radius, 2.0 * bottom_radius) + (2.0 * p_uv2_padding);
+ float height_v = height / vertical_length;
+ float padding_v = p_uv2_padding / vertical_length;
+
+ float horizonal_length = MAX(MAX(2.0 * (top_radius + bottom_radius + p_uv2_padding), top_circumference + p_uv2_padding), bottom_circumference + p_uv2_padding);
+ float center_h = 0.5 * (horizonal_length - p_uv2_padding) / horizonal_length;
+ float top_h = top_circumference / horizonal_length;
+ float bottom_h = bottom_circumference / horizonal_length;
+ float padding_h = p_uv2_padding / horizonal_length;
Vector<Vector3> points;
Vector<Vector3> normals;
Vector<float> tangents;
Vector<Vector2> uvs;
+ Vector<Vector2> uv2s;
Vector<int> indices;
point = 0;
@@ -777,6 +1002,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
v /= (rings + 1);
radius = top_radius + ((bottom_radius - top_radius) * v);
+ radius_h = top_h + ((bottom_h - top_h) * v);
y = height * v;
y = (height * 0.5) - y;
@@ -793,6 +1019,9 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
normals.push_back(Vector3(x, side_normal_y, z).normalized());
ADD_TANGENT(z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u, v * 0.5));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(center_h + (u - 0.5) * radius_h, v * height_v));
+ }
point++;
if (i > 0 && j > 0) {
@@ -810,6 +1039,12 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
thisrow = point;
};
+ // Adjust for buttom section, only used if we calculate UV2s
+ top_h = top_radius / horizonal_length;
+ float top_v = top_radius / vertical_length;
+ bottom_h = bottom_radius / horizonal_length;
+ float bottom_v = bottom_radius / vertical_length;
+
// add top
if (cap_top && top_radius > 0.0) {
y = height * 0.5;
@@ -819,6 +1054,9 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
normals.push_back(Vector3(0.0, 1.0, 0.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
uvs.push_back(Vector2(0.25, 0.75));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(top_h, height_v + padding_v + MAX(top_v, bottom_v)));
+ }
point++;
for (i = 0; i <= radial_segments; i++) {
@@ -836,6 +1074,9 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
normals.push_back(Vector3(0.0, 1.0, 0.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
uvs.push_back(Vector2(u, v));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(top_h + (x * top_h), height_v + padding_v + MAX(top_v, bottom_v) + (z * top_v)));
+ }
point++;
if (i > 0) {
@@ -855,6 +1096,9 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
normals.push_back(Vector3(0.0, -1.0, 0.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
uvs.push_back(Vector2(0.75, 0.75));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(top_h + top_h + padding_h + bottom_h, height_v + padding_v + MAX(top_v, bottom_v)));
+ }
point++;
for (i = 0; i <= radial_segments; i++) {
@@ -872,6 +1116,9 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
normals.push_back(Vector3(0.0, -1.0, 0.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
uvs.push_back(Vector2(u, v));
+ if (p_add_uv2) {
+ uv2s.push_back(Vector2(top_h + top_h + padding_h + bottom_h + (x * bottom_h), height_v + padding_v + MAX(top_v, bottom_v) - (z * bottom_v)));
+ }
point++;
if (i > 0) {
@@ -886,6 +1133,9 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
p_arr[RS::ARRAY_NORMAL] = normals;
p_arr[RS::ARRAY_TANGENT] = tangents;
p_arr[RS::ARRAY_TEX_UV] = uvs;
+ if (p_add_uv2) {
+ p_arr[RS::ARRAY_TEX_UV2] = uv2s;
+ }
p_arr[RS::ARRAY_INDEX] = indices;
}
@@ -919,6 +1169,7 @@ void CylinderMesh::_bind_methods() {
void CylinderMesh::set_top_radius(const float p_radius) {
top_radius = p_radius;
+ _update_lightmap_size();
_request_update();
}
@@ -928,6 +1179,7 @@ float CylinderMesh::get_top_radius() const {
void CylinderMesh::set_bottom_radius(const float p_radius) {
bottom_radius = p_radius;
+ _update_lightmap_size();
_request_update();
}
@@ -937,6 +1189,7 @@ float CylinderMesh::get_bottom_radius() const {
void CylinderMesh::set_height(const float p_height) {
height = p_height;
+ _update_lightmap_size();
_request_update();
}
@@ -986,10 +1239,26 @@ CylinderMesh::CylinderMesh() {}
PlaneMesh
*/
+void PlaneMesh::_update_lightmap_size() {
+ if (get_add_uv2()) {
+ // size must have changed, update lightmap size hint
+ Size2i _lightmap_size_hint;
+ float texel_size = get_lightmap_texel_size();
+ float padding = get_uv2_padding();
+
+ _lightmap_size_hint.x = MAX(1.0, (size.x / texel_size) + padding);
+ _lightmap_size_hint.y = MAX(1.0, (size.y / texel_size) + padding);
+
+ set_lightmap_size_hint(_lightmap_size_hint);
+ }
+}
+
void PlaneMesh::_create_mesh_array(Array &p_arr) const {
int i, j, prevrow, thisrow, point;
float x, z;
+ // Plane mesh can use default UV2 calculation as implemented in Primitive Mesh
+
Size2 start_pos = size * -0.5;
Vector3 normal = Vector3(0.0, 1.0, 0.0);
@@ -1088,6 +1357,7 @@ void PlaneMesh::_bind_methods() {
void PlaneMesh::set_size(const Size2 &p_size) {
size = p_size;
+ _update_lightmap_size();
_request_update();
}
@@ -1137,12 +1407,49 @@ PlaneMesh::PlaneMesh() {}
PrismMesh
*/
+void PrismMesh::_update_lightmap_size() {
+ if (get_add_uv2()) {
+ // size must have changed, update lightmap size hint
+ Size2i _lightmap_size_hint;
+ float texel_size = get_lightmap_texel_size();
+ float padding = get_uv2_padding();
+
+ // left_to_right does not effect the surface area of the prism so we ignore that.
+ // TODO we could combine the two triangles and save some space but we need to re-align the uv1 and adjust the tangent.
+
+ float width = (size.x + size.z) / texel_size;
+ float length = (size.y + size.y + size.z) / texel_size;
+
+ _lightmap_size_hint.x = MAX(1.0, width) + 2.0 * padding;
+ _lightmap_size_hint.y = MAX(1.0, length) + 3.0 * padding;
+
+ set_lightmap_size_hint(_lightmap_size_hint);
+ }
+}
+
void PrismMesh::_create_mesh_array(Array &p_arr) const {
int i, j, prevrow, thisrow, point;
float x, y, z;
float onethird = 1.0 / 3.0;
float twothirds = 2.0 / 3.0;
+ // Only used if we calculate UV2
+ bool _add_uv2 = get_add_uv2();
+ float texel_size = get_lightmap_texel_size();
+ float _uv2_padding = get_uv2_padding() * texel_size;
+
+ float horizontal_total = size.x + size.z + 2.0 * _uv2_padding;
+ float width_h = size.x / horizontal_total;
+ float depth_h = size.z / horizontal_total;
+ float padding_h = _uv2_padding / horizontal_total;
+
+ float vertical_total = (size.y + size.y + size.z) + (3.0 * _uv2_padding);
+ float height_v = size.y / vertical_total;
+ float depth_v = size.z / vertical_total;
+ float padding_v = _uv2_padding / vertical_total;
+
+ // and start building
+
Vector3 start_pos = size * -0.5;
// set our bounding box
@@ -1151,6 +1458,7 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
Vector<Vector3> normals;
Vector<float> tangents;
Vector<Vector2> uvs;
+ Vector<Vector2> uv2s;
Vector<int> indices;
point = 0;
@@ -1171,12 +1479,15 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
float offset_front = (1.0 - scale) * onethird * left_to_right;
float offset_back = (1.0 - scale) * onethird * (1.0 - left_to_right);
+ float v = j;
+ float v2 = j / (subdivide_h + 1.0);
+ v /= (2.0 * (subdivide_h + 1.0));
+
x = 0.0;
for (i = 0; i <= (subdivide_w + 1); i++) {
float u = i;
- float v = j;
+ float u2 = i / (subdivide_w + 1.0);
u /= (3.0 * (subdivide_w + 1.0));
- v /= (2.0 * (subdivide_h + 1.0));
u *= scale;
@@ -1185,6 +1496,9 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
normals.push_back(Vector3(0.0, 0.0, 1.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
uvs.push_back(Vector2(offset_front + u, v));
+ if (_add_uv2) {
+ uv2s.push_back(Vector2(u2 * scale * width_h, v2 * height_v));
+ }
point++;
/* back */
@@ -1192,6 +1506,9 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
normals.push_back(Vector3(0.0, 0.0, -1.0));
ADD_TANGENT(-1.0, 0.0, 0.0, 1.0);
uvs.push_back(Vector2(twothirds + offset_back + u, v));
+ if (_add_uv2) {
+ uv2s.push_back(Vector2(u2 * scale * width_h, height_v + padding_v + v2 * height_v));
+ }
point++;
if (i > 0 && j == 1) {
@@ -1246,6 +1563,10 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
thisrow = point;
prevrow = 0;
for (j = 0; j <= (subdivide_h + 1); j++) {
+ float v = j;
+ float v2 = j / (subdivide_h + 1.0);
+ v /= (2.0 * (subdivide_h + 1.0));
+
float left, right;
float scale = (y - start_pos.y) / size.y;
@@ -1255,15 +1576,17 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
z = start_pos.z;
for (i = 0; i <= (subdivide_d + 1); i++) {
float u = i;
- float v = j;
+ float u2 = u / (subdivide_d + 1.0);
u /= (3.0 * (subdivide_d + 1.0));
- v /= (2.0 * (subdivide_h + 1.0));
/* right */
points.push_back(Vector3(right, -y, -z));
normals.push_back(normal_right);
ADD_TANGENT(0.0, 0.0, -1.0, 1.0);
uvs.push_back(Vector2(onethird + u, v));
+ if (_add_uv2) {
+ uv2s.push_back(Vector2(width_h + padding_h + u2 * depth_h, v2 * height_v));
+ }
point++;
/* left */
@@ -1271,6 +1594,9 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
normals.push_back(normal_left);
ADD_TANGENT(0.0, 0.0, 1.0, 1.0);
uvs.push_back(Vector2(u, 0.5 + v));
+ if (_add_uv2) {
+ uv2s.push_back(Vector2(width_h + padding_h + u2 * depth_h, height_v + padding_v + v2 * height_v));
+ }
point++;
if (i > 0 && j > 0) {
@@ -1306,18 +1632,24 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
thisrow = point;
prevrow = 0;
for (j = 0; j <= (subdivide_d + 1); j++) {
+ float v = j;
+ float v2 = v / (subdivide_d + 1.0);
+ v /= (2.0 * (subdivide_d + 1.0));
+
x = start_pos.x;
for (i = 0; i <= (subdivide_w + 1); i++) {
float u = i;
- float v = j;
+ float u2 = u / (subdivide_w + 1.0);
u /= (3.0 * (subdivide_w + 1.0));
- v /= (2.0 * (subdivide_d + 1.0));
/* bottom */
points.push_back(Vector3(x, start_pos.y, -z));
normals.push_back(Vector3(0.0, -1.0, 0.0));
ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
uvs.push_back(Vector2(twothirds + u, 0.5 + v));
+ if (_add_uv2) {
+ uv2s.push_back(Vector2(u2 * width_h, 2.0 * (height_v + padding_v) + v2 * depth_v));
+ }
point++;
if (i > 0 && j > 0) {
@@ -1342,6 +1674,9 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
p_arr[RS::ARRAY_NORMAL] = normals;
p_arr[RS::ARRAY_TANGENT] = tangents;
p_arr[RS::ARRAY_TEX_UV] = uvs;
+ if (_add_uv2) {
+ p_arr[RS::ARRAY_TEX_UV2] = uv2s;
+ }
p_arr[RS::ARRAY_INDEX] = indices;
}
@@ -1377,6 +1712,7 @@ float PrismMesh::get_left_to_right() const {
void PrismMesh::set_size(const Vector3 &p_size) {
size = p_size;
+ _update_lightmap_size();
_request_update();
}
@@ -1417,22 +1753,50 @@ PrismMesh::PrismMesh() {}
SphereMesh
*/
+void SphereMesh::_update_lightmap_size() {
+ if (get_add_uv2()) {
+ // size must have changed, update lightmap size hint
+ Size2i _lightmap_size_hint;
+ float texel_size = get_lightmap_texel_size();
+ float padding = get_uv2_padding();
+
+ float _width = radius * Math_TAU;
+ _lightmap_size_hint.x = MAX(1.0, (_width / texel_size) + padding);
+ float _height = (is_hemisphere ? 1.0 : 0.5) * height * Math_PI; // note, with hemisphere height is our radius, while with a full sphere it is the diameter..
+ _lightmap_size_hint.y = MAX(1.0, (_height / texel_size) + padding);
+
+ set_lightmap_size_hint(_lightmap_size_hint);
+ }
+}
+
void SphereMesh::_create_mesh_array(Array &p_arr) const {
- create_mesh_array(p_arr, radius, height, radial_segments, rings, is_hemisphere);
+ bool _add_uv2 = get_add_uv2();
+ float texel_size = get_lightmap_texel_size();
+ float _uv2_padding = get_uv2_padding() * texel_size;
+
+ create_mesh_array(p_arr, radius, height, radial_segments, rings, is_hemisphere, _add_uv2, _uv2_padding);
}
-void SphereMesh::create_mesh_array(Array &p_arr, float radius, float height, int radial_segments, int rings, bool is_hemisphere) {
+void SphereMesh::create_mesh_array(Array &p_arr, float radius, float height, int radial_segments, int rings, bool is_hemisphere, bool p_add_uv2, const float p_uv2_padding) {
int i, j, prevrow, thisrow, point;
float x, y, z;
float scale = height * (is_hemisphere ? 1.0 : 0.5);
+ // Only used if we calculate UV2
+ float circumference = radius * Math_TAU;
+ float horizontal_length = circumference + p_uv2_padding;
+ float center_h = 0.5 * circumference / horizontal_length;
+
+ float height_v = scale * Math_PI / ((scale * Math_PI) + p_uv2_padding);
+
// set our bounding box
Vector<Vector3> points;
Vector<Vector3> normals;
Vector<float> tangents;
Vector<Vector2> uvs;
+ Vector<Vector2> uv2s;
Vector<int> indices;
point = 0;
@@ -1470,6 +1834,10 @@ void SphereMesh::create_mesh_array(Array &p_arr, float radius, float height, int
};
ADD_TANGENT(z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u, v));
+ if (p_add_uv2) {
+ float w_h = w * 2.0 * center_h;
+ uv2s.push_back(Vector2(center_h + ((u - 0.5) * w_h), v * height_v));
+ }
point++;
if (i > 0 && j > 0) {
@@ -1491,6 +1859,9 @@ void SphereMesh::create_mesh_array(Array &p_arr, float radius, float height, int
p_arr[RS::ARRAY_NORMAL] = normals;
p_arr[RS::ARRAY_TANGENT] = tangents;
p_arr[RS::ARRAY_TEX_UV] = uvs;
+ if (p_add_uv2) {
+ p_arr[RS::ARRAY_TEX_UV2] = uv2s;
+ }
p_arr[RS::ARRAY_INDEX] = indices;
}
@@ -1517,6 +1888,7 @@ void SphereMesh::_bind_methods() {
void SphereMesh::set_radius(const float p_radius) {
radius = p_radius;
+ _update_lightmap_size();
_request_update();
}
@@ -1526,6 +1898,7 @@ float SphereMesh::get_radius() const {
void SphereMesh::set_height(const float p_height) {
height = p_height;
+ _update_lightmap_size();
_request_update();
}
@@ -1553,6 +1926,7 @@ int SphereMesh::get_rings() const {
void SphereMesh::set_is_hemisphere(const bool p_is_hemisphere) {
is_hemisphere = p_is_hemisphere;
+ _update_lightmap_size();
_request_update();
}
@@ -1566,6 +1940,31 @@ SphereMesh::SphereMesh() {}
TorusMesh
*/
+void TorusMesh::_update_lightmap_size() {
+ if (get_add_uv2()) {
+ // size must have changed, update lightmap size hint
+ Size2i _lightmap_size_hint;
+ float texel_size = get_lightmap_texel_size();
+ float padding = get_uv2_padding();
+
+ float min_radius = inner_radius;
+ float max_radius = outer_radius;
+
+ if (min_radius > max_radius) {
+ SWAP(min_radius, max_radius);
+ }
+
+ float radius = (max_radius - min_radius) * 0.5;
+
+ float _width = max_radius * Math_TAU;
+ _lightmap_size_hint.x = MAX(1.0, (_width / texel_size) + padding);
+ float _height = radius * Math_TAU;
+ _lightmap_size_hint.y = MAX(1.0, (_height / texel_size) + padding);
+
+ set_lightmap_size_hint(_lightmap_size_hint);
+ }
+}
+
void TorusMesh::_create_mesh_array(Array &p_arr) const {
// set our bounding box
@@ -1573,6 +1972,7 @@ void TorusMesh::_create_mesh_array(Array &p_arr) const {
Vector<Vector3> normals;
Vector<float> tangents;
Vector<Vector2> uvs;
+ Vector<Vector2> uv2s;
Vector<int> indices;
#define ADD_TANGENT(m_x, m_y, m_z, m_d) \
@@ -1592,6 +1992,17 @@ void TorusMesh::_create_mesh_array(Array &p_arr) const {
float radius = (max_radius - min_radius) * 0.5;
+ // Only used if we calculate UV2
+ bool _add_uv2 = get_add_uv2();
+ float texel_size = get_lightmap_texel_size();
+ float _uv2_padding = get_uv2_padding() * texel_size;
+
+ float horizontal_total = max_radius * Math_TAU + _uv2_padding;
+ float max_h = max_radius * Math_TAU / horizontal_total;
+ float delta_h = (max_radius - min_radius) * Math_TAU / horizontal_total;
+
+ float height_v = radius * Math_TAU / (radius * Math_TAU + _uv2_padding);
+
for (int i = 0; i <= rings; i++) {
int prevrow = (i - 1) * (ring_segments + 1);
int thisrow = i * (ring_segments + 1);
@@ -1607,10 +2018,17 @@ void TorusMesh::_create_mesh_array(Array &p_arr) const {
Vector2 normalj = Vector2(-Math::cos(angj), Math::sin(angj));
Vector2 normalk = normalj * radius + Vector2(min_radius + radius, 0);
+ float offset_h = 0.5 * (1.0 - normalj.x) * delta_h;
+ float adj_h = max_h - offset_h;
+ offset_h *= 0.5;
+
points.push_back(Vector3(normali.x * normalk.x, normalk.y, normali.y * normalk.x));
normals.push_back(Vector3(normali.x * normalj.x, normalj.y, normali.y * normalj.x));
ADD_TANGENT(-Math::cos(angi), 0.0, Math::sin(angi), 1.0);
uvs.push_back(Vector2(inci, incj));
+ if (_add_uv2) {
+ uv2s.push_back(Vector2(offset_h + inci * adj_h, incj * height_v));
+ }
if (i > 0 && j > 0) {
indices.push_back(thisrow + j - 1);
@@ -1628,6 +2046,9 @@ void TorusMesh::_create_mesh_array(Array &p_arr) const {
p_arr[RS::ARRAY_NORMAL] = normals;
p_arr[RS::ARRAY_TANGENT] = tangents;
p_arr[RS::ARRAY_TEX_UV] = uvs;
+ if (_add_uv2) {
+ p_arr[RS::ARRAY_TEX_UV2] = uv2s;
+ }
p_arr[RS::ARRAY_INDEX] = indices;
}
@@ -1785,6 +2206,8 @@ Transform3D TubeTrailMesh::get_builtin_bind_pose(int p_index) const {
}
void TubeTrailMesh::_create_mesh_array(Array &p_arr) const {
+ // Seeing use case for TubeTrailMesh, no need to do anything more then default UV2 calculation
+
PackedVector3Array points;
PackedVector3Array normals;
PackedFloat32Array tangents;
@@ -2109,6 +2532,8 @@ Transform3D RibbonTrailMesh::get_builtin_bind_pose(int p_index) const {
}
void RibbonTrailMesh::_create_mesh_array(Array &p_arr) const {
+ // Seeing use case of ribbon trail mesh, no need to implement special UV2 calculation
+
PackedVector3Array points;
PackedVector3Array normals;
PackedFloat32Array tangents;
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index ee61f0ac55..06f9781b84 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -56,6 +56,9 @@ private:
Ref<Material> material;
bool flip_faces = false;
+ bool add_uv2 = false;
+ float uv2_padding = 2.0;
+
// make sure we do an update after we've finished constructing our object
mutable bool pending_request = true;
void _update() const;
@@ -70,6 +73,10 @@ protected:
void _request_update();
GDVIRTUAL0RC(Array, _create_mesh_array)
+ Vector2 get_uv2_scale(Vector2 p_margin_scale = Vector2(1.0, 1.0)) const;
+ float get_lightmap_texel_size() const;
+ virtual void _update_lightmap_size(){};
+
public:
virtual int get_surface_count() const override;
virtual int surface_get_array_len(int p_idx) const override;
@@ -98,6 +105,12 @@ public:
void set_flip_faces(bool p_enable);
bool get_flip_faces() const;
+ void set_add_uv2(bool p_enable);
+ bool get_add_uv2() const { return add_uv2; }
+
+ void set_uv2_padding(float p_padding);
+ float get_uv2_padding() const { return uv2_padding; }
+
PrimitiveMesh();
~PrimitiveMesh();
};
@@ -118,8 +131,10 @@ protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
+ virtual void _update_lightmap_size() override;
+
public:
- static void create_mesh_array(Array &p_arr, float radius, float height, int radial_segments = 64, int rings = 8);
+ static void create_mesh_array(Array &p_arr, float radius, float height, int radial_segments = 64, int rings = 8, bool p_add_uv2 = false, const float p_uv2_padding = 1.0);
void set_radius(const float p_radius);
float get_radius() const;
@@ -152,8 +167,10 @@ protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
+ virtual void _update_lightmap_size() override;
+
public:
- static void create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w = 0, int subdivide_h = 0, int subdivide_d = 0);
+ static void create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w = 0, int subdivide_h = 0, int subdivide_d = 0, bool p_add_uv2 = false, const float p_uv2_padding = 1.0);
void set_size(const Vector3 &p_size);
Vector3 get_size() const;
@@ -190,8 +207,10 @@ protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
+ virtual void _update_lightmap_size() override;
+
public:
- static void create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments = 64, int rings = 4, bool cap_top = true, bool cap_bottom = true);
+ static void create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments = 64, int rings = 4, bool cap_top = true, bool cap_bottom = true, bool p_add_uv2 = false, const float p_uv2_padding = 1.0);
void set_top_radius(const float p_radius);
float get_top_radius() const;
@@ -241,6 +260,8 @@ protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
+ virtual void _update_lightmap_size() override;
+
public:
void set_size(const Size2 &p_size);
Size2 get_size() const;
@@ -292,6 +313,8 @@ protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
+ virtual void _update_lightmap_size() override;
+
public:
void set_left_to_right(const float p_left_to_right);
float get_left_to_right() const;
@@ -328,8 +351,10 @@ protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
+ virtual void _update_lightmap_size() override;
+
public:
- static void create_mesh_array(Array &p_arr, float radius, float height, int radial_segments = 64, int rings = 32, bool is_hemisphere = false);
+ static void create_mesh_array(Array &p_arr, float radius, float height, int radial_segments = 64, int rings = 32, bool is_hemisphere = false, bool p_add_uv2 = false, const float p_uv2_padding = 1.0);
void set_radius(const float p_radius);
float get_radius() const;
@@ -365,6 +390,8 @@ protected:
static void _bind_methods();
virtual void _create_mesh_array(Array &p_arr) const override;
+ virtual void _update_lightmap_size() override;
+
public:
void set_inner_radius(const float p_inner_radius);
float get_inner_radius() const;
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 4d566178a5..3a671edeea 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -177,7 +177,7 @@ bool Shader::is_text_shader() const {
}
bool Shader::has_parameter(const StringName &p_name) const {
- return params_cache.has("shader_parameter/" + p_name);
+ return params_cache.has(p_name);
}
void Shader::_update_shader() const {
diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp
index 61daf801e8..af84144591 100644
--- a/scene/resources/shape_2d.cpp
+++ b/scene/resources/shape_2d.cpp
@@ -116,7 +116,7 @@ bool Shape2D::is_collision_outline_enabled() {
return true;
}
#endif
- return GLOBAL_DEF("debug/shapes/collision/draw_2d_outlines", true);
+ return GLOBAL_GET("debug/shapes/collision/draw_2d_outlines");
}
Shape2D::Shape2D(const RID &p_rid) {
diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp
index ca1cd54349..afab44834d 100644
--- a/scene/resources/text_line.cpp
+++ b/scene/resources/text_line.cpp
@@ -317,11 +317,7 @@ float TextLine::get_width() const {
Size2 TextLine::get_size() const {
const_cast<TextLine *>(this)->_shape();
- if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y);
- } else {
- return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y);
- }
+ return TS->shaped_text_get_size(rid);
}
float TextLine::get_line_ascent() const {
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 04637983b5..03abac1b3e 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -3108,9 +3108,9 @@ void VisualShaderNodeUVFunc::set_function(VisualShaderNodeUVFunc::Function p_fun
return;
}
if (p_func == FUNC_PANNING) {
- set_input_port_default_value(2, Vector2()); // offset
+ set_input_port_default_value(2, Vector2(), get_input_port_default_value(2)); // offset
} else { // FUNC_SCALING
- set_input_port_default_value(2, Vector2(0.5, 0.5)); // pivot
+ set_input_port_default_value(2, Vector2(0.5, 0.5), get_input_port_default_value(2)); // pivot
}
func = p_func;
emit_changed();
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 07cb59aaee..52d7f66203 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -302,19 +302,12 @@ void DisplayServer::tts_post_utterance_event(TTSUtteranceEvent p_event, int p_id
case DisplayServer::TTS_UTTERANCE_ENDED:
case DisplayServer::TTS_UTTERANCE_CANCELED: {
if (utterance_callback[p_event].is_valid()) {
- Variant args[1];
- args[0] = p_id;
- const Variant *argp[] = { &args[0] };
- utterance_callback[p_event].call_deferredp(argp, 1); // Should be deferred, on some platforms utterance events can be called from different threads in a rapid succession.
+ utterance_callback[p_event].call_deferred(p_id); // Should be deferred, on some platforms utterance events can be called from different threads in a rapid succession.
}
} break;
case DisplayServer::TTS_UTTERANCE_BOUNDARY: {
if (utterance_callback[p_event].is_valid()) {
- Variant args[2];
- args[0] = p_pos;
- args[1] = p_id;
- const Variant *argp[] = { &args[0], &args[1] };
- utterance_callback[p_event].call_deferredp(argp, 2); // Should be deferred, on some platforms utterance events can be called from different threads in a rapid succession.
+ utterance_callback[p_event].call_deferred(p_pos, p_id); // Should be deferred, on some platforms utterance events can be called from different threads in a rapid succession.
}
} break;
default:
@@ -833,6 +826,7 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(DISPLAY_HANDLE);
BIND_ENUM_CONSTANT(WINDOW_HANDLE);
BIND_ENUM_CONSTANT(WINDOW_VIEW);
+ BIND_ENUM_CONSTANT(OPENGL_CONTEXT);
BIND_ENUM_CONSTANT(TTS_UTTERANCE_STARTED);
BIND_ENUM_CONSTANT(TTS_UTTERANCE_ENDED);
diff --git a/servers/display_server.h b/servers/display_server.h
index 55e9fb55dc..a796377f88 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -70,6 +70,7 @@ public:
DISPLAY_HANDLE,
WINDOW_HANDLE,
WINDOW_VIEW,
+ OPENGL_CONTEXT,
};
typedef DisplayServer *(*CreateFunction)(const String &, WindowMode, VSyncMode, uint32_t, const Point2i *, const Size2i &, Error &r_error);
diff --git a/servers/physics_2d/godot_space_2d.cpp b/servers/physics_2d/godot_space_2d.cpp
index a82d7dbbc4..89afb0e2a0 100644
--- a/servers/physics_2d/godot_space_2d.cpp
+++ b/servers/physics_2d/godot_space_2d.cpp
@@ -1225,7 +1225,7 @@ GodotSpace2D::GodotSpace2D() {
ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/solver/solver_iterations", PropertyInfo(Variant::INT, "physics/2d/solver/solver_iterations", PROPERTY_HINT_RANGE, "1,32,1,or_greater"));
contact_recycle_radius = GLOBAL_DEF("physics/2d/solver/contact_recycle_radius", 1.0);
- ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/solver/contact_recycle_radius", PropertyInfo(Variant::FLOAT, "physics/2d/solver/contact_max_separation", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater"));
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/solver/contact_recycle_radius", PropertyInfo(Variant::FLOAT, "physics/2d/solver/contact_recycle_radius", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater"));
contact_max_separation = GLOBAL_DEF("physics/2d/solver/contact_max_separation", 1.5);
ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/solver/contact_max_separation", PropertyInfo(Variant::FLOAT, "physics/2d/solver/contact_max_separation", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater"));
diff --git a/servers/physics_3d/godot_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp
index c23485279d..c98409e2c4 100644
--- a/servers/physics_3d/godot_space_3d.cpp
+++ b/servers/physics_3d/godot_space_3d.cpp
@@ -1258,7 +1258,7 @@ GodotSpace3D::GodotSpace3D() {
ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/solver/solver_iterations", PropertyInfo(Variant::INT, "physics/3d/solver/solver_iterations", PROPERTY_HINT_RANGE, "1,32,1,or_greater"));
contact_recycle_radius = GLOBAL_DEF("physics/3d/solver/contact_recycle_radius", 0.01);
- ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/solver/contact_recycle_radius", PropertyInfo(Variant::FLOAT, "physics/3d/solver/contact_max_separation", PROPERTY_HINT_RANGE, "0,0.1,0.01,or_greater"));
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/solver/contact_recycle_radius", PropertyInfo(Variant::FLOAT, "physics/3d/solver/contact_recycle_radius", PROPERTY_HINT_RANGE, "0,0.1,0.01,or_greater"));
contact_max_separation = GLOBAL_DEF("physics/3d/solver/contact_max_separation", 0.05);
ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/solver/contact_max_separation", PropertyInfo(Variant::FLOAT, "physics/3d/solver/contact_max_separation", PROPERTY_HINT_RANGE, "0,0.1,0.01,or_greater"));
diff --git a/servers/rendering/dummy/storage/mesh_storage.h b/servers/rendering/dummy/storage/mesh_storage.h
index b0914e70e4..4399f4ab66 100644
--- a/servers/rendering/dummy/storage/mesh_storage.h
+++ b/servers/rendering/dummy/storage/mesh_storage.h
@@ -81,6 +81,7 @@ public:
s->vertex_count = p_surface.vertex_count;
s->index_data = p_surface.index_data;
s->index_count = p_surface.index_count;
+ s->aabb = p_surface.aabb;
s->skin_data = p_surface.skin_data;
}
diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h
index ad28dd68c3..a17d734e10 100644
--- a/servers/rendering/dummy/storage/texture_storage.h
+++ b/servers/rendering/dummy/storage/texture_storage.h
@@ -126,6 +126,8 @@ public:
virtual Size2 texture_size_with_proxy(RID p_proxy) override { return Size2(); };
+ virtual RID texture_get_rd_texture_rid(RID p_texture, bool p_srgb = false) const override { return RID(); };
+
/* DECAL API */
virtual RID decal_allocate() override { return RID(); }
virtual void decal_initialize(RID p_rid) override {}
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index 41d4ca8d5e..16d382a5f3 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -1964,7 +1964,7 @@ void RendererCanvasCull::update_visibility_notifiers() {
if (!visibility_notifier->enter_callable.is_null()) {
if (RSG::threaded) {
- visibility_notifier->enter_callable.call_deferredp(nullptr, 0);
+ visibility_notifier->enter_callable.call_deferred();
} else {
Callable::CallError ce;
Variant ret;
@@ -1977,7 +1977,7 @@ void RendererCanvasCull::update_visibility_notifiers() {
if (!visibility_notifier->exit_callable.is_null()) {
if (RSG::threaded) {
- visibility_notifier->exit_callable.call_deferredp(nullptr, 0);
+ visibility_notifier->exit_callable.call_deferred();
} else {
Callable::CallError ce;
Variant ret;
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp
index a14228eb3d..27f977a80b 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp
@@ -1122,8 +1122,8 @@ void CopyEffects::cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_f
roughness.push_constant.use_direct_write = p_roughness == 0.0;
roughness.push_constant.face_size = p_size;
- // setup our uniforms
- RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ // Setup our uniforms.
+ RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_rd_texture }));
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 ceed287184..86425512b8 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -2311,6 +2311,8 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page
scene_data.lod_distance_multiplier = p_lod_distance_multiplier;
scene_data.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
scene_data.opaque_prepass_threshold = 0.1f;
+ scene_data.time = time;
+ scene_data.time_step = time_step;
RenderDataRD render_data;
render_data.scene_data = &scene_data;
@@ -3349,7 +3351,7 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet
SceneShaderForwardClustered::MaterialData *material_shadow = nullptr;
void *surface_shadow = nullptr;
- if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_position && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass && !p_material->shader_data->uses_alpha_clip && p_material->shader_data->cull_mode == SceneShaderForwardClustered::ShaderData::CULL_BACK) {
+ if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_position && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass && !p_material->shader_data->uses_alpha_clip && p_material->shader_data->cull_mode == SceneShaderForwardClustered::ShaderData::CULL_BACK && !p_material->shader_data->uses_point_size) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
material_shadow = static_cast<SceneShaderForwardClustered::MaterialData *>(RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index c1b23af82f..bd9c736d6a 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -115,6 +115,9 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
actions.usage_flag_pointers["ALPHA_SCISSOR_THRESHOLD"] = &uses_alpha_clip;
+ // Use alpha clip pipeline for alpha hash/dither.
+ // This prevents sorting issues inherent to alpha blending and allows such materials to cast shadows.
+ actions.usage_flag_pointers["ALPHA_HASH_SCALE"] = &uses_alpha_clip;
actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass;
actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index f76d016ae7..16711b0d5d 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -1269,6 +1269,8 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr
scene_data.lod_distance_multiplier = p_lod_distance_multiplier;
scene_data.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
scene_data.opaque_prepass_threshold = 0.1;
+ scene_data.time = time;
+ scene_data.time_step = time_step;
RenderDataRD render_data;
render_data.scene_data = &scene_data;
@@ -2004,6 +2006,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
RID prev_index_array_rd;
RID prev_pipeline_rd;
RID prev_xforms_uniform_set;
+ bool should_request_redraw = false;
bool shadow_pass = (p_params->pass_mode == PASS_MODE_SHADOW) || (p_params->pass_mode == PASS_MODE_SHADOW_DP);
@@ -2090,6 +2093,11 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
continue;
}
+ //request a redraw if one of the shaders uses TIME
+ if (shader->uses_time) {
+ should_request_redraw = true;
+ }
+
//find cull variant
SceneShaderForwardMobile::ShaderData::CullVariant cull_variant;
@@ -2191,6 +2199,11 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
}
+
+ // Make the actual redraw request
+ if (should_request_redraw) {
+ RenderingServerDefault::redraw_request();
+ }
}
/* Geometry instance */
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index 02bd30d32d..db9db2fa44 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -116,6 +116,9 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
actions.usage_flag_pointers["ALPHA_SCISSOR_THRESHOLD"] = &uses_alpha_clip;
+ // Use alpha clip pipeline for alpha hash/dither.
+ // This prevents sorting issues inherent to alpha blending and allows such materials to cast shadows.
+ actions.usage_flag_pointers["ALPHA_HASH_SCALE"] = &uses_alpha_clip;
actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass;
// actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index cbc5cc337c..7e0070f8b7 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -706,7 +706,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
//bind textures
- _bind_canvas_texture(p_draw_list, RID(), current_filter, current_repeat, last_texture, push_constant, texpixel_size);
+ _bind_canvas_texture(p_draw_list, primitive->texture, current_filter, current_repeat, last_texture, push_constant, texpixel_size);
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, primitive_arrays.index_array[MIN(3u, primitive->point_count) - 1]);
diff --git a/servers/rendering/renderer_rd/shaders/cluster_render.glsl b/servers/rendering/renderer_rd/shaders/cluster_render.glsl
index 932312de82..8c26a67926 100644
--- a/servers/rendering/renderer_rd/shaders/cluster_render.glsl
+++ b/servers/rendering/renderer_rd/shaders/cluster_render.glsl
@@ -142,7 +142,11 @@ void main() {
}
}
#else
- if (!gl_HelperInvocation) {
+// MoltenVK/Metal fails to compile shaders using gl_HelperInvocation for some GPUs
+#ifndef MOLTENVK_USED
+ if (!gl_HelperInvocation)
+#endif
+ {
atomicOr(cluster_render.data[usage_write_offset], usage_write_bit);
}
#endif
@@ -162,7 +166,11 @@ void main() {
}
}
#else
- if (!gl_HelperInvocation) {
+// MoltenVK/Metal fails to compile shaders using gl_HelperInvocation for some GPUs
+#ifndef MOLTENVK_USED
+ if (!gl_HelperInvocation)
+#endif
+ {
atomicOr(cluster_render.data[z_write_offset], z_write_bit);
}
#endif
diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl
index 3a6dd579b9..9f6aa7adc0 100644
--- a/servers/rendering/renderer_rd/shaders/particles.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles.glsl
@@ -462,7 +462,7 @@ void main() {
if (any(lessThan(uvw_pos, vec3(0.0))) || any(greaterThan(uvw_pos, vec3(1.0)))) {
continue;
}
- vec3 s = texture(sampler3D(sdf_vec_textures[FRAME.attractors[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).xyz * 2.0 - 1.0;
+ vec3 s = texture(sampler3D(sdf_vec_textures[FRAME.attractors[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).xyz * -2.0 + 1.0;
dir = mat3(FRAME.attractors[i].transform) * safe_normalize(s); //revert direction
amount = length(s);
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
index 7fa0bb64a3..854976692e 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
@@ -425,7 +425,7 @@ void ParticlesStorage::particles_set_trails(RID p_particles, bool p_enable, doub
p_length = MIN(10.0, p_length);
particles->trails_enabled = p_enable;
- particles->trail_length = p_length;
+ particles->trail_lifetime = p_length;
_particles_free_data(particles);
@@ -1351,7 +1351,7 @@ void ParticlesStorage::update_particles() {
int history_size = 1;
int trail_steps = 1;
if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
- history_size = MAX(1, int(particles->trail_length * fixed_fps));
+ history_size = MAX(1, int(particles->trail_lifetime * fixed_fps));
trail_steps = particles->trail_bind_poses.size();
}
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
index 017844626f..a9cc98abb9 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
@@ -97,7 +97,7 @@ private:
uint32_t type;
uint32_t texture_index; //texture index for vector field
- real_t scale;
+ float scale;
uint32_t pad[2];
};
@@ -106,8 +106,8 @@ private:
float prev_system_phase;
uint32_t cycle;
- real_t explosiveness;
- real_t randomness;
+ float explosiveness;
+ float randomness;
float time;
float delta;
@@ -232,7 +232,7 @@ private:
Dependency dependency;
- double trail_length = 1.0;
+ double trail_lifetime = 0.3;
bool trails_enabled = false;
LocalVector<ParticlesFrameParams> frame_history;
LocalVector<ParticlesFrameParams> trail_params;
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index 3785c3899b..077fde58b8 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -1336,6 +1336,13 @@ Size2 TextureStorage::texture_size_with_proxy(RID p_proxy) {
return texture_2d_get_size(p_proxy);
}
+RID TextureStorage::texture_get_rd_texture_rid(RID p_texture, bool p_srgb) const {
+ Texture *tex = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND_V(!tex, RID());
+
+ return (p_srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture;
+}
+
Ref<Image> TextureStorage::_validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format) {
Ref<Image> image = p_image->duplicate();
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
index 72d4c90159..f4737eb63d 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
@@ -491,6 +491,8 @@ public:
virtual Size2 texture_size_with_proxy(RID p_proxy) override;
+ virtual RID texture_get_rd_texture_rid(RID p_texture, bool p_srgb = false) const override;
+
//internal usage
_FORCE_INLINE_ TextureType texture_get_type(RID p_texture) {
RendererRD::TextureStorage::Texture *tex = texture_owner.get_or_null(p_texture);
diff --git a/servers/rendering/renderer_rd/storage_rd/utilities.cpp b/servers/rendering/renderer_rd/storage_rd/utilities.cpp
index 4048c46d28..625f089f66 100644
--- a/servers/rendering/renderer_rd/storage_rd/utilities.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/utilities.cpp
@@ -200,7 +200,7 @@ void Utilities::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_de
if (p_enter) {
if (!vn->enter_callback.is_null()) {
if (p_deferred) {
- vn->enter_callback.call_deferredp(nullptr, 0);
+ vn->enter_callback.call_deferred();
} else {
Variant r;
Callable::CallError ce;
@@ -210,7 +210,7 @@ void Utilities::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_de
} else {
if (!vn->exit_callback.is_null()) {
if (p_deferred) {
- vn->exit_callback.call_deferredp(nullptr, 0);
+ vn->exit_callback.call_deferred();
} else {
Variant r;
Callable::CallError ce;
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 93118f39e7..bb4c41df52 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -393,6 +393,7 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("vertex_buffer_create", "size_bytes", "data", "use_as_storage"), &RenderingDevice::vertex_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("vertex_format_create", "vertex_descriptions"), &RenderingDevice::_vertex_format_create);
+ ClassDB::bind_method(D_METHOD("vertex_array_create", "vertex_count", "vertex_format", "src_buffers"), &RenderingDevice::_vertex_array_create);
ClassDB::bind_method(D_METHOD("index_buffer_create", "size_indices", "format", "data", "use_restart_indices"), &RenderingDevice::index_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("index_array_create", "index_buffer", "index_offset", "index_count"), &RenderingDevice::index_array_create);
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 6d2d0d9906..b77b95bb62 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -212,6 +212,7 @@ public:
FUNC1(texture_debug_usage, List<TextureInfo> *)
FUNC2(texture_set_force_redraw_if_visible, RID, bool)
+ FUNC2RC(RID, texture_get_rd_texture_rid, RID, bool)
/* SHADER API */
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 2f5846f520..14c09c1512 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -8178,6 +8178,10 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
}
}
#endif // DEBUG_ENABLED
+ if (String(shader_type_identifier) != "spatial") {
+ _set_error(vformat(RTR("Uniform instances are not yet implemented for '%s' shaders."), shader_type_identifier));
+ return ERR_PARSE_ERROR;
+ }
if (uniform_scope == ShaderNode::Uniform::SCOPE_LOCAL) {
tk = _get_token();
if (tk.type != TK_UNIFORM) {
diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h
index 3207181471..31fb5e8791 100644
--- a/servers/rendering/storage/texture_storage.h
+++ b/servers/rendering/storage/texture_storage.h
@@ -100,6 +100,8 @@ public:
virtual Size2 texture_size_with_proxy(RID p_proxy) = 0;
+ virtual RID texture_get_rd_texture_rid(RID p_texture, bool p_srgb = false) const = 0;
+
/* Decal API */
virtual RID decal_allocate() = 0;
virtual void decal_initialize(RID p_rid) = 0;
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index cf30d377b7..7691bede07 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -1691,6 +1691,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("texture_get_path", "texture"), &RenderingServer::texture_get_path);
ClassDB::bind_method(D_METHOD("texture_set_force_redraw_if_visible", "texture", "enable"), &RenderingServer::texture_set_force_redraw_if_visible);
+ ClassDB::bind_method(D_METHOD("texture_get_rd_texture", "texture", "srgb"), &RenderingServer::texture_get_rd_texture_rid, DEFVAL(false));
BIND_ENUM_CONSTANT(TEXTURE_LAYERED_2D_ARRAY);
BIND_ENUM_CONSTANT(TEXTURE_LAYERED_CUBEMAP);
@@ -2871,14 +2872,6 @@ void RenderingServer::init() {
GLOBAL_DEF("rendering/2d/shadow_atlas/size", 2048);
- // Already defined in some RenderingDevice*::initialize, which run before this code.
- // We re-define them here just for doctool's sake. Make sure to keep default values in sync.
- GLOBAL_DEF("rendering/rendering_device/staging_buffer/block_size_kb", 256);
- GLOBAL_DEF("rendering/rendering_device/staging_buffer/max_size_mb", 128);
- GLOBAL_DEF("rendering/rendering_device/staging_buffer/texture_upload_region_size_px", 64);
- // Vulkan-specific.
- GLOBAL_DEF("rendering/rendering_device/vulkan/max_descriptors_per_pool", 64);
-
// Number of commands that can be drawn per frame.
GLOBAL_DEF_RST("rendering/gl_compatibility/item_buffer_size", 16384);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/item_buffer_size", PropertyInfo(Variant::INT, "rendering/gl_compatibility/item_buffer_size", PROPERTY_HINT_RANGE, "1024,1048576,1"));
@@ -2981,7 +2974,6 @@ void RenderingServer::init() {
ProjectSettings::get_singleton()->set_custom_property_info("rendering/textures/light_projectors/filter", PropertyInfo(Variant::INT, "rendering/textures/light_projectors/filter", PROPERTY_HINT_ENUM, "Nearest (Fast),Linear (Fast),Nearest Mipmap (Fast),Linear Mipmap (Fast),Nearest Mipmap Anisotropic (Average),Linear Mipmap Anisotropic (Average)"));
GLOBAL_DEF_RST("rendering/occlusion_culling/occlusion_rays_per_thread", 512);
- GLOBAL_DEF_RST("rendering/occlusion_culling/bvh_build_quality", 2);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/occlusion_culling/bvh_build_quality", PropertyInfo(Variant::INT, "rendering/occlusion_culling/bvh_build_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"));
GLOBAL_DEF("rendering/environment/glow/upscale_mode", 1);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 97fafd1b14..1d364dfcff 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -157,6 +157,8 @@ public:
virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) = 0;
+ virtual RID texture_get_rd_texture_rid(RID p_texture, bool p_srgb = false) const = 0;
+
/* SHADER API */
enum ShaderMode {
diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp
index a5ee1d5726..4d58d24405 100644
--- a/servers/xr/xr_interface.cpp
+++ b/servers/xr/xr_interface.cpp
@@ -72,6 +72,8 @@ void XRInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_passthrough_enabled"), &XRInterface::is_passthrough_enabled);
ClassDB::bind_method(D_METHOD("start_passthrough"), &XRInterface::start_passthrough);
ClassDB::bind_method(D_METHOD("stop_passthrough"), &XRInterface::stop_passthrough);
+ ClassDB::bind_method(D_METHOD("get_transform_for_view", "view", "cam_transform"), &XRInterface::get_transform_for_view);
+ ClassDB::bind_method(D_METHOD("get_projection_for_view", "view", "aspect", "near", "far"), &XRInterface::get_projection_for_view);
ADD_GROUP("AR", "ar_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ar_is_anchor_detection_enabled"), "set_anchor_detection_is_enabled", "get_anchor_detection_is_enabled");
diff --git a/tests/core/io/test_json.h b/tests/core/io/test_json.h
index 478cf1766e..af450da3b8 100644
--- a/tests/core/io/test_json.h
+++ b/tests/core/io/test_json.h
@@ -83,7 +83,7 @@ TEST_CASE("[JSON] Parsing single data types") {
json.get_error_line() == 0,
"Parsing a floating-point number as JSON should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(double(json.get_data()), 0.123456),
+ double(json.get_data()) == doctest::Approx(0.123456),
"Parsing a floating-point number as JSON should return the expected value.");
json.parse("\"hello\"");
diff --git a/tests/core/math/test_aabb.h b/tests/core/math/test_aabb.h
index ebaf441abf..23969556be 100644
--- a/tests/core/math/test_aabb.h
+++ b/tests/core/math/test_aabb.h
@@ -91,7 +91,7 @@ TEST_CASE("[AABB] Basic setters") {
TEST_CASE("[AABB] Volume getters") {
AABB aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6));
CHECK_MESSAGE(
- Math::is_equal_approx(aabb.get_volume(), 120),
+ aabb.get_volume() == doctest::Approx(120),
"get_volume() should return the expected value with positive size.");
CHECK_MESSAGE(
aabb.has_volume(),
@@ -99,17 +99,17 @@ TEST_CASE("[AABB] Volume getters") {
aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(-4, 5, 6));
CHECK_MESSAGE(
- Math::is_equal_approx(aabb.get_volume(), -120),
+ aabb.get_volume() == doctest::Approx(-120),
"get_volume() should return the expected value with negative size (1 component).");
aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(-4, -5, 6));
CHECK_MESSAGE(
- Math::is_equal_approx(aabb.get_volume(), 120),
+ aabb.get_volume() == doctest::Approx(120),
"get_volume() should return the expected value with negative size (2 components).");
aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(-4, -5, -6));
CHECK_MESSAGE(
- Math::is_equal_approx(aabb.get_volume(), -120),
+ aabb.get_volume() == doctest::Approx(-120),
"get_volume() should return the expected value with negative size (3 components).");
aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 0, 6));
diff --git a/tests/core/math/test_basis.h b/tests/core/math/test_basis.h
index a4099ebf7d..dce9d5cec3 100644
--- a/tests/core/math/test_basis.h
+++ b/tests/core/math/test_basis.h
@@ -223,7 +223,7 @@ TEST_CASE("[Basis] Set axis angle") {
// Testing the singularity when the angle is 180°.
Basis singularityPi(-1, 0, 0, 0, 1, 0, 0, 0, -1);
singularityPi.get_axis_angle(axis, angle);
- CHECK(Math::is_equal_approx(angle, pi));
+ CHECK(angle == doctest::Approx(pi));
// Testing reversing the an axis (of an 30° angle).
float cos30deg = Math::cos(Math::deg_to_rad((real_t)30.0));
@@ -231,17 +231,17 @@ TEST_CASE("[Basis] Set axis angle") {
Basis z_negative(cos30deg, 0.5, 0, -0.5, cos30deg, 0, 0, 0, 1);
z_positive.get_axis_angle(axis, angle);
- CHECK(Math::is_equal_approx(angle, Math::deg_to_rad((real_t)30.0)));
+ CHECK(angle == doctest::Approx(Math::deg_to_rad((real_t)30.0)));
CHECK(axis == Vector3(0, 0, 1));
z_negative.get_axis_angle(axis, angle);
- CHECK(Math::is_equal_approx(angle, Math::deg_to_rad((real_t)30.0)));
+ CHECK(angle == doctest::Approx(Math::deg_to_rad((real_t)30.0)));
CHECK(axis == Vector3(0, 0, -1));
// Testing a rotation of 90° on x-y-z.
Basis x90deg(1, 0, 0, 0, 0, -1, 0, 1, 0);
x90deg.get_axis_angle(axis, angle);
- CHECK(Math::is_equal_approx(angle, pi / (real_t)2));
+ CHECK(angle == doctest::Approx(pi / (real_t)2));
CHECK(axis == Vector3(1, 0, 0));
Basis y90deg(0, 0, 1, 0, 1, 0, -1, 0, 0);
@@ -255,7 +255,7 @@ TEST_CASE("[Basis] Set axis angle") {
// Regression test: checks that the method returns a small angle (not 0).
Basis tiny(1, 0, 0, 0, 0.9999995, -0.001, 0, 001, 0.9999995); // The min angle possible with float is 0.001rad.
tiny.get_axis_angle(axis, angle);
- CHECK(Math::is_equal_approx(angle, (real_t)0.001, (real_t)0.0001));
+ CHECK(angle == doctest::Approx(0.001).epsilon(0.0001));
// Regression test: checks that the method returns an angle which is a number (not NaN)
Basis bugNan(1.00000024, 0, 0.000100001693, 0, 1, 0, -0.000100009143, 0, 1.00000024);
diff --git a/tests/core/math/test_color.h b/tests/core/math/test_color.h
index 51c3bc8bdc..c6550778e8 100644
--- a/tests/core/math/test_color.h
+++ b/tests/core/math/test_color.h
@@ -101,13 +101,13 @@ TEST_CASE("[Color] Reading methods") {
const Color dark_blue = Color(0, 0, 0.5, 0.4);
CHECK_MESSAGE(
- Math::is_equal_approx(dark_blue.get_h(), 240.0f / 360.0f),
+ dark_blue.get_h() == doctest::Approx(240.0f / 360.0f),
"The returned HSV hue should match the expected value.");
CHECK_MESSAGE(
- Math::is_equal_approx(dark_blue.get_s(), 1.0f),
+ dark_blue.get_s() == doctest::Approx(1.0f),
"The returned HSV saturation should match the expected value.");
CHECK_MESSAGE(
- Math::is_equal_approx(dark_blue.get_v(), 0.5f),
+ dark_blue.get_v() == doctest::Approx(0.5f),
"The returned HSV value should match the expected value.");
}
diff --git a/tests/core/math/test_expression.h b/tests/core/math/test_expression.h
index 6e3be541b0..9734fd9f36 100644
--- a/tests/core/math/test_expression.h
+++ b/tests/core/math/test_expression.h
@@ -83,42 +83,42 @@ TEST_CASE("[Expression] Floating-point arithmetic") {
expression.parse("-123.456") == OK,
"Float identity should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(double(expression.execute()), -123.456),
+ double(expression.execute()) == doctest::Approx(-123.456),
"Float identity should return the expected result.");
CHECK_MESSAGE(
expression.parse("2.0 + 3.0") == OK,
"Float addition should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(double(expression.execute()), 5),
+ double(expression.execute()) == doctest::Approx(5),
"Float addition should return the expected result.");
CHECK_MESSAGE(
expression.parse("3.0 / 10") == OK,
"Float / integer division should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(double(expression.execute()), 0.3),
+ double(expression.execute()) == doctest::Approx(0.3),
"Float / integer division should return the expected result.");
CHECK_MESSAGE(
expression.parse("3 / 10.0") == OK,
"Basic integer / float division should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(double(expression.execute()), 0.3),
+ double(expression.execute()) == doctest::Approx(0.3),
"Basic integer / float division should return the expected result.");
CHECK_MESSAGE(
expression.parse("3.0 / 10.0") == OK,
"Float / float division should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(double(expression.execute()), 0.3),
+ double(expression.execute()) == doctest::Approx(0.3),
"Float / float division should return the expected result.");
CHECK_MESSAGE(
expression.parse("2.5 * (6.0 + 14.25) / 2.0 - 5.12345") == OK,
"Float multiplication-addition-subtraction-division should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(double(expression.execute()), 20.18905),
+ double(expression.execute()) == doctest::Approx(20.18905),
"Float multiplication-addition-subtraction-division should return the expected result.");
}
@@ -129,7 +129,7 @@ TEST_CASE("[Expression] Scientific notation") {
expression.parse("2.e5") == OK,
"The expression should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(double(expression.execute()), 200'000),
+ double(expression.execute()) == doctest::Approx(200'000),
"The expression should return the expected result.");
// The middle "e" is ignored here.
@@ -137,14 +137,14 @@ TEST_CASE("[Expression] Scientific notation") {
expression.parse("2e5") == OK,
"The expression should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(double(expression.execute()), 2e5),
+ double(expression.execute()) == doctest::Approx(2e5),
"The expression should return the expected result.");
CHECK_MESSAGE(
expression.parse("2e.5") == OK,
"The expression should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(double(expression.execute()), 2),
+ double(expression.execute()) == doctest::Approx(2),
"The expression should return the expected result.");
}
@@ -176,7 +176,7 @@ TEST_CASE("[Expression] Built-in functions") {
expression.parse("snapped(sin(0.5), 0.01)") == OK,
"The expression should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(double(expression.execute()), 0.48),
+ double(expression.execute()) == doctest::Approx(0.48),
"`snapped(sin(0.5), 0.01)` should return the expected result.");
CHECK_MESSAGE(
diff --git a/tests/core/math/test_geometry_2d.h b/tests/core/math/test_geometry_2d.h
index 54893a0b87..27c9e7f58b 100644
--- a/tests/core/math/test_geometry_2d.h
+++ b/tests/core/math/test_geometry_2d.h
@@ -171,43 +171,43 @@ TEST_CASE("[Geometry2D] Segment intersection with circle") {
real_t one = 1.0;
CHECK_MESSAGE(
- Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(0, 0), Vector2(4, 0), Vector2(0, 0), 1.0), one_quarter),
+ Geometry2D::segment_intersects_circle(Vector2(0, 0), Vector2(4, 0), Vector2(0, 0), 1.0) == doctest::Approx(one_quarter),
"Segment from inside to outside of circle should intersect it.");
CHECK_MESSAGE(
- Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(4, 0), Vector2(0, 0), Vector2(0, 0), 1.0), three_quarters),
+ Geometry2D::segment_intersects_circle(Vector2(4, 0), Vector2(0, 0), Vector2(0, 0), 1.0) == doctest::Approx(three_quarters),
"Segment from outside to inside of circle should intersect it.");
CHECK_MESSAGE(
- Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(-2, 0), Vector2(2, 0), Vector2(0, 0), 1.0), one_quarter),
+ Geometry2D::segment_intersects_circle(Vector2(-2, 0), Vector2(2, 0), Vector2(0, 0), 1.0) == doctest::Approx(one_quarter),
"Segment running through circle should intersect it.");
CHECK_MESSAGE(
- Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(-2, 0), Vector2(0, 0), 1.0), one_quarter),
+ Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(-2, 0), Vector2(0, 0), 1.0) == doctest::Approx(one_quarter),
"Segment running through circle should intersect it.");
CHECK_MESSAGE(
- Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(0, 0), Vector2(1, 0), Vector2(0, 0), 1.0), one),
+ Geometry2D::segment_intersects_circle(Vector2(0, 0), Vector2(1, 0), Vector2(0, 0), 1.0) == doctest::Approx(one),
"Segment starting inside the circle and ending on the circle should intersect it");
CHECK_MESSAGE(
- Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(0, 0), Vector2(0, 0), 1.0), zero),
+ Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(0, 0), Vector2(0, 0), 1.0) == doctest::Approx(zero),
"Segment starting on the circle and going inwards should intersect it");
CHECK_MESSAGE(
- Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(2, 0), Vector2(0, 0), 1.0), zero),
+ Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(2, 0), Vector2(0, 0), 1.0) == doctest::Approx(zero),
"Segment starting on the circle and going outwards should intersect it");
CHECK_MESSAGE(
- Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(1, 0), Vector2(0, 0), 1.0), one),
+ Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(1, 0), Vector2(0, 0), 1.0) == doctest::Approx(one),
"Segment starting outside the circle and ending on the circle intersect it");
CHECK_MESSAGE(
- Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(-1, 0), Vector2(1, 0), Vector2(0, 0), 2.0), minus_one),
+ Geometry2D::segment_intersects_circle(Vector2(-1, 0), Vector2(1, 0), Vector2(0, 0), 2.0) == doctest::Approx(minus_one),
"Segment completely within the circle should not intersect it");
CHECK_MESSAGE(
- Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(-1, 0), Vector2(0, 0), 2.0), minus_one),
+ Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(-1, 0), Vector2(0, 0), 2.0) == doctest::Approx(minus_one),
"Segment completely within the circle should not intersect it");
CHECK_MESSAGE(
- Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(3, 0), Vector2(0, 0), 1.0), minus_one),
+ Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(3, 0), Vector2(0, 0), 1.0) == doctest::Approx(minus_one),
"Segment completely outside the circle should not intersect it");
CHECK_MESSAGE(
- Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(3, 0), Vector2(2, 0), Vector2(0, 0), 1.0), minus_one),
+ Geometry2D::segment_intersects_circle(Vector2(3, 0), Vector2(2, 0), Vector2(0, 0), 1.0) == doctest::Approx(minus_one),
"Segment completely outside the circle should not intersect it");
}
diff --git a/tests/core/math/test_rect2.h b/tests/core/math/test_rect2.h
index d784875c1c..9984823331 100644
--- a/tests/core/math/test_rect2.h
+++ b/tests/core/math/test_rect2.h
@@ -102,16 +102,16 @@ TEST_CASE("[Rect2] Basic setters") {
TEST_CASE("[Rect2] Area getters") {
CHECK_MESSAGE(
- Math::is_equal_approx(Rect2(0, 100, 1280, 720).get_area(), 921'600),
+ Rect2(0, 100, 1280, 720).get_area() == doctest::Approx(921'600),
"get_area() should return the expected value.");
CHECK_MESSAGE(
- Math::is_equal_approx(Rect2(0, 100, -1280, -720).get_area(), 921'600),
+ Rect2(0, 100, -1280, -720).get_area() == doctest::Approx(921'600),
"get_area() should return the expected value.");
CHECK_MESSAGE(
- Math::is_equal_approx(Rect2(0, 100, 1280, -720).get_area(), -921'600),
+ Rect2(0, 100, 1280, -720).get_area() == doctest::Approx(-921'600),
"get_area() should return the expected value.");
CHECK_MESSAGE(
- Math::is_equal_approx(Rect2(0, 100, -1280, 720).get_area(), -921'600),
+ Rect2(0, 100, -1280, 720).get_area() == doctest::Approx(-921'600),
"get_area() should return the expected value.");
CHECK_MESSAGE(
Math::is_zero_approx(Rect2(0, 100, 0, 720).get_area()),
diff --git a/tests/core/math/test_vector2.h b/tests/core/math/test_vector2.h
index f7e9259329..8f8fccd717 100644
--- a/tests/core/math/test_vector2.h
+++ b/tests/core/math/test_vector2.h
@@ -49,16 +49,16 @@ TEST_CASE("[Vector2] Angle methods") {
const Vector2 vector_x = Vector2(1, 0);
const Vector2 vector_y = Vector2(0, 1);
CHECK_MESSAGE(
- Math::is_equal_approx(vector_x.angle_to(vector_y), (real_t)Math_TAU / 4),
+ vector_x.angle_to(vector_y) == doctest::Approx((real_t)Math_TAU / 4),
"Vector2 angle_to should work as expected.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector_y.angle_to(vector_x), (real_t)-Math_TAU / 4),
+ vector_y.angle_to(vector_x) == doctest::Approx((real_t)-Math_TAU / 4),
"Vector2 angle_to should work as expected.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector_x.angle_to_point(vector_y), (real_t)Math_TAU * 3 / 8),
+ vector_x.angle_to_point(vector_y) == doctest::Approx((real_t)Math_TAU * 3 / 8),
"Vector2 angle_to_point should work as expected.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector_y.angle_to_point(vector_x), (real_t)-Math_TAU / 8),
+ vector_y.angle_to_point(vector_x) == doctest::Approx((real_t)-Math_TAU / 8),
"Vector2 angle_to_point should work as expected.");
}
@@ -113,10 +113,10 @@ TEST_CASE("[Vector2] Interpolation methods") {
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),
+ vector1.slerp(vector2, 0.5).length() == doctest::Approx((real_t)4.31959610746631919),
"Vector2 slerp with different length input should return a vector with an interpolated length.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector1.angle_to(vector1.slerp(vector2, 0.5)) * 2, vector1.angle_to(vector2)),
+ vector1.angle_to(vector1.slerp(vector2, 0.5)) * 2 == doctest::Approx(vector1.angle_to(vector2)),
"Vector2 slerp with different length input should return a vector with an interpolated angle.");
CHECK_MESSAGE(
vector1.cubic_interpolate(vector2, Vector2(), Vector2(7, 7), 0.5) == Vector2(2.375, 3.5),
@@ -136,19 +136,19 @@ TEST_CASE("[Vector2] Length methods") {
vector1.length_squared() == 200,
"Vector2 length_squared should work as expected and return exact result.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector1.length(), 10 * (real_t)Math_SQRT2),
+ vector1.length() == doctest::Approx(10 * (real_t)Math_SQRT2),
"Vector2 length should work as expected.");
CHECK_MESSAGE(
vector2.length_squared() == 1300,
"Vector2 length_squared should work as expected and return exact result.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector2.length(), (real_t)36.05551275463989293119),
+ vector2.length() == doctest::Approx((real_t)36.05551275463989293119),
"Vector2 length should work as expected.");
CHECK_MESSAGE(
vector1.distance_squared_to(vector2) == 500,
"Vector2 distance_squared_to should work as expected and return exact result.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector1.distance_to(vector2), (real_t)22.36067977499789696409),
+ vector1.distance_to(vector2) == doctest::Approx((real_t)22.36067977499789696409),
"Vector2 distance_to should work as expected.");
}
@@ -294,7 +294,7 @@ TEST_CASE("[Vector2] Operators") {
TEST_CASE("[Vector2] Other methods") {
const Vector2 vector = Vector2(1.2, 3.4);
CHECK_MESSAGE(
- Math::is_equal_approx(vector.aspect(), (real_t)1.2 / (real_t)3.4),
+ vector.aspect() == doctest::Approx((real_t)1.2 / (real_t)3.4),
"Vector2 aspect should work as expected.");
CHECK_MESSAGE(
@@ -443,10 +443,10 @@ TEST_CASE("[Vector2] Linear algebra methods") {
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),
+ a.cross(b) == doctest::Approx((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(-a.x, a.y).cross(Vector2(b.x, -b.y)) == doctest::Approx((real_t)-28.1),
"Vector2 cross should return expected value.");
CHECK_MESSAGE(
@@ -459,10 +459,10 @@ TEST_CASE("[Vector2] Linear algebra methods") {
(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),
+ a.dot(b) == doctest::Approx((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(-a.x, a.y).dot(Vector2(b.x, -b.y)) == doctest::Approx((real_t)-57.3),
"Vector2 dot should return expected value.");
}
diff --git a/tests/core/math/test_vector2i.h b/tests/core/math/test_vector2i.h
index 49b0632e3c..c7a0dccdcc 100644
--- a/tests/core/math/test_vector2i.h
+++ b/tests/core/math/test_vector2i.h
@@ -79,13 +79,13 @@ TEST_CASE("[Vector2i] Length methods") {
vector1.length_squared() == 200,
"Vector2i length_squared should work as expected and return exact result.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector1.length(), 10 * Math_SQRT2),
+ vector1.length() == doctest::Approx(10 * Math_SQRT2),
"Vector2i length should work as expected.");
CHECK_MESSAGE(
vector2.length_squared() == 1300,
"Vector2i length_squared should work as expected and return exact result.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector2.length(), 36.05551275463989293119),
+ vector2.length() == doctest::Approx(36.05551275463989293119),
"Vector2i length should work as expected.");
}
@@ -127,7 +127,7 @@ TEST_CASE("[Vector2i] Operators") {
TEST_CASE("[Vector2i] Other methods") {
const Vector2i vector = Vector2i(1, 3);
CHECK_MESSAGE(
- Math::is_equal_approx(vector.aspect(), (real_t)1.0 / (real_t)3.0),
+ vector.aspect() == doctest::Approx((real_t)1.0 / (real_t)3.0),
"Vector2i aspect should work as expected.");
CHECK_MESSAGE(
diff --git a/tests/core/math/test_vector3.h b/tests/core/math/test_vector3.h
index 77d3a9d93c..89d73ee6de 100644
--- a/tests/core/math/test_vector3.h
+++ b/tests/core/math/test_vector3.h
@@ -52,26 +52,26 @@ TEST_CASE("[Vector3] Angle methods") {
const Vector3 vector_y = Vector3(0, 1, 0);
const Vector3 vector_yz = Vector3(0, 1, 1);
CHECK_MESSAGE(
- Math::is_equal_approx(vector_x.angle_to(vector_y), (real_t)Math_TAU / 4),
+ vector_x.angle_to(vector_y) == doctest::Approx((real_t)Math_TAU / 4),
"Vector3 angle_to should work as expected.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector_x.angle_to(vector_yz), (real_t)Math_TAU / 4),
+ vector_x.angle_to(vector_yz) == doctest::Approx((real_t)Math_TAU / 4),
"Vector3 angle_to should work as expected.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector_yz.angle_to(vector_x), (real_t)Math_TAU / 4),
+ vector_yz.angle_to(vector_x) == doctest::Approx((real_t)Math_TAU / 4),
"Vector3 angle_to should work as expected.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector_y.angle_to(vector_yz), (real_t)Math_TAU / 8),
+ vector_y.angle_to(vector_yz) == doctest::Approx((real_t)Math_TAU / 8),
"Vector3 angle_to should work as expected.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector_x.signed_angle_to(vector_y, vector_y), (real_t)Math_TAU / 4),
+ vector_x.signed_angle_to(vector_y, vector_y) == doctest::Approx((real_t)Math_TAU / 4),
"Vector3 signed_angle_to edge case should be positive.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector_x.signed_angle_to(vector_yz, vector_y), (real_t)Math_TAU / -4),
+ vector_x.signed_angle_to(vector_yz, vector_y) == doctest::Approx((real_t)Math_TAU / -4),
"Vector3 signed_angle_to should work as expected.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector_yz.signed_angle_to(vector_x, vector_y), (real_t)Math_TAU / 4),
+ vector_yz.signed_angle_to(vector_x, vector_y) == doctest::Approx((real_t)Math_TAU / 4),
"Vector3 signed_angle_to should work as expected.");
}
@@ -130,10 +130,10 @@ TEST_CASE("[Vector3] Interpolation methods") {
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),
+ vector1.slerp(vector2, 0.5).length() == doctest::Approx((real_t)6.25831088708303172),
"Vector3 slerp with different length input should return a vector with an interpolated length.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector1.angle_to(vector1.slerp(vector2, 0.5)) * 2, vector1.angle_to(vector2)),
+ vector1.angle_to(vector1.slerp(vector2, 0.5)) * 2 == doctest::Approx(vector1.angle_to(vector2)),
"Vector3 slerp with different length input should return a vector with an interpolated angle.");
CHECK_MESSAGE(
vector1.cubic_interpolate(vector2, Vector3(), Vector3(7, 7, 7), 0.5) == Vector3(2.375, 3.5, 4.625),
@@ -153,19 +153,19 @@ TEST_CASE("[Vector3] Length methods") {
vector1.length_squared() == 300,
"Vector3 length_squared should work as expected and return exact result.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector1.length(), 10 * (real_t)Math_SQRT3),
+ vector1.length() == doctest::Approx(10 * (real_t)Math_SQRT3),
"Vector3 length should work as expected.");
CHECK_MESSAGE(
vector2.length_squared() == 2900,
"Vector3 length_squared should work as expected and return exact result.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector2.length(), (real_t)53.8516480713450403125),
+ vector2.length() == doctest::Approx((real_t)53.8516480713450403125),
"Vector3 length should work as expected.");
CHECK_MESSAGE(
vector1.distance_squared_to(vector2) == 1400,
"Vector3 distance_squared_to should work as expected and return exact result.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector1.distance_to(vector2), (real_t)37.41657386773941385584),
+ vector1.distance_to(vector2) == doctest::Approx((real_t)37.41657386773941385584),
"Vector3 distance_to should work as expected.");
}
@@ -473,10 +473,10 @@ TEST_CASE("[Vector3] Linear algebra methods") {
(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),
+ a.dot(b) == doctest::Approx((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(-a.x, a.y, -a.z).dot(Vector3(b.x, -b.y, b.z)) == doctest::Approx((real_t)-75.24),
"Vector3 dot should return expected value.");
}
diff --git a/tests/core/math/test_vector3i.h b/tests/core/math/test_vector3i.h
index 2050b222d0..56578f99eb 100644
--- a/tests/core/math/test_vector3i.h
+++ b/tests/core/math/test_vector3i.h
@@ -82,13 +82,13 @@ TEST_CASE("[Vector3i] Length methods") {
vector1.length_squared() == 300,
"Vector3i length_squared should work as expected and return exact result.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector1.length(), 10 * Math_SQRT3),
+ vector1.length() == doctest::Approx(10 * Math_SQRT3),
"Vector3i length should work as expected.");
CHECK_MESSAGE(
vector2.length_squared() == 2900,
"Vector3i length_squared should work as expected and return exact result.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector2.length(), 53.8516480713450403125),
+ vector2.length() == doctest::Approx(53.8516480713450403125),
"Vector3i length should work as expected.");
}
diff --git a/tests/core/math/test_vector4.h b/tests/core/math/test_vector4.h
index b31db56f67..6ed85661cb 100644
--- a/tests/core/math/test_vector4.h
+++ b/tests/core/math/test_vector4.h
@@ -91,19 +91,19 @@ TEST_CASE("[Vector4] Length methods") {
vector1.length_squared() == 400,
"Vector4 length_squared should work as expected and return exact result.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector1.length(), 20),
+ vector1.length() == doctest::Approx(20),
"Vector4 length should work as expected.");
CHECK_MESSAGE(
vector2.length_squared() == 5400,
"Vector4 length_squared should work as expected and return exact result.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector2.length(), (real_t)73.484692283495),
+ vector2.length() == doctest::Approx((real_t)73.484692283495),
"Vector4 length should work as expected.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector1.distance_to(vector2), (real_t)54.772255750517),
+ vector1.distance_to(vector2) == doctest::Approx((real_t)54.772255750517),
"Vector4 distance_to should work as expected.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector1.distance_squared_to(vector2), 3000),
+ vector1.distance_squared_to(vector2) == doctest::Approx(3000),
"Vector4 distance_squared_to should work as expected.");
}
@@ -311,7 +311,7 @@ TEST_CASE("[Vector4] Linear algebra methods") {
(vector_x * 10).dot(vector_x * 10) == 100.0,
"Vector4 dot product of same direction vectors should behave as expected.");
CHECK_MESSAGE(
- Math::is_equal_approx((vector1 * 2).dot(vector2 * 4), (real_t)-25.9 * 8),
+ (vector1 * 2).dot(vector2 * 4) == doctest::Approx((real_t)-25.9 * 8),
"Vector4 dot product should work as expected.");
}
diff --git a/tests/core/math/test_vector4i.h b/tests/core/math/test_vector4i.h
index 309162c3f7..30d38607dd 100644
--- a/tests/core/math/test_vector4i.h
+++ b/tests/core/math/test_vector4i.h
@@ -82,13 +82,13 @@ TEST_CASE("[Vector4i] Length methods") {
vector1.length_squared() == 400,
"Vector4i length_squared should work as expected and return exact result.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector1.length(), 20),
+ vector1.length() == doctest::Approx(20),
"Vector4i length should work as expected.");
CHECK_MESSAGE(
vector2.length_squared() == 5400,
"Vector4i length_squared should work as expected and return exact result.");
CHECK_MESSAGE(
- Math::is_equal_approx(vector2.length(), 73.4846922835),
+ vector2.length() == doctest::Approx(73.4846922835),
"Vector4i length should work as expected.");
}
diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h
index cd1b421ce8..7e4e3aa9f0 100644
--- a/tests/core/string/test_string.h
+++ b/tests/core/string/test_string.h
@@ -485,6 +485,7 @@ TEST_CASE("[String] Splitting") {
const char *slices_l[3] = { "Mars", "Jupiter", "Saturn,Uranus" };
const char *slices_r[3] = { "Mars,Jupiter", "Saturn", "Uranus" };
+ const char *slices_3[4] = { "t", "e", "s", "t" };
l = s.split(",", true, 2);
CHECK(l.size() == 3);
@@ -498,6 +499,13 @@ TEST_CASE("[String] Splitting") {
CHECK(l[i] == slices_r[i]);
}
+ s = "test";
+ l = s.split();
+ CHECK(l.size() == 4);
+ for (int i = 0; i < l.size(); i++) {
+ CHECK(l[i] == slices_3[i]);
+ }
+
s = "Mars Jupiter Saturn Uranus";
const char *slices_s[4] = { "Mars", "Jupiter", "Saturn", "Uranus" };
l = s.split_spaces();
diff --git a/tests/scene/test_animation.h b/tests/scene/test_animation.h
index ca80f0ecab..e921779c23 100644
--- a/tests/scene/test_animation.h
+++ b/tests/scene/test_animation.h
@@ -40,8 +40,8 @@ namespace TestAnimation {
TEST_CASE("[Animation] Empty animation getters") {
const Ref<Animation> animation = memnew(Animation);
- CHECK(Math::is_equal_approx(animation->get_length(), real_t(1.0)));
- CHECK(Math::is_equal_approx(animation->get_step(), real_t(0.1)));
+ CHECK(animation->get_length() == doctest::Approx(real_t(1.0)));
+ CHECK(animation->get_step() == doctest::Approx(real_t(0.1)));
}
TEST_CASE("[Animation] Create value track") {
@@ -59,33 +59,33 @@ TEST_CASE("[Animation] Create value track") {
CHECK(int(animation->track_get_key_value(0, 0)) == 0);
CHECK(int(animation->track_get_key_value(0, 1)) == 100);
- CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, -0.2), 0.0));
- CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, 0.0), 0.0));
- CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, 0.2), 40.0));
- CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, 0.4), 80.0));
- CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, 0.5), 100.0));
- CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, 0.6), 100.0));
+ CHECK(animation->value_track_interpolate(0, -0.2) == doctest::Approx(0.0));
+ CHECK(animation->value_track_interpolate(0, 0.0) == doctest::Approx(0.0));
+ CHECK(animation->value_track_interpolate(0, 0.2) == doctest::Approx(40.0));
+ CHECK(animation->value_track_interpolate(0, 0.4) == doctest::Approx(80.0));
+ CHECK(animation->value_track_interpolate(0, 0.5) == doctest::Approx(100.0));
+ CHECK(animation->value_track_interpolate(0, 0.6) == doctest::Approx(100.0));
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 0), real_t(1.0)));
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 1), real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 0) == doctest::Approx(real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 1) == doctest::Approx(real_t(1.0)));
ERR_PRINT_OFF;
// Nonexistent keys.
CHECK(animation->track_get_key_value(0, 2).is_null());
CHECK(animation->track_get_key_value(0, -1).is_null());
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 2), real_t(-1.0)));
+ CHECK(animation->track_get_key_transition(0, 2) == doctest::Approx(real_t(-1.0)));
// Nonexistent track (and keys).
CHECK(animation->track_get_key_value(1, 0).is_null());
CHECK(animation->track_get_key_value(1, 1).is_null());
CHECK(animation->track_get_key_value(1, 2).is_null());
CHECK(animation->track_get_key_value(1, -1).is_null());
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(1, 0), real_t(-1.0)));
+ CHECK(animation->track_get_key_transition(1, 0) == doctest::Approx(real_t(-1.0)));
// This is a value track, so the methods below should return errors.
CHECK(animation->position_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
CHECK(animation->rotation_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
CHECK(animation->scale_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
- CHECK(Math::is_zero_approx(animation->bezier_track_interpolate(0, 0.0)));
+ CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(0.0));
CHECK(animation->blend_shape_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
ERR_PRINT_ON;
}
@@ -123,15 +123,15 @@ TEST_CASE("[Animation] Create 3D position track") {
CHECK(r_interpolation.is_equal_approx(Vector3(3.5, 4, 5)));
// 3D position tracks always use linear interpolation for performance reasons.
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 0), real_t(1.0)));
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 1), real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 0) == doctest::Approx(real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 1) == doctest::Approx(real_t(1.0)));
// This is a 3D position track, so the methods below should return errors.
ERR_PRINT_OFF;
CHECK(animation->value_track_interpolate(0, 0.0).is_null());
CHECK(animation->rotation_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
CHECK(animation->scale_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
- CHECK(Math::is_zero_approx(animation->bezier_track_interpolate(0, 0.0)));
+ CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(0.0));
CHECK(animation->blend_shape_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
ERR_PRINT_ON;
}
@@ -169,15 +169,15 @@ TEST_CASE("[Animation] Create 3D rotation track") {
CHECK(r_interpolation.is_equal_approx(Quaternion(0.231055, 0.374912, 0.761204, 0.476048)));
// 3D rotation tracks always use linear interpolation for performance reasons.
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 0), real_t(1.0)));
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 1), real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 0) == doctest::Approx(real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 1) == doctest::Approx(real_t(1.0)));
// This is a 3D rotation track, so the methods below should return errors.
ERR_PRINT_OFF;
CHECK(animation->value_track_interpolate(0, 0.0).is_null());
CHECK(animation->position_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
CHECK(animation->scale_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
- CHECK(Math::is_zero_approx(animation->bezier_track_interpolate(0, 0.0)));
+ CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(real_t(0.0)));
CHECK(animation->blend_shape_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
ERR_PRINT_ON;
}
@@ -215,15 +215,15 @@ TEST_CASE("[Animation] Create 3D scale track") {
CHECK(r_interpolation.is_equal_approx(Vector3(3.5, 4, 5)));
// 3D scale tracks always use linear interpolation for performance reasons.
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 0), real_t(1.0)));
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 1), real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 0) == doctest::Approx(1.0));
+ CHECK(animation->track_get_key_transition(0, 1) == doctest::Approx(1.0));
// This is a 3D scale track, so the methods below should return errors.
ERR_PRINT_OFF;
CHECK(animation->value_track_interpolate(0, 0.0).is_null());
CHECK(animation->position_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
CHECK(animation->rotation_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
- CHECK(Math::is_zero_approx(animation->bezier_track_interpolate(0, 0.0)));
+ CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(0.0));
CHECK(animation->blend_shape_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
ERR_PRINT_ON;
}
@@ -242,32 +242,32 @@ TEST_CASE("[Animation] Create blend shape track") {
float r_blend = 0.0f;
CHECK(animation->blend_shape_track_get_key(0, 0, &r_blend) == OK);
- CHECK(Math::is_equal_approx(r_blend, -1.0f));
+ CHECK(r_blend == doctest::Approx(-1.0f));
CHECK(animation->blend_shape_track_get_key(0, 1, &r_blend) == OK);
- CHECK(Math::is_equal_approx(r_blend, 1.0f));
+ CHECK(r_blend == doctest::Approx(1.0f));
CHECK(animation->blend_shape_track_interpolate(0, -0.2, &r_blend) == OK);
- CHECK(Math::is_equal_approx(r_blend, -1.0f));
+ CHECK(r_blend == doctest::Approx(-1.0f));
CHECK(animation->blend_shape_track_interpolate(0, 0.0, &r_blend) == OK);
- CHECK(Math::is_equal_approx(r_blend, -1.0f));
+ CHECK(r_blend == doctest::Approx(-1.0f));
CHECK(animation->blend_shape_track_interpolate(0, 0.2, &r_blend) == OK);
- CHECK(Math::is_equal_approx(r_blend, -0.2f));
+ CHECK(r_blend == doctest::Approx(-0.2f));
CHECK(animation->blend_shape_track_interpolate(0, 0.4, &r_blend) == OK);
- CHECK(Math::is_equal_approx(r_blend, 0.6f));
+ CHECK(r_blend == doctest::Approx(0.6f));
CHECK(animation->blend_shape_track_interpolate(0, 0.5, &r_blend) == OK);
- CHECK(Math::is_equal_approx(r_blend, 1.0f));
+ CHECK(r_blend == doctest::Approx(1.0f));
CHECK(animation->blend_shape_track_interpolate(0, 0.6, &r_blend) == OK);
- CHECK(Math::is_equal_approx(r_blend, 1.0f));
+ CHECK(r_blend == doctest::Approx(1.0f));
// Blend shape tracks always use linear interpolation for performance reasons.
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 0), real_t(1.0)));
- CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 1), real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 0) == doctest::Approx(real_t(1.0)));
+ CHECK(animation->track_get_key_transition(0, 1) == doctest::Approx(real_t(1.0)));
// This is a blend shape track, so the methods below should return errors.
ERR_PRINT_OFF;
@@ -275,7 +275,7 @@ TEST_CASE("[Animation] Create blend shape track") {
CHECK(animation->position_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
CHECK(animation->rotation_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
CHECK(animation->scale_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER);
- CHECK(Math::is_zero_approx(animation->bezier_track_interpolate(0, 0.0)));
+ CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(0.0));
ERR_PRINT_ON;
}
@@ -289,15 +289,15 @@ TEST_CASE("[Animation] Create Bezier track") {
CHECK(animation->get_track_count() == 1);
CHECK(!animation->track_is_compressed(0));
- CHECK(Math::is_equal_approx(animation->bezier_track_get_key_value(0, 0), real_t(-1.0)));
- CHECK(Math::is_equal_approx(animation->bezier_track_get_key_value(0, 1), real_t(1.0)));
+ CHECK(animation->bezier_track_get_key_value(0, 0) == doctest::Approx(real_t(-1.0)));
+ CHECK(animation->bezier_track_get_key_value(0, 1) == doctest::Approx(real_t(1.0)));
- CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, -0.2), real_t(-1.0)));
- CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, 0.0), real_t(-1.0)));
- CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, 0.2), real_t(-0.76057207584381)));
- CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, 0.4), real_t(-0.39975279569626)));
- CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, 0.5), real_t(1.0)));
- CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, 0.6), real_t(1.0)));
+ CHECK(animation->bezier_track_interpolate(0, -0.2) == doctest::Approx(real_t(-1.0)));
+ CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(real_t(-1.0)));
+ CHECK(animation->bezier_track_interpolate(0, 0.2) == doctest::Approx(real_t(-0.76057207584381)));
+ CHECK(animation->bezier_track_interpolate(0, 0.4) == doctest::Approx(real_t(-0.39975279569626)));
+ CHECK(animation->bezier_track_interpolate(0, 0.5) == doctest::Approx(real_t(1.0)));
+ CHECK(animation->bezier_track_interpolate(0, 0.6) == doctest::Approx(real_t(1.0)));
// This is a bezier track, so the methods below should return errors.
ERR_PRINT_OFF;
diff --git a/tests/scene/test_audio_stream_wav.h b/tests/scene/test_audio_stream_wav.h
index 4ba431dfc2..c84c66b0e6 100644
--- a/tests/scene/test_audio_stream_wav.h
+++ b/tests/scene/test_audio_stream_wav.h
@@ -138,7 +138,7 @@ void run_test(String file_name, AudioStreamWAV::Format data_format, bool stereo,
CHECK(stream->get_data() == test_data);
SUBCASE("Stream length is computed properly") {
- CHECK(Math::is_equal_approx(stream->get_length(), double(wav_count / wav_rate)));
+ CHECK(stream->get_length() == doctest::Approx(double(wav_count / wav_rate)));
}
SUBCASE("Stream can be saved as .wav") {
diff --git a/tests/scene/test_curve.h b/tests/scene/test_curve.h
index ad7625ddc5..36ec0c0a4d 100644
--- a/tests/scene/test_curve.h
+++ b/tests/scene/test_curve.h
@@ -83,54 +83,54 @@ TEST_CASE("[Curve] Custom curve with free tangents") {
Math::is_zero_approx(curve->sample(-0.1)),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.1), (real_t)0.352),
+ curve->sample(0.1) == doctest::Approx((real_t)0.352),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.4), (real_t)0.352),
+ curve->sample(0.4) == doctest::Approx((real_t)0.352),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.7), (real_t)0.896),
+ curve->sample(0.7) == doctest::Approx((real_t)0.896),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(1), 1),
+ curve->sample(1) == doctest::Approx(1),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(2), 1),
+ curve->sample(2) == doctest::Approx(1),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
Math::is_zero_approx(curve->sample_baked(-0.1)),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.1), (real_t)0.352),
+ curve->sample_baked(0.1) == doctest::Approx((real_t)0.352),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.4), (real_t)0.352),
+ curve->sample_baked(0.4) == doctest::Approx((real_t)0.352),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.7), (real_t)0.896),
+ curve->sample_baked(0.7) == doctest::Approx((real_t)0.896),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(1), 1),
+ curve->sample_baked(1) == doctest::Approx(1),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(2), 1),
+ curve->sample_baked(2) == doctest::Approx(1),
"Custom free curve should return the expected baked value at offset 0.1.");
curve->remove_point(1);
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.1), 0),
+ curve->sample(0.1) == doctest::Approx(0),
"Custom free curve should return the expected value at offset 0.1 after removing point at index 1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.1), 0),
+ curve->sample_baked(0.1) == doctest::Approx(0),
"Custom free curve should return the expected baked value at offset 0.1 after removing point at index 1.");
curve->clear_points();
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.6), 0),
+ curve->sample(0.6) == doctest::Approx(0),
"Custom free curve should return the expected value at offset 0.6 after clearing all points.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.6), 0),
+ curve->sample_baked(0.6) == doctest::Approx(0),
"Custom free curve should return the expected baked value at offset 0.6 after clearing all points.");
}
@@ -143,7 +143,7 @@ TEST_CASE("[Curve] Custom curve with linear tangents") {
curve->add_point(Vector2(0.75, 1), 0, 0, Curve::TangentMode::TANGENT_LINEAR, Curve::TangentMode::TANGENT_LINEAR);
CHECK_MESSAGE(
- Math::is_equal_approx(curve->get_point_left_tangent(3), 4),
+ curve->get_point_left_tangent(3) == doctest::Approx(4),
"get_point_left_tangent() should return the expected value for point index 3.");
CHECK_MESSAGE(
Math::is_zero_approx(curve->get_point_right_tangent(3)),
@@ -172,48 +172,48 @@ TEST_CASE("[Curve] Custom curve with linear tangents") {
Math::is_zero_approx(curve->sample(-0.1)),
"Custom linear curve should return the expected value at offset -0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.1), (real_t)0.4),
+ curve->sample(0.1) == doctest::Approx((real_t)0.4),
"Custom linear curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.4), (real_t)0.4),
+ curve->sample(0.4) == doctest::Approx((real_t)0.4),
"Custom linear curve should return the expected value at offset 0.4.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.7), (real_t)0.8),
+ curve->sample(0.7) == doctest::Approx((real_t)0.8),
"Custom linear curve should return the expected value at offset 0.7.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(1), 1),
+ curve->sample(1) == doctest::Approx(1),
"Custom linear curve should return the expected value at offset 1.0.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(2), 1),
+ curve->sample(2) == doctest::Approx(1),
"Custom linear curve should return the expected value at offset 2.0.");
CHECK_MESSAGE(
Math::is_zero_approx(curve->sample_baked(-0.1)),
"Custom linear curve should return the expected baked value at offset -0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.1), (real_t)0.4),
+ curve->sample_baked(0.1) == doctest::Approx((real_t)0.4),
"Custom linear curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.4), (real_t)0.4),
+ curve->sample_baked(0.4) == doctest::Approx((real_t)0.4),
"Custom linear curve should return the expected baked value at offset 0.4.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.7), (real_t)0.8),
+ curve->sample_baked(0.7) == doctest::Approx((real_t)0.8),
"Custom linear curve should return the expected baked value at offset 0.7.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(1), 1),
+ curve->sample_baked(1) == doctest::Approx(1),
"Custom linear curve should return the expected baked value at offset 1.0.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(2), 1),
+ curve->sample_baked(2) == doctest::Approx(1),
"Custom linear curve should return the expected baked value at offset 2.0.");
ERR_PRINT_OFF;
curve->remove_point(10);
ERR_PRINT_ON;
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample(0.7), (real_t)0.8),
+ curve->sample(0.7) == doctest::Approx((real_t)0.8),
"Custom free curve should return the expected value at offset 0.7 after removing point at invalid index 10.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->sample_baked(0.7), (real_t)0.8),
+ curve->sample_baked(0.7) == doctest::Approx((real_t)0.8),
"Custom free curve should return the expected baked value at offset 0.7 after removing point at invalid index 10.");
}
diff --git a/tests/scene/test_primitives.h b/tests/scene/test_primitives.h
index ceec117700..8bac903d93 100644
--- a/tests/scene/test_primitives.h
+++ b/tests/scene/test_primitives.h
@@ -57,9 +57,9 @@ TEST_CASE("[SceneTree][Primitive][Capsule] Capsule Primitive") {
capsule->set_radial_segments(16);
capsule->set_rings(32);
- CHECK_MESSAGE(Math::is_equal_approx(capsule->get_radius(), 1.3f),
+ CHECK_MESSAGE(capsule->get_radius() == doctest::Approx(1.3f),
"Get/Set radius work with one set.");
- CHECK_MESSAGE(Math::is_equal_approx(capsule->get_height(), 7.1f),
+ CHECK_MESSAGE(capsule->get_height() == doctest::Approx(7.1f),
"Get/Set radius work with one set.");
CHECK_MESSAGE(capsule->get_radial_segments() == 16,
"Get/Set radius work with one set.");
@@ -129,7 +129,7 @@ TEST_CASE("[SceneTree][Primitive][Capsule] Capsule Primitive") {
if (normals[ii].y == 0.f) {
float mag_of_normal = Math::sqrt(normals[ii].x * normals[ii].x + normals[ii].z * normals[ii].z);
Vector3 normalized_normal = normals[ii] / mag_of_normal;
- CHECK_MESSAGE(Math::is_equal_approx(point_dist_from_yaxis, radius),
+ CHECK_MESSAGE(point_dist_from_yaxis == doctest::Approx(radius),
"Points on the tube of the capsule are radius away from y-axis.");
CHECK_MESSAGE(normalized_normal.is_equal_approx(yaxis_to_point),
"Normal points orthogonal from mid cylinder.");
@@ -244,9 +244,9 @@ TEST_CASE("[SceneTree][Primitive][Cylinder] Cylinder Primitive") {
cylinder->set_cap_top(false);
cylinder->set_cap_bottom(false);
- CHECK(Math::is_equal_approx(cylinder->get_top_radius(), 4.3f));
- CHECK(Math::is_equal_approx(cylinder->get_bottom_radius(), 1.2f));
- CHECK(Math::is_equal_approx(cylinder->get_height(), 9.77f));
+ CHECK(cylinder->get_top_radius() == doctest::Approx(4.3f));
+ CHECK(cylinder->get_bottom_radius() == doctest::Approx(1.2f));
+ CHECK(cylinder->get_height() == doctest::Approx(9.77f));
CHECK(cylinder->get_radial_segments() == 12);
CHECK(cylinder->get_rings() == 16);
CHECK(!cylinder->is_cap_top());
@@ -478,7 +478,7 @@ TEST_CASE("[SceneTree][Primitive][Prism] Prism Primitive") {
prism->set_subdivide_height(5);
prism->set_subdivide_depth(64);
- CHECK(Math::is_equal_approx(prism->get_left_to_right(), 3.4f));
+ CHECK(prism->get_left_to_right() == doctest::Approx(3.4f));
CHECK(prism->get_size().is_equal_approx(size));
CHECK(prism->get_subdivide_width() == 36);
CHECK(prism->get_subdivide_height() == 5);
@@ -513,8 +513,8 @@ TEST_CASE("[SceneTree][Primitive][Sphere] Sphere Primitive") {
sphere->set_rings(5);
sphere->set_is_hemisphere(true);
- CHECK(Math::is_equal_approx(sphere->get_radius(), 3.4f));
- CHECK(Math::is_equal_approx(sphere->get_height(), 2.2f));
+ CHECK(sphere->get_radius() == doctest::Approx(3.4f));
+ CHECK(sphere->get_height() == doctest::Approx(2.2f));
CHECK(sphere->get_radial_segments() == 36);
CHECK(sphere->get_rings() == 5);
CHECK(sphere->get_is_hemisphere());
@@ -581,8 +581,8 @@ TEST_CASE("[SceneTree][Primitive][Torus] Torus Primitive") {
torus->set_rings(19);
torus->set_ring_segments(43);
- CHECK(Math::is_equal_approx(torus->get_inner_radius(), 3.2f));
- CHECK(Math::is_equal_approx(torus->get_outer_radius(), 9.5f));
+ CHECK(torus->get_inner_radius() == doctest::Approx(3.2f));
+ CHECK(torus->get_outer_radius() == doctest::Approx(9.5f));
CHECK(torus->get_rings() == 19);
CHECK(torus->get_ring_segments() == 43);
}
@@ -610,8 +610,8 @@ TEST_CASE("[SceneTree][Primitive][TubeTrail] TubeTrail Primitive") {
Ref<Curve> curve = memnew(Curve);
tube->set_curve(curve);
- CHECK(Math::is_equal_approx(tube->get_radius(), 7.2f));
- CHECK(Math::is_equal_approx(tube->get_section_length(), 5.5f));
+ CHECK(tube->get_radius() == doctest::Approx(7.2f));
+ CHECK(tube->get_section_length() == doctest::Approx(5.5f));
CHECK(tube->get_radial_steps() == 9);
CHECK(tube->get_sections() == 33);
CHECK(tube->get_section_rings() == 12);
@@ -670,8 +670,8 @@ TEST_CASE("[SceneTree][Primitive][RibbonTrail] RibbonTrail Primitive") {
ribbon->set_section_segments(9);
ribbon->set_curve(curve);
- CHECK(Math::is_equal_approx(ribbon->get_size(), 4.3f));
- CHECK(Math::is_equal_approx(ribbon->get_section_length(), 1.3f));
+ CHECK(ribbon->get_size() == doctest::Approx(4.3f));
+ CHECK(ribbon->get_section_length() == doctest::Approx(1.3f));
CHECK(ribbon->get_sections() == 16);
CHECK(ribbon->get_section_segments() == 9);
CHECK(ribbon->get_curve() == curve);
@@ -781,11 +781,11 @@ TEST_CASE("[SceneTree][Primitive][Text] Text Primitive") {
CHECK(text->get_structured_text_bidi_override_options() == options);
CHECK(text->is_uppercase() == true);
CHECK(text->get_offset() == offset);
- CHECK(Math::is_equal_approx(text->get_line_spacing(), 1.7f));
- CHECK(Math::is_equal_approx(text->get_width(), width));
- CHECK(Math::is_equal_approx(text->get_depth(), depth));
- CHECK(Math::is_equal_approx(text->get_curve_step(), curve_step));
- CHECK(Math::is_equal_approx(text->get_pixel_size(), pixel_size));
+ CHECK(text->get_line_spacing() == doctest::Approx(1.7f));
+ CHECK(text->get_width() == doctest::Approx(width));
+ CHECK(text->get_depth() == doctest::Approx(depth));
+ CHECK(text->get_curve_step() == doctest::Approx(curve_step));
+ CHECK(text->get_pixel_size() == doctest::Approx(pixel_size));
}
SUBCASE("[Primitive][Text] Set objects multiple times.") {
diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h
index e34f2970d4..5dad7d06e1 100644
--- a/tests/scene/test_text_edit.h
+++ b/tests/scene/test_text_edit.h
@@ -734,13 +734,20 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
}
SUBCASE("[TextEdit] add selection for next occurrence") {
- text_edit->set_text("\ntest other_test\nrandom test\nword test word");
+ text_edit->set_text("\ntest other_test\nrandom test\nword test word nonrandom");
text_edit->set_caret_column(0);
text_edit->set_caret_line(1);
- text_edit->select_word_under_caret();
- CHECK(text_edit->has_selection(0));
+ // First selection made by the implicit select_word_under_caret call
+ text_edit->add_selection_for_next_occurrence();
+ CHECK(text_edit->get_caret_count() == 1);
CHECK(text_edit->get_selected_text(0) == "test");
+ CHECK(text_edit->get_selection_from_line(0) == 1);
+ CHECK(text_edit->get_selection_from_column(0) == 0);
+ CHECK(text_edit->get_selection_to_line(0) == 1);
+ CHECK(text_edit->get_selection_to_column(0) == 4);
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 4);
text_edit->add_selection_for_next_occurrence();
CHECK(text_edit->get_caret_count() == 2);
@@ -771,6 +778,27 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_selection_to_column(3) == 9);
CHECK(text_edit->get_caret_line(3) == 3);
CHECK(text_edit->get_caret_column(3) == 9);
+
+ // A different word with a new manually added caret
+ text_edit->add_caret(2, 1);
+ text_edit->select(2, 0, 2, 4, 4);
+ CHECK(text_edit->get_selected_text(4) == "rand");
+
+ text_edit->add_selection_for_next_occurrence();
+ CHECK(text_edit->get_caret_count() == 6);
+ CHECK(text_edit->get_selected_text(5) == "rand");
+ CHECK(text_edit->get_selection_from_line(5) == 3);
+ CHECK(text_edit->get_selection_from_column(5) == 18);
+ CHECK(text_edit->get_selection_to_line(5) == 3);
+ CHECK(text_edit->get_selection_to_column(5) == 22);
+ CHECK(text_edit->get_caret_line(5) == 3);
+ CHECK(text_edit->get_caret_column(5) == 22);
+
+ // Make sure the previous selections are still active
+ CHECK(text_edit->get_selected_text(0) == "test");
+ CHECK(text_edit->get_selected_text(1) == "test");
+ CHECK(text_edit->get_selected_text(2) == "test");
+ CHECK(text_edit->get_selected_text(3) == "test");
}
SUBCASE("[TextEdit] deselect on focus loss") {
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index cee110414e..d58c19ac32 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -192,11 +192,8 @@ struct GodotTestCaseListener : public doctest::IReporter {
String name = String(p_in.m_name);
if (name.find("[SceneTree]") != -1) {
- GLOBAL_DEF("memory/limits/multithreaded_server/rid_pool_prealloc", 60);
memnew(MessageQueue);
- GLOBAL_DEF("internationalization/rendering/force_right_to_left_layout_direction", false);
-
memnew(Input);
Error err = OK;