summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.git-blame-ignore-revs3
-rw-r--r--core/core_bind.cpp6
-rw-r--r--core/core_bind.h2
-rw-r--r--core/extension/gdextension_interface.cpp58
-rw-r--r--core/extension/gdextension_interface.h55
-rw-r--r--core/io/dir_access.h4
-rw-r--r--core/io/file_access.h4
-rw-r--r--core/io/image.cpp10
-rw-r--r--core/math/bvh.h2
-rw-r--r--core/math/bvh_abb.h2
-rw-r--r--core/math/bvh_tree.h8
-rw-r--r--core/math/disjoint_set.h14
-rw-r--r--core/math/dynamic_bvh.h12
-rw-r--r--core/math/expression.h2
-rw-r--r--core/math/projection.h2
-rw-r--r--core/math/random_pcg.h2
-rw-r--r--core/object/callable_method_pointer.h45
-rw-r--r--core/object/class_db.cpp25
-rw-r--r--core/object/class_db.h33
-rw-r--r--core/object/method_bind.h42
-rw-r--r--core/object/object.cpp55
-rw-r--r--core/object/object.h6
-rw-r--r--core/object/ref_counted.h20
-rw-r--r--core/object/script_instance.cpp22
-rw-r--r--core/object/script_instance.h2
-rw-r--r--core/object/script_language.cpp16
-rw-r--r--core/object/script_language.h9
-rw-r--r--core/object/script_language_extension.cpp3
-rw-r--r--core/object/script_language_extension.h27
-rw-r--r--core/object/worker_thread_pool.h8
-rw-r--r--core/os/condition_variable.h4
-rw-r--r--core/os/memory.h10
-rw-r--r--core/os/mutex.h8
-rw-r--r--core/string/ustring.cpp2
-rw-r--r--core/string/ustring.h6
-rw-r--r--core/templates/bin_sorted_array.h2
-rw-r--r--core/templates/command_queue_mt.h68
-rw-r--r--core/templates/cowdata.h28
-rw-r--r--core/templates/hash_map.h10
-rw-r--r--core/templates/hash_set.h6
-rw-r--r--core/templates/hashfuncs.h12
-rw-r--r--core/templates/list.h12
-rw-r--r--core/templates/local_vector.h6
-rw-r--r--core/templates/lru.h2
-rw-r--r--core/templates/oa_hash_map.h6
-rw-r--r--core/templates/paged_allocator.h6
-rw-r--r--core/templates/paged_array.h4
-rw-r--r--core/templates/pair.h18
-rw-r--r--core/templates/pooled_list.h4
-rw-r--r--core/templates/rb_map.h2
-rw-r--r--core/templates/rb_set.h2
-rw-r--r--core/templates/rid_owner.h6
-rw-r--r--core/templates/safe_list.h2
-rw-r--r--core/templates/safe_refcount.h2
-rw-r--r--core/templates/search_array.h2
-rw-r--r--core/templates/self_list.h4
-rw-r--r--core/templates/simple_type.h8
-rw-r--r--core/templates/sort_array.h4
-rw-r--r--core/templates/vector.h16
-rw-r--r--core/templates/vmap.h2
-rw-r--r--core/templates/vset.h2
-rw-r--r--core/typedefs.h6
-rw-r--r--core/variant/binder_common.h142
-rw-r--r--core/variant/callable.cpp19
-rw-r--r--core/variant/callable.h2
-rw-r--r--core/variant/callable_bind.cpp16
-rw-r--r--core/variant/callable_bind.h2
-rw-r--r--core/variant/method_ptrcall.h6
-rw-r--r--core/variant/native_ptr.h12
-rw-r--r--core/variant/type_info.h4
-rw-r--r--core/variant/typed_array.h14
-rw-r--r--core/variant/variant.cpp6
-rw-r--r--core/variant/variant.h2
-rw-r--r--core/variant/variant_call.cpp143
-rw-r--r--core/variant/variant_callable.cpp9
-rw-r--r--core/variant/variant_callable.h1
-rw-r--r--core/variant/variant_construct.cpp2
-rw-r--r--core/variant/variant_construct.h12
-rw-r--r--core/variant/variant_destruct.cpp2
-rw-r--r--core/variant/variant_destruct.h2
-rw-r--r--core/variant/variant_internal.h20
-rw-r--r--core/variant/variant_op.cpp2
-rw-r--r--core/variant/variant_op.h80
-rw-r--r--core/variant/variant_parser.cpp2
-rw-r--r--core/variant/variant_parser.h2
-rw-r--r--core/variant/variant_setget.cpp6
-rw-r--r--core/variant/variant_utility.cpp38
-rw-r--r--doc/classes/@GlobalScope.xml4
-rw-r--r--doc/classes/ArrayMesh.xml2
-rw-r--r--doc/classes/Callable.xml6
-rw-r--r--doc/classes/ClassDB.xml9
-rw-r--r--doc/classes/Color.xml2
-rw-r--r--doc/classes/Crypto.xml2
-rw-r--r--doc/classes/Engine.xml4
-rw-r--r--doc/classes/Environment.xml2
-rw-r--r--doc/classes/FileAccess.xml2
-rw-r--r--doc/classes/FontFile.xml4
-rw-r--r--doc/classes/HashingContext.xml6
-rw-r--r--doc/classes/Image.xml2
-rw-r--r--doc/classes/ImporterMesh.xml2
-rw-r--r--doc/classes/Input.xml2
-rw-r--r--doc/classes/Object.xml8
-rw-r--r--doc/classes/ProjectSettings.xml15
-rw-r--r--doc/classes/RayCast2D.xml5
-rw-r--r--doc/classes/RayCast3D.xml5
-rw-r--r--doc/classes/RenderingServer.xml2
-rw-r--r--doc/classes/ScriptExtension.xml7
-rw-r--r--doc/classes/SurfaceTool.xml2
-rw-r--r--doc/classes/TextServer.xml12
-rw-r--r--doc/classes/TextServerExtension.xml431
-rw-r--r--doc/classes/Viewport.xml2
-rw-r--r--doc/classes/XMLParser.xml2
-rw-r--r--drivers/d3d12/rendering_context_driver_d3d12.h2
-rw-r--r--drivers/d3d12/rendering_device_driver_d3d12.cpp2
-rw-r--r--drivers/d3d12/rendering_device_driver_d3d12.h2
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp10
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp2
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp8
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h2
-rw-r--r--drivers/gles3/shader_gles3.cpp4
-rw-r--r--drivers/gles3/storage/texture_storage.cpp6
-rw-r--r--editor/editor_data.h2
-rw-r--r--editor/editor_file_system.cpp8
-rw-r--r--editor/editor_help_search.h2
-rw-r--r--editor/editor_plugin.h4
-rw-r--r--editor/export/editor_export_platform.cpp5
-rw-r--r--editor/filesystem_dock.cpp58
-rw-r--r--editor/filesystem_dock.h5
-rw-r--r--editor/icons/FadeCross.svg1
-rw-r--r--editor/icons/FadeDisabled.svg1
-rw-r--r--editor/icons/FadeIn.svg1
-rw-r--r--editor/icons/FadeOut.svg1
-rw-r--r--editor/import/3d/resource_importer_scene.h8
-rw-r--r--editor/import/resource_importer_bmfont.cpp18
-rw-r--r--editor/import_dock.cpp58
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp2
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp6
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp2
-rw-r--r--main/main.cpp28
-rw-r--r--main/main.h2
-rw-r--r--modules/gdscript/gdscript.cpp34
-rw-r--r--modules/gdscript/gdscript.h6
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp97
-rw-r--r--modules/gdscript/gdscript_function.h1
-rw-r--r--modules/gdscript/gdscript_lambda_callable.cpp18
-rw-r--r--modules/gdscript/gdscript_lambda_callable.h2
-rw-r--r--modules/gdscript/gdscript_parser.cpp318
-rw-r--r--modules/gdscript/gdscript_parser.h31
-rw-r--r--modules/gdscript/gdscript_rpc_callable.cpp4
-rw-r--r--modules/gdscript/gdscript_rpc_callable.h1
-rw-r--r--modules/gdscript/gdscript_utility_callable.cpp15
-rw-r--r--modules/gdscript/gdscript_utility_callable.h1
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp2
-rw-r--r--modules/gdscript/gdscript_utility_functions.h2
-rw-r--r--modules/gdscript/gdscript_warning.cpp36
-rw-r--r--modules/gdscript/gdscript_warning.h20
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd15
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/warning_ignore_targets.gd35
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/warning_ignore_targets.out29
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/warning_ignore_warnings.gd156
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/warning_ignore_warnings.out1
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/unused_private_class_variable.out4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.gd12
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.out5
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/duplicate_tool.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/class_inheritance_access.gd1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/lambda_ends_with_new_line.gd1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/match.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/features/signal_declaration.gd12
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/standalone_ternary.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/standalone_ternary.out10
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/argument_count.gd102
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/argument_count.out27
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/member_info.gd10
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.gd4
-rw-r--r--modules/gltf/doc_classes/GLTFMesh.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFTexture.xml2
-rw-r--r--modules/gltf/gltf_document.cpp4
-rw-r--r--modules/gltf/gltf_document.h2
-rw-r--r--modules/gltf/gltf_template_convert.h12
-rw-r--r--modules/gltf/structures/gltf_animation.h2
-rw-r--r--modules/interactive_music/SCsub11
-rw-r--r--modules/interactive_music/audio_stream_interactive.cpp1030
-rw-r--r--modules/interactive_music/audio_stream_interactive.h270
-rw-r--r--modules/interactive_music/audio_stream_playlist.cpp406
-rw-r--r--modules/interactive_music/audio_stream_playlist.h125
-rw-r--r--modules/interactive_music/audio_stream_synchronized.cpp312
-rw-r--r--modules/interactive_music/audio_stream_synchronized.h119
-rw-r--r--modules/interactive_music/config.py21
-rw-r--r--modules/interactive_music/doc_classes/AudioStreamInteractive.xml229
-rw-r--r--modules/interactive_music/doc_classes/AudioStreamPlaybackInteractive.xml27
-rw-r--r--modules/interactive_music/doc_classes/AudioStreamPlaybackPlaylist.xml10
-rw-r--r--modules/interactive_music/doc_classes/AudioStreamPlaybackSynchronized.xml9
-rw-r--r--modules/interactive_music/doc_classes/AudioStreamPlaylist.xml52
-rw-r--r--modules/interactive_music/doc_classes/AudioStreamSynchronized.xml53
-rw-r--r--modules/interactive_music/editor/audio_stream_interactive_editor_plugin.cpp416
-rw-r--r--modules/interactive_music/editor/audio_stream_interactive_editor_plugin.h110
-rw-r--r--modules/interactive_music/register_types.cpp60
-rw-r--r--modules/interactive_music/register_types.h39
-rw-r--r--modules/ktx/texture_loader_ktx.cpp2
-rw-r--r--modules/minimp3/doc_classes/ResourceImporterMP3.xml4
-rw-r--r--modules/mono/csharp_script.cpp51
-rw-r--r--modules/mono/csharp_script.h2
-rw-r--r--modules/mono/editor/hostfxr_resolver.cpp2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs23
-rw-r--r--modules/mono/managed_callable.cpp4
-rw-r--r--modules/mono/managed_callable.h1
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.cpp1
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h2
-rw-r--r--modules/msdfgen/SCsub3
-rw-r--r--modules/multiplayer/scene_replication_interface.h2
-rw-r--r--modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml2
-rw-r--r--modules/openxr/openxr_api.h2
-rw-r--r--modules/text_server_adv/SCsub1
-rw-r--r--modules/text_server_adv/gdextension_build/SConstruct4
-rw-r--r--modules/text_server_adv/text_server_adv.cpp12
-rw-r--r--modules/text_server_fb/SCsub1
-rw-r--r--modules/text_server_fb/gdextension_build/SConstruct2
-rw-r--r--modules/text_server_fb/text_server_fb.cpp18
-rw-r--r--modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml2
-rw-r--r--modules/websocket/packet_buffer.h2
-rw-r--r--platform/ios/os_ios.mm2
-rw-r--r--platform/linuxbsd/wayland/detect_prime_egl.cpp2
-rw-r--r--platform/linuxbsd/wayland/wayland_thread.cpp8
-rw-r--r--platform/macos/display_server_macos.mm2
-rw-r--r--platform/macos/os_macos.mm2
-rw-r--r--platform/web/doc_classes/EditorExportPlatformWeb.xml2
-rw-r--r--platform/windows/crash_handler_windows.cpp2
-rw-r--r--platform/windows/display_server_windows.cpp76
-rw-r--r--platform/windows/gl_manager_windows_native.cpp20
-rw-r--r--platform/windows/os_windows.cpp28
-rw-r--r--platform/windows/os_windows.h2
-rw-r--r--platform/windows/tts_windows.cpp4
-rw-r--r--platform/windows/wgl_detect_version.cpp2
-rw-r--r--scene/main/node.h2
-rw-r--r--scene/resources/animation.cpp10
-rw-r--r--scene/resources/animation.h12
-rw-r--r--scene/resources/audio_stream_wav.cpp2
-rw-r--r--scene/resources/audio_stream_wav.h2
-rw-r--r--scene/resources/font.cpp11
-rw-r--r--scene/resources/font.h2
-rw-r--r--scene/resources/material.cpp995
-rw-r--r--servers/SCsub22
-rw-r--r--servers/camera_server.h4
-rw-r--r--servers/physics_2d/godot_broad_phase_2d_bvh.h4
-rw-r--r--servers/physics_2d/godot_collision_solver_2d_sat.cpp2
-rw-r--r--servers/physics_3d/godot_broad_phase_3d_bvh.h4
-rw-r--r--servers/physics_3d/godot_collision_solver_3d_sat.cpp2
-rw-r--r--servers/register_server_types.cpp60
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp2
-rw-r--r--servers/rendering/renderer_canvas_cull.h2
-rw-r--r--servers/rendering/renderer_canvas_render.h2
-rw-r--r--servers/rendering/renderer_compositor.cpp2
-rw-r--r--servers/rendering/renderer_rd/effects/vrs.cpp5
-rw-r--r--servers/rendering/renderer_scene_cull.h3
-rw-r--r--servers/rendering/renderer_viewport.cpp14
-rw-r--r--servers/rendering/renderer_viewport.h5
-rw-r--r--servers/rendering/rendering_device.cpp2
-rw-r--r--servers/rendering/rendering_device.h2
-rw-r--r--servers/rendering/rendering_device_driver.h8
-rw-r--r--servers/rendering/rendering_method.h7
-rw-r--r--servers/rendering/rendering_server_default.cpp2
-rw-r--r--servers/rendering/shader_language.h2
-rw-r--r--servers/rendering/storage/variant_converters.h4
-rw-r--r--servers/text/text_server_dummy.h84
-rw-r--r--servers/text/text_server_extension.cpp182
-rw-r--r--servers/text_server.cpp42
-rw-r--r--servers/text_server.h6
-rw-r--r--tests/core/object/test_object.h6
-rw-r--r--tests/core/variant/test_callable.h140
-rw-r--r--tests/test_main.cpp1
-rw-r--r--thirdparty/README.md4
-rw-r--r--thirdparty/icu4c/common/unicode/uvernum.h6
-rw-r--r--thirdparty/icu4c/icudt74l.datbin4419920 -> 4419952 bytes
-rw-r--r--thirdparty/msdfgen/LICENSE.txt2
-rw-r--r--thirdparty/msdfgen/core/Bitmap.h10
-rw-r--r--thirdparty/msdfgen/core/Bitmap.hpp10
-rw-r--r--thirdparty/msdfgen/core/BitmapRef.hpp8
-rw-r--r--thirdparty/msdfgen/core/Contour.cpp2
-rw-r--r--thirdparty/msdfgen/core/Contour.h2
-rw-r--r--thirdparty/msdfgen/core/EdgeColor.h2
-rw-r--r--thirdparty/msdfgen/core/EdgeHolder.cpp12
-rw-r--r--thirdparty/msdfgen/core/EdgeHolder.h12
-rw-r--r--thirdparty/msdfgen/core/MSDFErrorCorrection.cpp8
-rw-r--r--thirdparty/msdfgen/core/Projection.h2
-rw-r--r--thirdparty/msdfgen/core/Scanline.cpp2
-rw-r--r--thirdparty/msdfgen/core/Scanline.h1
-rw-r--r--thirdparty/msdfgen/core/Shape.cpp41
-rw-r--r--thirdparty/msdfgen/core/Shape.h2
-rw-r--r--thirdparty/msdfgen/core/ShapeDistanceFinder.h2
-rw-r--r--thirdparty/msdfgen/core/ShapeDistanceFinder.hpp6
-rw-r--r--thirdparty/msdfgen/core/SignedDistance.cpp29
-rw-r--r--thirdparty/msdfgen/core/SignedDistance.h23
-rw-r--r--thirdparty/msdfgen/core/SignedDistance.hpp38
-rw-r--r--thirdparty/msdfgen/core/Vector2.cpp146
-rw-r--r--thirdparty/msdfgen/core/Vector2.h66
-rw-r--r--thirdparty/msdfgen/core/Vector2.hpp167
-rw-r--r--thirdparty/msdfgen/core/arithmetics.hpp2
-rw-r--r--thirdparty/msdfgen/core/base.h16
-rw-r--r--thirdparty/msdfgen/core/bitmap-interpolation.hpp2
-rw-r--r--thirdparty/msdfgen/core/contour-combiners.cpp4
-rw-r--r--thirdparty/msdfgen/core/contour-combiners.h4
-rw-r--r--thirdparty/msdfgen/core/edge-coloring.cpp11
-rw-r--r--thirdparty/msdfgen/core/edge-segments.cpp32
-rw-r--r--thirdparty/msdfgen/core/edge-segments.h36
-rw-r--r--thirdparty/msdfgen/core/edge-selectors.h4
-rw-r--r--thirdparty/msdfgen/core/equation-solver.cpp2
-rw-r--r--thirdparty/msdfgen/core/equation-solver.h2
-rw-r--r--thirdparty/msdfgen/core/generator-config.h1
-rw-r--r--thirdparty/msdfgen/core/msdf-error-correction.h2
-rw-r--r--thirdparty/msdfgen/core/pixel-conversion.hpp2
-rw-r--r--thirdparty/msdfgen/core/rasterization.h2
-rw-r--r--thirdparty/msdfgen/core/render-sdf.h2
-rw-r--r--thirdparty/msdfgen/core/sdf-error-estimation.h2
-rw-r--r--thirdparty/msdfgen/core/shape-description.cpp59
-rw-r--r--thirdparty/msdfgen/core/shape-description.h1
-rw-r--r--thirdparty/msdfgen/msdfgen.h5
320 files changed, 7388 insertions, 1816 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index eed5b661b8..ebfd3b515a 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -51,3 +51,6 @@ bd282ff43f23fe845f29a3e25c8efc01bd65ffb0
# Add "Godot Engine contributors" copyright line
df61dc4b2bd54a5a40c515493c76f5a458e5b541
+
+# Enforce template syntax `typename` over `class`
+9903e6779b70fc03aae70a37b9cf053f4f355b91
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index a0df1b6240..6927db002b 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -1434,6 +1434,10 @@ bool ClassDB::class_has_method(const StringName &p_class, const StringName &p_me
return ::ClassDB::has_method(p_class, p_method, p_no_inheritance);
}
+int ClassDB::class_get_method_argument_count(const StringName &p_class, const StringName &p_method, bool p_no_inheritance) const {
+ return ::ClassDB::get_method_argument_count(p_class, p_method, nullptr, p_no_inheritance);
+}
+
TypedArray<Dictionary> ClassDB::class_get_method_list(const StringName &p_class, bool p_no_inheritance) const {
List<MethodInfo> methods;
::ClassDB::get_method_list(p_class, &methods, p_no_inheritance);
@@ -1562,6 +1566,8 @@ void ClassDB::_bind_methods() {
::ClassDB::bind_method(D_METHOD("class_has_method", "class", "method", "no_inheritance"), &ClassDB::class_has_method, DEFVAL(false));
+ ::ClassDB::bind_method(D_METHOD("class_get_method_argument_count", "class", "method", "no_inheritance"), &ClassDB::class_get_method_argument_count, DEFVAL(false));
+
::ClassDB::bind_method(D_METHOD("class_get_method_list", "class", "no_inheritance"), &ClassDB::class_get_method_list, DEFVAL(false));
::ClassDB::bind_method(D_METHOD("class_get_integer_constant_list", "class", "no_inheritance"), &ClassDB::class_get_integer_constant_list, DEFVAL(false));
diff --git a/core/core_bind.h b/core/core_bind.h
index 64ab4dd7e2..305f616cef 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -447,6 +447,8 @@ public:
bool class_has_method(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const;
+ int class_get_method_argument_count(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const;
+
TypedArray<Dictionary> class_get_method_list(const StringName &p_class, bool p_no_inheritance = false) const;
PackedStringArray class_get_integer_constant_list(const StringName &p_class, bool p_no_inheritance = false) const;
diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp
index 67ec09d764..9b4aa98357 100644
--- a/core/extension/gdextension_interface.cpp
+++ b/core/extension/gdextension_interface.cpp
@@ -59,6 +59,8 @@ class CallableCustomExtension : public CallableCustom {
GDExtensionCallableCustomToString to_string_func;
+ GDExtensionCallableCustomGetArgumentCount get_argument_count_func;
+
uint32_t _hash;
static bool default_compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
@@ -143,6 +145,21 @@ public:
return object;
}
+ int get_argument_count(bool &r_is_valid) const override {
+ if (get_argument_count_func != nullptr) {
+ GDExtensionBool is_valid = false;
+
+ GDExtensionInt ret = get_argument_count_func(userdata, &is_valid);
+
+ if (is_valid) {
+ r_is_valid = true;
+ return ret;
+ }
+ }
+ r_is_valid = false;
+ return 0;
+ }
+
void *get_userdata(void *p_token) const {
return (p_token == token) ? userdata : nullptr;
}
@@ -157,6 +174,7 @@ public:
r_call_error.expected = error.expected;
}
+#ifndef DISABLE_DEPRECATED
CallableCustomExtension(GDExtensionCallableCustomInfo *p_info) {
userdata = p_info->callable_userdata;
token = p_info->token;
@@ -172,6 +190,35 @@ public:
to_string_func = p_info->to_string_func;
+ get_argument_count_func = nullptr;
+
+ // Pre-calculate the hash.
+ if (p_info->hash_func != nullptr) {
+ _hash = p_info->hash_func(userdata);
+ } else {
+ _hash = hash_murmur3_one_64((uint64_t)call_func);
+ _hash = hash_murmur3_one_64((uint64_t)userdata, _hash);
+ }
+ }
+#endif
+
+ CallableCustomExtension(GDExtensionCallableCustomInfo2 *p_info) {
+ userdata = p_info->callable_userdata;
+ token = p_info->token;
+
+ object = p_info->object_id;
+
+ call_func = p_info->call_func;
+ is_valid_func = p_info->is_valid_func;
+ free_func = p_info->free_func;
+
+ equal_func = p_info->equal_func;
+ less_than_func = p_info->less_than_func;
+
+ to_string_func = p_info->to_string_func;
+
+ get_argument_count_func = p_info->get_argument_count_func;
+
// Pre-calculate the hash.
if (p_info->hash_func != nullptr) {
_hash = p_info->hash_func(userdata);
@@ -1255,6 +1302,7 @@ static GDExtensionScriptInstancePtr gdextension_script_instance_create(const GDE
info_3->get_property_type_func = p_info->get_property_type_func;
info_3->validate_property_func = nullptr;
info_3->has_method_func = p_info->has_method_func;
+ info_3->get_method_argument_count_func = nullptr;
info_3->call_func = p_info->call_func;
info_3->notification_func = nullptr;
info_3->to_string_func = p_info->to_string_func;
@@ -1294,6 +1342,7 @@ static GDExtensionScriptInstancePtr gdextension_script_instance_create2(const GD
info_3->get_property_type_func = p_info->get_property_type_func;
info_3->validate_property_func = nullptr;
info_3->has_method_func = p_info->has_method_func;
+ info_3->get_method_argument_count_func = nullptr;
info_3->call_func = p_info->call_func;
info_3->notification_func = p_info->notification_func;
info_3->to_string_func = p_info->to_string_func;
@@ -1378,9 +1427,15 @@ static GDExtensionScriptInstancePtr gdextension_object_get_script_instance(GDExt
return script_instance_extension->instance;
}
+#ifndef DISABLE_DEPRECATED
static void gdextension_callable_custom_create(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo *p_custom_callable_info) {
memnew_placement(r_callable, Callable(memnew(CallableCustomExtension(p_custom_callable_info))));
}
+#endif
+
+static void gdextension_callable_custom_create2(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo2 *p_custom_callable_info) {
+ memnew_placement(r_callable, Callable(memnew(CallableCustomExtension(p_custom_callable_info))));
+}
static void *gdextension_callable_custom_get_userdata(GDExtensionTypePtr p_callable, void *p_token) {
const Callable &callable = *reinterpret_cast<const Callable *>(p_callable);
@@ -1595,7 +1650,10 @@ void gdextension_setup_interface() {
REGISTER_INTERFACE_FUNC(placeholder_script_instance_create);
REGISTER_INTERFACE_FUNC(placeholder_script_instance_update);
REGISTER_INTERFACE_FUNC(object_get_script_instance);
+#ifndef DISABLE_DEPRECATED
REGISTER_INTERFACE_FUNC(callable_custom_create);
+#endif // DISABLE_DEPRECATED
+ REGISTER_INTERFACE_FUNC(callable_custom_create2);
REGISTER_INTERFACE_FUNC(callable_custom_get_userdata);
REGISTER_INTERFACE_FUNC(classdb_construct_object);
REGISTER_INTERFACE_FUNC(classdb_get_method_bind);
diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h
index e7497a9d4c..e9c570e994 100644
--- a/core/extension/gdextension_interface.h
+++ b/core/extension/gdextension_interface.h
@@ -442,6 +442,8 @@ typedef GDExtensionBool (*GDExtensionCallableCustomLessThan)(void *callable_user
typedef void (*GDExtensionCallableCustomToString)(void *callable_userdata, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out);
+typedef GDExtensionInt (*GDExtensionCallableCustomGetArgumentCount)(void *callable_userdata, GDExtensionBool *r_is_valid);
+
typedef struct {
/* Only `call_func` and `token` are strictly required, however, `object_id` should be passed if its not a static method.
*
@@ -471,7 +473,40 @@ typedef struct {
GDExtensionCallableCustomLessThan less_than_func;
GDExtensionCallableCustomToString to_string_func;
-} GDExtensionCallableCustomInfo;
+} GDExtensionCallableCustomInfo; // Deprecated. Use GDExtensionCallableCustomInfo2 instead.
+
+typedef struct {
+ /* Only `call_func` and `token` are strictly required, however, `object_id` should be passed if its not a static method.
+ *
+ * `token` should point to an address that uniquely identifies the GDExtension (for example, the
+ * `GDExtensionClassLibraryPtr` passed to the entry symbol function.
+ *
+ * `hash_func`, `equal_func`, and `less_than_func` are optional. If not provided both `call_func` and
+ * `callable_userdata` together are used as the identity of the callable for hashing and comparison purposes.
+ *
+ * The hash returned by `hash_func` is cached, `hash_func` will not be called more than once per callable.
+ *
+ * `is_valid_func` is necessary if the validity of the callable can change before destruction.
+ *
+ * `free_func` is necessary if `callable_userdata` needs to be cleaned up when the callable is freed.
+ */
+ void *callable_userdata;
+ void *token;
+
+ GDObjectInstanceID object_id;
+
+ GDExtensionCallableCustomCall call_func;
+ GDExtensionCallableCustomIsValid is_valid_func;
+ GDExtensionCallableCustomFree free_func;
+
+ GDExtensionCallableCustomHash hash_func;
+ GDExtensionCallableCustomEqual equal_func;
+ GDExtensionCallableCustomLessThan less_than_func;
+
+ GDExtensionCallableCustomToString to_string_func;
+
+ GDExtensionCallableCustomGetArgumentCount get_argument_count_func;
+} GDExtensionCallableCustomInfo2;
/* SCRIPT INSTANCE EXTENSION */
@@ -500,6 +535,8 @@ typedef void (*GDExtensionScriptInstanceFreeMethodList2)(GDExtensionScriptInstan
typedef GDExtensionBool (*GDExtensionScriptInstanceHasMethod)(GDExtensionScriptInstanceDataPtr p_instance, GDExtensionConstStringNamePtr p_name);
+typedef GDExtensionInt (*GDExtensionScriptInstanceGetMethodArgumentCount)(GDExtensionScriptInstanceDataPtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionBool *r_is_valid);
+
typedef void (*GDExtensionScriptInstanceCall)(GDExtensionScriptInstanceDataPtr p_self, GDExtensionConstStringNamePtr p_method, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
typedef void (*GDExtensionScriptInstanceNotification)(GDExtensionScriptInstanceDataPtr p_instance, int32_t p_what); // Deprecated. Use GDExtensionScriptInstanceNotification2 instead.
typedef void (*GDExtensionScriptInstanceNotification2)(GDExtensionScriptInstanceDataPtr p_instance, int32_t p_what, GDExtensionBool p_reversed);
@@ -619,6 +656,8 @@ typedef struct {
GDExtensionScriptInstanceHasMethod has_method_func;
+ GDExtensionScriptInstanceGetMethodArgumentCount get_method_argument_count_func;
+
GDExtensionScriptInstanceCall call_func;
GDExtensionScriptInstanceNotification2 notification_func;
@@ -2510,6 +2549,7 @@ typedef GDExtensionScriptInstanceDataPtr (*GDExtensionInterfaceObjectGetScriptIn
/**
* @name callable_custom_create
* @since 4.2
+ * @deprecated in Godot 4.3. Use `callable_custom_create2` instead.
*
* Creates a custom Callable object from a function pointer.
*
@@ -2521,6 +2561,19 @@ typedef GDExtensionScriptInstanceDataPtr (*GDExtensionInterfaceObjectGetScriptIn
typedef void (*GDExtensionInterfaceCallableCustomCreate)(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo *p_callable_custom_info);
/**
+ * @name callable_custom_create2
+ * @since 4.3
+ *
+ * Creates a custom Callable object from a function pointer.
+ *
+ * Provided struct can be safely freed once the function returns.
+ *
+ * @param r_callable A pointer that will receive the new Callable.
+ * @param p_callable_custom_info The info required to construct a Callable.
+ */
+typedef void (*GDExtensionInterfaceCallableCustomCreate2)(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo2 *p_callable_custom_info);
+
+/**
* @name callable_custom_get_userdata
* @since 4.2
*
diff --git a/core/io/dir_access.h b/core/io/dir_access.h
index d175235b98..e9c864c56b 100644
--- a/core/io/dir_access.h
+++ b/core/io/dir_access.h
@@ -70,7 +70,7 @@ protected:
AccessType get_access_type() const;
virtual String fix_path(const String &p_path) const;
- template <class T>
+ template <typename T>
static Ref<DirAccess> _create_builtin() {
return memnew(T);
}
@@ -130,7 +130,7 @@ public:
static Ref<DirAccess> create(AccessType p_access);
static Error get_open_error();
- template <class T>
+ template <typename T>
static void make_default(AccessType p_access) {
create_func[p_access] = _create_builtin<T>;
}
diff --git a/core/io/file_access.h b/core/io/file_access.h
index 7d346ca2f4..122ae3b190 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -114,7 +114,7 @@ private:
AccessType _access_type = ACCESS_FILESYSTEM;
static CreateFunc create_func[ACCESS_MAX]; /** default file access creation function for a platform */
- template <class T>
+ template <typename T>
static Ref<FileAccess> _create_builtin() {
return memnew(T);
}
@@ -226,7 +226,7 @@ public:
static PackedByteArray _get_file_as_bytes(const String &p_path) { return get_file_as_bytes(p_path, &last_file_open_error); }
static String _get_file_as_string(const String &p_path) { return get_file_as_string(p_path, &last_file_open_error); }
- template <class T>
+ template <typename T>
static void make_default(AccessType p_access) {
create_func[p_access] = _create_builtin<T>;
}
diff --git a/core/io/image.cpp b/core/io/image.cpp
index b094290ac8..c454f06d67 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -679,7 +679,7 @@ static double _bicubic_interp_kernel(double x) {
return bc;
}
-template <int CC, class T>
+template <int CC, typename T>
static void _scale_cubic(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
// get source image size
int width = p_src_width;
@@ -766,7 +766,7 @@ static void _scale_cubic(const uint8_t *__restrict p_src, uint8_t *__restrict p_
}
}
-template <int CC, class T>
+template <int CC, typename T>
static void _scale_bilinear(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
enum {
FRAC_BITS = 8,
@@ -856,7 +856,7 @@ static void _scale_bilinear(const uint8_t *__restrict p_src, uint8_t *__restrict
}
}
-template <int CC, class T>
+template <int CC, typename T>
static void _scale_nearest(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
for (uint32_t i = 0; i < p_dst_height; i++) {
uint32_t src_yofs = i * p_src_height / p_dst_height;
@@ -883,7 +883,7 @@ static float _lanczos(float p_x) {
return Math::abs(p_x) >= LANCZOS_TYPE ? 0 : Math::sincn(p_x) * Math::sincn(p_x / LANCZOS_TYPE);
}
-template <int CC, class T>
+template <int CC, typename T>
static void _scale_lanczos(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
int32_t src_width = p_src_width;
int32_t src_height = p_src_height;
@@ -1665,7 +1665,7 @@ bool Image::_can_modify(Format p_format) const {
return p_format <= FORMAT_RGBE9995;
}
-template <class Component, int CC, bool renormalize,
+template <typename Component, int CC, bool renormalize,
void (*average_func)(Component &, const Component &, const Component &, const Component &, const Component &),
void (*renormalize_func)(Component *)>
static void _generate_po2_mipmap(const Component *p_src, Component *p_dst, uint32_t p_width, uint32_t p_height) {
diff --git a/core/math/bvh.h b/core/math/bvh.h
index 8fbbd8e7fd..4815466e89 100644
--- a/core/math/bvh.h
+++ b/core/math/bvh.h
@@ -57,7 +57,7 @@
#define BVHTREE_CLASS BVH_Tree<T, NUM_TREES, 2, MAX_ITEMS, USER_PAIR_TEST_FUNCTION, USER_CULL_TEST_FUNCTION, USE_PAIRS, BOUNDS, POINT>
#define BVH_LOCKED_FUNCTION BVHLockedFunction _lock_guard(&_mutex, BVH_THREAD_SAFE &&_thread_safe);
-template <class T, int NUM_TREES = 1, bool USE_PAIRS = false, int MAX_ITEMS = 32, class USER_PAIR_TEST_FUNCTION = BVH_DummyPairTestFunction<T>, class USER_CULL_TEST_FUNCTION = BVH_DummyCullTestFunction<T>, class BOUNDS = AABB, class POINT = Vector3, bool BVH_THREAD_SAFE = true>
+template <typename T, int NUM_TREES = 1, bool USE_PAIRS = false, int MAX_ITEMS = 32, typename USER_PAIR_TEST_FUNCTION = BVH_DummyPairTestFunction<T>, typename USER_CULL_TEST_FUNCTION = BVH_DummyCullTestFunction<T>, typename BOUNDS = AABB, typename POINT = Vector3, bool BVH_THREAD_SAFE = true>
class BVH_Manager {
public:
// note we are using uint32_t instead of BVHHandle, losing type safety, but this
diff --git a/core/math/bvh_abb.h b/core/math/bvh_abb.h
index fb0207e0bd..cec3dc90db 100644
--- a/core/math/bvh_abb.h
+++ b/core/math/bvh_abb.h
@@ -32,7 +32,7 @@
#define BVH_ABB_H
// special optimized version of axis aligned bounding box
-template <class BOUNDS = AABB, class POINT = Vector3>
+template <typename BOUNDS = AABB, typename POINT = Vector3>
struct BVH_ABB {
struct ConvexHull {
// convex hulls (optional)
diff --git a/core/math/bvh_tree.h b/core/math/bvh_tree.h
index ce296668db..0faa50555f 100644
--- a/core/math/bvh_tree.h
+++ b/core/math/bvh_tree.h
@@ -106,7 +106,7 @@ struct BVHHandle {
};
// helper class to make iterative versions of recursive functions
-template <class T>
+template <typename T>
class BVH_IterativeInfo {
public:
enum {
@@ -152,7 +152,7 @@ public:
}
};
-template <class T>
+template <typename T>
class BVH_DummyPairTestFunction {
public:
static bool user_collision_check(T *p_a, T *p_b) {
@@ -161,7 +161,7 @@ public:
}
};
-template <class T>
+template <typename T>
class BVH_DummyCullTestFunction {
public:
static bool user_cull_check(T *p_a, T *p_b) {
@@ -170,7 +170,7 @@ public:
}
};
-template <class T, int NUM_TREES, int MAX_CHILDREN, int MAX_ITEMS, class USER_PAIR_TEST_FUNCTION = BVH_DummyPairTestFunction<T>, class USER_CULL_TEST_FUNCTION = BVH_DummyCullTestFunction<T>, bool USE_PAIRS = false, class BOUNDS = AABB, class POINT = Vector3>
+template <typename T, int NUM_TREES, int MAX_CHILDREN, int MAX_ITEMS, typename USER_PAIR_TEST_FUNCTION = BVH_DummyPairTestFunction<T>, typename USER_CULL_TEST_FUNCTION = BVH_DummyCullTestFunction<T>, bool USE_PAIRS = false, typename BOUNDS = AABB, typename POINT = Vector3>
class BVH_Tree {
friend class BVH;
diff --git a/core/math/disjoint_set.h b/core/math/disjoint_set.h
index 2ece991fea..4348da992d 100644
--- a/core/math/disjoint_set.h
+++ b/core/math/disjoint_set.h
@@ -35,7 +35,7 @@
#include "core/templates/vector.h"
/* This DisjointSet class uses Find with path compression and Union by rank */
-template <typename T, class H = HashMapHasherDefault, class C = HashMapComparatorDefault<T>, class AL = DefaultAllocator>
+template <typename T, typename H = HashMapHasherDefault, typename C = HashMapComparatorDefault<T>, typename AL = DefaultAllocator>
class DisjointSet {
struct Element {
T object;
@@ -65,14 +65,14 @@ public:
/* FUNCTIONS */
-template <typename T, class H, class C, class AL>
+template <typename T, typename H, typename C, typename AL>
DisjointSet<T, H, C, AL>::~DisjointSet() {
for (KeyValue<T, Element *> &E : elements) {
memdelete_allocator<Element, AL>(E.value);
}
}
-template <typename T, class H, class C, class AL>
+template <typename T, typename H, typename C, typename AL>
typename DisjointSet<T, H, C, AL>::Element *DisjointSet<T, H, C, AL>::get_parent(Element *element) {
if (element->parent != element) {
element->parent = get_parent(element->parent);
@@ -81,7 +81,7 @@ typename DisjointSet<T, H, C, AL>::Element *DisjointSet<T, H, C, AL>::get_parent
return element->parent;
}
-template <typename T, class H, class C, class AL>
+template <typename T, typename H, typename C, typename AL>
typename DisjointSet<T, H, C, AL>::Element *DisjointSet<T, H, C, AL>::insert_or_get(T object) {
typename MapT::Iterator itr = elements.find(object);
if (itr != nullptr) {
@@ -96,7 +96,7 @@ typename DisjointSet<T, H, C, AL>::Element *DisjointSet<T, H, C, AL>::insert_or_
return new_element;
}
-template <typename T, class H, class C, class AL>
+template <typename T, typename H, typename C, typename AL>
void DisjointSet<T, H, C, AL>::create_union(T a, T b) {
Element *x = insert_or_get(a);
Element *y = insert_or_get(b);
@@ -121,7 +121,7 @@ void DisjointSet<T, H, C, AL>::create_union(T a, T b) {
}
}
-template <typename T, class H, class C, class AL>
+template <typename T, typename H, typename C, typename AL>
void DisjointSet<T, H, C, AL>::get_representatives(Vector<T> &out_representatives) {
for (KeyValue<T, Element *> &E : elements) {
Element *element = E.value;
@@ -131,7 +131,7 @@ void DisjointSet<T, H, C, AL>::get_representatives(Vector<T> &out_representative
}
}
-template <typename T, class H, class C, class AL>
+template <typename T, typename H, typename C, typename AL>
void DisjointSet<T, H, C, AL>::get_members(Vector<T> &out_members, T representative) {
typename MapT::Iterator rep_itr = elements.find(representative);
ERR_FAIL_NULL(rep_itr);
diff --git a/core/math/dynamic_bvh.h b/core/math/dynamic_bvh.h
index 9b49fcc3c8..f586b845c3 100644
--- a/core/math/dynamic_bvh.h
+++ b/core/math/dynamic_bvh.h
@@ -305,11 +305,11 @@ public:
virtual ~DefaultQueryResult() {}
};
- template <class QueryResult>
+ template <typename QueryResult>
_FORCE_INLINE_ void aabb_query(const AABB &p_aabb, QueryResult &r_result);
- template <class QueryResult>
+ template <typename QueryResult>
_FORCE_INLINE_ void convex_query(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, QueryResult &r_result);
- template <class QueryResult>
+ template <typename QueryResult>
_FORCE_INLINE_ void ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResult &r_result);
void set_index(uint32_t p_index);
@@ -318,7 +318,7 @@ public:
~DynamicBVH();
};
-template <class QueryResult>
+template <typename QueryResult>
void DynamicBVH::aabb_query(const AABB &p_box, QueryResult &r_result) {
if (!bvh_root) {
return;
@@ -363,7 +363,7 @@ void DynamicBVH::aabb_query(const AABB &p_box, QueryResult &r_result) {
} while (depth > 0);
}
-template <class QueryResult>
+template <typename QueryResult>
void DynamicBVH::convex_query(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, QueryResult &r_result) {
if (!bvh_root) {
return;
@@ -420,7 +420,7 @@ void DynamicBVH::convex_query(const Plane *p_planes, int p_plane_count, const Ve
}
} while (depth > 0);
}
-template <class QueryResult>
+template <typename QueryResult>
void DynamicBVH::ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResult &r_result) {
if (!bvh_root) {
return;
diff --git a/core/math/expression.h b/core/math/expression.h
index c6ad1bd634..46bc3618df 100644
--- a/core/math/expression.h
+++ b/core/math/expression.h
@@ -243,7 +243,7 @@ private:
}
};
- template <class T>
+ template <typename T>
T *alloc_node() {
T *node = memnew(T);
node->next = nodes;
diff --git a/core/math/projection.h b/core/math/projection.h
index a7adc9017e..b98f636344 100644
--- a/core/math/projection.h
+++ b/core/math/projection.h
@@ -34,7 +34,7 @@
#include "core/math/vector3.h"
#include "core/math/vector4.h"
-template <class T>
+template <typename T>
class Vector;
struct AABB;
diff --git a/core/math/random_pcg.h b/core/math/random_pcg.h
index fd0934b24a..6bad70059f 100644
--- a/core/math/random_pcg.h
+++ b/core/math/random_pcg.h
@@ -59,7 +59,7 @@ static int __bsr_clz32(uint32_t x) {
#define LDEXPF(s, e) ldexp(s, e)
#endif
-template <class T>
+template <typename T>
class Vector;
class RandomPCG {
diff --git a/core/object/callable_method_pointer.h b/core/object/callable_method_pointer.h
index f8e8c4d7e9..1b29e1778a 100644
--- a/core/object/callable_method_pointer.h
+++ b/core/object/callable_method_pointer.h
@@ -77,7 +77,7 @@ public:
virtual uint32_t hash() const;
};
-template <class T, class... P>
+template <typename T, typename... P>
class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
@@ -93,6 +93,11 @@ public:
return data.instance->get_instance_id();
}
+ virtual int get_argument_count(bool &r_is_valid) const {
+ r_is_valid = true;
+ return sizeof...(P);
+ }
+
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error);
@@ -107,7 +112,7 @@ public:
}
};
-template <class T, class... P>
+template <typename T, typename... P>
Callable create_custom_callable_function_pointer(T *p_instance,
#ifdef DEBUG_METHODS_ENABLED
const char *p_func_text,
@@ -123,7 +128,7 @@ Callable create_custom_callable_function_pointer(T *p_instance,
// VERSION WITH RETURN
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
@@ -140,6 +145,11 @@ public:
return data.instance->get_instance_id();
}
+ virtual int get_argument_count(bool &r_is_valid) const {
+ r_is_valid = true;
+ return sizeof...(P);
+ }
+
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
@@ -154,7 +164,7 @@ public:
}
};
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
Callable create_custom_callable_function_pointer(T *p_instance,
#ifdef DEBUG_METHODS_ENABLED
const char *p_func_text,
@@ -170,7 +180,7 @@ Callable create_custom_callable_function_pointer(T *p_instance,
// CONST VERSION WITH RETURN
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
@@ -187,6 +197,11 @@ public:
return data.instance->get_instance_id();
}
+ virtual int get_argument_count(bool &r_is_valid) const override {
+ r_is_valid = true;
+ return sizeof...(P);
+ }
+
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override {
ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
@@ -201,7 +216,7 @@ public:
}
};
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
Callable create_custom_callable_function_pointer(T *p_instance,
#ifdef DEBUG_METHODS_ENABLED
const char *p_func_text,
@@ -223,7 +238,7 @@ Callable create_custom_callable_function_pointer(T *p_instance,
// STATIC VERSIONS
-template <class... P>
+template <typename... P>
class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase {
struct Data {
void (*method)(P...);
@@ -238,6 +253,11 @@ public:
return ObjectID();
}
+ virtual int get_argument_count(bool &r_is_valid) const override {
+ r_is_valid = true;
+ return sizeof...(P);
+ }
+
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override {
call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
r_return_value = Variant();
@@ -250,7 +270,7 @@ public:
}
};
-template <class T, class... P>
+template <typename T, typename... P>
Callable create_custom_callable_static_function_pointer(
#ifdef DEBUG_METHODS_ENABLED
const char *p_func_text,
@@ -264,7 +284,7 @@ Callable create_custom_callable_static_function_pointer(
return Callable(ccmp);
}
-template <class R, class... P>
+template <typename R, typename... P>
class CallableCustomStaticMethodPointerRet : public CallableCustomMethodPointerBase {
struct Data {
R(*method)
@@ -280,6 +300,11 @@ public:
return ObjectID();
}
+ virtual int get_argument_count(bool &r_is_valid) const override {
+ r_is_valid = true;
+ return sizeof...(P);
+ }
+
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override {
call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
@@ -291,7 +316,7 @@ public:
}
};
-template <class R, class... P>
+template <typename R, typename... P>
Callable create_custom_callable_static_function_pointer(
#ifdef DEBUG_METHODS_ENABLED
const char *p_func_text,
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index 231a8e4d68..80a2703c2f 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -1666,6 +1666,31 @@ bool ClassDB::has_method(const StringName &p_class, const StringName &p_method,
return false;
}
+int ClassDB::get_method_argument_count(const StringName &p_class, const StringName &p_method, bool *r_is_valid, bool p_no_inheritance) {
+ OBJTYPE_RLOCK;
+
+ ClassInfo *type = classes.getptr(p_class);
+
+ while (type) {
+ MethodBind **method = type->method_map.getptr(p_method);
+ if (method && *method) {
+ if (r_is_valid) {
+ *r_is_valid = true;
+ }
+ return (*method)->get_argument_count();
+ }
+ if (p_no_inheritance) {
+ break;
+ }
+ type = type->inherits_ptr;
+ }
+
+ if (r_is_valid) {
+ *r_is_valid = false;
+ }
+ return 0;
+}
+
void ClassDB::bind_method_custom(const StringName &p_class, MethodBind *p_method) {
_bind_method_custom(p_class, p_method, false);
}
diff --git a/core/object/class_db.h b/core/object/class_db.h
index 7f117b4a9b..adb525cbe8 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -140,7 +140,7 @@ public:
~ClassInfo() {}
};
- template <class T>
+ template <typename T>
static Object *creator() {
return memnew(T);
}
@@ -187,12 +187,12 @@ private:
public:
// DO NOT USE THIS!!!!!! NEEDS TO BE PUBLIC BUT DO NOT USE NO MATTER WHAT!!!
- template <class T>
+ template <typename T>
static void _add_class() {
_add_class2(T::get_class_static(), T::get_parent_class_static());
}
- template <class T>
+ template <typename T>
static void register_class(bool p_virtual = false) {
GLOBAL_LOCK_FUNCTION;
static_assert(types_are_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
@@ -207,7 +207,7 @@ public:
T::register_custom_data_to_otdb();
}
- template <class T>
+ template <typename T>
static void register_abstract_class() {
GLOBAL_LOCK_FUNCTION;
static_assert(types_are_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
@@ -220,7 +220,7 @@ public:
//nothing
}
- template <class T>
+ template <typename T>
static void register_internal_class() {
GLOBAL_LOCK_FUNCTION;
static_assert(types_are_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
@@ -235,7 +235,7 @@ public:
T::register_custom_data_to_otdb();
}
- template <class T>
+ template <typename T>
static void register_runtime_class() {
GLOBAL_LOCK_FUNCTION;
static_assert(types_are_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
@@ -255,12 +255,12 @@ public:
static void register_extension_class(ObjectGDExtension *p_extension);
static void unregister_extension_class(const StringName &p_class, bool p_free_method_binds = true);
- template <class T>
+ template <typename T>
static Object *_create_ptr_func() {
return T::create();
}
- template <class T>
+ template <typename T>
static void register_custom_instance_class() {
GLOBAL_LOCK_FUNCTION;
static_assert(types_are_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
@@ -314,7 +314,7 @@ public:
using return_type = R;
};
- template <class N, class M, typename... VarArgs>
+ template <typename N, typename M, typename... VarArgs>
static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args) {
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
const Variant *argptrs[sizeof...(p_args) + 1];
@@ -328,7 +328,7 @@ public:
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, false, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
}
- template <class N, class M, typename... VarArgs>
+ template <typename N, typename M, typename... VarArgs>
static MethodBind *bind_static_method(const StringName &p_class, N p_method_name, M p_method, VarArgs... p_args) {
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
const Variant *argptrs[sizeof...(p_args) + 1];
@@ -343,7 +343,7 @@ public:
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, false, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
}
- template <class N, class M, typename... VarArgs>
+ template <typename N, typename M, typename... VarArgs>
static MethodBind *bind_compatibility_method(N p_method_name, M p_method, VarArgs... p_args) {
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
const Variant *argptrs[sizeof...(p_args) + 1];
@@ -357,7 +357,7 @@ public:
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, true, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
}
- template <class N, class M, typename... VarArgs>
+ template <typename N, typename M, typename... VarArgs>
static MethodBind *bind_compatibility_static_method(const StringName &p_class, N p_method_name, M p_method, VarArgs... p_args) {
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
const Variant *argptrs[sizeof...(p_args) + 1];
@@ -372,7 +372,7 @@ public:
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, true, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
}
- template <class M>
+ template <typename M>
static MethodBind *bind_vararg_method(uint32_t p_flags, const StringName &p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const Vector<Variant> &p_default_args = Vector<Variant>(), bool p_return_nil_is_variant = true) {
GLOBAL_LOCK_FUNCTION;
@@ -385,7 +385,7 @@ public:
return _bind_vararg_method(bind, p_name, p_default_args, false);
}
- template <class M>
+ template <typename M>
static MethodBind *bind_compatibility_vararg_method(uint32_t p_flags, const StringName &p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const Vector<Variant> &p_default_args = Vector<Variant>(), bool p_return_nil_is_variant = true) {
GLOBAL_LOCK_FUNCTION;
@@ -430,6 +430,7 @@ public:
static void get_method_list(const StringName &p_class, List<MethodInfo> *p_methods, bool p_no_inheritance = false, bool p_exclude_from_properties = false);
static void get_method_list_with_compatibility(const StringName &p_class, List<Pair<MethodInfo, uint32_t>> *p_methods_with_hash, bool p_no_inheritance = false, bool p_exclude_from_properties = false);
static bool get_method_info(const StringName &p_class, const StringName &p_method, MethodInfo *r_info, bool p_no_inheritance = false, bool p_exclude_from_properties = false);
+ static int get_method_argument_count(const StringName &p_class, const StringName &p_method, bool *r_is_valid = nullptr, bool p_no_inheritance = false);
static MethodBind *get_method(const StringName &p_class, const StringName &p_name);
static MethodBind *get_method_with_compatibility(const StringName &p_class, const StringName &p_name, uint64_t p_hash, bool *r_method_exists = nullptr, bool *r_is_deprecated = nullptr);
static Vector<uint32_t> get_method_compatibility_hashes(const StringName &p_class, const StringName &p_name);
@@ -497,13 +498,13 @@ _FORCE_INLINE_ void errarray_add_str(Vector<Error> &arr, const Error &p_err) {
arr.push_back(p_err);
}
-template <class... P>
+template <typename... P>
_FORCE_INLINE_ void errarray_add_str(Vector<Error> &arr, const Error &p_err, P... p_args) {
arr.push_back(p_err);
errarray_add_str(arr, p_args...);
}
-template <class... P>
+template <typename... P>
_FORCE_INLINE_ Vector<Error> errarray(P... p_args) {
Vector<Error> arr;
errarray_add_str(arr, p_args...);
diff --git a/core/object/method_bind.h b/core/object/method_bind.h
index 88b867a1ca..e97f4abc6a 100644
--- a/core/object/method_bind.h
+++ b/core/object/method_bind.h
@@ -140,7 +140,7 @@ public:
};
// MethodBindVarArg base CRTP
-template <class Derived, class T, class R, bool should_returns>
+template <typename Derived, typename T, typename R, bool should_returns>
class MethodBindVarArgBase : public MethodBind {
protected:
R(T::*method)
@@ -219,7 +219,7 @@ private:
};
// variadic, no return
-template <class T>
+template <typename T>
class MethodBindVarArgT : public MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false> {
friend class MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>;
@@ -245,7 +245,7 @@ private:
}
};
-template <class T>
+template <typename T>
MethodBind *create_vararg_method_bind(void (T::*p_method)(const Variant **, int, Callable::CallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
MethodBind *a = memnew((MethodBindVarArgT<T>)(p_method, p_info, p_return_nil_is_variant));
a->set_instance_class(T::get_class_static());
@@ -253,7 +253,7 @@ MethodBind *create_vararg_method_bind(void (T::*p_method)(const Variant **, int,
}
// variadic, return
-template <class T, class R>
+template <typename T, typename R>
class MethodBindVarArgTR : public MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true> {
friend class MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>;
@@ -287,7 +287,7 @@ private:
}
};
-template <class T, class R>
+template <typename T, typename R>
MethodBind *create_vararg_method_bind(R (T::*p_method)(const Variant **, int, Callable::CallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
MethodBind *a = memnew((MethodBindVarArgTR<T, R>)(p_method, p_info, p_return_nil_is_variant));
a->set_instance_class(T::get_class_static());
@@ -305,9 +305,9 @@ class __UnexistingClass;
// no return, not const
#ifdef TYPED_METHOD_BIND
-template <class T, class... P>
+template <typename T, typename... P>
#else
-template <class... P>
+template <typename... P>
#endif
class MethodBindT : public MethodBind {
void (MB_T::*method)(P...);
@@ -375,7 +375,7 @@ public:
}
};
-template <class T, class... P>
+template <typename T, typename... P>
MethodBind *create_method_bind(void (T::*p_method)(P...)) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindT<T, P...>)(p_method));
@@ -389,9 +389,9 @@ MethodBind *create_method_bind(void (T::*p_method)(P...)) {
// no return, const
#ifdef TYPED_METHOD_BIND
-template <class T, class... P>
+template <typename T, typename... P>
#else
-template <class... P>
+template <typename... P>
#endif
class MethodBindTC : public MethodBind {
void (MB_T::*method)(P...) const;
@@ -460,7 +460,7 @@ public:
}
};
-template <class T, class... P>
+template <typename T, typename... P>
MethodBind *create_method_bind(void (T::*p_method)(P...) const) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindTC<T, P...>)(p_method));
@@ -474,9 +474,9 @@ MethodBind *create_method_bind(void (T::*p_method)(P...) const) {
// return, not const
#ifdef TYPED_METHOD_BIND
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
#else
-template <class R, class... P>
+template <typename R, typename... P>
#endif
class MethodBindTR : public MethodBind {
R(MB_T::*method)
@@ -555,7 +555,7 @@ public:
}
};
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
MethodBind *create_method_bind(R (T::*p_method)(P...)) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindTR<T, R, P...>)(p_method));
@@ -570,9 +570,9 @@ MethodBind *create_method_bind(R (T::*p_method)(P...)) {
// return, const
#ifdef TYPED_METHOD_BIND
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
#else
-template <class R, class... P>
+template <typename R, typename... P>
#endif
class MethodBindTRC : public MethodBind {
R(MB_T::*method)
@@ -652,7 +652,7 @@ public:
}
};
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
MethodBind *create_method_bind(R (T::*p_method)(P...) const) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindTRC<T, R, P...>)(p_method));
@@ -667,7 +667,7 @@ MethodBind *create_method_bind(R (T::*p_method)(P...) const) {
// no return
-template <class... P>
+template <typename... P>
class MethodBindTS : public MethodBind {
void (*function)(P...);
@@ -717,7 +717,7 @@ public:
}
};
-template <class... P>
+template <typename... P>
MethodBind *create_static_method_bind(void (*p_method)(P...)) {
MethodBind *a = memnew((MethodBindTS<P...>)(p_method));
return a;
@@ -725,7 +725,7 @@ MethodBind *create_static_method_bind(void (*p_method)(P...)) {
// return
-template <class R, class... P>
+template <typename R, typename... P>
class MethodBindTRS : public MethodBind {
R(*function)
(P...);
@@ -784,7 +784,7 @@ public:
}
};
-template <class R, class... P>
+template <typename R, typename... P>
MethodBind *create_static_method_bind(R (*p_method)(P...)) {
MethodBind *a = memnew((MethodBindTRS<R, P...>)(p_method));
return a;
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 6a5a9efefa..e5d771844b 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -688,6 +688,59 @@ bool Object::has_method(const StringName &p_method) const {
return false;
}
+int Object::_get_method_argument_count_bind(const StringName &p_method) const {
+ return get_method_argument_count(p_method);
+}
+
+int Object::get_method_argument_count(const StringName &p_method, bool *r_is_valid) const {
+ if (p_method == CoreStringNames::get_singleton()->_free) {
+ if (r_is_valid) {
+ *r_is_valid = true;
+ }
+ return 0;
+ }
+
+ if (script_instance) {
+ bool valid = false;
+ int ret = script_instance->get_method_argument_count(p_method, &valid);
+ if (valid) {
+ if (r_is_valid) {
+ *r_is_valid = true;
+ }
+ return ret;
+ }
+ }
+
+ {
+ bool valid = false;
+ int ret = ClassDB::get_method_argument_count(get_class_name(), p_method, &valid);
+ if (valid) {
+ if (r_is_valid) {
+ *r_is_valid = true;
+ }
+ return ret;
+ }
+ }
+
+ const Script *scr = Object::cast_to<Script>(this);
+ while (scr != nullptr) {
+ bool valid = false;
+ int ret = scr->get_script_method_argument_count(p_method, &valid);
+ if (valid) {
+ if (r_is_valid) {
+ *r_is_valid = true;
+ }
+ return ret;
+ }
+ scr = scr->get_base_script().ptr();
+ }
+
+ if (r_is_valid) {
+ *r_is_valid = false;
+ }
+ return 0;
+}
+
Variant Object::getvar(const Variant &p_key, bool *r_valid) const {
if (r_valid) {
*r_valid = false;
@@ -1644,6 +1697,8 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_method", "method"), &Object::has_method);
+ ClassDB::bind_method(D_METHOD("get_method_argument_count", "method"), &Object::_get_method_argument_count_bind);
+
ClassDB::bind_method(D_METHOD("has_signal", "signal"), &Object::has_signal);
ClassDB::bind_method(D_METHOD("get_signal_list"), &Object::_get_signal_list);
ClassDB::bind_method(D_METHOD("get_signal_connection_list", "signal"), &Object::_get_signal_connection_list);
diff --git a/core/object/object.h b/core/object/object.h
index cb1495296d..d9551ecd01 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -654,6 +654,7 @@ private:
Variant _get_bind(const StringName &p_name) const;
void _set_indexed_bind(const NodePath &p_name, const Variant &p_value);
Variant _get_indexed_bind(const NodePath &p_name) const;
+ int _get_method_argument_count_bind(const StringName &p_name) const;
_FORCE_INLINE_ void _construct_object(bool p_reference);
@@ -796,12 +797,12 @@ public:
void detach_from_objectdb();
_FORCE_INLINE_ ObjectID get_instance_id() const { return _instance_id; }
- template <class T>
+ template <typename T>
static T *cast_to(Object *p_object) {
return p_object ? dynamic_cast<T *>(p_object) : nullptr;
}
- template <class T>
+ template <typename T>
static const T *cast_to(const Object *p_object) {
return p_object ? dynamic_cast<const T *>(p_object) : nullptr;
}
@@ -865,6 +866,7 @@ public:
Variant property_get_revert(const StringName &p_name) const;
bool has_method(const StringName &p_method) const;
+ int get_method_argument_count(const StringName &p_method, bool *r_is_valid = nullptr) const;
void get_method_list(List<MethodInfo> *p_list) const;
Variant callv(const StringName &p_method, const Array &p_args);
virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h
index 10be27b879..5b358135c4 100644
--- a/core/object/ref_counted.h
+++ b/core/object/ref_counted.h
@@ -53,7 +53,7 @@ public:
~RefCounted() {}
};
-template <class T>
+template <typename T>
class Ref {
T *reference = nullptr;
@@ -117,7 +117,7 @@ public:
ref(p_from);
}
- template <class T_Other>
+ template <typename T_Other>
void operator=(const Ref<T_Other> &p_from) {
RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
if (!refb) {
@@ -149,7 +149,7 @@ public:
}
}
- template <class T_Other>
+ template <typename T_Other>
void reference_ptr(T_Other *p_ptr) {
if (reference == p_ptr) {
return;
@@ -166,7 +166,7 @@ public:
ref(p_from);
}
- template <class T_Other>
+ template <typename T_Other>
Ref(const Ref<T_Other> &p_from) {
RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
if (!refb) {
@@ -240,7 +240,7 @@ public:
WeakRef() {}
};
-template <class T>
+template <typename T>
struct PtrToArg<Ref<T>> {
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
if (p_ptr == nullptr) {
@@ -258,7 +258,7 @@ struct PtrToArg<Ref<T>> {
}
};
-template <class T>
+template <typename T>
struct PtrToArg<const Ref<T> &> {
typedef Ref<T> EncodeT;
@@ -271,7 +271,7 @@ struct PtrToArg<const Ref<T> &> {
}
};
-template <class T>
+template <typename T>
struct GetTypeInfo<Ref<T>> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
@@ -281,7 +281,7 @@ struct GetTypeInfo<Ref<T>> {
}
};
-template <class T>
+template <typename T>
struct GetTypeInfo<const Ref<T> &> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
@@ -291,13 +291,13 @@ struct GetTypeInfo<const Ref<T> &> {
}
};
-template <class T>
+template <typename T>
struct VariantInternalAccessor<Ref<T>> {
static _FORCE_INLINE_ Ref<T> get(const Variant *v) { return Ref<T>(*VariantInternal::get_object(v)); }
static _FORCE_INLINE_ void set(Variant *v, const Ref<T> &p_ref) { VariantInternal::refcounted_object_assign(v, p_ref.ptr()); }
};
-template <class T>
+template <typename T>
struct VariantInternalAccessor<const Ref<T> &> {
static _FORCE_INLINE_ Ref<T> get(const Variant *v) { return Ref<T>(*VariantInternal::get_object(v)); }
static _FORCE_INLINE_ void set(Variant *v, const Ref<T> &p_ref) { VariantInternal::refcounted_object_assign(v, p_ref.ptr()); }
diff --git a/core/object/script_instance.cpp b/core/object/script_instance.cpp
index 303b127db1..65f44e8a6b 100644
--- a/core/object/script_instance.cpp
+++ b/core/object/script_instance.cpp
@@ -32,6 +32,28 @@
#include "core/object/script_language.h"
+int ScriptInstance::get_method_argument_count(const StringName &p_method, bool *r_is_valid) const {
+ // Default implementation simply traverses hierarchy.
+ Ref<Script> script = get_script();
+ while (script.is_valid()) {
+ bool valid = false;
+ int ret = script->get_script_method_argument_count(p_method, &valid);
+ if (valid) {
+ if (r_is_valid) {
+ *r_is_valid = true;
+ }
+ return ret;
+ }
+
+ script = script->get_base_script();
+ }
+
+ if (r_is_valid) {
+ *r_is_valid = false;
+ }
+ return 0;
+}
+
Variant ScriptInstance::call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
return callp(p_method, p_args, p_argcount, r_error);
}
diff --git a/core/object/script_instance.h b/core/object/script_instance.h
index 45d51534fc..2c8132ec1f 100644
--- a/core/object/script_instance.h
+++ b/core/object/script_instance.h
@@ -53,6 +53,8 @@ public:
virtual void get_method_list(List<MethodInfo> *p_list) const = 0;
virtual bool has_method(const StringName &p_method) const = 0;
+ virtual int get_method_argument_count(const StringName &p_method, bool *r_is_valid = nullptr) const;
+
virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = 0;
template <typename... VarArgs>
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index 14894e1710..1196c2f787 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -102,6 +102,22 @@ Dictionary Script::_get_script_constant_map() {
return ret;
}
+int Script::get_script_method_argument_count(const StringName &p_method, bool *r_is_valid) const {
+ MethodInfo mi = get_method_info(p_method);
+
+ if (mi == MethodInfo()) {
+ if (r_is_valid) {
+ *r_is_valid = false;
+ }
+ return 0;
+ }
+
+ if (r_is_valid) {
+ *r_is_valid = true;
+ }
+ return mi.arguments.size();
+}
+
#ifdef TOOLS_ENABLED
PropertyInfo Script::get_class_category() const {
diff --git a/core/object/script_language.h b/core/object/script_language.h
index 95e9d2b4af..be50e58d79 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -151,6 +151,8 @@ public:
virtual bool has_method(const StringName &p_method) const = 0;
virtual bool has_static_method(const StringName &p_method) const { return false; }
+ virtual int get_script_method_argument_count(const StringName &p_method, bool *r_is_valid = nullptr) const;
+
virtual MethodInfo get_method_info(const StringName &p_method) const = 0;
virtual bool is_tool() const = 0;
@@ -442,6 +444,13 @@ public:
virtual void get_method_list(List<MethodInfo> *p_list) const override;
virtual bool has_method(const StringName &p_method) const override;
+ virtual int get_method_argument_count(const StringName &p_method, bool *r_is_valid = nullptr) const override {
+ if (r_is_valid) {
+ *r_is_valid = false;
+ }
+ return 0;
+ }
+
virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
return Variant();
diff --git a/core/object/script_language_extension.cpp b/core/object/script_language_extension.cpp
index ec99c7cf4e..a18ef8d4d7 100644
--- a/core/object/script_language_extension.cpp
+++ b/core/object/script_language_extension.cpp
@@ -56,6 +56,9 @@ void ScriptExtension::_bind_methods() {
GDVIRTUAL_BIND(_has_method, "method");
GDVIRTUAL_BIND(_has_static_method, "method");
+
+ GDVIRTUAL_BIND(_get_script_method_argument_count, "method");
+
GDVIRTUAL_BIND(_get_method_info, "method");
GDVIRTUAL_BIND(_is_tool);
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
index 18105ec8cd..1db322526d 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -101,6 +101,19 @@ public:
EXBIND1RC(bool, has_method, const StringName &)
EXBIND1RC(bool, has_static_method, const StringName &)
+ GDVIRTUAL1RC(Variant, _get_script_method_argument_count, const StringName &)
+ virtual int get_script_method_argument_count(const StringName &p_method, bool *r_is_valid = nullptr) const override {
+ Variant ret;
+ if (GDVIRTUAL_CALL(_get_script_method_argument_count, p_method, ret) && ret.get_type() == Variant::INT) {
+ if (r_is_valid) {
+ *r_is_valid = true;
+ }
+ return ret.operator int();
+ }
+ // Fallback to default.
+ return Script::get_script_method_argument_count(p_method, r_is_valid);
+ }
+
GDVIRTUAL1RC(Dictionary, _get_method_info, const StringName &)
virtual MethodInfo get_method_info(const StringName &p_method) const override {
Dictionary mi;
@@ -807,6 +820,19 @@ public:
return false;
}
+ virtual int get_method_argument_count(const StringName &p_method, bool *r_is_valid = nullptr) const override {
+ if (native_info->get_method_argument_count_func) {
+ GDExtensionBool is_valid = 0;
+ GDExtensionInt ret = native_info->get_method_argument_count_func(instance, (GDExtensionStringNamePtr)&p_method, &is_valid);
+ if (r_is_valid) {
+ *r_is_valid = is_valid != 0;
+ }
+ return ret;
+ }
+ // Fallback to default.
+ return ScriptInstance::get_method_argument_count(p_method, r_is_valid);
+ }
+
virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override {
Variant ret;
if (native_info->call_func) {
@@ -894,7 +920,6 @@ public:
return reinterpret_cast<ScriptLanguage *>(lang);
}
return nullptr;
- ;
}
virtual ~ScriptInstanceExtension() {
if (native_info->free_func) {
diff --git a/core/object/worker_thread_pool.h b/core/object/worker_thread_pool.h
index c9921c808d..fdddc9a647 100644
--- a/core/object/worker_thread_pool.h
+++ b/core/object/worker_thread_pool.h
@@ -157,7 +157,7 @@ private:
TaskID _add_task(const Callable &p_callable, void (*p_func)(void *), void *p_userdata, BaseTemplateUserdata *p_template_userdata, bool p_high_priority, const String &p_description);
GroupID _add_group_task(const Callable &p_callable, void (*p_func)(void *, uint32_t), void *p_userdata, BaseTemplateUserdata *p_template_userdata, int p_elements, int p_tasks, bool p_high_priority, const String &p_description);
- template <class C, class M, class U>
+ template <typename C, typename M, typename U>
struct TaskUserData : public BaseTemplateUserdata {
C *instance;
M method;
@@ -167,7 +167,7 @@ private:
}
};
- template <class C, class M, class U>
+ template <typename C, typename M, typename U>
struct GroupUserData : public BaseTemplateUserdata {
C *instance;
M method;
@@ -181,7 +181,7 @@ protected:
static void _bind_methods();
public:
- template <class C, class M, class U>
+ template <typename C, typename M, typename U>
TaskID add_template_task(C *p_instance, M p_method, U p_userdata, bool p_high_priority = false, const String &p_description = String()) {
typedef TaskUserData<C, M, U> TUD;
TUD *ud = memnew(TUD);
@@ -196,7 +196,7 @@ public:
bool is_task_completed(TaskID p_task_id) const;
Error wait_for_task_completion(TaskID p_task_id);
- template <class C, class M, class U>
+ template <typename C, typename M, typename U>
GroupID add_template_group_task(C *p_instance, M p_method, U p_userdata, int p_elements, int p_tasks = -1, bool p_high_priority = false, const String &p_description = String()) {
typedef GroupUserData<C, M, U> GroupUD;
GroupUD *ud = memnew(GroupUD);
diff --git a/core/os/condition_variable.h b/core/os/condition_variable.h
index 2b6b272e18..fa1355e98c 100644
--- a/core/os/condition_variable.h
+++ b/core/os/condition_variable.h
@@ -54,7 +54,7 @@ class ConditionVariable {
mutable THREADING_NAMESPACE::condition_variable condition;
public:
- template <class BinaryMutexT>
+ template <typename BinaryMutexT>
_ALWAYS_INLINE_ void wait(const MutexLock<BinaryMutexT> &p_lock) const {
condition.wait(const_cast<THREADING_NAMESPACE::unique_lock<THREADING_NAMESPACE::mutex> &>(p_lock.lock));
}
@@ -72,7 +72,7 @@ public:
class ConditionVariable {
public:
- template <class BinaryMutexT>
+ template <typename BinaryMutexT>
void wait(const MutexLock<BinaryMutexT> &p_lock) const {}
void notify_one() const {}
void notify_all() const {}
diff --git a/core/os/memory.h b/core/os/memory.h
index 6f3f6fed39..d03e08d785 100644
--- a/core/os/memory.h
+++ b/core/os/memory.h
@@ -92,7 +92,7 @@ void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_d
_ALWAYS_INLINE_ void postinitialize_handler(void *) {}
-template <class T>
+template <typename T>
_ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
postinitialize_handler(p_obj);
return p_obj;
@@ -107,7 +107,7 @@ _ALWAYS_INLINE_ bool predelete_handler(void *) {
return true;
}
-template <class T>
+template <typename T>
void memdelete(T *p_class) {
if (!predelete_handler(p_class)) {
return; // doesn't want to be deleted
@@ -119,7 +119,7 @@ void memdelete(T *p_class) {
Memory::free_static(p_class, false);
}
-template <class T, class A>
+template <typename T, typename A>
void memdelete_allocator(T *p_class) {
if (!predelete_handler(p_class)) {
return; // doesn't want to be deleted
@@ -213,10 +213,10 @@ struct _GlobalNilClass {
static _GlobalNil _nil;
};
-template <class T>
+template <typename T>
class DefaultTypedAllocator {
public:
- template <class... Args>
+ template <typename... Args>
_FORCE_INLINE_ T *new_allocation(const Args &&...p_args) { return memnew(T(p_args...)); }
_FORCE_INLINE_ void delete_allocation(T *p_allocation) { memdelete(p_allocation); }
};
diff --git a/core/os/mutex.h b/core/os/mutex.h
index a4eab0cd86..3e7aa81bc1 100644
--- a/core/os/mutex.h
+++ b/core/os/mutex.h
@@ -45,10 +45,10 @@
#ifdef THREADS_ENABLED
-template <class MutexT>
+template <typename MutexT>
class MutexLock;
-template <class StdMutexT>
+template <typename StdMutexT>
class MutexImpl {
friend class MutexLock<MutexImpl<StdMutexT>>;
@@ -70,7 +70,7 @@ public:
}
};
-template <class MutexT>
+template <typename MutexT>
class MutexLock {
friend class ConditionVariable;
@@ -100,7 +100,7 @@ public:
bool try_lock() const { return true; }
};
-template <class MutexT>
+template <typename MutexT>
class MutexLock {
public:
MutexLock(const MutexT &p_mutex) {}
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 1d27933016..a7e12138f2 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -2459,7 +2459,7 @@ bool String::is_numeric() const {
return true; // TODO: Use the parser below for this instead
}
-template <class C>
+template <typename C>
static double built_in_strtod(
/* A decimal ASCII floating-point number,
* optionally preceded by white space. Must
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 468a015302..0fb72fccd2 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -43,7 +43,7 @@
/* CharProxy */
/*************************************************************************/
-template <class T>
+template <typename T>
class CharProxy {
friend class Char16String;
friend class CharString;
@@ -602,13 +602,13 @@ _FORCE_INLINE_ void sarray_add_str(Vector<String> &arr, const String &p_str) {
arr.push_back(p_str);
}
-template <class... P>
+template <typename... P>
_FORCE_INLINE_ void sarray_add_str(Vector<String> &arr, const String &p_str, P... p_args) {
arr.push_back(p_str);
sarray_add_str(arr, p_args...);
}
-template <class... P>
+template <typename... P>
_FORCE_INLINE_ Vector<String> sarray(P... p_args) {
Vector<String> arr;
sarray_add_str(arr, p_args...);
diff --git a/core/templates/bin_sorted_array.h b/core/templates/bin_sorted_array.h
index 500d1f1377..30c1fefbbd 100644
--- a/core/templates/bin_sorted_array.h
+++ b/core/templates/bin_sorted_array.h
@@ -34,7 +34,7 @@
#include "core/templates/local_vector.h"
#include "core/templates/paged_array.h"
-template <class T>
+template <typename T>
class BinSortedArray {
PagedArray<T> array;
LocalVector<uint64_t> bin_limits;
diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h
index b1010f7f43..4056119851 100644
--- a/core/templates/command_queue_mt.h
+++ b/core/templates/command_queue_mt.h
@@ -207,41 +207,41 @@
#define ARG(N) p##N
#define PARAM(N) P##N p##N
-#define TYPE_PARAM(N) class P##N
+#define TYPE_PARAM(N) typename P##N
#define PARAM_DECL(N) typename GetSimpleTypeT<P##N>::type_t p##N
-#define DECL_CMD(N) \
- template <class T, class M COMMA(N) COMMA_SEP_LIST(TYPE_PARAM, N)> \
- struct Command##N : public CommandBase { \
- T *instance; \
- M method; \
- SEMIC_SEP_LIST(PARAM_DECL, N); \
- virtual void call() override { \
- (instance->*method)(COMMA_SEP_LIST(ARG, N)); \
- } \
+#define DECL_CMD(N) \
+ template <typename T, typename M COMMA(N) COMMA_SEP_LIST(TYPE_PARAM, N)> \
+ struct Command##N : public CommandBase { \
+ T *instance; \
+ M method; \
+ SEMIC_SEP_LIST(PARAM_DECL, N); \
+ virtual void call() override { \
+ (instance->*method)(COMMA_SEP_LIST(ARG, N)); \
+ } \
};
-#define DECL_CMD_RET(N) \
- template <class T, class M, COMMA_SEP_LIST(TYPE_PARAM, N) COMMA(N) class R> \
- struct CommandRet##N : public SyncCommand { \
- R *ret; \
- T *instance; \
- M method; \
- SEMIC_SEP_LIST(PARAM_DECL, N); \
- virtual void call() override { \
- *ret = (instance->*method)(COMMA_SEP_LIST(ARG, N)); \
- } \
+#define DECL_CMD_RET(N) \
+ template <typename T, typename M, COMMA_SEP_LIST(TYPE_PARAM, N) COMMA(N) typename R> \
+ struct CommandRet##N : public SyncCommand { \
+ R *ret; \
+ T *instance; \
+ M method; \
+ SEMIC_SEP_LIST(PARAM_DECL, N); \
+ virtual void call() override { \
+ *ret = (instance->*method)(COMMA_SEP_LIST(ARG, N)); \
+ } \
};
-#define DECL_CMD_SYNC(N) \
- template <class T, class M COMMA(N) COMMA_SEP_LIST(TYPE_PARAM, N)> \
- struct CommandSync##N : public SyncCommand { \
- T *instance; \
- M method; \
- SEMIC_SEP_LIST(PARAM_DECL, N); \
- virtual void call() override { \
- (instance->*method)(COMMA_SEP_LIST(ARG, N)); \
- } \
+#define DECL_CMD_SYNC(N) \
+ template <typename T, typename M COMMA(N) COMMA_SEP_LIST(TYPE_PARAM, N)> \
+ struct CommandSync##N : public SyncCommand { \
+ T *instance; \
+ M method; \
+ SEMIC_SEP_LIST(PARAM_DECL, N); \
+ virtual void call() override { \
+ (instance->*method)(COMMA_SEP_LIST(ARG, N)); \
+ } \
};
#define TYPE_ARG(N) P##N
@@ -249,7 +249,7 @@
#define CMD_ASSIGN_PARAM(N) cmd->p##N = p##N
#define DECL_PUSH(N) \
- template <class T, class M COMMA(N) COMMA_SEP_LIST(TYPE_PARAM, N)> \
+ template <typename T, typename M COMMA(N) COMMA_SEP_LIST(TYPE_PARAM, N)> \
void push(T *p_instance, M p_method COMMA(N) COMMA_SEP_LIST(PARAM, N)) { \
CMD_TYPE(N) *cmd = allocate_and_lock<CMD_TYPE(N)>(); \
cmd->instance = p_instance; \
@@ -263,7 +263,7 @@
#define CMD_RET_TYPE(N) CommandRet##N<T, M, COMMA_SEP_LIST(TYPE_ARG, N) COMMA(N) R>
#define DECL_PUSH_AND_RET(N) \
- template <class T, class M, COMMA_SEP_LIST(TYPE_PARAM, N) COMMA(N) class R> \
+ template <typename T, typename M, COMMA_SEP_LIST(TYPE_PARAM, N) COMMA(N) typename R> \
void push_and_ret(T *p_instance, M p_method, COMMA_SEP_LIST(PARAM, N) COMMA(N) R *r_ret) { \
SyncSemaphore *ss = _alloc_sync_sem(); \
CMD_RET_TYPE(N) *cmd = allocate_and_lock<CMD_RET_TYPE(N)>(); \
@@ -282,7 +282,7 @@
#define CMD_SYNC_TYPE(N) CommandSync##N<T, M COMMA(N) COMMA_SEP_LIST(TYPE_ARG, N)>
#define DECL_PUSH_AND_SYNC(N) \
- template <class T, class M COMMA(N) COMMA_SEP_LIST(TYPE_PARAM, N)> \
+ template <typename T, typename M COMMA(N) COMMA_SEP_LIST(TYPE_PARAM, N)> \
void push_and_sync(T *p_instance, M p_method COMMA(N) COMMA_SEP_LIST(PARAM, N)) { \
SyncSemaphore *ss = _alloc_sync_sem(); \
CMD_SYNC_TYPE(N) *cmd = allocate_and_lock<CMD_SYNC_TYPE(N)>(); \
@@ -343,7 +343,7 @@ class CommandQueueMT {
Semaphore *sync = nullptr;
uint64_t flush_read_ptr = 0;
- template <class T>
+ template <typename T>
T *allocate() {
// alloc size is size+T+safeguard
uint32_t alloc_size = ((sizeof(T) + 8 - 1) & ~(8 - 1));
@@ -354,7 +354,7 @@ class CommandQueueMT {
return cmd;
}
- template <class T>
+ template <typename T>
T *allocate_and_lock() {
lock();
T *ret = allocate<T>();
diff --git a/core/templates/cowdata.h b/core/templates/cowdata.h
index 466658951e..f22ae1f1d3 100644
--- a/core/templates/cowdata.h
+++ b/core/templates/cowdata.h
@@ -38,12 +38,12 @@
#include <string.h>
#include <type_traits>
-template <class T>
+template <typename T>
class Vector;
class String;
class Char16String;
class CharString;
-template <class T, class V>
+template <typename T, typename V>
class VMap;
static_assert(std::is_trivially_destructible_v<std::atomic<uint64_t>>);
@@ -54,14 +54,14 @@ static_assert(std::is_trivially_destructible_v<std::atomic<uint64_t>>);
#pragma GCC diagnostic ignored "-Wplacement-new"
#endif
-template <class T>
+template <typename T>
class CowData {
- template <class TV>
+ template <typename TV>
friend class Vector;
friend class String;
friend class Char16String;
friend class CharString;
- template <class TV, class VV>
+ template <typename TV, typename VV>
friend class VMap;
public:
@@ -241,7 +241,7 @@ public:
_FORCE_INLINE_ CowData(CowData<T> &p_from) { _ref(p_from); };
};
-template <class T>
+template <typename T>
void CowData<T>::_unref(void *p_data) {
if (!p_data) {
return;
@@ -268,7 +268,7 @@ void CowData<T>::_unref(void *p_data) {
Memory::free_static(((uint8_t *)p_data) - DATA_OFFSET, false);
}
-template <class T>
+template <typename T>
typename CowData<T>::USize CowData<T>::_copy_on_write() {
if (!_ptr) {
return 0;
@@ -308,7 +308,7 @@ typename CowData<T>::USize CowData<T>::_copy_on_write() {
return rc;
}
-template <class T>
+template <typename T>
template <bool p_ensure_zero>
Error CowData<T>::resize(Size p_size) {
ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER);
@@ -401,7 +401,7 @@ Error CowData<T>::resize(Size p_size) {
return OK;
}
-template <class T>
+template <typename T>
typename CowData<T>::Size CowData<T>::find(const T &p_val, Size p_from) const {
Size ret = -1;
@@ -419,7 +419,7 @@ typename CowData<T>::Size CowData<T>::find(const T &p_val, Size p_from) const {
return ret;
}
-template <class T>
+template <typename T>
typename CowData<T>::Size CowData<T>::rfind(const T &p_val, Size p_from) const {
const Size s = size();
@@ -438,7 +438,7 @@ typename CowData<T>::Size CowData<T>::rfind(const T &p_val, Size p_from) const {
return -1;
}
-template <class T>
+template <typename T>
typename CowData<T>::Size CowData<T>::count(const T &p_val) const {
Size amount = 0;
for (Size i = 0; i < size(); i++) {
@@ -449,12 +449,12 @@ typename CowData<T>::Size CowData<T>::count(const T &p_val) const {
return amount;
}
-template <class T>
+template <typename T>
void CowData<T>::_ref(const CowData *p_from) {
_ref(*p_from);
}
-template <class T>
+template <typename T>
void CowData<T>::_ref(const CowData &p_from) {
if (_ptr == p_from._ptr) {
return; // self assign, do nothing.
@@ -472,7 +472,7 @@ void CowData<T>::_ref(const CowData &p_from) {
}
}
-template <class T>
+template <typename T>
CowData<T>::~CowData() {
_unref(_ptr);
}
diff --git a/core/templates/hash_map.h b/core/templates/hash_map.h
index e1745110d7..a3e8c2c788 100644
--- a/core/templates/hash_map.h
+++ b/core/templates/hash_map.h
@@ -51,7 +51,7 @@
* The assignment operator copy the pairs from one map to the other.
*/
-template <class TKey, class TValue>
+template <typename TKey, typename TValue>
struct HashMapElement {
HashMapElement *next = nullptr;
HashMapElement *prev = nullptr;
@@ -61,10 +61,10 @@ struct HashMapElement {
data(p_key, p_value) {}
};
-template <class TKey, class TValue,
- class Hasher = HashMapHasherDefault,
- class Comparator = HashMapComparatorDefault<TKey>,
- class Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
+template <typename TKey, typename TValue,
+ typename Hasher = HashMapHasherDefault,
+ typename Comparator = HashMapComparatorDefault<TKey>,
+ typename Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
class HashMap {
public:
static constexpr uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.
diff --git a/core/templates/hash_set.h b/core/templates/hash_set.h
index 00f4acbc9c..295b07e5e7 100644
--- a/core/templates/hash_set.h
+++ b/core/templates/hash_set.h
@@ -46,9 +46,9 @@
*
*/
-template <class TKey,
- class Hasher = HashMapHasherDefault,
- class Comparator = HashMapComparatorDefault<TKey>>
+template <typename TKey,
+ typename Hasher = HashMapHasherDefault,
+ typename Comparator = HashMapComparatorDefault<TKey>>
class HashSet {
public:
static constexpr uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.
diff --git a/core/templates/hashfuncs.h b/core/templates/hashfuncs.h
index a16f655524..fc7a78bcf5 100644
--- a/core/templates/hashfuncs.h
+++ b/core/templates/hashfuncs.h
@@ -248,7 +248,7 @@ static _FORCE_INLINE_ uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev
return ((p_prev << 5) + p_prev) + hash_one_uint64(u.i);
}
-template <class T>
+template <typename T>
static _FORCE_INLINE_ uint32_t hash_make_uint32_t(T p_in) {
union {
T t;
@@ -281,7 +281,7 @@ static _FORCE_INLINE_ uint64_t hash_djb2_one_64(uint64_t p_in, uint64_t p_prev =
return ((p_prev << 5) + p_prev) ^ p_in;
}
-template <class T>
+template <typename T>
static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) {
union {
T t;
@@ -293,15 +293,15 @@ static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) {
return _u._u64;
}
-template <class T>
+template <typename T>
class Ref;
struct HashMapHasherDefault {
// Generic hash function for any type.
- template <class T>
+ template <typename T>
static _FORCE_INLINE_ uint32_t hash(const T *p_pointer) { return hash_one_uint64((uint64_t)p_pointer); }
- template <class T>
+ template <typename T>
static _FORCE_INLINE_ uint32_t hash(const Ref<T> &p_ref) { return hash_one_uint64((uint64_t)p_ref.operator->()); }
static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); }
@@ -387,7 +387,7 @@ struct HashMapHasherDefault {
};
// TODO: Fold this into HashMapHasherDefault once C++20 concepts are allowed
-template <class T>
+template <typename T>
struct HashableHasher {
static _FORCE_INLINE_ uint32_t hash(const T &hashable) { return hashable.hash(); }
};
diff --git a/core/templates/list.h b/core/templates/list.h
index 354e826a43..b4d4beb930 100644
--- a/core/templates/list.h
+++ b/core/templates/list.h
@@ -43,7 +43,7 @@
* from the iterator.
*/
-template <class T, class A = DefaultAllocator>
+template <typename T, typename A = DefaultAllocator>
class List {
struct _Data;
@@ -410,7 +410,7 @@ public:
/**
* find an element in the list,
*/
- template <class T_v>
+ template <typename T_v>
Element *find(const T_v &p_val) {
Element *it = front();
while (it) {
@@ -646,7 +646,7 @@ public:
sort_custom<Comparator<T>>();
}
- template <class C>
+ template <typename C>
void sort_custom_inplace() {
if (size() < 2) {
return;
@@ -693,7 +693,7 @@ public:
_data->last = to;
}
- template <class C>
+ template <typename C>
struct AuxiliaryComparator {
C compare;
_FORCE_INLINE_ bool operator()(const Element *a, const Element *b) const {
@@ -701,7 +701,7 @@ public:
}
};
- template <class C>
+ template <typename C>
void sort_custom() {
//this version uses auxiliary memory for speed.
//if you don't want to use auxiliary memory, use the in_place version
@@ -764,7 +764,7 @@ public:
}
};
-template <class T, class A>
+template <typename T, typename A>
void List<T, A>::Element::transfer_to_back(List<T, A> *p_dst_list) {
// Detach from current.
diff --git a/core/templates/local_vector.h b/core/templates/local_vector.h
index 17ddbf6161..6478297fd1 100644
--- a/core/templates/local_vector.h
+++ b/core/templates/local_vector.h
@@ -41,7 +41,7 @@
// If tight, it grows strictly as much as needed.
// Otherwise, it grows exponentially (the default and what you want in most cases).
-template <class T, class U = uint32_t, bool force_trivial = false, bool tight = false>
+template <typename T, typename U = uint32_t, bool force_trivial = false, bool tight = false>
class LocalVector {
private:
U count = 0;
@@ -248,7 +248,7 @@ public:
return -1;
}
- template <class C>
+ template <typename C>
void sort_custom() {
U len = count;
if (len == 0) {
@@ -322,7 +322,7 @@ public:
}
};
-template <class T, class U = uint32_t, bool force_trivial = false>
+template <typename T, typename U = uint32_t, bool force_trivial = false>
using TightLocalVector = LocalVector<T, U, force_trivial, true>;
#endif // LOCAL_VECTOR_H
diff --git a/core/templates/lru.h b/core/templates/lru.h
index aecb735c48..919c5605aa 100644
--- a/core/templates/lru.h
+++ b/core/templates/lru.h
@@ -35,7 +35,7 @@
#include "hash_map.h"
#include "list.h"
-template <class TKey, class TData, class Hasher = HashMapHasherDefault, class Comparator = HashMapComparatorDefault<TKey>>
+template <typename TKey, typename TData, typename Hasher = HashMapHasherDefault, typename Comparator = HashMapComparatorDefault<TKey>>
class LRUCache {
private:
struct Pair {
diff --git a/core/templates/oa_hash_map.h b/core/templates/oa_hash_map.h
index 752e264a49..7afb58b7c2 100644
--- a/core/templates/oa_hash_map.h
+++ b/core/templates/oa_hash_map.h
@@ -50,9 +50,9 @@
*
* The assignment operator copy the pairs from one map to the other.
*/
-template <class TKey, class TValue,
- class Hasher = HashMapHasherDefault,
- class Comparator = HashMapComparatorDefault<TKey>>
+template <typename TKey, typename TValue,
+ typename Hasher = HashMapHasherDefault,
+ typename Comparator = HashMapComparatorDefault<TKey>>
class OAHashMap {
private:
TValue *values = nullptr;
diff --git a/core/templates/paged_allocator.h b/core/templates/paged_allocator.h
index 48110d37e5..4854e1b866 100644
--- a/core/templates/paged_allocator.h
+++ b/core/templates/paged_allocator.h
@@ -40,7 +40,7 @@
#include <type_traits>
#include <typeinfo>
-template <class T, bool thread_safe = false, uint32_t DEFAULT_PAGE_SIZE = 4096>
+template <typename T, bool thread_safe = false, uint32_t DEFAULT_PAGE_SIZE = 4096>
class PagedAllocator {
T **page_pool = nullptr;
T ***available_pool = nullptr;
@@ -53,7 +53,7 @@ class PagedAllocator {
SpinLock spin_lock;
public:
- template <class... Args>
+ template <typename... Args>
T *alloc(Args &&...p_args) {
if (thread_safe) {
spin_lock.lock();
@@ -95,7 +95,7 @@ public:
}
}
- template <class... Args>
+ template <typename... Args>
T *new_allocation(Args &&...p_args) { return alloc(p_args...); }
void delete_allocation(T *p_mem) { free(p_mem); }
diff --git a/core/templates/paged_array.h b/core/templates/paged_array.h
index 21053dd033..1aa8fa2485 100644
--- a/core/templates/paged_array.h
+++ b/core/templates/paged_array.h
@@ -41,7 +41,7 @@
// PageArrayPool manages central page allocation in a thread safe matter
-template <class T>
+template <typename T>
class PagedArrayPool {
T **page_pool = nullptr;
uint32_t pages_allocated = 0;
@@ -134,7 +134,7 @@ public:
// It does so by allocating pages from a PagedArrayPool.
// It is safe to use multiple PagedArrays from different threads, sharing a single PagedArrayPool
-template <class T>
+template <typename T>
class PagedArray {
PagedArrayPool<T> *page_pool = nullptr;
diff --git a/core/templates/pair.h b/core/templates/pair.h
index ff093a58e6..fd774641c2 100644
--- a/core/templates/pair.h
+++ b/core/templates/pair.h
@@ -33,7 +33,7 @@
#include "core/templates/hashfuncs.h"
#include "core/typedefs.h"
-template <class F, class S>
+template <typename F, typename S>
struct Pair {
F first;
S second;
@@ -49,17 +49,17 @@ struct Pair {
}
};
-template <class F, class S>
+template <typename F, typename S>
bool operator==(const Pair<F, S> &pair, const Pair<F, S> &other) {
return (pair.first == other.first) && (pair.second == other.second);
}
-template <class F, class S>
+template <typename F, typename S>
bool operator!=(const Pair<F, S> &pair, const Pair<F, S> &other) {
return (pair.first != other.first) || (pair.second != other.second);
}
-template <class F, class S>
+template <typename F, typename S>
struct PairSort {
bool operator()(const Pair<F, S> &A, const Pair<F, S> &B) const {
if (A.first != B.first) {
@@ -69,7 +69,7 @@ struct PairSort {
}
};
-template <class F, class S>
+template <typename F, typename S>
struct PairHash {
static uint32_t hash(const Pair<F, S> &P) {
uint64_t h1 = HashMapHasherDefault::hash(P.first);
@@ -78,7 +78,7 @@ struct PairHash {
}
};
-template <class K, class V>
+template <typename K, typename V>
struct KeyValue {
const K key;
V value;
@@ -94,17 +94,17 @@ struct KeyValue {
}
};
-template <class K, class V>
+template <typename K, typename V>
bool operator==(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
return (pair.key == other.key) && (pair.value == other.value);
}
-template <class K, class V>
+template <typename K, typename V>
bool operator!=(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
return (pair.key != other.key) || (pair.value != other.value);
}
-template <class K, class V>
+template <typename K, typename V>
struct KeyValueSort {
bool operator()(const KeyValue<K, V> &A, const KeyValue<K, V> &B) const {
return A.key < B.key;
diff --git a/core/templates/pooled_list.h b/core/templates/pooled_list.h
index 0d96bbb239..0e7048732e 100644
--- a/core/templates/pooled_list.h
+++ b/core/templates/pooled_list.h
@@ -55,7 +55,7 @@
#include "core/templates/local_vector.h"
-template <class T, class U = uint32_t, bool force_trivial = false, bool zero_on_first_request = false>
+template <typename T, typename U = uint32_t, bool force_trivial = false, bool zero_on_first_request = false>
class PooledList {
LocalVector<T, U, force_trivial> list;
LocalVector<U, U, true> freelist;
@@ -128,7 +128,7 @@ public:
};
// a pooled list which automatically keeps a list of the active members
-template <class T, class U = uint32_t, bool force_trivial = false, bool zero_on_first_request = false>
+template <typename T, typename U = uint32_t, bool force_trivial = false, bool zero_on_first_request = false>
class TrackedPooledList {
public:
U pool_used_size() const { return _pool.used_size(); }
diff --git a/core/templates/rb_map.h b/core/templates/rb_map.h
index 152fddd011..ef555e4a16 100644
--- a/core/templates/rb_map.h
+++ b/core/templates/rb_map.h
@@ -38,7 +38,7 @@
// based on the very nice implementation of rb-trees by:
// https://web.archive.org/web/20120507164830/https://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
-template <class K, class V, class C = Comparator<K>, class A = DefaultAllocator>
+template <typename K, typename V, typename C = Comparator<K>, typename A = DefaultAllocator>
class RBMap {
enum Color {
RED,
diff --git a/core/templates/rb_set.h b/core/templates/rb_set.h
index 0fc88709e4..ac7a8df36a 100644
--- a/core/templates/rb_set.h
+++ b/core/templates/rb_set.h
@@ -37,7 +37,7 @@
// based on the very nice implementation of rb-trees by:
// https://web.archive.org/web/20120507164830/https://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
-template <class T, class C = Comparator<T>, class A = DefaultAllocator>
+template <typename T, typename C = Comparator<T>, typename A = DefaultAllocator>
class RBSet {
enum Color {
RED,
diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h
index f92e0f4162..86304d3c73 100644
--- a/core/templates/rid_owner.h
+++ b/core/templates/rid_owner.h
@@ -67,7 +67,7 @@ public:
virtual ~RID_AllocBase() {}
};
-template <class T, bool THREAD_SAFE = false>
+template <typename T, bool THREAD_SAFE = false>
class RID_Alloc : public RID_AllocBase {
T **chunks = nullptr;
uint32_t **free_list_chunks = nullptr;
@@ -364,7 +364,7 @@ public:
}
};
-template <class T, bool THREAD_SAFE = false>
+template <typename T, bool THREAD_SAFE = false>
class RID_PtrOwner {
RID_Alloc<T *, THREAD_SAFE> alloc;
@@ -423,7 +423,7 @@ public:
alloc(p_target_chunk_byte_size) {}
};
-template <class T, bool THREAD_SAFE = false>
+template <typename T, bool THREAD_SAFE = false>
class RID_Owner {
RID_Alloc<T, THREAD_SAFE> alloc;
diff --git a/core/templates/safe_list.h b/core/templates/safe_list.h
index 79457db24c..60ccdd9423 100644
--- a/core/templates/safe_list.h
+++ b/core/templates/safe_list.h
@@ -48,7 +48,7 @@
// This is used in very specific areas of the engine where it's critical that these guarantees are held.
-template <class T, class A = DefaultAllocator>
+template <typename T, typename A = DefaultAllocator>
class SafeList {
struct SafeListNode {
std::atomic<SafeListNode *> next = nullptr;
diff --git a/core/templates/safe_refcount.h b/core/templates/safe_refcount.h
index 7bbceadc8d..637b068da9 100644
--- a/core/templates/safe_refcount.h
+++ b/core/templates/safe_refcount.h
@@ -59,7 +59,7 @@
static_assert(sizeof(SafeFlag) == sizeof(bool)); \
static_assert(alignof(SafeFlag) == alignof(bool));
-template <class T>
+template <typename T>
class SafeNumeric {
std::atomic<T> value;
diff --git a/core/templates/search_array.h b/core/templates/search_array.h
index 9c3f527323..835bcd63a6 100644
--- a/core/templates/search_array.h
+++ b/core/templates/search_array.h
@@ -33,7 +33,7 @@
#include <core/templates/sort_array.h>
-template <class T, class Comparator = _DefaultComparator<T>>
+template <typename T, typename Comparator = _DefaultComparator<T>>
class SearchArray {
public:
Comparator compare;
diff --git a/core/templates/self_list.h b/core/templates/self_list.h
index afa0501c75..a04972594e 100644
--- a/core/templates/self_list.h
+++ b/core/templates/self_list.h
@@ -34,7 +34,7 @@
#include "core/error/error_macros.h"
#include "core/typedefs.h"
-template <class T>
+template <typename T>
class SelfList {
public:
class List {
@@ -109,7 +109,7 @@ public:
sort_custom<Comparator<T>>();
}
- template <class C>
+ template <typename C>
void sort_custom() {
if (_first == _last) {
return;
diff --git a/core/templates/simple_type.h b/core/templates/simple_type.h
index 3950158c5a..b2ae0110e2 100644
--- a/core/templates/simple_type.h
+++ b/core/templates/simple_type.h
@@ -33,22 +33,22 @@
/* Batch of specializations to obtain the actual simple type */
-template <class T>
+template <typename T>
struct GetSimpleTypeT {
typedef T type_t;
};
-template <class T>
+template <typename T>
struct GetSimpleTypeT<T &> {
typedef T type_t;
};
-template <class T>
+template <typename T>
struct GetSimpleTypeT<T const> {
typedef T type_t;
};
-template <class T>
+template <typename T>
struct GetSimpleTypeT<T const &> {
typedef T type_t;
};
diff --git a/core/templates/sort_array.h b/core/templates/sort_array.h
index 45aeaf1579..e7eaf8ee81 100644
--- a/core/templates/sort_array.h
+++ b/core/templates/sort_array.h
@@ -40,7 +40,7 @@
break; \
}
-template <class T>
+template <typename T>
struct _DefaultComparator {
_FORCE_INLINE_ bool operator()(const T &a, const T &b) const { return (a < b); }
};
@@ -51,7 +51,7 @@ struct _DefaultComparator {
#define SORT_ARRAY_VALIDATE_ENABLED false
#endif
-template <class T, class Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
+template <typename T, typename Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
class SortArray {
enum {
INTROSORT_THRESHOLD = 16
diff --git a/core/templates/vector.h b/core/templates/vector.h
index 0de6a34ced..52c10eea68 100644
--- a/core/templates/vector.h
+++ b/core/templates/vector.h
@@ -45,7 +45,7 @@
#include <climits>
#include <initializer_list>
-template <class T>
+template <typename T>
class VectorWriteProxy {
public:
_FORCE_INLINE_ T &operator[](typename CowData<T>::Size p_index) {
@@ -55,7 +55,7 @@ public:
}
};
-template <class T>
+template <typename T>
class Vector {
friend class VectorWriteProxy<T>;
@@ -108,7 +108,7 @@ public:
sort_custom<_DefaultComparator<T>>();
}
- template <class Comparator, bool Validate = SORT_ARRAY_VALIDATE_ENABLED, class... Args>
+ template <typename Comparator, bool Validate = SORT_ARRAY_VALIDATE_ENABLED, typename... Args>
void sort_custom(Args &&...args) {
Size len = _cowdata.size();
if (len == 0) {
@@ -124,7 +124,7 @@ public:
return bsearch_custom<_DefaultComparator<T>>(p_value, p_before);
}
- template <class Comparator, class Value, class... Args>
+ template <typename Comparator, typename Value, typename... Args>
Size bsearch_custom(const Value &p_value, bool p_before, Args &&...args) {
SearchArray<T, Comparator> search{ args... };
return search.bisect(ptrw(), size(), p_value, p_before);
@@ -291,7 +291,7 @@ public:
_FORCE_INLINE_ ~Vector() {}
};
-template <class T>
+template <typename T>
void Vector<T>::reverse() {
for (Size i = 0; i < size() / 2; i++) {
T *p = ptrw();
@@ -299,7 +299,7 @@ void Vector<T>::reverse() {
}
}
-template <class T>
+template <typename T>
void Vector<T>::append_array(const Vector<T> &p_other) {
const Size ds = p_other.size();
if (ds == 0) {
@@ -312,7 +312,7 @@ void Vector<T>::append_array(const Vector<T> &p_other) {
}
}
-template <class T>
+template <typename T>
bool Vector<T>::push_back(T p_elem) {
Error err = resize(size() + 1);
ERR_FAIL_COND_V(err, true);
@@ -321,7 +321,7 @@ bool Vector<T>::push_back(T p_elem) {
return false;
}
-template <class T>
+template <typename T>
void Vector<T>::fill(T p_elem) {
T *p = ptrw();
for (Size i = 0; i < size(); i++) {
diff --git a/core/templates/vmap.h b/core/templates/vmap.h
index 5620bd3772..2ad074942b 100644
--- a/core/templates/vmap.h
+++ b/core/templates/vmap.h
@@ -34,7 +34,7 @@
#include "core/templates/cowdata.h"
#include "core/typedefs.h"
-template <class T, class V>
+template <typename T, typename V>
class VMap {
public:
struct Pair {
diff --git a/core/templates/vset.h b/core/templates/vset.h
index a4886ca965..614d0e1e5f 100644
--- a/core/templates/vset.h
+++ b/core/templates/vset.h
@@ -34,7 +34,7 @@
#include "core/templates/vector.h"
#include "core/typedefs.h"
-template <class T>
+template <typename T>
class VSet {
Vector<T> _data;
diff --git a/core/typedefs.h b/core/typedefs.h
index 8807ee3c99..2b90a911cd 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -132,7 +132,7 @@ constexpr auto CLAMP(const T m_a, const T2 m_min, const T3 m_max) {
// Generic swap template.
#ifndef SWAP
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
-template <class T>
+template <typename T>
inline void __swap_tmpl(T &x, T &y) {
T aux = x;
x = y;
@@ -186,7 +186,7 @@ static inline int get_shift_from_power_of_2(unsigned int p_bits) {
return -1;
}
-template <class T>
+template <typename T>
static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) {
--x;
@@ -256,7 +256,7 @@ static inline uint64_t BSWAP64(uint64_t x) {
#endif
// Generic comparator used in Map, List, etc.
-template <class T>
+template <typename T>
struct Comparator {
_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
};
diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h
index a44b938395..0fe4518b0f 100644
--- a/core/variant/binder_common.h
+++ b/core/variant/binder_common.h
@@ -47,7 +47,7 @@
// Variant cannot define an implicit cast operator for every Object subclass, so the
// casting is done here, to allow binding methods with parameters more specific than Object *
-template <class T>
+template <typename T>
struct VariantCaster {
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
using TStripped = std::remove_pointer_t<T>;
@@ -59,7 +59,7 @@ struct VariantCaster {
}
};
-template <class T>
+template <typename T>
struct VariantCaster<T &> {
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
using TStripped = std::remove_pointer_t<T>;
@@ -71,7 +71,7 @@ struct VariantCaster<T &> {
}
};
-template <class T>
+template <typename T>
struct VariantCaster<const T &> {
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
using TStripped = std::remove_pointer_t<T>;
@@ -249,7 +249,7 @@ struct VariantObjectClassChecker<const Ref<T> &> {
#ifdef DEBUG_METHODS_ENABLED
-template <class T>
+template <typename T>
struct VariantCasterAndValidate {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
@@ -264,7 +264,7 @@ struct VariantCasterAndValidate {
}
};
-template <class T>
+template <typename T>
struct VariantCasterAndValidate<T &> {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
@@ -279,7 +279,7 @@ struct VariantCasterAndValidate<T &> {
}
};
-template <class T>
+template <typename T>
struct VariantCasterAndValidate<const T &> {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
@@ -296,7 +296,7 @@ struct VariantCasterAndValidate<const T &> {
#endif // DEBUG_METHODS_ENABLED
-template <class T, class... P, size_t... Is>
+template <typename T, typename... P, size_t... Is>
void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
r_error.error = Callable::CallError::CALL_OK;
@@ -308,7 +308,7 @@ void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), con
(void)(p_args); //avoid warning
}
-template <class T, class... P, size_t... Is>
+template <typename T, typename... P, size_t... Is>
void call_with_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
r_error.error = Callable::CallError::CALL_OK;
@@ -320,87 +320,87 @@ void call_with_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) con
(void)(p_args); //avoid warning
}
-template <class T, class... P, size_t... Is>
+template <typename T, typename... P, size_t... Is>
void call_with_ptr_args_helper(T *p_instance, void (T::*p_method)(P...), const void **p_args, IndexSequence<Is...>) {
(p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
}
-template <class T, class... P, size_t... Is>
+template <typename T, typename... P, size_t... Is>
void call_with_ptr_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const void **p_args, IndexSequence<Is...>) {
(p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
}
-template <class T, class R, class... P, size_t... Is>
+template <typename T, typename R, typename... P, size_t... Is>
void call_with_ptr_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const void **p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
}
-template <class T, class R, class... P, size_t... Is>
+template <typename T, typename R, typename... P, size_t... Is>
void call_with_ptr_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const void **p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
}
-template <class T, class... P, size_t... Is>
+template <typename T, typename... P, size_t... Is>
void call_with_ptr_args_static_helper(T *p_instance, void (*p_method)(T *, P...), const void **p_args, IndexSequence<Is...>) {
p_method(p_instance, PtrToArg<P>::convert(p_args[Is])...);
}
-template <class T, class R, class... P, size_t... Is>
+template <typename T, typename R, typename... P, size_t... Is>
void call_with_ptr_args_static_retc_helper(T *p_instance, R (*p_method)(T *, P...), const void **p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode(p_method(p_instance, PtrToArg<P>::convert(p_args[Is])...), r_ret);
}
-template <class R, class... P, size_t... Is>
+template <typename R, typename... P, size_t... Is>
void call_with_ptr_args_static_method_ret_helper(R (*p_method)(P...), const void **p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode(p_method(PtrToArg<P>::convert(p_args[Is])...), r_ret);
}
-template <class... P, size_t... Is>
+template <typename... P, size_t... Is>
void call_with_ptr_args_static_method_helper(void (*p_method)(P...), const void **p_args, IndexSequence<Is...>) {
p_method(PtrToArg<P>::convert(p_args[Is])...);
}
-template <class T, class... P, size_t... Is>
+template <typename T, typename... P, size_t... Is>
void call_with_validated_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, IndexSequence<Is...>) {
(p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
}
-template <class T, class... P, size_t... Is>
+template <typename T, typename... P, size_t... Is>
void call_with_validated_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, IndexSequence<Is...>) {
(p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
}
-template <class T, class R, class... P, size_t... Is>
+template <typename T, typename R, typename... P, size_t... Is>
void call_with_validated_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
}
-template <class T, class R, class... P, size_t... Is>
+template <typename T, typename R, typename... P, size_t... Is>
void call_with_validated_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
}
-template <class T, class R, class... P, size_t... Is>
+template <typename T, typename R, typename... P, size_t... Is>
void call_with_validated_variant_args_static_retc_helper(T *p_instance, R (*p_method)(T *, P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, p_method(p_instance, (VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
}
-template <class T, class... P, size_t... Is>
+template <typename T, typename... P, size_t... Is>
void call_with_validated_variant_args_static_helper(T *p_instance, void (*p_method)(T *, P...), const Variant **p_args, IndexSequence<Is...>) {
p_method(p_instance, (VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
}
-template <class R, class... P, size_t... Is>
+template <typename R, typename... P, size_t... Is>
void call_with_validated_variant_args_static_method_ret_helper(R (*p_method)(P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, p_method((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
}
-template <class... P, size_t... Is>
+template <typename... P, size_t... Is>
void call_with_validated_variant_args_static_method_helper(void (*p_method)(P...), const Variant **p_args, IndexSequence<Is...>) {
p_method((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
}
-template <class T, class... P>
+template <typename T, typename... P>
void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
#ifdef DEBUG_METHODS_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -418,7 +418,7 @@ void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Vari
call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class... P>
+template <typename T, typename... P>
void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error, const Vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -451,7 +451,7 @@ void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const V
call_with_variant_args_helper(p_instance, p_method, args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class... P>
+template <typename T, typename... P>
void call_with_variant_argsc(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
#ifdef DEBUG_METHODS_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -469,7 +469,7 @@ void call_with_variant_argsc(T *p_instance, void (T::*p_method)(P...) const, con
call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class... P>
+template <typename T, typename... P>
void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Callable::CallError &r_error, const Vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -502,7 +502,7 @@ void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const,
call_with_variant_argsc_helper(p_instance, p_method, args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error, const Vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -535,7 +535,7 @@ void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const
call_with_variant_args_ret_helper(p_instance, p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error, const Vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -568,111 +568,111 @@ void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const,
call_with_variant_args_retc_helper(p_instance, p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class... P>
+template <typename T, typename... P>
void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...), const void **p_args) {
call_with_ptr_args_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class... P>
+template <typename T, typename... P>
void call_with_ptr_argsc(T *p_instance, void (T::*p_method)(P...) const, const void **p_args) {
call_with_ptr_argsc_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
void call_with_ptr_args_ret(T *p_instance, R (T::*p_method)(P...), const void **p_args, void *r_ret) {
call_with_ptr_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
void call_with_ptr_args_retc(T *p_instance, R (T::*p_method)(P...) const, const void **p_args, void *r_ret) {
call_with_ptr_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class... P>
+template <typename T, typename... P>
void call_with_ptr_args_static(T *p_instance, void (*p_method)(T *, P...), const void **p_args) {
call_with_ptr_args_static_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
void call_with_ptr_args_static_retc(T *p_instance, R (*p_method)(T *, P...), const void **p_args, void *r_ret) {
call_with_ptr_args_static_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
-template <class R, class... P>
+template <typename R, typename... P>
void call_with_ptr_args_static_method_ret(R (*p_method)(P...), const void **p_args, void *r_ret) {
call_with_ptr_args_static_method_ret_helper<R, P...>(p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
-template <class... P>
+template <typename... P>
void call_with_ptr_args_static_method(void (*p_method)(P...), const void **p_args) {
call_with_ptr_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
// Validated
-template <class T, class... P>
+template <typename T, typename... P>
void call_with_validated_variant_args(Variant *base, void (T::*p_method)(P...), const Variant **p_args) {
call_with_validated_variant_args_helper<T, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
void call_with_validated_variant_args_ret(Variant *base, R (T::*p_method)(P...), const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_ret_helper<T, R, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
void call_with_validated_variant_args_retc(Variant *base, R (T::*p_method)(P...) const, const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_retc_helper<T, R, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class... P>
+template <typename T, typename... P>
void call_with_validated_variant_args_static(Variant *base, void (*p_method)(T *, P...), const Variant **p_args) {
call_with_validated_variant_args_static_helper<T, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
void call_with_validated_variant_args_static_retc(Variant *base, R (*p_method)(T *, P...), const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_static_retc_helper<T, R, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
-template <class... P>
+template <typename... P>
void call_with_validated_variant_args_static_method(void (*p_method)(P...), const Variant **p_args) {
call_with_validated_variant_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
-template <class R, class... P>
+template <typename R, typename... P>
void call_with_validated_variant_args_static_method_ret(R (*p_method)(P...), const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_static_method_ret_helper<R, P...>(p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
// Validated Object
-template <class T, class... P>
+template <typename T, typename... P>
void call_with_validated_object_instance_args(T *base, void (T::*p_method)(P...), const Variant **p_args) {
call_with_validated_variant_args_helper<T, P...>(base, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class... P>
+template <typename T, typename... P>
void call_with_validated_object_instance_argsc(T *base, void (T::*p_method)(P...) const, const Variant **p_args) {
call_with_validated_variant_argsc_helper<T, P...>(base, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
void call_with_validated_object_instance_args_ret(T *base, R (T::*p_method)(P...), const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_ret_helper<T, R, P...>(base, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
void call_with_validated_object_instance_args_retc(T *base, R (T::*p_method)(P...) const, const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_retc_helper<T, R, P...>(base, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class... P>
+template <typename T, typename... P>
void call_with_validated_object_instance_args_static(T *base, void (*p_method)(T *, P...), const Variant **p_args) {
call_with_validated_variant_args_static_helper<T, P...>(base, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
void call_with_validated_object_instance_args_static_retc(T *base, R (*p_method)(T *, P...), const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_static_retc_helper<T, R, P...>(base, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
@@ -684,7 +684,7 @@ void call_with_validated_object_instance_args_static_retc(T *base, R (*p_method)
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#endif
-template <class Q>
+template <typename Q>
void call_get_argument_type_helper(int p_arg, int &index, Variant::Type &type) {
if (p_arg == index) {
type = GetTypeInfo<Q>::VARIANT_TYPE;
@@ -692,7 +692,7 @@ void call_get_argument_type_helper(int p_arg, int &index, Variant::Type &type) {
index++;
}
-template <class... P>
+template <typename... P>
Variant::Type call_get_argument_type(int p_arg) {
Variant::Type type = Variant::NIL;
int index = 0;
@@ -704,7 +704,7 @@ Variant::Type call_get_argument_type(int p_arg) {
return type;
}
-template <class Q>
+template <typename Q>
void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &info) {
if (p_arg == index) {
info = GetTypeInfo<Q>::get_class_info();
@@ -712,7 +712,7 @@ void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &inf
index++;
}
-template <class... P>
+template <typename... P>
void call_get_argument_type_info(int p_arg, PropertyInfo &info) {
int index = 0;
// I think rocket science is simpler than modern C++.
@@ -723,7 +723,7 @@ void call_get_argument_type_info(int p_arg, PropertyInfo &info) {
}
#ifdef DEBUG_METHODS_ENABLED
-template <class Q>
+template <typename Q>
void call_get_argument_metadata_helper(int p_arg, int &index, GodotTypeInfo::Metadata &md) {
if (p_arg == index) {
md = GetTypeInfo<Q>::METADATA;
@@ -731,7 +731,7 @@ void call_get_argument_metadata_helper(int p_arg, int &index, GodotTypeInfo::Met
index++;
}
-template <class... P>
+template <typename... P>
GodotTypeInfo::Metadata call_get_argument_metadata(int p_arg) {
GodotTypeInfo::Metadata md = GodotTypeInfo::METADATA_NONE;
@@ -748,7 +748,7 @@ GodotTypeInfo::Metadata call_get_argument_metadata(int p_arg) {
//////////////////////
-template <class T, class R, class... P, size_t... Is>
+template <typename T, typename R, typename... P, size_t... Is>
void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
r_error.error = Callable::CallError::CALL_OK;
@@ -759,7 +759,7 @@ void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), co
#endif
}
-template <class R, class... P, size_t... Is>
+template <typename R, typename... P, size_t... Is>
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
r_error.error = Callable::CallError::CALL_OK;
@@ -770,7 +770,7 @@ void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_ar
#endif
}
-template <class... P, size_t... Is>
+template <typename... P, size_t... Is>
void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
r_error.error = Callable::CallError::CALL_OK;
@@ -781,7 +781,7 @@ void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_arg
#endif
}
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
#ifdef DEBUG_METHODS_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -799,7 +799,7 @@ void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Var
call_with_variant_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class R, class... P, size_t... Is>
+template <typename T, typename R, typename... P, size_t... Is>
void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
r_error.error = Callable::CallError::CALL_OK;
@@ -811,7 +811,7 @@ void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) co
(void)p_args;
}
-template <class R, class... P>
+template <typename R, typename... P>
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
#ifdef DEBUG_METHODS_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -829,7 +829,7 @@ void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_ar
call_with_variant_args_static_ret<R, P...>(p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
-template <class... P>
+template <typename... P>
void call_with_variant_args_static_ret(void (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
#ifdef DEBUG_METHODS_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -847,7 +847,7 @@ void call_with_variant_args_static_ret(void (*p_method)(P...), const Variant **p
call_with_variant_args_static<P...>(p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
#ifdef DEBUG_METHODS_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -865,7 +865,7 @@ void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, co
call_with_variant_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class R, class... P, size_t... Is>
+template <typename T, typename R, typename... P, size_t... Is>
void call_with_variant_args_retc_static_helper(T *p_instance, R (*p_method)(T *, P...), const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
r_error.error = Callable::CallError::CALL_OK;
@@ -878,7 +878,7 @@ void call_with_variant_args_retc_static_helper(T *p_instance, R (*p_method)(T *,
(void)p_args;
}
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
void call_with_variant_args_retc_static_helper_dv(T *p_instance, R (*p_method)(T *, P...), const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &default_values, Callable::CallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -911,7 +911,7 @@ void call_with_variant_args_retc_static_helper_dv(T *p_instance, R (*p_method)(T
call_with_variant_args_retc_static_helper(p_instance, p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
-template <class T, class... P, size_t... Is>
+template <typename T, typename... P, size_t... Is>
void call_with_variant_args_static_helper(T *p_instance, void (*p_method)(T *, P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
r_error.error = Callable::CallError::CALL_OK;
@@ -924,7 +924,7 @@ void call_with_variant_args_static_helper(T *p_instance, void (*p_method)(T *, P
(void)p_args;
}
-template <class T, class... P>
+template <typename T, typename... P>
void call_with_variant_args_static_helper_dv(T *p_instance, void (*p_method)(T *, P...), const Variant **p_args, int p_argcount, const Vector<Variant> &default_values, Callable::CallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -957,7 +957,7 @@ void call_with_variant_args_static_helper_dv(T *p_instance, void (*p_method)(T *
call_with_variant_args_static_helper(p_instance, p_method, args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
-template <class R, class... P>
+template <typename R, typename... P>
void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error, const Vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
@@ -990,7 +990,7 @@ void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const Variant **p
call_with_variant_args_static_ret(p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
-template <class... P>
+template <typename... P>
void call_with_variant_args_static_dv(void (*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error, const Vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index 47271118a0..c6fbfd93a1 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -184,6 +184,20 @@ StringName Callable::get_method() const {
return method;
}
+int Callable::get_argument_count(bool *r_is_valid) const {
+ if (is_custom()) {
+ bool valid = false;
+ return custom->get_argument_count(r_is_valid ? *r_is_valid : valid);
+ } else if (!is_null()) {
+ return get_object()->get_method_argument_count(method, r_is_valid);
+ } else {
+ if (r_is_valid) {
+ *r_is_valid = false;
+ }
+ return 0;
+ }
+}
+
int Callable::get_bound_arguments_count() const {
if (!is_null() && is_custom()) {
return custom->get_bound_arguments_count();
@@ -438,6 +452,11 @@ const Callable *CallableCustom::get_base_comparator() const {
return nullptr;
}
+int CallableCustom::get_argument_count(bool &r_is_valid) const {
+ r_is_valid = false;
+ return 0;
+}
+
int CallableCustom::get_bound_arguments_count() const {
return 0;
}
diff --git a/core/variant/callable.h b/core/variant/callable.h
index bba69d453e..63757d9d6e 100644
--- a/core/variant/callable.h
+++ b/core/variant/callable.h
@@ -109,6 +109,7 @@ public:
ObjectID get_object_id() const;
StringName get_method() const;
CallableCustom *get_custom() const;
+ int get_argument_count(bool *r_is_valid = nullptr) const;
int get_bound_arguments_count() const;
void get_bound_arguments_ref(Vector<Variant> &r_arguments, int &r_argcount) const; // Internal engine use, the exposed one is below.
Array get_bound_arguments() const;
@@ -155,6 +156,7 @@ public:
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const = 0;
virtual Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const;
virtual const Callable *get_base_comparator() const;
+ virtual int get_argument_count(bool &r_is_valid) const;
virtual int get_bound_arguments_count() const;
virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const;
diff --git a/core/variant/callable_bind.cpp b/core/variant/callable_bind.cpp
index 6d6c60cbd4..d82aa3583d 100644
--- a/core/variant/callable_bind.cpp
+++ b/core/variant/callable_bind.cpp
@@ -91,6 +91,14 @@ const Callable *CallableCustomBind::get_base_comparator() const {
return callable.get_base_comparator();
}
+int CallableCustomBind::get_argument_count(bool &r_is_valid) const {
+ int ret = callable.get_argument_count(&r_is_valid);
+ if (r_is_valid) {
+ return ret - binds.size();
+ }
+ return 0;
+}
+
int CallableCustomBind::get_bound_arguments_count() const {
return callable.get_bound_arguments_count() + binds.size();
}
@@ -225,6 +233,14 @@ const Callable *CallableCustomUnbind::get_base_comparator() const {
return callable.get_base_comparator();
}
+int CallableCustomUnbind::get_argument_count(bool &r_is_valid) const {
+ int ret = callable.get_argument_count(&r_is_valid);
+ if (r_is_valid) {
+ return ret + argcount;
+ }
+ return 0;
+}
+
int CallableCustomUnbind::get_bound_arguments_count() const {
return callable.get_bound_arguments_count() - argcount;
}
diff --git a/core/variant/callable_bind.h b/core/variant/callable_bind.h
index 5798797a3d..43cebb45f0 100644
--- a/core/variant/callable_bind.h
+++ b/core/variant/callable_bind.h
@@ -53,6 +53,7 @@ public:
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
virtual Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const override;
virtual const Callable *get_base_comparator() const override;
+ virtual int get_argument_count(bool &r_is_valid) const override;
virtual int get_bound_arguments_count() const override;
virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const override;
Callable get_callable() { return callable; }
@@ -81,6 +82,7 @@ public:
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
virtual Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const override;
virtual const Callable *get_base_comparator() const override;
+ virtual int get_argument_count(bool &r_is_valid) const override;
virtual int get_bound_arguments_count() const override;
virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const override;
diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h
index 1be54ba3fd..123f2067e2 100644
--- a/core/variant/method_ptrcall.h
+++ b/core/variant/method_ptrcall.h
@@ -35,7 +35,7 @@
#include "core/typedefs.h"
#include "core/variant/variant.h"
-template <class T>
+template <typename T>
struct PtrToArg {};
#define MAKE_PTRARG(m_type) \
@@ -156,7 +156,7 @@ MAKE_PTRARG_BY_REFERENCE(Variant);
// This is for Object.
-template <class T>
+template <typename T>
struct PtrToArg<T *> {
_FORCE_INLINE_ static T *convert(const void *p_ptr) {
if (p_ptr == nullptr) {
@@ -170,7 +170,7 @@ struct PtrToArg<T *> {
}
};
-template <class T>
+template <typename T>
struct PtrToArg<const T *> {
_FORCE_INLINE_ static const T *convert(const void *p_ptr) {
if (p_ptr == nullptr) {
diff --git a/core/variant/native_ptr.h b/core/variant/native_ptr.h
index 9199b12845..33ba038132 100644
--- a/core/variant/native_ptr.h
+++ b/core/variant/native_ptr.h
@@ -35,7 +35,7 @@
#include "core/variant/method_ptrcall.h"
#include "core/variant/type_info.h"
-template <class T>
+template <typename T>
struct GDExtensionConstPtr {
const T *data = nullptr;
GDExtensionConstPtr(const T *p_assign) { data = p_assign; }
@@ -44,7 +44,7 @@ struct GDExtensionConstPtr {
operator Variant() const { return uint64_t(data); }
};
-template <class T>
+template <typename T>
struct GDExtensionPtr {
T *data = nullptr;
GDExtensionPtr(T *p_assign) { data = p_assign; }
@@ -95,7 +95,7 @@ struct GDExtensionPtr {
static _FORCE_INLINE_ void set(Variant *v, const GDExtensionPtr<m_type> &p_value) { *VariantInternal::get_int(v) = uint64_t(p_value.data); } \
};
-template <class T>
+template <typename T>
struct GetTypeInfo<GDExtensionConstPtr<T>> {
static const Variant::Type VARIANT_TYPE = Variant::NIL;
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
@@ -104,7 +104,7 @@ struct GetTypeInfo<GDExtensionConstPtr<T>> {
}
};
-template <class T>
+template <typename T>
struct GetTypeInfo<GDExtensionPtr<T>> {
static const Variant::Type VARIANT_TYPE = Variant::NIL;
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
@@ -113,7 +113,7 @@ struct GetTypeInfo<GDExtensionPtr<T>> {
}
};
-template <class T>
+template <typename T>
struct PtrToArg<GDExtensionConstPtr<T>> {
_FORCE_INLINE_ static GDExtensionConstPtr<T> convert(const void *p_ptr) {
return GDExtensionConstPtr<T>(reinterpret_cast<const T *>(p_ptr));
@@ -123,7 +123,7 @@ struct PtrToArg<GDExtensionConstPtr<T>> {
*((const T **)p_ptr) = p_val.data;
}
};
-template <class T>
+template <typename T>
struct PtrToArg<GDExtensionPtr<T>> {
_FORCE_INLINE_ static GDExtensionPtr<T> convert(const void *p_ptr) {
return GDExtensionPtr<T>(reinterpret_cast<const T *>(p_ptr));
diff --git a/core/variant/type_info.h b/core/variant/type_info.h
index 49c4db8229..32c410463b 100644
--- a/core/variant/type_info.h
+++ b/core/variant/type_info.h
@@ -80,7 +80,7 @@ enum Metadata {
// If 'T' is a class that inherits 'Object', make sure it can see the actual class declaration
// instead of a forward declaration. You can always forward declare 'T' in a header file, and then
// include the actual declaration of 'T' in the source file where 'GetTypeInfo<T>' is instantiated.
-template <class T, typename = void>
+template <typename T, typename = void>
struct GetTypeInfo;
#define MAKE_TYPE_INFO(m_type, m_var_type) \
@@ -278,7 +278,7 @@ inline StringName __constant_get_enum_name(T param, const String &p_constant) {
return GetTypeInfo<T>::get_class_info().class_name;
}
-template <class T>
+template <typename T>
class BitField {
int64_t value = 0;
diff --git a/core/variant/typed_array.h b/core/variant/typed_array.h
index ed973b9daa..0befd19864 100644
--- a/core/variant/typed_array.h
+++ b/core/variant/typed_array.h
@@ -38,7 +38,7 @@
#include "core/variant/type_info.h"
#include "core/variant/variant.h"
-template <class T>
+template <typename T>
class TypedArray : public Array {
public:
_FORCE_INLINE_ void operator=(const Array &p_array) {
@@ -56,12 +56,12 @@ public:
}
};
-template <class T>
+template <typename T>
struct VariantInternalAccessor<TypedArray<T>> {
static _FORCE_INLINE_ TypedArray<T> get(const Variant *v) { return *VariantInternal::get_array(v); }
static _FORCE_INLINE_ void set(Variant *v, const TypedArray<T> &p_array) { *VariantInternal::get_array(v) = p_array; }
};
-template <class T>
+template <typename T>
struct VariantInternalAccessor<const TypedArray<T> &> {
static _FORCE_INLINE_ TypedArray<T> get(const Variant *v) { return *VariantInternal::get_array(v); }
static _FORCE_INLINE_ void set(Variant *v, const TypedArray<T> &p_array) { *VariantInternal::get_array(v) = p_array; }
@@ -136,7 +136,7 @@ MAKE_TYPED_ARRAY(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_ARRAY(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
MAKE_TYPED_ARRAY(IPAddress, Variant::STRING)
-template <class T>
+template <typename T>
struct PtrToArg<TypedArray<T>> {
_FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
@@ -147,7 +147,7 @@ struct PtrToArg<TypedArray<T>> {
}
};
-template <class T>
+template <typename T>
struct PtrToArg<const TypedArray<T> &> {
typedef Array EncodeT;
_FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
@@ -155,7 +155,7 @@ struct PtrToArg<const TypedArray<T> &> {
}
};
-template <class T>
+template <typename T>
struct GetTypeInfo<TypedArray<T>> {
static const Variant::Type VARIANT_TYPE = Variant::ARRAY;
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
@@ -164,7 +164,7 @@ struct GetTypeInfo<TypedArray<T>> {
}
};
-template <class T>
+template <typename T>
struct GetTypeInfo<const TypedArray<T> &> {
static const Variant::Type VARIANT_TYPE = Variant::ARRAY;
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index ce5423fafc..89c22c05dd 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -1697,7 +1697,7 @@ String stringify_variant_clean(const Variant &p_variant, int recursion_count) {
return s;
}
-template <class T>
+template <typename T>
String stringify_vector(const T &vec, int recursion_count) {
String str("[");
for (int i = 0; i < vec.size(); i++) {
@@ -2188,7 +2188,7 @@ Variant::operator Signal() const {
}
}
-template <class DA, class SA>
+template <typename DA, typename SA>
inline DA _convert_array(const SA &p_array) {
DA da;
da.resize(p_array.size());
@@ -2200,7 +2200,7 @@ inline DA _convert_array(const SA &p_array) {
return da;
}
-template <class DA>
+template <typename DA>
inline DA _convert_array_from_variant(const Variant &p_variant) {
switch (p_variant.get_type()) {
case Variant::ARRAY: {
diff --git a/core/variant/variant.h b/core/variant/variant.h
index c358559c9b..e8eec8171b 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -204,7 +204,7 @@ private:
_FORCE_INLINE_ virtual ~PackedArrayRefBase() {} //needs virtual destructor, but make inline
};
- template <class T>
+ template <typename T>
struct PackedArrayRef : public PackedArrayRefBase {
Vector<T> array;
static _FORCE_INLINE_ PackedArrayRef<T> *create() {
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 060ea007ff..5f04c42536 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -43,329 +43,329 @@
typedef void (*VariantFunc)(Variant &r_ret, Variant &p_self, const Variant **p_args);
typedef void (*VariantConstructFunc)(Variant &r_ret, const Variant **p_args);
-template <class R, class... P>
+template <typename R, typename... P>
static _FORCE_INLINE_ void vc_static_method_call(R (*method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
call_with_variant_args_static_ret_dv(method, p_args, p_argcount, r_ret, r_error, p_defvals);
}
-template <class... P>
+template <typename... P>
static _FORCE_INLINE_ void vc_static_method_call(void (*method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
call_with_variant_args_static_dv(method, p_args, p_argcount, r_error, p_defvals);
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ void vc_method_call(R (T::*method)(P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
call_with_variant_args_ret_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, r_error, p_defvals);
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ void vc_method_call(R (T::*method)(P...) const, Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
call_with_variant_args_retc_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, r_error, p_defvals);
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ void vc_method_call(void (T::*method)(P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
VariantInternal::clear(&r_ret);
call_with_variant_args_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_error, p_defvals);
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ void vc_method_call(void (T::*method)(P...) const, Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
VariantInternal::clear(&r_ret);
call_with_variant_argsc_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_error, p_defvals);
}
-template <class From, class R, class T, class... P>
+template <typename From, typename R, typename T, typename... P>
static _FORCE_INLINE_ void vc_convert_method_call(R (T::*method)(P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base)));
call_with_variant_args_ret_dv(&converted, method, p_args, p_argcount, r_ret, r_error, p_defvals);
}
-template <class From, class R, class T, class... P>
+template <typename From, typename R, typename T, typename... P>
static _FORCE_INLINE_ void vc_convert_method_call(R (T::*method)(P...) const, Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base)));
call_with_variant_args_retc_dv(&converted, method, p_args, p_argcount, r_ret, r_error, p_defvals);
}
-template <class From, class T, class... P>
+template <typename From, typename T, typename... P>
static _FORCE_INLINE_ void vc_convert_method_call(void (T::*method)(P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base)));
call_with_variant_args_dv(&converted, method, p_args, p_argcount, r_error, p_defvals);
}
-template <class From, class T, class... P>
+template <typename From, typename T, typename... P>
static _FORCE_INLINE_ void vc_convert_method_call(void (T::*method)(P...) const, Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base)));
call_with_variant_argsc_dv(&converted, method, p_args, p_argcount, r_error, p_defvals);
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ void vc_method_call_static(R (*method)(T *, P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
call_with_variant_args_retc_static_helper_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, p_defvals, r_error);
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ void vc_method_call_static(void (*method)(T *, P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
call_with_variant_args_static_helper_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, p_defvals, r_error);
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ void vc_validated_call(R (T::*method)(P...), Variant *base, const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_ret(base, method, p_args, r_ret);
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ void vc_validated_call(R (T::*method)(P...) const, Variant *base, const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_retc(base, method, p_args, r_ret);
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ void vc_validated_call(void (T::*method)(P...), Variant *base, const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args(base, method, p_args);
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ void vc_validated_call(void (T::*method)(P...) const, Variant *base, const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_argsc(base, method, p_args);
}
-template <class From, class R, class T, class... P>
+template <typename From, typename R, typename T, typename... P>
static _FORCE_INLINE_ void vc_convert_validated_call(R (T::*method)(P...), Variant *base, const Variant **p_args, Variant *r_ret) {
T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base)));
call_with_validated_variant_args_ret_helper<T, R, P...>(&converted, method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
-template <class From, class R, class T, class... P>
+template <typename From, typename R, typename T, typename... P>
static _FORCE_INLINE_ void vc_convert_validated_call(R (T::*method)(P...) const, Variant *base, const Variant **p_args, Variant *r_ret) {
T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base)));
call_with_validated_variant_args_retc_helper<T, R, P...>(&converted, method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
-template <class From, class T, class... P>
+template <typename From, typename T, typename... P>
static _FORCE_INLINE_ void vc_convert_validated_call(void (T::*method)(P...), Variant *base, const Variant **p_args, Variant *r_ret) {
T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base)));
call_with_validated_variant_args_helper<T, P...>(&converted, method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
-template <class From, class T, class... P>
+template <typename From, typename T, typename... P>
static _FORCE_INLINE_ void vc_convert_validated_call(void (T::*method)(P...) const, Variant *base, const Variant **p_args, Variant *r_ret) {
T converted(static_cast<T>(*VariantGetInternalPtr<From>::get_ptr(base)));
call_with_validated_variant_argsc_helper<T, P...>(&converted, method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ void vc_validated_call_static(R (*method)(T *, P...), Variant *base, const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_static_retc(base, method, p_args, r_ret);
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ void vc_validated_call_static(void (*method)(T *, P...), Variant *base, const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_static(base, method, p_args);
}
-template <class R, class... P>
+template <typename R, typename... P>
static _FORCE_INLINE_ void vc_validated_static_call(R (*method)(P...), const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_static_method_ret(method, p_args, r_ret);
}
-template <class... P>
+template <typename... P>
static _FORCE_INLINE_ void vc_validated_static_call(void (*method)(P...), const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_static_method(method, p_args);
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ void vc_ptrcall(R (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) {
call_with_ptr_args_ret(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ void vc_ptrcall(R (T::*method)(P...) const, void *p_base, const void **p_args, void *r_ret) {
call_with_ptr_args_retc(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ void vc_ptrcall(void (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) {
call_with_ptr_args(reinterpret_cast<T *>(p_base), method, p_args);
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ void vc_ptrcall(void (T::*method)(P...) const, void *p_base, const void **p_args, void *r_ret) {
call_with_ptr_argsc(reinterpret_cast<T *>(p_base), method, p_args);
}
-template <class From, class R, class T, class... P>
+template <typename From, typename R, typename T, typename... P>
static _FORCE_INLINE_ void vc_convert_ptrcall(R (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) {
T converted(*reinterpret_cast<From *>(p_base));
call_with_ptr_args_ret(&converted, method, p_args, r_ret);
}
-template <class From, class R, class T, class... P>
+template <typename From, typename R, typename T, typename... P>
static _FORCE_INLINE_ void vc_convert_ptrcall(R (T::*method)(P...) const, void *p_base, const void **p_args, void *r_ret) {
T converted(*reinterpret_cast<From *>(p_base));
call_with_ptr_args_retc(&converted, method, p_args, r_ret);
}
-template <class From, class T, class... P>
+template <typename From, typename T, typename... P>
static _FORCE_INLINE_ void vc_convert_ptrcall(void (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) {
T converted(*reinterpret_cast<From *>(p_base));
call_with_ptr_args(&converted, method, p_args);
}
-template <class From, class T, class... P>
+template <typename From, typename T, typename... P>
static _FORCE_INLINE_ void vc_convert_ptrcall(void (T::*method)(P...) const, void *p_base, const void **p_args, void *r_ret) {
T converted(*reinterpret_cast<From *>(p_base));
call_with_ptr_argsc(&converted, method, p_args);
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ int vc_get_argument_count(R (T::*method)(P...)) {
return sizeof...(P);
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ int vc_get_argument_count(R (T::*method)(P...) const) {
return sizeof...(P);
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ int vc_get_argument_count(void (T::*method)(P...)) {
return sizeof...(P);
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ int vc_get_argument_count(void (T::*method)(P...) const) {
return sizeof...(P);
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ int vc_get_argument_count(R (*method)(T *, P...)) {
return sizeof...(P);
}
-template <class R, class... P>
+template <typename R, typename... P>
static _FORCE_INLINE_ int vc_get_argument_count_static(R (*method)(P...)) {
return sizeof...(P);
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ Variant::Type vc_get_argument_type(R (T::*method)(P...), int p_arg) {
return call_get_argument_type<P...>(p_arg);
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ Variant::Type vc_get_argument_type(R (T::*method)(P...) const, int p_arg) {
return call_get_argument_type<P...>(p_arg);
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ Variant::Type vc_get_argument_type(void (T::*method)(P...), int p_arg) {
return call_get_argument_type<P...>(p_arg);
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ Variant::Type vc_get_argument_type(void (T::*method)(P...) const, int p_arg) {
return call_get_argument_type<P...>(p_arg);
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ Variant::Type vc_get_argument_type(R (*method)(T *, P...), int p_arg) {
return call_get_argument_type<P...>(p_arg);
}
-template <class R, class... P>
+template <typename R, typename... P>
static _FORCE_INLINE_ Variant::Type vc_get_argument_type_static(R (*method)(P...), int p_arg) {
return call_get_argument_type<P...>(p_arg);
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ Variant::Type vc_get_return_type(R (T::*method)(P...)) {
return GetTypeInfo<R>::VARIANT_TYPE;
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ Variant::Type vc_get_return_type(R (T::*method)(P...) const) {
return GetTypeInfo<R>::VARIANT_TYPE;
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ Variant::Type vc_get_return_type(void (T::*method)(P...)) {
return Variant::NIL;
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ Variant::Type vc_get_return_type(void (T::*method)(P...) const) {
return Variant::NIL;
}
-template <class R, class... P>
+template <typename R, typename... P>
static _FORCE_INLINE_ Variant::Type vc_get_return_type(R (*method)(P...)) {
return GetTypeInfo<R>::VARIANT_TYPE;
}
-template <class... P>
+template <typename... P>
static _FORCE_INLINE_ Variant::Type vc_get_return_type(void (*method)(P...)) {
return Variant::NIL;
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ bool vc_has_return_type(R (T::*method)(P...)) {
return true;
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ bool vc_has_return_type(R (T::*method)(P...) const) {
return true;
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ bool vc_has_return_type(void (T::*method)(P...)) {
return false;
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ bool vc_has_return_type(void (T::*method)(P...) const) {
return false;
}
-template <class... P>
+template <typename... P>
static _FORCE_INLINE_ bool vc_has_return_type_static(void (*method)(P...)) {
return false;
}
-template <class R, class... P>
+template <typename R, typename... P>
static _FORCE_INLINE_ bool vc_has_return_type_static(R (*method)(P...)) {
return true;
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ bool vc_is_const(R (T::*method)(P...)) {
return false;
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ bool vc_is_const(R (T::*method)(P...) const) {
return true;
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ bool vc_is_const(void (T::*method)(P...)) {
return false;
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ bool vc_is_const(void (T::*method)(P...) const) {
return true;
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ Variant::Type vc_get_base_type(R (T::*method)(P...)) {
return GetTypeInfo<T>::VARIANT_TYPE;
}
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ Variant::Type vc_get_base_type(R (T::*method)(P...) const) {
return GetTypeInfo<T>::VARIANT_TYPE;
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ Variant::Type vc_get_base_type(void (T::*method)(P...)) {
return GetTypeInfo<T>::VARIANT_TYPE;
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ Variant::Type vc_get_base_type(void (T::*method)(P...) const) {
return GetTypeInfo<T>::VARIANT_TYPE;
}
@@ -450,12 +450,12 @@ static _FORCE_INLINE_ Variant::Type vc_get_base_type(void (T::*method)(P...) con
} \
};
-template <class R, class... P>
+template <typename R, typename... P>
static _FORCE_INLINE_ void vc_static_ptrcall(R (*method)(P...), const void **p_args, void *r_ret) {
call_with_ptr_args_static_method_ret<R, P...>(method, p_args, r_ret);
}
-template <class... P>
+template <typename... P>
static _FORCE_INLINE_ void vc_static_ptrcall(void (*method)(P...), const void **p_args, void *r_ret) {
call_with_ptr_args_static_method<P...>(method, p_args);
}
@@ -500,12 +500,12 @@ static _FORCE_INLINE_ void vc_static_ptrcall(void (*method)(P...), const void **
} \
};
-template <class R, class T, class... P>
+template <typename R, typename T, typename... P>
static _FORCE_INLINE_ void vc_ptrcall(R (*method)(T *, P...), void *p_base, const void **p_args, void *r_ret) {
call_with_ptr_args_static_retc<T, R, P...>(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
}
-template <class T, class... P>
+template <typename T, typename... P>
static _FORCE_INLINE_ void vc_ptrcall(void (*method)(T *, P...), void *p_base, const void **p_args, void *r_ret) {
call_with_ptr_args_static<T, P...>(reinterpret_cast<T *>(p_base), method, p_args);
}
@@ -1053,6 +1053,10 @@ struct _VariantCall {
r_ret = callable->bindp(p_args, p_argcount);
}
+ static int func_Callable_get_argument_count(Callable *p_callable) {
+ return p_callable->get_argument_count();
+ }
+
static void func_Signal_emit(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
Signal *signal = VariantGetInternalPtr<Signal>::get_ptr(v);
signal->emit(p_args, p_argcount);
@@ -1160,7 +1164,7 @@ typedef OAHashMap<StringName, VariantBuiltInMethodInfo> BuiltinMethodMap;
static BuiltinMethodMap *builtin_method_info;
static List<StringName> *builtin_method_names;
-template <class T>
+template <typename T>
static void register_builtin_method(const Vector<String> &p_argnames, const Vector<Variant> &p_def_args) {
StringName name = T::get_name();
@@ -2048,6 +2052,7 @@ static void _register_variant_builtin_methods() {
bind_method(Callable, get_object, sarray(), varray());
bind_method(Callable, get_object_id, sarray(), varray());
bind_method(Callable, get_method, sarray(), varray());
+ bind_function(Callable, get_argument_count, _VariantCall::func_Callable_get_argument_count, sarray(), varray());
bind_method(Callable, get_bound_arguments_count, sarray(), varray());
bind_method(Callable, get_bound_arguments, sarray(), varray());
bind_method(Callable, hash, sarray(), varray());
diff --git a/core/variant/variant_callable.cpp b/core/variant/variant_callable.cpp
index dc31b6d1ac..21f9a4f52b 100644
--- a/core/variant/variant_callable.cpp
+++ b/core/variant/variant_callable.cpp
@@ -68,6 +68,15 @@ ObjectID VariantCallable::get_object() const {
return ObjectID();
}
+int VariantCallable::get_argument_count(bool &r_is_valid) const {
+ if (!Variant::has_builtin_method(variant.get_type(), method)) {
+ r_is_valid = false;
+ return 0;
+ }
+ r_is_valid = true;
+ return Variant::get_builtin_method_argument_count(variant.get_type(), method);
+}
+
void VariantCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
Variant v = variant;
v.callp(method, p_arguments, p_argcount, r_return_value, r_call_error);
diff --git a/core/variant/variant_callable.h b/core/variant/variant_callable.h
index 3f2b058aaf..1811f3bb9a 100644
--- a/core/variant/variant_callable.h
+++ b/core/variant/variant_callable.h
@@ -50,6 +50,7 @@ public:
bool is_valid() const override;
StringName get_method() const override;
ObjectID get_object() const override;
+ int get_argument_count(bool &r_is_valid) const override;
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
VariantCallable(const Variant &p_variant, const StringName &p_method);
diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp
index 3427950224..b0ed49be5d 100644
--- a/core/variant/variant_construct.cpp
+++ b/core/variant/variant_construct.cpp
@@ -41,7 +41,7 @@ struct VariantConstructData {
static LocalVector<VariantConstructData> construct_data[Variant::VARIANT_MAX];
-template <class T>
+template <typename T>
static void add_constructor(const Vector<String> &arg_names) {
ERR_FAIL_COND_MSG(arg_names.size() != T::get_argument_count(), "Argument names size mismatch for " + Variant::get_type_name(T::get_base_type()) + ".");
diff --git a/core/variant/variant_construct.h b/core/variant/variant_construct.h
index 36935907ae..a93723a910 100644
--- a/core/variant/variant_construct.h
+++ b/core/variant/variant_construct.h
@@ -42,7 +42,7 @@
#include "core/templates/local_vector.h"
#include "core/templates/oa_hash_map.h"
-template <class T>
+template <typename T>
struct PtrConstruct {};
#define MAKE_PTRCONSTRUCT(m_type) \
@@ -99,7 +99,7 @@ MAKE_PTRCONSTRUCT(PackedVector3Array);
MAKE_PTRCONSTRUCT(PackedColorArray);
MAKE_PTRCONSTRUCT(Variant);
-template <class T, class... P>
+template <typename T, typename... P>
class VariantConstructor {
template <size_t... Is>
static _FORCE_INLINE_ void construct_helper(T &base, const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
@@ -222,7 +222,7 @@ public:
}
};
-template <class T>
+template <typename T>
class VariantConstructorFromString {
public:
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
@@ -470,7 +470,7 @@ public:
}
};
-template <class T>
+template <typename T>
class VariantConstructorToArray {
public:
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
@@ -529,7 +529,7 @@ public:
}
};
-template <class T>
+template <typename T>
class VariantConstructorFromArray {
public:
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
@@ -622,7 +622,7 @@ public:
}
};
-template <class T>
+template <typename T>
class VariantConstructNoArgs {
public:
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
diff --git a/core/variant/variant_destruct.cpp b/core/variant/variant_destruct.cpp
index 5308eba97d..c7455d5117 100644
--- a/core/variant/variant_destruct.cpp
+++ b/core/variant/variant_destruct.cpp
@@ -34,7 +34,7 @@
static Variant::PTRDestructor destruct_pointers[Variant::VARIANT_MAX] = { nullptr };
-template <class T>
+template <typename T>
static void add_destructor() {
destruct_pointers[T::get_base_type()] = T::ptr_destruct;
}
diff --git a/core/variant/variant_destruct.h b/core/variant/variant_destruct.h
index c5f9c260c0..c496189c6d 100644
--- a/core/variant/variant_destruct.h
+++ b/core/variant/variant_destruct.h
@@ -35,7 +35,7 @@
#include "core/object/class_db.h"
-template <class T>
+template <typename T>
struct VariantDestruct {};
#define MAKE_PTRDESTRUCT(m_type) \
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
index 79bed9be33..dbd4a6a7ad 100644
--- a/core/variant/variant_internal.h
+++ b/core/variant/variant_internal.h
@@ -211,7 +211,7 @@ public:
_FORCE_INLINE_ static const ObjectID get_object_id(const Variant *v) { return v->_get_obj().id; }
- template <class T>
+ template <typename T>
_FORCE_INLINE_ static void init_generic(Variant *v) {
v->type = GetTypeInfo<T>::VARIANT_TYPE;
}
@@ -510,7 +510,7 @@ public:
}
};
-template <class T>
+template <typename T>
struct VariantGetInternalPtr {
};
@@ -797,7 +797,7 @@ struct VariantGetInternalPtr<PackedColorArray> {
static const PackedColorArray *get_ptr(const Variant *v) { return VariantInternal::get_color_array(v); }
};
-template <class T>
+template <typename T>
struct VariantInternalAccessor {
};
@@ -830,13 +830,13 @@ struct VariantInternalAccessor<ObjectID> {
static _FORCE_INLINE_ void set(Variant *v, ObjectID p_value) { *VariantInternal::get_int(v) = p_value; }
};
-template <class T>
+template <typename T>
struct VariantInternalAccessor<T *> {
static _FORCE_INLINE_ T *get(const Variant *v) { return const_cast<T *>(static_cast<const T *>(*VariantInternal::get_object(v))); }
static _FORCE_INLINE_ void set(Variant *v, const T *p_value) { VariantInternal::object_assign(v, p_value); }
};
-template <class T>
+template <typename T>
struct VariantInternalAccessor<const T *> {
static _FORCE_INLINE_ const T *get(const Variant *v) { return static_cast<const T *>(*VariantInternal::get_object(v)); }
static _FORCE_INLINE_ void set(Variant *v, const T *p_value) { VariantInternal::object_assign(v, p_value); }
@@ -1091,7 +1091,7 @@ struct VariantInternalAccessor<Vector<Variant>> {
}
};
-template <class T>
+template <typename T>
struct VariantInitializer {
};
@@ -1301,7 +1301,7 @@ struct VariantInitializer<Object *> {
static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_object(v); }
};
-template <class T>
+template <typename T>
struct VariantDefaultInitializer {
};
@@ -1490,7 +1490,7 @@ struct VariantDefaultInitializer<PackedColorArray> {
static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_color_array(v) = PackedColorArray(); }
};
-template <class T>
+template <typename T>
struct VariantTypeChanger {
static _FORCE_INLINE_ void change(Variant *v) {
if (v->get_type() != GetTypeInfo<T>::VARIANT_TYPE || GetTypeInfo<T>::VARIANT_TYPE >= Variant::PACKED_BYTE_ARRAY) { //second condition removed by optimizer
@@ -1508,7 +1508,7 @@ struct VariantTypeChanger {
}
};
-template <class T>
+template <typename T>
struct VariantTypeAdjust {
_FORCE_INLINE_ static void adjust(Variant *r_ret) {
VariantTypeChanger<typename GetSimpleTypeT<T>::type_t>::change(r_ret);
@@ -1532,7 +1532,7 @@ struct VariantTypeAdjust<Object *> {
// GDExtension helpers.
-template <class T>
+template <typename T>
struct VariantTypeConstructor {
_FORCE_INLINE_ static void variant_from_type(void *r_variant, void *p_value) {
// r_variant is provided by caller as uninitialized memory
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index 4f9c38dc4c..60ae09c6f1 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -37,7 +37,7 @@ static VariantEvaluatorFunction operator_evaluator_table[Variant::OP_MAX][Varian
static Variant::ValidatedOperatorEvaluator validated_operator_evaluator_table[Variant::OP_MAX][Variant::VARIANT_MAX][Variant::VARIANT_MAX];
static Variant::PTROperatorEvaluator ptr_operator_evaluator_table[Variant::OP_MAX][Variant::VARIANT_MAX][Variant::VARIANT_MAX];
-template <class T>
+template <typename T>
void register_op(Variant::Operator p_op, Variant::Type p_type_a, Variant::Type p_type_b) {
operator_return_type_table[p_op][p_type_a][p_type_b] = T::get_return_type();
operator_evaluator_table[p_op][p_type_a][p_type_b] = T::evaluate;
diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h
index 17ad126891..3142f49fc6 100644
--- a/core/variant/variant_op.h
+++ b/core/variant/variant_op.h
@@ -37,7 +37,7 @@
#include "core/debugger/engine_debugger.h"
#include "core/object/class_db.h"
-template <class R, class A, class B>
+template <typename R, typename A, typename B>
class OperatorEvaluatorAdd {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -55,7 +55,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
};
-template <class R, class A, class B>
+template <typename R, typename A, typename B>
class OperatorEvaluatorSub {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -73,7 +73,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
};
-template <class R, class A, class B>
+template <typename R, typename A, typename B>
class OperatorEvaluatorMul {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -91,7 +91,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
};
-template <class R, class A, class B>
+template <typename R, typename A, typename B>
class OperatorEvaluatorPow {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -109,7 +109,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
};
-template <class R, class A, class B>
+template <typename R, typename A, typename B>
class OperatorEvaluatorXForm {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -127,7 +127,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
};
-template <class R, class A, class B>
+template <typename R, typename A, typename B>
class OperatorEvaluatorXFormInv {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -145,7 +145,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
};
-template <class R, class A, class B>
+template <typename R, typename A, typename B>
class OperatorEvaluatorDiv {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -163,7 +163,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
};
-template <class R, class A, class B>
+template <typename R, typename A, typename B>
class OperatorEvaluatorDivNZ {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -258,7 +258,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<Vector4i>::VARIANT_TYPE; }
};
-template <class R, class A, class B>
+template <typename R, typename A, typename B>
class OperatorEvaluatorMod {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -276,7 +276,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
};
-template <class R, class A, class B>
+template <typename R, typename A, typename B>
class OperatorEvaluatorModNZ {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -371,7 +371,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<Vector4i>::VARIANT_TYPE; }
};
-template <class R, class A>
+template <typename R, typename A>
class OperatorEvaluatorNeg {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -388,7 +388,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
};
-template <class R, class A>
+template <typename R, typename A>
class OperatorEvaluatorPos {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -405,7 +405,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
};
-template <class R, class A, class B>
+template <typename R, typename A, typename B>
class OperatorEvaluatorShiftLeft {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -431,7 +431,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
};
-template <class R, class A, class B>
+template <typename R, typename A, typename B>
class OperatorEvaluatorShiftRight {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -457,7 +457,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
};
-template <class R, class A, class B>
+template <typename R, typename A, typename B>
class OperatorEvaluatorBitOr {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -475,7 +475,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
};
-template <class R, class A, class B>
+template <typename R, typename A, typename B>
class OperatorEvaluatorBitAnd {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -493,7 +493,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
};
-template <class R, class A, class B>
+template <typename R, typename A, typename B>
class OperatorEvaluatorBitXor {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -511,7 +511,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
};
-template <class R, class A>
+template <typename R, typename A>
class OperatorEvaluatorBitNeg {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -528,7 +528,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
};
-template <class A, class B>
+template <typename A, typename B>
class OperatorEvaluatorEqual {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -599,7 +599,7 @@ public:
static Variant::Type get_return_type() { return Variant::BOOL; }
};
-template <class A, class B>
+template <typename A, typename B>
class OperatorEvaluatorNotEqual {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -670,7 +670,7 @@ public:
static Variant::Type get_return_type() { return Variant::BOOL; }
};
-template <class A, class B>
+template <typename A, typename B>
class OperatorEvaluatorLess {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -688,7 +688,7 @@ public:
static Variant::Type get_return_type() { return Variant::BOOL; }
};
-template <class A, class B>
+template <typename A, typename B>
class OperatorEvaluatorLessEqual {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -706,7 +706,7 @@ public:
static Variant::Type get_return_type() { return Variant::BOOL; }
};
-template <class A, class B>
+template <typename A, typename B>
class OperatorEvaluatorGreater {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -724,7 +724,7 @@ public:
static Variant::Type get_return_type() { return Variant::BOOL; }
};
-template <class A, class B>
+template <typename A, typename B>
class OperatorEvaluatorGreaterEqual {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -742,7 +742,7 @@ public:
static Variant::Type get_return_type() { return Variant::BOOL; }
};
-template <class A, class B>
+template <typename A, typename B>
class OperatorEvaluatorAnd {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -760,7 +760,7 @@ public:
static Variant::Type get_return_type() { return Variant::BOOL; }
};
-template <class A, class B>
+template <typename A, typename B>
class OperatorEvaluatorOr {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -779,7 +779,7 @@ public:
};
#define XOR_OP(m_a, m_b) (((m_a) || (m_b)) && !((m_a) && (m_b)))
-template <class A, class B>
+template <typename A, typename B>
class OperatorEvaluatorXor {
public:
_FORCE_INLINE_ static bool xor_op(const A &a, const B &b) {
@@ -800,7 +800,7 @@ public:
static Variant::Type get_return_type() { return Variant::BOOL; }
};
-template <class A>
+template <typename A>
class OperatorEvaluatorNot {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -857,7 +857,7 @@ public:
static Variant::Type get_return_type() { return Variant::ARRAY; }
};
-template <class T>
+template <typename T>
class OperatorEvaluatorAppendArray {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -880,7 +880,7 @@ public:
static Variant::Type get_return_type() { return GetTypeInfo<Vector<T>>::VARIANT_TYPE; }
};
-template <class Left, class Right>
+template <typename Left, typename Right>
class OperatorEvaluatorStringConcat {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -902,10 +902,10 @@ public:
static Variant::Type get_return_type() { return Variant::STRING; }
};
-template <class S, class T>
+template <typename S, typename T>
class OperatorEvaluatorStringFormat;
-template <class S>
+template <typename S>
class OperatorEvaluatorStringFormat<S, void> {
public:
_FORCE_INLINE_ static String do_mod(const String &s, bool *r_valid) {
@@ -933,7 +933,7 @@ public:
static Variant::Type get_return_type() { return Variant::STRING; }
};
-template <class S>
+template <typename S>
class OperatorEvaluatorStringFormat<S, Array> {
public:
_FORCE_INLINE_ static String do_mod(const String &s, const Array &p_values, bool *r_valid) {
@@ -958,7 +958,7 @@ public:
static Variant::Type get_return_type() { return Variant::STRING; }
};
-template <class S>
+template <typename S>
class OperatorEvaluatorStringFormat<S, Object> {
public:
_FORCE_INLINE_ static String do_mod(const String &s, const Object *p_object, bool *r_valid) {
@@ -986,7 +986,7 @@ public:
static Variant::Type get_return_type() { return Variant::STRING; }
};
-template <class S, class T>
+template <typename S, typename T>
class OperatorEvaluatorStringFormat {
public:
_FORCE_INLINE_ static String do_mod(const String &s, const T &p_value, bool *r_valid) {
@@ -1317,10 +1317,10 @@ public:
////
-template <class Left, class Right>
+template <typename Left, typename Right>
class OperatorEvaluatorInStringFind;
-template <class Left>
+template <typename Left>
class OperatorEvaluatorInStringFind<Left, String> {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -1341,7 +1341,7 @@ public:
static Variant::Type get_return_type() { return Variant::BOOL; }
};
-template <class Left>
+template <typename Left>
class OperatorEvaluatorInStringFind<Left, StringName> {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -1362,7 +1362,7 @@ public:
static Variant::Type get_return_type() { return Variant::BOOL; }
};
-template <class A, class B>
+template <typename A, typename B>
class OperatorEvaluatorInArrayFind {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
@@ -1417,7 +1417,7 @@ public:
static Variant::Type get_return_type() { return Variant::BOOL; }
};
-template <class A>
+template <typename A>
class OperatorEvaluatorInDictionaryHas {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index e35751fd61..46c450d9f8 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -546,7 +546,7 @@ Error VariantParser::_parse_enginecfg(Stream *p_stream, Vector<String> &strings,
}
}
-template <class T>
+template <typename T>
Error VariantParser::_parse_construct(Stream *p_stream, Vector<T> &r_construct, int &line, String &r_err_str) {
Token token;
get_token(p_stream, token, line, r_err_str);
diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h
index 8505fff739..18448100e0 100644
--- a/core/variant/variant_parser.h
+++ b/core/variant/variant_parser.h
@@ -139,7 +139,7 @@ public:
private:
static const char *tk_name[TK_MAX];
- template <class T>
+ template <typename T>
static Error _parse_construct(Stream *p_stream, Vector<T> &r_construct, int &line, String &r_err_str);
static Error _parse_enginecfg(Stream *p_stream, Vector<String> &strings, int &line, String &r_err_str);
static Error _parse_dictionary(Dictionary &object, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser = nullptr);
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index 20941b944f..9d5ed22b1a 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -45,7 +45,7 @@ struct VariantSetterGetterInfo {
static LocalVector<VariantSetterGetterInfo> variant_setters_getters[Variant::VARIANT_MAX];
static LocalVector<StringName> variant_setters_getters_names[Variant::VARIANT_MAX]; //one next to another to make it cache friendly
-template <class T>
+template <typename T>
static void register_member(Variant::Type p_type, const StringName &p_member) {
VariantSetterGetterInfo sgi;
sgi.setter = T::set;
@@ -873,7 +873,7 @@ struct VariantIndexedSetterGetterInfo {
static VariantIndexedSetterGetterInfo variant_indexed_setters_getters[Variant::VARIANT_MAX];
-template <class T>
+template <typename T>
static void register_indexed_member(Variant::Type p_type) {
VariantIndexedSetterGetterInfo &sgi = variant_indexed_setters_getters[p_type];
@@ -1094,7 +1094,7 @@ struct VariantKeyedSetterGetterInfo {
static VariantKeyedSetterGetterInfo variant_keyed_setters_getters[Variant::VARIANT_MAX];
-template <class T>
+template <typename T>
static void register_keyed_member(Variant::Type p_type) {
VariantKeyedSetterGetterInfo &sgi = variant_keyed_setters_getters[p_type];
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index 7136fa00c4..916ba7aa2f 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -1235,7 +1235,7 @@ bool VariantUtilityFunctions::is_same(const Variant &p_a, const Variant &p_b) {
#define VCALL p_func(VariantCaster<P>::cast(*p_args[Is])...)
#endif
-template <class R, class... P, size_t... Is>
+template <typename R, typename... P, size_t... Is>
static _FORCE_INLINE_ void call_helperpr(R (*p_func)(P...), Variant *ret, const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
r_error.error = Callable::CallError::CALL_OK;
VCALLR;
@@ -1243,51 +1243,51 @@ static _FORCE_INLINE_ void call_helperpr(R (*p_func)(P...), Variant *ret, const
(void)r_error;
}
-template <class R, class... P, size_t... Is>
+template <typename R, typename... P, size_t... Is>
static _FORCE_INLINE_ void validated_call_helperpr(R (*p_func)(P...), Variant *ret, const Variant **p_args, IndexSequence<Is...>) {
*ret = p_func(VariantCaster<P>::cast(*p_args[Is])...);
(void)p_args;
}
-template <class R, class... P, size_t... Is>
+template <typename R, typename... P, size_t... Is>
static _FORCE_INLINE_ void ptr_call_helperpr(R (*p_func)(P...), void *ret, const void **p_args, IndexSequence<Is...>) {
PtrToArg<R>::encode(p_func(PtrToArg<P>::convert(p_args[Is])...), ret);
(void)p_args;
}
-template <class R, class... P>
+template <typename R, typename... P>
static _FORCE_INLINE_ void call_helperr(R (*p_func)(P...), Variant *ret, const Variant **p_args, Callable::CallError &r_error) {
call_helperpr(p_func, ret, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
-template <class R, class... P>
+template <typename R, typename... P>
static _FORCE_INLINE_ void validated_call_helperr(R (*p_func)(P...), Variant *ret, const Variant **p_args) {
validated_call_helperpr(p_func, ret, p_args, BuildIndexSequence<sizeof...(P)>{});
}
-template <class R, class... P>
+template <typename R, typename... P>
static _FORCE_INLINE_ void ptr_call_helperr(R (*p_func)(P...), void *ret, const void **p_args) {
ptr_call_helperpr(p_func, ret, p_args, BuildIndexSequence<sizeof...(P)>{});
}
-template <class R, class... P>
+template <typename R, typename... P>
static _FORCE_INLINE_ int get_arg_count_helperr(R (*p_func)(P...)) {
return sizeof...(P);
}
-template <class R, class... P>
+template <typename R, typename... P>
static _FORCE_INLINE_ Variant::Type get_arg_type_helperr(R (*p_func)(P...), int p_arg) {
return call_get_argument_type<P...>(p_arg);
}
-template <class R, class... P>
+template <typename R, typename... P>
static _FORCE_INLINE_ Variant::Type get_ret_type_helperr(R (*p_func)(P...)) {
return GetTypeInfo<R>::VARIANT_TYPE;
}
// WITHOUT RET
-template <class... P, size_t... Is>
+template <typename... P, size_t... Is>
static _FORCE_INLINE_ void call_helperp(void (*p_func)(P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
r_error.error = Callable::CallError::CALL_OK;
VCALL;
@@ -1295,44 +1295,44 @@ static _FORCE_INLINE_ void call_helperp(void (*p_func)(P...), const Variant **p_
(void)r_error;
}
-template <class... P, size_t... Is>
+template <typename... P, size_t... Is>
static _FORCE_INLINE_ void validated_call_helperp(void (*p_func)(P...), const Variant **p_args, IndexSequence<Is...>) {
p_func(VariantCaster<P>::cast(*p_args[Is])...);
(void)p_args;
}
-template <class... P, size_t... Is>
+template <typename... P, size_t... Is>
static _FORCE_INLINE_ void ptr_call_helperp(void (*p_func)(P...), const void **p_args, IndexSequence<Is...>) {
p_func(PtrToArg<P>::convert(p_args[Is])...);
(void)p_args;
}
-template <class... P>
+template <typename... P>
static _FORCE_INLINE_ void call_helper(void (*p_func)(P...), const Variant **p_args, Callable::CallError &r_error) {
call_helperp(p_func, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
-template <class... P>
+template <typename... P>
static _FORCE_INLINE_ void validated_call_helper(void (*p_func)(P...), const Variant **p_args) {
validated_call_helperp(p_func, p_args, BuildIndexSequence<sizeof...(P)>{});
}
-template <class... P>
+template <typename... P>
static _FORCE_INLINE_ void ptr_call_helper(void (*p_func)(P...), const void **p_args) {
ptr_call_helperp(p_func, p_args, BuildIndexSequence<sizeof...(P)>{});
}
-template <class... P>
+template <typename... P>
static _FORCE_INLINE_ int get_arg_count_helper(void (*p_func)(P...)) {
return sizeof...(P);
}
-template <class... P>
+template <typename... P>
static _FORCE_INLINE_ Variant::Type get_arg_type_helper(void (*p_func)(P...), int p_arg) {
return call_get_argument_type<P...>(p_arg);
}
-template <class... P>
+template <typename... P>
static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) {
return Variant::NIL;
}
@@ -1645,7 +1645,7 @@ struct VariantUtilityFunctionInfo {
static OAHashMap<StringName, VariantUtilityFunctionInfo> utility_function_table;
static List<StringName> utility_function_name_table;
-template <class T>
+template <typename T>
static void register_utility_function(const String &p_name, const Vector<String> &argnames) {
String name = p_name;
if (name.begins_with("_")) {
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 095756c1b1..3a1bd83c18 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -1099,14 +1099,14 @@
<method name="rid_allocate_id">
<return type="int" />
<description>
- Allocates a unique ID which can be used by the implementation to construct a RID. This is used mainly from native extensions to implement servers.
+ Allocates a unique ID which can be used by the implementation to construct an RID. This is used mainly from native extensions to implement servers.
</description>
</method>
<method name="rid_from_int64">
<return type="RID" />
<param index="0" name="base" type="int" />
<description>
- Creates a RID from a [param base]. This is used mainly from native extensions to build servers.
+ Creates an RID from a [param base]. This is used mainly from native extensions to build servers.
</description>
</method>
<method name="rotate_toward">
diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml
index dde7153d5f..0f6bf89cd7 100644
--- a/doc/classes/ArrayMesh.xml
+++ b/doc/classes/ArrayMesh.xml
@@ -71,7 +71,7 @@
Surfaces are created to be rendered using a [param primitive], which may be any of the values defined in [enum Mesh.PrimitiveType].
The [param arrays] argument is an array of arrays. Each of the [constant Mesh.ARRAY_MAX] elements contains an array with some of the mesh data for this surface as described by the corresponding member of [enum Mesh.ArrayType] or [code]null[/code] if it is not used by the surface. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this surface into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used.
The [param blend_shapes] argument is an array of vertex data for each blend shape. Each element is an array of the same structure as [param arrays], but [constant Mesh.ARRAY_VERTEX], [constant Mesh.ARRAY_NORMAL], and [constant Mesh.ARRAY_TANGENT] are set if and only if they are set in [param arrays] and all other entries are [code]null[/code].
- The [param lods] argument is a dictionary with [float] keys and [PackedInt32Array] values. Each entry in the dictionary represents a LOD level of the surface, where the value is the [constant Mesh.ARRAY_INDEX] array to use for the LOD level and the key is roughly proportional to the distance at which the LOD stats being used. I.e., increasing the key of a LOD also increases the distance that the objects has to be from the camera before the LOD is used.
+ The [param lods] argument is a dictionary with [float] keys and [PackedInt32Array] values. Each entry in the dictionary represents an LOD level of the surface, where the value is the [constant Mesh.ARRAY_INDEX] array to use for the LOD level and the key is roughly proportional to the distance at which the LOD stats being used. I.e., increasing the key of an LOD also increases the distance that the objects has to be from the camera before the LOD is used.
The [param flags] argument is the bitwise or of, as required: One value of [enum Mesh.ArrayCustomFormat] left shifted by [code]ARRAY_FORMAT_CUSTOMn_SHIFT[/code] for each custom channel in use, [constant Mesh.ARRAY_FLAG_USE_DYNAMIC_UPDATE], [constant Mesh.ARRAY_FLAG_USE_8_BONE_WEIGHTS], or [constant Mesh.ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY].
[b]Note:[/b] When using indices, it is recommended to only use points, lines, or triangles.
</description>
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index 3965fd4f8f..05174abb07 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -147,6 +147,12 @@
[b]Note:[/b] This method is always necessary for the [Dictionary] type, as property syntax is used to access its entries. You may also use this method when [param variant]'s type is not known in advance (for polymorphism).
</description>
</method>
+ <method name="get_argument_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the total number of arguments this [Callable] should take, including optional arguments. This means that any arguments bound with [method bind] are [i]subtracted[/i] from the result, and any arguments unbound with [method unbind] are [i]added[/i] to the result.
+ </description>
+ </method>
<method name="get_bound_arguments" qualifiers="const">
<return type="Array" />
<description>
diff --git a/doc/classes/ClassDB.xml b/doc/classes/ClassDB.xml
index d24181c3d3..3f71406091 100644
--- a/doc/classes/ClassDB.xml
+++ b/doc/classes/ClassDB.xml
@@ -65,6 +65,15 @@
Returns an array with the names all the integer constants of [param class] or its ancestry.
</description>
</method>
+ <method name="class_get_method_argument_count" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="class" type="StringName" />
+ <param index="1" name="method" type="StringName" />
+ <param index="2" name="no_inheritance" type="bool" default="false" />
+ <description>
+ Returns the number of arguments of the method [param method] of [param class] or its ancestry if [param no_inheritance] is [code]false[/code].
+ </description>
+ </method>
<method name="class_get_method_list" qualifiers="const">
<return type="Dictionary[]" />
<param index="0" name="class" type="StringName" />
diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml
index 517fb6bef7..942d3bc80d 100644
--- a/doc/classes/Color.xml
+++ b/doc/classes/Color.xml
@@ -181,7 +181,7 @@
<return type="Color" />
<param index="0" name="rgbe" type="int" />
<description>
- Decodes a [Color] from a RGBE9995 format integer. See [constant Image.FORMAT_RGBE9995].
+ Decodes a [Color] from an RGBE9995 format integer. See [constant Image.FORMAT_RGBE9995].
</description>
</method>
<method name="from_string" qualifiers="static">
diff --git a/doc/classes/Crypto.xml b/doc/classes/Crypto.xml
index 59d19b03f4..65abc4c641 100644
--- a/doc/classes/Crypto.xml
+++ b/doc/classes/Crypto.xml
@@ -123,7 +123,7 @@
<param index="3" name="not_after" type="String" default="&quot;20340101000000&quot;" />
<description>
Generates a self-signed [X509Certificate] from the given [CryptoKey] and [param issuer_name]. The certificate validity will be defined by [param not_before] and [param not_after] (first valid date and last valid date). The [param issuer_name] must contain at least "CN=" (common name, i.e. the domain name), "O=" (organization, i.e. your company name), "C=" (country, i.e. 2 lettered ISO-3166 code of the country the organization is based in).
- A small example to generate an RSA key and a X509 self-signed certificate.
+ A small example to generate an RSA key and an X509 self-signed certificate.
[codeblocks]
[gdscript]
var crypto = Crypto.new()
diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml
index d923d229e0..ca78054875 100644
--- a/doc/classes/Engine.xml
+++ b/doc/classes/Engine.xml
@@ -28,7 +28,7 @@
GD.Print("Running a 32-bit build of Godot.");
[/csharp]
[/codeblocks]
- [b]Note:[/b] This method does [i]not[/i] return the name of the system's CPU architecture (like [method OS.get_processor_name]). For example, when running a [code]x86_32[/code] Godot binary on a [code]x86_64[/code] system, the returned value will still be [code]"x86_32"[/code].
+ [b]Note:[/b] This method does [i]not[/i] return the name of the system's CPU architecture (like [method OS.get_processor_name]). For example, when running an [code]x86_32[/code] Godot binary on an [code]x86_64[/code] system, the returned value will still be [code]"x86_32"[/code].
</description>
</method>
<method name="get_author_info" qualifiers="const">
@@ -314,7 +314,7 @@
The maximum number of frames that can be rendered every second (FPS). A value of [code]0[/code] means the framerate is uncapped.
Limiting the FPS can be useful to reduce the host machine's power consumption, which reduces heat, noise emissions, and improves battery life.
If [member ProjectSettings.display/window/vsync/vsync_mode] is [b]Enabled[/b] or [b]Adaptive[/b], the setting takes precedence and the max FPS number cannot exceed the monitor's refresh rate.
- If [member ProjectSettings.display/window/vsync/vsync_mode] is [b]Enabled[/b], on monitors with variable refresh rate enabled (G-Sync/FreeSync), using a FPS limit a few frames lower than the monitor's refresh rate will [url=https://blurbusters.com/howto-low-lag-vsync-on/]reduce input lag while avoiding tearing[/url].
+ If [member ProjectSettings.display/window/vsync/vsync_mode] is [b]Enabled[/b], on monitors with variable refresh rate enabled (G-Sync/FreeSync), using an FPS limit a few frames lower than the monitor's refresh rate will [url=https://blurbusters.com/howto-low-lag-vsync-on/]reduce input lag while avoiding tearing[/url].
See also [member physics_ticks_per_second] and [member ProjectSettings.application/run/max_fps].
[b]Note:[/b] The actual number of frames per second may still be below this value if the CPU or GPU cannot keep up with the project's logic and rendering.
[b]Note:[/b] If [member ProjectSettings.display/window/vsync/vsync_mode] is [b]Disabled[/b], limiting the FPS to a high value that can be consistently reached on the system can reduce input lag compared to an uncapped framerate. Since this works by ensuring the GPU load is lower than 100%, this latency reduction is only effective in GPU-bottlenecked scenarios, not CPU-bottlenecked scenarios.
diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml
index bf91d02b3a..189517c392 100644
--- a/doc/classes/Environment.xml
+++ b/doc/classes/Environment.xml
@@ -317,7 +317,7 @@
The default exposure used for tonemapping. Higher values result in a brighter image. See also [member tonemap_white].
</member>
<member name="tonemap_mode" type="int" setter="set_tonemapper" getter="get_tonemapper" enum="Environment.ToneMapper" default="0">
- The tonemapping mode to use. Tonemapping is the process that "converts" HDR values to be suitable for rendering on a LDR display. (Godot doesn't support rendering on HDR displays yet.)
+ The tonemapping mode to use. Tonemapping is the process that "converts" HDR values to be suitable for rendering on an LDR display. (Godot doesn't support rendering on HDR displays yet.)
</member>
<member name="tonemap_white" type="float" setter="set_tonemap_white" getter="get_tonemap_white" default="1.0">
The white reference value for tonemapping (also called "whitepoint"). Higher values can make highlights look less blown out, and will also slightly darken the whole scene as a result. Only effective if the [member tonemap_mode] isn't set to [constant TONE_MAPPER_LINEAR]. See also [member tonemap_exposure].
diff --git a/doc/classes/FileAccess.xml b/doc/classes/FileAccess.xml
index 2abd9974ca..fad6cbcc93 100644
--- a/doc/classes/FileAccess.xml
+++ b/doc/classes/FileAccess.xml
@@ -257,7 +257,7 @@
<return type="String" />
<param index="0" name="path" type="String" />
<description>
- Returns a SHA-256 [String] representing the file at the given path or an empty [String] on failure.
+ Returns an SHA-256 [String] representing the file at the given path or an empty [String] on failure.
</description>
</method>
<method name="get_unix_permissions" qualifiers="static">
diff --git a/doc/classes/FontFile.xml b/doc/classes/FontFile.xml
index 424f1931ff..1b8fa00772 100644
--- a/doc/classes/FontFile.xml
+++ b/doc/classes/FontFile.xml
@@ -42,7 +42,7 @@
<param index="0" name="cache_index" type="int" />
<param index="1" name="size" type="Vector2i" />
<description>
- Removes all rendered glyphs information from the cache entry.
+ Removes all rendered glyph information from the cache entry.
[b]Note:[/b] This function will not remove textures associated with the glyphs, use [method remove_texture] to remove them manually.
</description>
</method>
@@ -579,7 +579,7 @@
<param index="0" name="cache_index" type="int" />
<param index="1" name="transform" type="Transform2D" />
<description>
- Sets 2D transform, applied to the font outlines, can be used for slanting, flipping and rotating glyphs.
+ Sets 2D transform, applied to the font outlines, can be used for slanting, flipping, and rotating glyphs.
</description>
</method>
<method name="set_variation_coordinates">
diff --git a/doc/classes/HashingContext.xml b/doc/classes/HashingContext.xml
index 86d69bc2f7..f2681ae7b3 100644
--- a/doc/classes/HashingContext.xml
+++ b/doc/classes/HashingContext.xml
@@ -14,7 +14,7 @@
# Check that file exists.
if not FileAccess.file_exists(path):
return
- # Start a SHA-256 context.
+ # Start an SHA-256 context.
var ctx = HashingContext.new()
ctx.start(HashingContext.HASH_SHA256)
# Open the file to hash.
@@ -37,7 +37,7 @@
{
return;
}
- // Start a SHA-256 context.
+ // Start an SHA-256 context.
var ctx = new HashingContext();
ctx.Start(HashingContext.HashType.Sha256);
// Open the file to hash.
@@ -68,7 +68,7 @@
<return type="int" enum="Error" />
<param index="0" name="type" type="int" enum="HashingContext.HashType" />
<description>
- Starts a new hash computation of the given [param type] (e.g. [constant HASH_SHA256] to start computation of a SHA-256).
+ Starts a new hash computation of the given [param type] (e.g. [constant HASH_SHA256] to start computation of an SHA-256).
</description>
</method>
<method name="update">
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index 67b373ddfe..68d4deaffd 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -368,7 +368,7 @@
<param index="0" name="svg_str" type="String" />
<param index="1" name="scale" type="float" default="1.0" />
<description>
- Loads an image from the string contents of a SVG file ([b].svg[/b]).
+ Loads an image from the string contents of an SVG file ([b].svg[/b]).
[b]Note:[/b] This method is only available in engine builds with the SVG module enabled. By default, the SVG module is enabled, but it can be disabled at build-time using the [code]module_svg_enabled=no[/code] SCons option.
</description>
</method>
diff --git a/doc/classes/ImporterMesh.xml b/doc/classes/ImporterMesh.xml
index 9bc1bf035e..eeabcd6e12 100644
--- a/doc/classes/ImporterMesh.xml
+++ b/doc/classes/ImporterMesh.xml
@@ -31,7 +31,7 @@
Surfaces are created to be rendered using a [param primitive], which may be any of the values defined in [enum Mesh.PrimitiveType].
The [param arrays] argument is an array of arrays. Each of the [constant Mesh.ARRAY_MAX] elements contains an array with some of the mesh data for this surface as described by the corresponding member of [enum Mesh.ArrayType] or [code]null[/code] if it is not used by the surface. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this surface into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used.
The [param blend_shapes] argument is an array of vertex data for each blend shape. Each element is an array of the same structure as [param arrays], but [constant Mesh.ARRAY_VERTEX], [constant Mesh.ARRAY_NORMAL], and [constant Mesh.ARRAY_TANGENT] are set if and only if they are set in [param arrays] and all other entries are [code]null[/code].
- The [param lods] argument is a dictionary with [float] keys and [PackedInt32Array] values. Each entry in the dictionary represents a LOD level of the surface, where the value is the [constant Mesh.ARRAY_INDEX] array to use for the LOD level and the key is roughly proportional to the distance at which the LOD stats being used. I.e., increasing the key of a LOD also increases the distance that the objects has to be from the camera before the LOD is used.
+ The [param lods] argument is a dictionary with [float] keys and [PackedInt32Array] values. Each entry in the dictionary represents an LOD level of the surface, where the value is the [constant Mesh.ARRAY_INDEX] array to use for the LOD level and the key is roughly proportional to the distance at which the LOD stats being used. I.e., increasing the key of an LOD also increases the distance that the objects has to be from the camera before the LOD is used.
The [param flags] argument is the bitwise or of, as required: One value of [enum Mesh.ArrayCustomFormat] left shifted by [code]ARRAY_FORMAT_CUSTOMn_SHIFT[/code] for each custom channel in use, [constant Mesh.ARRAY_FLAG_USE_DYNAMIC_UPDATE], [constant Mesh.ARRAY_FLAG_USE_8_BONE_WEIGHTS], or [constant Mesh.ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY].
[b]Note:[/b] When using indices, it is recommended to only use points, lines, or triangles.
</description>
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index abb04fd462..e622a6bce3 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -118,7 +118,7 @@
<return type="String" />
<param index="0" name="device" type="int" />
<description>
- Returns a SDL2-compatible device GUID on platforms that use gamepad remapping, e.g. [code]030000004c050000c405000000010000[/code]. Returns [code]"Default Gamepad"[/code] otherwise. Godot uses the [url=https://github.com/gabomdq/SDL_GameControllerDB]SDL2 game controller database[/url] to determine gamepad names and mappings based on this GUID.
+ Returns an SDL2-compatible device GUID on platforms that use gamepad remapping, e.g. [code]030000004c050000c405000000010000[/code]. Returns [code]"Default Gamepad"[/code] otherwise. Godot uses the [url=https://github.com/gabomdq/SDL_GameControllerDB]SDL2 game controller database[/url] to determine gamepad names and mappings based on this GUID.
</description>
</method>
<method name="get_joy_info" qualifiers="const">
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index 065b75382d..85b9cf16f2 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -711,6 +711,14 @@
Returns the object's metadata entry names as a [PackedStringArray].
</description>
</method>
+ <method name="get_method_argument_count" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="method" type="StringName" />
+ <description>
+ Returns the number of arguments of the given [param method] by name.
+ [b]Note:[/b] In C#, [param method] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]MethodName[/code] class to avoid allocating a new [StringName] on each call.
+ </description>
+ </method>
<method name="get_method_list" qualifiers="const">
<return type="Dictionary[]" />
<description>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 6e864316f1..407041289c 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -353,7 +353,7 @@
Maximum number of frames per second allowed. A value of [code]0[/code] means "no limit". The actual number of frames per second may still be below this value if the CPU or GPU cannot keep up with the project logic and rendering.
Limiting the FPS can be useful to reduce system power consumption, which reduces heat and noise emissions (and improves battery life on mobile devices).
If [member display/window/vsync/vsync_mode] is set to [code]Enabled[/code] or [code]Adaptive[/code], it takes precedence and the forced FPS number cannot exceed the monitor's refresh rate.
- If [member display/window/vsync/vsync_mode] is [code]Enabled[/code], on monitors with variable refresh rate enabled (G-Sync/FreeSync), using a FPS limit a few frames lower than the monitor's refresh rate will [url=https://blurbusters.com/howto-low-lag-vsync-on/]reduce input lag while avoiding tearing[/url].
+ If [member display/window/vsync/vsync_mode] is [code]Enabled[/code], on monitors with variable refresh rate enabled (G-Sync/FreeSync), using an FPS limit a few frames lower than the monitor's refresh rate will [url=https://blurbusters.com/howto-low-lag-vsync-on/]reduce input lag while avoiding tearing[/url].
If [member display/window/vsync/vsync_mode] is [code]Disabled[/code], limiting the FPS to a high value that can be consistently reached on the system can reduce input lag compared to an uncapped framerate. Since this works by ensuring the GPU load is lower than 100%, this latency reduction is only effective in GPU-bottlenecked scenarios, not CPU-bottlenecked scenarios.
See also [member physics/common/physics_ticks_per_second].
This setting can be overridden using the [code]--max-fps &lt;fps&gt;[/code] command line argument (including with a value of [code]0[/code] for unlimited framerate).
@@ -470,11 +470,12 @@
<member name="debug/gdscript/warnings/confusable_local_usage" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an identifier that will be shadowed below in the block is used.
</member>
- <member name="debug/gdscript/warnings/constant_used_as_function" type="int" setter="" getter="" default="1">
+ <member name="debug/gdscript/warnings/constant_used_as_function" type="int" setter="" getter="" default="1" deprecated="This warning is never produced. Instead, an error is generated if the expression type is known at compile time.">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a constant is used as a function.
</member>
<member name="debug/gdscript/warnings/deprecated_keyword" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when deprecated keywords are used.
+ [b]Note:[/b] There are currently no deprecated keywords, so this warning is never produced.
</member>
<member name="debug/gdscript/warnings/empty_file" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an empty file is parsed.
@@ -485,7 +486,7 @@
<member name="debug/gdscript/warnings/exclude_addons" type="bool" setter="" getter="" default="true">
If [code]true[/code], scripts in the [code]res://addons[/code] folder will not generate warnings.
</member>
- <member name="debug/gdscript/warnings/function_used_as_property" type="int" setter="" getter="" default="1">
+ <member name="debug/gdscript/warnings/function_used_as_property" type="int" setter="" getter="" default="1" deprecated="This warning is never produced. When a function is used as a property, a [Callable] is returned.">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when using a function as if it is a property.
</member>
<member name="debug/gdscript/warnings/get_node_default_without_onready" type="int" setter="" getter="" default="2">
@@ -519,7 +520,7 @@
<member name="debug/gdscript/warnings/onready_with_export" type="int" setter="" getter="" default="2">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when the [code]@onready[/code] annotation is used together with the [code]@export[/code] annotation, since it may not behave as expected.
</member>
- <member name="debug/gdscript/warnings/property_used_as_function" type="int" setter="" getter="" default="1">
+ <member name="debug/gdscript/warnings/property_used_as_function" type="int" setter="" getter="" default="1" deprecated="This warning is never produced. Instead, an error is generated if the expression type is known at compile time.">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when using a property as if it is a function.
</member>
<member name="debug/gdscript/warnings/redundant_await" type="int" setter="" getter="" default="1">
@@ -593,7 +594,7 @@
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a private member variable is never used.
</member>
<member name="debug/gdscript/warnings/unused_signal" type="int" setter="" getter="" default="1">
- When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a signal is declared but never emitted.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a signal is declared but never explicitly used in the class.
</member>
<member name="debug/gdscript/warnings/unused_variable" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a local variable is unused.
@@ -962,7 +963,7 @@
<member name="editor/run/main_run_args" type="String" setter="" getter="" default="&quot;&quot;">
The command-line arguments to append to Godot's own command line when running the project. This doesn't affect the editor itself.
It is possible to make another executable run Godot by using the [code]%command%[/code] placeholder. The placeholder will be replaced with Godot's own command line. Program-specific arguments should be placed [i]before[/i] the placeholder, whereas Godot-specific arguments should be placed [i]after[/i] the placeholder.
- For example, this can be used to force the project to run on the dedicated GPU in a NVIDIA Optimus system on Linux:
+ For example, this can be used to force the project to run on the dedicated GPU in an NVIDIA Optimus system on Linux:
[codeblock]
prime-run %command%
[/codeblock]
@@ -989,7 +990,7 @@
</member>
<member name="filesystem/import/fbx2gltf/enabled" type="bool" setter="" getter="" default="true">
If [code]true[/code], Autodesk FBX 3D scene files with the [code].fbx[/code] extension will be imported by converting them to glTF 2.0.
- This requires configuring a path to a FBX2glTF executable in the editor settings at [member EditorSettings.filesystem/import/fbx2gltf/fbx2gltf_path].
+ This requires configuring a path to an FBX2glTF executable in the editor settings at [member EditorSettings.filesystem/import/fbx2gltf/fbx2gltf_path].
</member>
<member name="filesystem/import/fbx2gltf/enabled.android" type="bool" setter="" getter="" default="false">
Override for [member filesystem/import/fbx2gltf/enabled] on Android where FBX2glTF can't easily be accessed from Godot.
diff --git a/doc/classes/RayCast2D.xml b/doc/classes/RayCast2D.xml
index a101fd24de..31daaab417 100644
--- a/doc/classes/RayCast2D.xml
+++ b/doc/classes/RayCast2D.xml
@@ -69,13 +69,14 @@
<return type="Vector2" />
<description>
Returns the normal of the intersecting object's shape at the collision point, or [code]Vector2(0, 0)[/code] if the ray starts inside the shape and [member hit_from_inside] is [code]true[/code].
+ [b]Note:[/b] Check that [method is_colliding] returns [code]true[/code] before calling this method to ensure the returned normal is valid and up-to-date.
</description>
</method>
<method name="get_collision_point" qualifiers="const">
<return type="Vector2" />
<description>
- Returns the collision point at which the ray intersects the closest object. If [member hit_from_inside] is [code]true[/code] and the ray starts inside of a collision shape, this function will return the origin point of the ray.
- [b]Note:[/b] This point is in the [b]global[/b] coordinate system.
+ Returns the collision point at which the ray intersects the closest object, in the global coordinate system. If [member hit_from_inside] is [code]true[/code] and the ray starts inside of a collision shape, this function will return the origin point of the ray.
+ [b]Note:[/b] Check that [method is_colliding] returns [code]true[/code] before calling this method to ensure the returned point is valid and up-to-date.
</description>
</method>
<method name="is_colliding" qualifiers="const">
diff --git a/doc/classes/RayCast3D.xml b/doc/classes/RayCast3D.xml
index 641c5ec653..f9f94e5cfc 100644
--- a/doc/classes/RayCast3D.xml
+++ b/doc/classes/RayCast3D.xml
@@ -76,13 +76,14 @@
<return type="Vector3" />
<description>
Returns the normal of the intersecting object's shape at the collision point, or [code]Vector3(0, 0, 0)[/code] if the ray starts inside the shape and [member hit_from_inside] is [code]true[/code].
+ [b]Note:[/b] Check that [method is_colliding] returns [code]true[/code] before calling this method to ensure the returned normal is valid and up-to-date.
</description>
</method>
<method name="get_collision_point" qualifiers="const">
<return type="Vector3" />
<description>
- Returns the collision point at which the ray intersects the closest object. If [member hit_from_inside] is [code]true[/code] and the ray starts inside of a collision shape, this function will return the origin point of the ray.
- [b]Note:[/b] This point is in the [b]global[/b] coordinate system.
+ Returns the collision point at which the ray intersects the closest object, in the global coordinate system. If [member hit_from_inside] is [code]true[/code] and the ray starts inside of a collision shape, this function will return the origin point of the ray.
+ [b]Note:[/b] Check that [method is_colliding] returns [code]true[/code] before calling this method to ensure the returned point is valid and up-to-date.
</description>
</method>
<method name="is_colliding" qualifiers="const">
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 152518e7da..324e6d50b6 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -3903,7 +3903,7 @@
<param index="0" name="viewport" type="RID" />
<param index="1" name="enabled" type="bool" />
<description>
- If [code]true[/code], 2D rendering will use a high dynamic range (HDR) format framebuffer matching the bit depth of the 3D framebuffer. When using the Forward+ renderer this will be a [code]RGBA16[/code] framebuffer, while when using the Mobile renderer it will be a [code]RGB10_A2[/code] framebuffer. Additionally, 2D rendering will take place in linear color space and will be converted to sRGB space immediately before blitting to the screen (if the Viewport is attached to the screen). Practically speaking, this means that the end result of the Viewport will not be clamped into the [code]0-1[/code] range and can be used in 3D rendering without color space adjustments. This allows 2D rendering to take advantage of effects requiring high dynamic range (e.g. 2D glow) as well as substantially improves the appearance of effects requiring highly detailed gradients. This setting has the same effect as [member Viewport.use_hdr_2d].
+ If [code]true[/code], 2D rendering will use a high dynamic range (HDR) format framebuffer matching the bit depth of the 3D framebuffer. When using the Forward+ renderer this will be an [code]RGBA16[/code] framebuffer, while when using the Mobile renderer it will be an [code]RGB10_A2[/code] framebuffer. Additionally, 2D rendering will take place in linear color space and will be converted to sRGB space immediately before blitting to the screen (if the Viewport is attached to the screen). Practically speaking, this means that the end result of the Viewport will not be clamped into the [code]0-1[/code] range and can be used in 3D rendering without color space adjustments. This allows 2D rendering to take advantage of effects requiring high dynamic range (e.g. 2D glow) as well as substantially improves the appearance of effects requiring highly detailed gradients. This setting has the same effect as [member Viewport.use_hdr_2d].
[b]Note:[/b] This setting will have no effect when using the GL Compatibility renderer as the GL Compatibility renderer always renders in low dynamic range for performance reasons.
</description>
</method>
diff --git a/doc/classes/ScriptExtension.xml b/doc/classes/ScriptExtension.xml
index 51958a2a2a..d102676035 100644
--- a/doc/classes/ScriptExtension.xml
+++ b/doc/classes/ScriptExtension.xml
@@ -80,6 +80,13 @@
<description>
</description>
</method>
+ <method name="_get_script_method_argument_count" qualifiers="virtual const">
+ <return type="Variant" />
+ <param index="0" name="method" type="StringName" />
+ <description>
+ Return the expected argument count for the given [param method], or [code]null[/code] if it can't be determined (which will then fall back to the default behavior).
+ </description>
+ </method>
<method name="_get_script_method_list" qualifiers="virtual const">
<return type="Dictionary[]" />
<description>
diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml
index b4a88513ec..094275c349 100644
--- a/doc/classes/SurfaceTool.xml
+++ b/doc/classes/SurfaceTool.xml
@@ -124,7 +124,7 @@
<param index="0" name="nd_threshold" type="float" />
<param index="1" name="target_index_count" type="int" default="3" />
<description>
- Generates a LOD for a given [param nd_threshold] in linear units (square root of quadric error metric), using at most [param target_index_count] indices.
+ Generates an LOD for a given [param nd_threshold] in linear units (square root of quadric error metric), using at most [param target_index_count] indices.
</description>
</method>
<method name="generate_normals">
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index 4102187350..cd70316aa9 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -27,7 +27,7 @@
<param index="0" name="direction" type="int" enum="TextServer.Direction" default="0" />
<param index="1" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
- Creates new buffer for complex text layout, with the given [param direction] and [param orientation]. To free the resulting buffer, use [method free_rid] method.
+ Creates a new buffer for complex text layout, with the given [param direction] and [param orientation]. To free the resulting buffer, use [method free_rid] method.
[b]Note:[/b] Direction is ignored if server does not support [constant FEATURE_BIDI_LAYOUT] feature (supported by [TextServerAdvanced]).
[b]Note:[/b] Orientation is ignored if server does not support [constant FEATURE_VERTICAL_LAYOUT] feature (supported by [TextServerAdvanced]).
</description>
@@ -48,7 +48,7 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="Vector2i" />
<description>
- Removes all rendered glyphs information from the cache entry.
+ Removes all rendered glyph information from the cache entry.
[b]Note:[/b] This function will not remove textures associated with the glyphs, use [method font_remove_texture] to remove them manually.
</description>
</method>
@@ -956,7 +956,7 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="transform" type="Transform2D" />
<description>
- Sets 2D transform, applied to the font outlines, can be used for slanting, flipping and rotating glyphs.
+ Sets 2D transform, applied to the font outlines, can be used for slanting, flipping, and rotating glyphs.
For example, to simulate italic typeface by slanting, apply the following transform [code]Transform2D(1.0, slant, 0.0, 1.0, 0.0, 0.0)[/code].
</description>
</method>
@@ -1115,7 +1115,7 @@
<return type="int" />
<param index="0" name="name" type="String" />
<description>
- Converts readable feature, variation, script or language name to OpenType tag.
+ Converts readable feature, variation, script, or language name to OpenType tag.
</description>
</method>
<method name="parse_number" qualifiers="const">
@@ -1173,7 +1173,7 @@
<param index="3" name="size" type="int" />
<param index="4" name="opentype_features" type="Dictionary" default="{}" />
<description>
- Changes text span font, font size and OpenType features, without changing the text.
+ Changes text span font, font size, and OpenType features, without changing the text.
</description>
</method>
<method name="shaped_text_add_object">
@@ -1758,7 +1758,7 @@
<return type="String" />
<param index="0" name="tag" type="int" />
<description>
- Converts OpenType tag to readable feature, variation, script or language name.
+ Converts OpenType tag to readable feature, variation, script, or language name.
</description>
</method>
</methods>
diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml
index aa9062b844..9b7fc42ddf 100644
--- a/doc/classes/TextServerExtension.xml
+++ b/doc/classes/TextServerExtension.xml
@@ -12,17 +12,23 @@
<method name="_cleanup" qualifiers="virtual">
<return type="void" />
<description>
+ [b]Optional.[/b]
+ This method is called before text server is unregistered.
</description>
</method>
<method name="_create_font" qualifiers="virtual">
<return type="RID" />
<description>
+ [b]Required.[/b]
+ Creates a new, empty font cache entry resource.
</description>
</method>
<method name="_create_font_linked_variation" qualifiers="virtual">
<return type="RID" />
<param index="0" name="font_rid" type="RID" />
<description>
+ Optional, implement if font supports extra spacing or baseline offset.
+ Creates a new variation existing font which is reusing the same glyph cache and font data.
</description>
</method>
<method name="_create_shaped_text" qualifiers="virtual">
@@ -30,6 +36,8 @@
<param index="0" name="direction" type="int" enum="TextServer.Direction" />
<param index="1" name="orientation" type="int" enum="TextServer.Orientation" />
<description>
+ [b]Required.[/b]
+ Creates a new buffer for complex text layout, with the given [param direction] and [param orientation].
</description>
</method>
<method name="_draw_hex_code_box" qualifiers="virtual const">
@@ -40,6 +48,8 @@
<param index="3" name="index" type="int" />
<param index="4" name="color" type="Color" />
<description>
+ [b]Optional.[/b]
+ Draws box displaying character hexadecimal code.
</description>
</method>
<method name="_font_clear_glyphs" qualifiers="virtual">
@@ -47,6 +57,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="Vector2i" />
<description>
+ [b]Required.[/b]
+ Removes all rendered glyph information from the cache entry.
</description>
</method>
<method name="_font_clear_kerning_map" qualifiers="virtual">
@@ -54,12 +66,16 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="int" />
<description>
+ [b]Optional.[/b]
+ Removes all kerning overrides.
</description>
</method>
<method name="_font_clear_size_cache" qualifiers="virtual">
<return type="void" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Required.[/b]
+ Removes all font sizes from the cache entry.
</description>
</method>
<method name="_font_clear_textures" qualifiers="virtual">
@@ -67,6 +83,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="Vector2i" />
<description>
+ [b]Required.[/b]
+ Removes all textures from font cache entry.
</description>
</method>
<method name="_font_draw_glyph" qualifiers="virtual const">
@@ -78,6 +96,8 @@
<param index="4" name="index" type="int" />
<param index="5" name="color" type="Color" />
<description>
+ [b]Required.[/b]
+ Draws single glyph into a canvas item at the position, using [param font_rid] at the size [param size].
</description>
</method>
<method name="_font_draw_glyph_outline" qualifiers="virtual const">
@@ -90,12 +110,16 @@
<param index="5" name="index" type="int" />
<param index="6" name="color" type="Color" />
<description>
+ [b]Required.[/b]
+ Draws single glyph outline of size [param outline_size] into a canvas item at the position, using [param font_rid] at the size [param size].
</description>
</method>
<method name="_font_get_antialiasing" qualifiers="virtual const">
<return type="int" enum="TextServer.FontAntialiasing" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns font anti-aliasing mode.
</description>
</method>
<method name="_font_get_ascent" qualifiers="virtual const">
@@ -103,12 +127,16 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="int" />
<description>
+ [b]Required.[/b]
+ Returns the font ascent (number of pixels above the baseline).
</description>
</method>
<method name="_font_get_baseline_offset" qualifiers="virtual const">
<return type="float" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns extra baseline offset (as a fraction of font height).
</description>
</method>
<method name="_font_get_char_from_glyph_index" qualifiers="virtual const">
@@ -117,6 +145,8 @@
<param index="1" name="size" type="int" />
<param index="2" name="glyph_index" type="int" />
<description>
+ [b]Required.[/b]
+ Returns character code associated with [param glyph_index], or [code]0[/code] if [param glyph_index] is invalid.
</description>
</method>
<method name="_font_get_descent" qualifiers="virtual const">
@@ -124,53 +154,71 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="int" />
<description>
+ [b]Required.[/b]
+ Returns the font descent (number of pixels below the baseline).
</description>
</method>
<method name="_font_get_disable_embedded_bitmaps" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns whether the font's embedded bitmap loading is disabled.
</description>
</method>
<method name="_font_get_embolden" qualifiers="virtual const">
<return type="float" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns font embolden strength.
</description>
</method>
<method name="_font_get_face_count" qualifiers="virtual const">
<return type="int" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns number of faces in the TrueType / OpenType collection.
</description>
</method>
<method name="_font_get_face_index" qualifiers="virtual const">
<return type="int" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns an active face index in the TrueType / OpenType collection.
</description>
</method>
<method name="_font_get_fixed_size" qualifiers="virtual const">
<return type="int" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns bitmap font fixed size.
</description>
</method>
<method name="_font_get_fixed_size_scale_mode" qualifiers="virtual const">
<return type="int" enum="TextServer.FixedSizeScaleMode" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns bitmap font scaling mode.
</description>
</method>
<method name="_font_get_generate_mipmaps" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns [code]true[/code] if font texture mipmap generation is enabled.
</description>
</method>
<method name="_font_get_global_oversampling" qualifiers="virtual const">
<return type="float" />
<description>
+ [b]Optional.[/b]
+ Returns the font oversampling factor, shared by all fonts in the TextServer.
</description>
</method>
<method name="_font_get_glyph_advance" qualifiers="virtual const">
@@ -179,6 +227,8 @@
<param index="1" name="size" type="int" />
<param index="2" name="glyph" type="int" />
<description>
+ [b]Required.[/b]
+ Returns glyph advance (offset of the next glyph).
</description>
</method>
<method name="_font_get_glyph_contours" qualifiers="virtual const">
@@ -187,6 +237,8 @@
<param index="1" name="size" type="int" />
<param index="2" name="index" type="int" />
<description>
+ [b]Optional.[/b]
+ Returns outline contours of the glyph.
</description>
</method>
<method name="_font_get_glyph_index" qualifiers="virtual const">
@@ -196,6 +248,8 @@
<param index="2" name="char" type="int" />
<param index="3" name="variation_selector" type="int" />
<description>
+ [b]Required.[/b]
+ Returns the glyph index of a [param char], optionally modified by the [param variation_selector].
</description>
</method>
<method name="_font_get_glyph_list" qualifiers="virtual const">
@@ -203,6 +257,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="Vector2i" />
<description>
+ [b]Required.[/b]
+ Returns list of rendered glyphs in the cache entry.
</description>
</method>
<method name="_font_get_glyph_offset" qualifiers="virtual const">
@@ -211,6 +267,8 @@
<param index="1" name="size" type="Vector2i" />
<param index="2" name="glyph" type="int" />
<description>
+ [b]Required.[/b]
+ Returns glyph offset from the baseline.
</description>
</method>
<method name="_font_get_glyph_size" qualifiers="virtual const">
@@ -219,6 +277,8 @@
<param index="1" name="size" type="Vector2i" />
<param index="2" name="glyph" type="int" />
<description>
+ [b]Required.[/b]
+ Returns size of the glyph.
</description>
</method>
<method name="_font_get_glyph_texture_idx" qualifiers="virtual const">
@@ -227,6 +287,8 @@
<param index="1" name="size" type="Vector2i" />
<param index="2" name="glyph" type="int" />
<description>
+ [b]Required.[/b]
+ Returns index of the cache texture containing the glyph.
</description>
</method>
<method name="_font_get_glyph_texture_rid" qualifiers="virtual const">
@@ -235,6 +297,8 @@
<param index="1" name="size" type="Vector2i" />
<param index="2" name="glyph" type="int" />
<description>
+ [b]Required.[/b]
+ Returns resource ID of the cache texture containing the glyph.
</description>
</method>
<method name="_font_get_glyph_texture_size" qualifiers="virtual const">
@@ -243,6 +307,8 @@
<param index="1" name="size" type="Vector2i" />
<param index="2" name="glyph" type="int" />
<description>
+ [b]Required.[/b]
+ Returns size of the cache texture containing the glyph.
</description>
</method>
<method name="_font_get_glyph_uv_rect" qualifiers="virtual const">
@@ -251,12 +317,16 @@
<param index="1" name="size" type="Vector2i" />
<param index="2" name="glyph" type="int" />
<description>
+ [b]Required.[/b]
+ Returns rectangle in the cache texture containing the glyph.
</description>
</method>
<method name="_font_get_hinting" qualifiers="virtual const">
<return type="int" enum="TextServer.Hinting" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns the font hinting mode. Used by dynamic fonts only.
</description>
</method>
<method name="_font_get_kerning" qualifiers="virtual const">
@@ -265,6 +335,8 @@
<param index="1" name="size" type="int" />
<param index="2" name="glyph_pair" type="Vector2i" />
<description>
+ [b]Optional.[/b]
+ Returns kerning for the pair of glyphs.
</description>
</method>
<method name="_font_get_kerning_list" qualifiers="virtual const">
@@ -272,6 +344,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="int" />
<description>
+ [b]Optional.[/b]
+ Returns list of the kerning overrides.
</description>
</method>
<method name="_font_get_language_support_override" qualifiers="virtual">
@@ -279,48 +353,64 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="language" type="String" />
<description>
+ [b]Optional.[/b]
+ Returns [code]true[/code] if support override is enabled for the [param language].
</description>
</method>
<method name="_font_get_language_support_overrides" qualifiers="virtual">
<return type="PackedStringArray" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns list of language support overrides.
</description>
</method>
<method name="_font_get_msdf_pixel_range" qualifiers="virtual const">
<return type="int" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns the width of the range around the shape between the minimum and maximum representable signed distance.
</description>
</method>
<method name="_font_get_msdf_size" qualifiers="virtual const">
<return type="int" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns source font size used to generate MSDF textures.
</description>
</method>
<method name="_font_get_name" qualifiers="virtual const">
<return type="String" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns font family name.
</description>
</method>
<method name="_font_get_opentype_feature_overrides" qualifiers="virtual const">
<return type="Dictionary" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns font OpenType feature set override.
</description>
</method>
<method name="_font_get_ot_name_strings" qualifiers="virtual const">
<return type="Dictionary" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns [Dictionary] with OpenType font name strings (localized font names, version, description, license information, sample text, etc.).
</description>
</method>
<method name="_font_get_oversampling" qualifiers="virtual const">
<return type="float" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns font oversampling factor, if set to [code]0.0[/code] global oversampling factor is used instead. Used by dynamic fonts only.
</description>
</method>
<method name="_font_get_scale" qualifiers="virtual const">
@@ -328,6 +418,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="int" />
<description>
+ [b]Required.[/b]
+ Returns scaling factor of the color bitmap font.
</description>
</method>
<method name="_font_get_script_support_override" qualifiers="virtual">
@@ -335,18 +427,24 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="script" type="String" />
<description>
+ [b]Optional.[/b]
+ Returns [code]true[/code] if support override is enabled for the [param script].
</description>
</method>
<method name="_font_get_script_support_overrides" qualifiers="virtual">
<return type="PackedStringArray" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns list of script support overrides.
</description>
</method>
<method name="_font_get_size_cache_list" qualifiers="virtual const">
<return type="Vector2i[]" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns list of the font sizes in the cache. Each size is [Vector2i] with font size and outline size.
</description>
</method>
<method name="_font_get_spacing" qualifiers="virtual const">
@@ -354,36 +452,48 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="spacing" type="int" enum="TextServer.SpacingType" />
<description>
+ [b]Optional.[/b]
+ Returns the spacing for [param spacing] (see [enum TextServer.SpacingType]) in pixels (not relative to the font size).
</description>
</method>
<method name="_font_get_stretch" qualifiers="virtual const">
<return type="int" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns font stretch amount, compared to a normal width. A percentage value between [code]50%[/code] and [code]200%[/code].
</description>
</method>
<method name="_font_get_style" qualifiers="virtual const">
<return type="int" enum="TextServer.FontStyle" is_bitfield="true" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns font style flags, see [enum TextServer.FontStyle].
</description>
</method>
<method name="_font_get_style_name" qualifiers="virtual const">
<return type="String" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns font style name.
</description>
</method>
<method name="_font_get_subpixel_positioning" qualifiers="virtual const">
<return type="int" enum="TextServer.SubpixelPositioning" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns font subpixel glyph positioning mode.
</description>
</method>
<method name="_font_get_supported_chars" qualifiers="virtual const">
<return type="String" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns a string containing all the characters available in the font.
</description>
</method>
<method name="_font_get_texture_count" qualifiers="virtual const">
@@ -391,6 +501,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="Vector2i" />
<description>
+ [b]Required.[/b]
+ Returns number of textures used by font cache entry.
</description>
</method>
<method name="_font_get_texture_image" qualifiers="virtual const">
@@ -399,6 +511,8 @@
<param index="1" name="size" type="Vector2i" />
<param index="2" name="texture_index" type="int" />
<description>
+ [b]Required.[/b]
+ Returns font cache texture image data.
</description>
</method>
<method name="_font_get_texture_offsets" qualifiers="virtual const">
@@ -407,12 +521,16 @@
<param index="1" name="size" type="Vector2i" />
<param index="2" name="texture_index" type="int" />
<description>
+ [b]Optional.[/b]
+ Returns array containing glyph packing data.
</description>
</method>
<method name="_font_get_transform" qualifiers="virtual const">
<return type="Transform2D" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns 2D transform applied to the font outlines.
</description>
</method>
<method name="_font_get_underline_position" qualifiers="virtual const">
@@ -420,6 +538,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="int" />
<description>
+ [b]Required.[/b]
+ Returns pixel offset of the underline below the baseline.
</description>
</method>
<method name="_font_get_underline_thickness" qualifiers="virtual const">
@@ -427,18 +547,24 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="int" />
<description>
+ [b]Required.[/b]
+ Returns thickness of the underline in pixels.
</description>
</method>
<method name="_font_get_variation_coordinates" qualifiers="virtual const">
<return type="Dictionary" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns variation coordinates for the specified font cache entry.
</description>
</method>
<method name="_font_get_weight" qualifiers="virtual const">
<return type="int" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns weight (boldness) of the font. A value in the [code]100...999[/code] range, normal font weight is [code]400[/code], bold font weight is [code]700[/code].
</description>
</method>
<method name="_font_has_char" qualifiers="virtual const">
@@ -446,18 +572,24 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="char" type="int" />
<description>
+ [b]Required.[/b]
+ Returns [code]true[/code] if a Unicode [param char] is available in the font.
</description>
</method>
<method name="_font_is_allow_system_fallback" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns [code]true[/code] if system fonts can be automatically used as fallbacks.
</description>
</method>
<method name="_font_is_force_autohinter" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns [code]true[/code] if auto-hinting is supported and preferred over font built-in hinting.
</description>
</method>
<method name="_font_is_language_supported" qualifiers="virtual const">
@@ -465,12 +597,16 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="language" type="String" />
<description>
+ [b]Optional.[/b]
+ Returns [code]true[/code], if font supports given language ([url=https://en.wikipedia.org/wiki/ISO_639-1]ISO 639[/url] code).
</description>
</method>
<method name="_font_is_multichannel_signed_distance_field" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns [code]true[/code] if glyphs of all sizes are rendered using single multichannel signed distance field generated from the dynamic font vector data.
</description>
</method>
<method name="_font_is_script_supported" qualifiers="virtual const">
@@ -478,6 +614,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="script" type="String" />
<description>
+ [b]Optional.[/b]
+ Returns [code]true[/code], if font supports given script (ISO 15924 code).
</description>
</method>
<method name="_font_remove_glyph" qualifiers="virtual">
@@ -486,6 +624,8 @@
<param index="1" name="size" type="Vector2i" />
<param index="2" name="glyph" type="int" />
<description>
+ [b]Required.[/b]
+ Removes specified rendered glyph information from the cache entry.
</description>
</method>
<method name="_font_remove_kerning" qualifiers="virtual">
@@ -494,6 +634,8 @@
<param index="1" name="size" type="int" />
<param index="2" name="glyph_pair" type="Vector2i" />
<description>
+ [b]Optional.[/b]
+ Removes kerning override for the pair of glyphs.
</description>
</method>
<method name="_font_remove_language_support_override" qualifiers="virtual">
@@ -501,6 +643,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="language" type="String" />
<description>
+ [b]Optional.[/b]
+ Remove language support override.
</description>
</method>
<method name="_font_remove_script_support_override" qualifiers="virtual">
@@ -508,6 +652,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="script" type="String" />
<description>
+ [b]Optional.[/b]
+ Removes script support override.
</description>
</method>
<method name="_font_remove_size_cache" qualifiers="virtual">
@@ -515,6 +661,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="size" type="Vector2i" />
<description>
+ [b]Required.[/b]
+ Removes specified font size from the cache entry.
</description>
</method>
<method name="_font_remove_texture" qualifiers="virtual">
@@ -523,6 +671,8 @@
<param index="1" name="size" type="Vector2i" />
<param index="2" name="texture_index" type="int" />
<description>
+ [b]Required.[/b]
+ Removes specified texture from the cache entry.
</description>
</method>
<method name="_font_render_glyph" qualifiers="virtual">
@@ -531,6 +681,8 @@
<param index="1" name="size" type="Vector2i" />
<param index="2" name="index" type="int" />
<description>
+ [b]Optional.[/b]
+ Renders specified glyph to the font cache texture.
</description>
</method>
<method name="_font_render_range" qualifiers="virtual">
@@ -540,6 +692,8 @@
<param index="2" name="start" type="int" />
<param index="3" name="end" type="int" />
<description>
+ [b]Optional.[/b]
+ Renders the range of characters to the font cache texture.
</description>
</method>
<method name="_font_set_allow_system_fallback" qualifiers="virtual">
@@ -547,6 +701,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="allow_system_fallback" type="bool" />
<description>
+ [b]Optional.[/b]
+ If set to [code]true[/code], system fonts can be automatically used as fallbacks.
</description>
</method>
<method name="_font_set_antialiasing" qualifiers="virtual">
@@ -554,6 +710,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="antialiasing" type="int" enum="TextServer.FontAntialiasing" />
<description>
+ [b]Optional.[/b]
+ Sets font anti-aliasing mode.
</description>
</method>
<method name="_font_set_ascent" qualifiers="virtual">
@@ -562,6 +720,8 @@
<param index="1" name="size" type="int" />
<param index="2" name="ascent" type="float" />
<description>
+ [b]Required.[/b]
+ Sets the font ascent (number of pixels above the baseline).
</description>
</method>
<method name="_font_set_baseline_offset" qualifiers="virtual">
@@ -569,6 +729,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="baseline_offset" type="float" />
<description>
+ [b]Optional.[/b]
+ Sets extra baseline offset (as a fraction of font height).
</description>
</method>
<method name="_font_set_data" qualifiers="virtual">
@@ -576,6 +738,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="data" type="PackedByteArray" />
<description>
+ [b]Optional.[/b]
+ Sets font source data, e.g contents of the dynamic font source file.
</description>
</method>
<method name="_font_set_data_ptr" qualifiers="virtual">
@@ -584,6 +748,8 @@
<param index="1" name="data_ptr" type="const uint8_t*" />
<param index="2" name="data_size" type="int" />
<description>
+ [b]Optional.[/b]
+ Sets pointer to the font source data, e.g contents of the dynamic font source file.
</description>
</method>
<method name="_font_set_descent" qualifiers="virtual">
@@ -592,6 +758,8 @@
<param index="1" name="size" type="int" />
<param index="2" name="descent" type="float" />
<description>
+ [b]Required.[/b]
+ Sets the font descent (number of pixels below the baseline).
</description>
</method>
<method name="_font_set_disable_embedded_bitmaps" qualifiers="virtual">
@@ -599,6 +767,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="disable_embedded_bitmaps" type="bool" />
<description>
+ [b]Optional.[/b]
+ If set to [code]true[/code], embedded font bitmap loading is disabled.
</description>
</method>
<method name="_font_set_embolden" qualifiers="virtual">
@@ -606,6 +776,7 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="strength" type="float" />
<description>
+ Sets font embolden strength. If [param strength] is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness.
</description>
</method>
<method name="_font_set_face_index" qualifiers="virtual">
@@ -613,6 +784,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="face_index" type="int" />
<description>
+ [b]Optional.[/b]
+ Sets an active face index in the TrueType / OpenType collection.
</description>
</method>
<method name="_font_set_fixed_size" qualifiers="virtual">
@@ -620,6 +793,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="fixed_size" type="int" />
<description>
+ [b]Required.[/b]
+ Sets bitmap font fixed size. If set to value greater than zero, same cache entry will be used for all font sizes.
</description>
</method>
<method name="_font_set_fixed_size_scale_mode" qualifiers="virtual">
@@ -627,6 +802,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="fixed_size_scale_mode" type="int" enum="TextServer.FixedSizeScaleMode" />
<description>
+ [b]Required.[/b]
+ Sets bitmap font scaling mode. This property is used only if [code]fixed_size[/code] is greater than zero.
</description>
</method>
<method name="_font_set_force_autohinter" qualifiers="virtual">
@@ -634,6 +811,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="force_autohinter" type="bool" />
<description>
+ [b]Optional.[/b]
+ If set to [code]true[/code] auto-hinting is preferred over font built-in hinting.
</description>
</method>
<method name="_font_set_generate_mipmaps" qualifiers="virtual">
@@ -641,12 +820,16 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="generate_mipmaps" type="bool" />
<description>
+ [b]Optional.[/b]
+ If set to [code]true[/code] font texture mipmap generation is enabled.
</description>
</method>
<method name="_font_set_global_oversampling" qualifiers="virtual">
<return type="void" />
<param index="0" name="oversampling" type="float" />
<description>
+ [b]Optional.[/b]
+ Sets oversampling factor, shared by all font in the TextServer.
</description>
</method>
<method name="_font_set_glyph_advance" qualifiers="virtual">
@@ -656,6 +839,8 @@
<param index="2" name="glyph" type="int" />
<param index="3" name="advance" type="Vector2" />
<description>
+ [b]Required.[/b]
+ Sets glyph advance (offset of the next glyph).
</description>
</method>
<method name="_font_set_glyph_offset" qualifiers="virtual">
@@ -665,6 +850,8 @@
<param index="2" name="glyph" type="int" />
<param index="3" name="offset" type="Vector2" />
<description>
+ [b]Required.[/b]
+ Sets glyph offset from the baseline.
</description>
</method>
<method name="_font_set_glyph_size" qualifiers="virtual">
@@ -674,6 +861,8 @@
<param index="2" name="glyph" type="int" />
<param index="3" name="gl_size" type="Vector2" />
<description>
+ [b]Required.[/b]
+ Sets size of the glyph.
</description>
</method>
<method name="_font_set_glyph_texture_idx" qualifiers="virtual">
@@ -683,6 +872,8 @@
<param index="2" name="glyph" type="int" />
<param index="3" name="texture_idx" type="int" />
<description>
+ [b]Required.[/b]
+ Sets index of the cache texture containing the glyph.
</description>
</method>
<method name="_font_set_glyph_uv_rect" qualifiers="virtual">
@@ -692,6 +883,8 @@
<param index="2" name="glyph" type="int" />
<param index="3" name="uv_rect" type="Rect2" />
<description>
+ [b]Required.[/b]
+ Sets rectangle in the cache texture containing the glyph.
</description>
</method>
<method name="_font_set_hinting" qualifiers="virtual">
@@ -699,6 +892,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="hinting" type="int" enum="TextServer.Hinting" />
<description>
+ [b]Optional.[/b]
+ Sets font hinting mode. Used by dynamic fonts only.
</description>
</method>
<method name="_font_set_kerning" qualifiers="virtual">
@@ -708,6 +903,8 @@
<param index="2" name="glyph_pair" type="Vector2i" />
<param index="3" name="kerning" type="Vector2" />
<description>
+ [b]Optional.[/b]
+ Sets kerning for the pair of glyphs.
</description>
</method>
<method name="_font_set_language_support_override" qualifiers="virtual">
@@ -716,6 +913,8 @@
<param index="1" name="language" type="String" />
<param index="2" name="supported" type="bool" />
<description>
+ [b]Optional.[/b]
+ Adds override for [method _font_is_language_supported].
</description>
</method>
<method name="_font_set_msdf_pixel_range" qualifiers="virtual">
@@ -723,6 +922,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="msdf_pixel_range" type="int" />
<description>
+ [b]Optional.[/b]
+ Sets the width of the range around the shape between the minimum and maximum representable signed distance.
</description>
</method>
<method name="_font_set_msdf_size" qualifiers="virtual">
@@ -730,6 +931,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="msdf_size" type="int" />
<description>
+ [b]Optional.[/b]
+ Sets source font size used to generate MSDF textures.
</description>
</method>
<method name="_font_set_multichannel_signed_distance_field" qualifiers="virtual">
@@ -737,6 +940,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="msdf" type="bool" />
<description>
+ [b]Optional.[/b]
+ If set to [code]true[/code], glyphs of all sizes are rendered using single multichannel signed distance field generated from the dynamic font vector data. MSDF rendering allows displaying the font at any scaling factor without blurriness, and without incurring a CPU cost when the font size changes (since the font no longer needs to be rasterized on the CPU). As a downside, font hinting is not available with MSDF. The lack of font hinting may result in less crisp and less readable fonts at small sizes.
</description>
</method>
<method name="_font_set_name" qualifiers="virtual">
@@ -744,6 +949,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="name" type="String" />
<description>
+ [b]Optional.[/b]
+ Sets the font family name.
</description>
</method>
<method name="_font_set_opentype_feature_overrides" qualifiers="virtual">
@@ -751,6 +958,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="overrides" type="Dictionary" />
<description>
+ [b]Optional.[/b]
+ Sets font OpenType feature set override.
</description>
</method>
<method name="_font_set_oversampling" qualifiers="virtual">
@@ -758,6 +967,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="oversampling" type="float" />
<description>
+ [b]Optional.[/b]
+ Sets font oversampling factor, if set to [code]0.0[/code] global oversampling factor is used instead. Used by dynamic fonts only.
</description>
</method>
<method name="_font_set_scale" qualifiers="virtual">
@@ -766,6 +977,8 @@
<param index="1" name="size" type="int" />
<param index="2" name="scale" type="float" />
<description>
+ [b]Required.[/b]
+ Sets scaling factor of the color bitmap font.
</description>
</method>
<method name="_font_set_script_support_override" qualifiers="virtual">
@@ -774,6 +987,8 @@
<param index="1" name="script" type="String" />
<param index="2" name="supported" type="bool" />
<description>
+ [b]Optional.[/b]
+ Adds override for [method _font_is_script_supported].
</description>
</method>
<method name="_font_set_spacing" qualifiers="virtual">
@@ -782,6 +997,8 @@
<param index="1" name="spacing" type="int" enum="TextServer.SpacingType" />
<param index="2" name="value" type="int" />
<description>
+ [b]Optional.[/b]
+ Sets the spacing for [param spacing] (see [enum TextServer.SpacingType]) to [param value] in pixels (not relative to the font size).
</description>
</method>
<method name="_font_set_stretch" qualifiers="virtual">
@@ -789,6 +1006,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="stretch" type="int" />
<description>
+ [b]Optional.[/b]
+ Sets font stretch amount, compared to a normal width. A percentage value between [code]50%[/code] and [code]200%[/code].
</description>
</method>
<method name="_font_set_style" qualifiers="virtual">
@@ -796,6 +1015,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="style" type="int" enum="TextServer.FontStyle" is_bitfield="true" />
<description>
+ [b]Optional.[/b]
+ Sets the font style flags, see [enum TextServer.FontStyle].
</description>
</method>
<method name="_font_set_style_name" qualifiers="virtual">
@@ -803,6 +1024,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="name_style" type="String" />
<description>
+ [b]Optional.[/b]
+ Sets the font style name.
</description>
</method>
<method name="_font_set_subpixel_positioning" qualifiers="virtual">
@@ -810,6 +1033,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="subpixel_positioning" type="int" enum="TextServer.SubpixelPositioning" />
<description>
+ [b]Optional.[/b]
+ Sets font subpixel glyph positioning mode.
</description>
</method>
<method name="_font_set_texture_image" qualifiers="virtual">
@@ -819,6 +1044,8 @@
<param index="2" name="texture_index" type="int" />
<param index="3" name="image" type="Image" />
<description>
+ [b]Required.[/b]
+ Sets font cache texture image data.
</description>
</method>
<method name="_font_set_texture_offsets" qualifiers="virtual">
@@ -828,6 +1055,8 @@
<param index="2" name="texture_index" type="int" />
<param index="3" name="offset" type="PackedInt32Array" />
<description>
+ [b]Optional.[/b]
+ Sets array containing glyph packing data.
</description>
</method>
<method name="_font_set_transform" qualifiers="virtual">
@@ -835,6 +1064,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="transform" type="Transform2D" />
<description>
+ [b]Optional.[/b]
+ Sets 2D transform, applied to the font outlines, can be used for slanting, flipping, and rotating glyphs.
</description>
</method>
<method name="_font_set_underline_position" qualifiers="virtual">
@@ -843,6 +1074,8 @@
<param index="1" name="size" type="int" />
<param index="2" name="underline_position" type="float" />
<description>
+ [b]Required.[/b]
+ Sets pixel offset of the underline below the baseline.
</description>
</method>
<method name="_font_set_underline_thickness" qualifiers="virtual">
@@ -851,6 +1084,8 @@
<param index="1" name="size" type="int" />
<param index="2" name="underline_thickness" type="float" />
<description>
+ [b]Required.[/b]
+ Sets thickness of the underline in pixels.
</description>
</method>
<method name="_font_set_variation_coordinates" qualifiers="virtual">
@@ -858,6 +1093,8 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="variation_coordinates" type="Dictionary" />
<description>
+ [b]Optional.[/b]
+ Sets variation coordinates for the specified font cache entry.
</description>
</method>
<method name="_font_set_weight" qualifiers="virtual">
@@ -865,36 +1102,48 @@
<param index="0" name="font_rid" type="RID" />
<param index="1" name="weight" type="int" />
<description>
+ [b]Optional.[/b]
+ Sets weight (boldness) of the font. A value in the [code]100...999[/code] range, normal font weight is [code]400[/code], bold font weight is [code]700[/code].
</description>
</method>
<method name="_font_supported_feature_list" qualifiers="virtual const">
<return type="Dictionary" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns the dictionary of the supported OpenType features.
</description>
</method>
<method name="_font_supported_variation_list" qualifiers="virtual const">
<return type="Dictionary" />
<param index="0" name="font_rid" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns the dictionary of the supported OpenType variation coordinates.
</description>
</method>
<method name="_format_number" qualifiers="virtual const">
<return type="String" />
- <param index="0" name="string" type="String" />
+ <param index="0" name="number" type="String" />
<param index="1" name="language" type="String" />
<description>
+ [b]Optional.[/b]
+ Converts a number from the Western Arabic (0..9) to the numeral systems used in [param language].
</description>
</method>
<method name="_free_rid" qualifiers="virtual">
<return type="void" />
<param index="0" name="rid" type="RID" />
<description>
+ [b]Required.[/b]
+ Frees an object created by this [TextServer].
</description>
</method>
<method name="_get_features" qualifiers="virtual const">
<return type="int" />
<description>
+ [b]Required.[/b]
+ Returns text server features, see [enum TextServer.Feature].
</description>
</method>
<method name="_get_hex_code_box_size" qualifiers="virtual const">
@@ -902,33 +1151,45 @@
<param index="0" name="size" type="int" />
<param index="1" name="index" type="int" />
<description>
+ [b]Optional.[/b]
+ Returns size of the replacement character (box with character hexadecimal code that is drawn in place of invalid characters).
</description>
</method>
<method name="_get_name" qualifiers="virtual const">
<return type="String" />
<description>
+ [b]Required.[/b]
+ Returns the name of the server interface.
</description>
</method>
<method name="_get_support_data_filename" qualifiers="virtual const">
<return type="String" />
<description>
+ [b]Optional.[/b]
+ Returns default TextServer database (e.g. ICU break iterators and dictionaries) filename.
</description>
</method>
<method name="_get_support_data_info" qualifiers="virtual const">
<return type="String" />
<description>
+ [b]Optional.[/b]
+ Returns TextServer database (e.g. ICU break iterators and dictionaries) description.
</description>
</method>
<method name="_has" qualifiers="virtual">
<return type="bool" />
<param index="0" name="rid" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns [code]true[/code] if [param rid] is valid resource owned by this text server.
</description>
</method>
<method name="_has_feature" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="feature" type="int" enum="TextServer.Feature" />
<description>
+ [b]Required.[/b]
+ Returns [code]true[/code] if the server supports a feature.
</description>
</method>
<method name="_is_confusable" qualifiers="virtual const">
@@ -936,37 +1197,49 @@
<param index="0" name="string" type="String" />
<param index="1" name="dict" type="PackedStringArray" />
<description>
+ [b]Optional.[/b]
+ Returns index of the first string in [param dict] which is visually confusable with the [param string], or [code]-1[/code] if none is found.
</description>
</method>
<method name="_is_locale_right_to_left" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="locale" type="String" />
<description>
+ [b]Required.[/b]
+ Returns [code]true[/code] if locale is right-to-left.
</description>
</method>
<method name="_is_valid_identifier" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="string" type="String" />
<description>
+ [b]Optional.[/b]
+ Returns [code]true[/code] if [param string] is a valid identifier.
</description>
</method>
<method name="_load_support_data" qualifiers="virtual">
<return type="bool" />
<param index="0" name="filename" type="String" />
<description>
+ [b]Optional.[/b]
+ Loads optional TextServer database (e.g. ICU break iterators and dictionaries).
</description>
</method>
<method name="_name_to_tag" qualifiers="virtual const">
<return type="int" />
<param index="0" name="name" type="String" />
<description>
+ [b]Optional.[/b]
+ Converts readable feature, variation, script, or language name to OpenType tag.
</description>
</method>
<method name="_parse_number" qualifiers="virtual const">
<return type="String" />
- <param index="0" name="string" type="String" />
+ <param index="0" name="number" type="String" />
<param index="1" name="language" type="String" />
<description>
+ [b]Optional.[/b]
+ Converts [param number] from the numeral systems used in [param language] to Western Arabic (0..9).
</description>
</method>
<method name="_parse_structured_text" qualifiers="virtual const">
@@ -975,24 +1248,32 @@
<param index="1" name="args" type="Array" />
<param index="2" name="text" type="String" />
<description>
+ [b]Optional.[/b]
+ Default implementation of the BiDi algorithm override function. See [enum TextServer.StructuredTextParser] for more info.
</description>
</method>
<method name="_percent_sign" qualifiers="virtual const">
<return type="String" />
<param index="0" name="language" type="String" />
<description>
+ [b]Optional.[/b]
+ Returns percent sign used in the [param language].
</description>
</method>
<method name="_save_support_data" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="filename" type="String" />
<description>
+ [b]Optional.[/b]
+ Saves optional TextServer database (e.g. ICU break iterators and dictionaries) to the file.
</description>
</method>
<method name="_shaped_get_span_count" qualifiers="virtual const">
<return type="int" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns number of text spans added using [method _shaped_text_add_string] or [method _shaped_text_add_object].
</description>
</method>
<method name="_shaped_get_span_meta" qualifiers="virtual const">
@@ -1000,6 +1281,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="index" type="int" />
<description>
+ [b]Required.[/b]
+ Returns text span metadata.
</description>
</method>
<method name="_shaped_set_span_update_font" qualifiers="virtual">
@@ -1010,6 +1293,8 @@
<param index="3" name="size" type="int" />
<param index="4" name="opentype_features" type="Dictionary" />
<description>
+ [b]Required.[/b]
+ Changes text span font, font size, and OpenType features, without changing the text.
</description>
</method>
<method name="_shaped_text_add_object" qualifiers="virtual">
@@ -1021,6 +1306,8 @@
<param index="4" name="length" type="int" />
<param index="5" name="baseline" type="float" />
<description>
+ [b]Required.[/b]
+ Adds inline object to the text buffer, [param key] must be unique. In the text, object is represented as [param length] object replacement characters.
</description>
</method>
<method name="_shaped_text_add_string" qualifiers="virtual">
@@ -1033,12 +1320,16 @@
<param index="5" name="language" type="String" />
<param index="6" name="meta" type="Variant" />
<description>
+ [b]Required.[/b]
+ Adds text span and font to draw it to the text buffer.
</description>
</method>
<method name="_shaped_text_clear" qualifiers="virtual">
<return type="void" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Clears text buffer (removes text and inline objects).
</description>
</method>
<method name="_shaped_text_closest_character_pos" qualifiers="virtual const">
@@ -1046,6 +1337,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="pos" type="int" />
<description>
+ [b]Optional.[/b]
+ Returns composite character position closest to the [param pos].
</description>
</method>
<method name="_shaped_text_draw" qualifiers="virtual const">
@@ -1057,6 +1350,8 @@
<param index="4" name="clip_r" type="float" />
<param index="5" name="color" type="Color" />
<description>
+ [b]Optional.[/b]
+ Draw shaped text into a canvas item at a given position, with [param color]. [param pos] specifies the leftmost point of the baseline (for horizontal layout) or topmost point of the baseline (for vertical layout).
</description>
</method>
<method name="_shaped_text_draw_outline" qualifiers="virtual const">
@@ -1069,6 +1364,8 @@
<param index="5" name="outline_size" type="int" />
<param index="6" name="color" type="Color" />
<description>
+ [b]Optional.[/b]
+ Draw the outline of the shaped text into a canvas item at a given position, with [param color]. [param pos] specifies the leftmost point of the baseline (for horizontal layout) or topmost point of the baseline (for vertical layout).
</description>
</method>
<method name="_shaped_text_fit_to_width" qualifiers="virtual">
@@ -1077,12 +1374,16 @@
<param index="1" name="width" type="float" />
<param index="2" name="justification_flags" type="int" enum="TextServer.JustificationFlag" is_bitfield="true" />
<description>
+ [b]Optional.[/b]
+ Adjusts text width to fit to specified width, returns new text width.
</description>
</method>
<method name="_shaped_text_get_ascent" qualifiers="virtual const">
<return type="float" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns the text ascent (number of pixels above the baseline for horizontal layout or to the left of baseline for vertical).
</description>
</method>
<method name="_shaped_text_get_carets" qualifiers="virtual const">
@@ -1091,36 +1392,48 @@
<param index="1" name="position" type="int" />
<param index="2" name="caret" type="CaretInfo*" />
<description>
+ [b]Optional.[/b]
+ Returns shapes of the carets corresponding to the character offset [param position] in the text. Returned caret shape is 1 pixel wide rectangle.
</description>
</method>
<method name="_shaped_text_get_character_breaks" qualifiers="virtual const">
<return type="PackedInt32Array" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns array of the composite character boundaries.
</description>
</method>
<method name="_shaped_text_get_custom_ellipsis" qualifiers="virtual const">
<return type="int" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns ellipsis character used for text clipping.
</description>
</method>
<method name="_shaped_text_get_custom_punctuation" qualifiers="virtual const">
<return type="String" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns custom punctuation character list, used for word breaking. If set to empty string, server defaults are used.
</description>
</method>
<method name="_shaped_text_get_descent" qualifiers="virtual const">
<return type="float" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns the text descent (number of pixels below the baseline for horizontal layout or to the right of baseline for vertical).
</description>
</method>
<method name="_shaped_text_get_direction" qualifiers="virtual const">
<return type="int" enum="TextServer.Direction" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns direction of the text.
</description>
</method>
<method name="_shaped_text_get_dominant_direction_in_range" qualifiers="virtual const">
@@ -1129,36 +1442,48 @@
<param index="1" name="start" type="int" />
<param index="2" name="end" type="int" />
<description>
+ [b]Optional.[/b]
+ Returns dominant direction of in the range of text.
</description>
</method>
<method name="_shaped_text_get_ellipsis_glyph_count" qualifiers="virtual const">
<return type="int" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns number of glyphs in the ellipsis.
</description>
</method>
<method name="_shaped_text_get_ellipsis_glyphs" qualifiers="virtual const">
<return type="const Glyph*" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns array of the glyphs in the ellipsis.
</description>
</method>
<method name="_shaped_text_get_ellipsis_pos" qualifiers="virtual const">
<return type="int" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns position of the ellipsis.
</description>
</method>
<method name="_shaped_text_get_glyph_count" qualifiers="virtual const">
<return type="int" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns number of glyphs in the buffer.
</description>
</method>
<method name="_shaped_text_get_glyphs" qualifiers="virtual const">
<return type="const Glyph*" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns an array of glyphs in the visual order.
</description>
</method>
<method name="_shaped_text_get_grapheme_bounds" qualifiers="virtual const">
@@ -1166,12 +1491,16 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="pos" type="int" />
<description>
+ [b]Optional.[/b]
+ Returns composite character's bounds as offsets from the start of the line.
</description>
</method>
<method name="_shaped_text_get_inferred_direction" qualifiers="virtual const">
<return type="int" enum="TextServer.Direction" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns direction of the text, inferred by the BiDi algorithm.
</description>
</method>
<method name="_shaped_text_get_line_breaks" qualifiers="virtual const">
@@ -1181,6 +1510,8 @@
<param index="2" name="start" type="int" />
<param index="3" name="break_flags" type="int" enum="TextServer.LineBreakFlag" is_bitfield="true" />
<description>
+ [b]Optional.[/b]
+ Breaks text to the lines and returns character ranges for each line.
</description>
</method>
<method name="_shaped_text_get_line_breaks_adv" qualifiers="virtual const">
@@ -1191,6 +1522,8 @@
<param index="3" name="once" type="bool" />
<param index="4" name="break_flags" type="int" enum="TextServer.LineBreakFlag" is_bitfield="true" />
<description>
+ [b]Optional.[/b]
+ Breaks text to the lines and columns. Returns character ranges for each segment.
</description>
</method>
<method name="_shaped_text_get_object_glyph" qualifiers="virtual const">
@@ -1198,6 +1531,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="key" type="Variant" />
<description>
+ [b]Required.[/b]
+ Returns the glyph index of the inline object.
</description>
</method>
<method name="_shaped_text_get_object_range" qualifiers="virtual const">
@@ -1205,6 +1540,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="key" type="Variant" />
<description>
+ [b]Required.[/b]
+ Returns the character range of the inline object.
</description>
</method>
<method name="_shaped_text_get_object_rect" qualifiers="virtual const">
@@ -1212,42 +1549,56 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="key" type="Variant" />
<description>
+ [b]Required.[/b]
+ Returns bounding rectangle of the inline object.
</description>
</method>
<method name="_shaped_text_get_objects" qualifiers="virtual const">
<return type="Array" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns array of inline objects.
</description>
</method>
<method name="_shaped_text_get_orientation" qualifiers="virtual const">
<return type="int" enum="TextServer.Orientation" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns text orientation.
</description>
</method>
<method name="_shaped_text_get_parent" qualifiers="virtual const">
<return type="RID" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns the parent buffer from which the substring originates.
</description>
</method>
<method name="_shaped_text_get_preserve_control" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns [code]true[/code] if text buffer is configured to display control characters.
</description>
</method>
<method name="_shaped_text_get_preserve_invalid" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Optional.[/b]
+ Returns [code]true[/code] if text buffer is configured to display hexadecimal codes in place of invalid characters.
</description>
</method>
<method name="_shaped_text_get_range" qualifiers="virtual const">
<return type="Vector2i" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns substring buffer character range in the parent buffer.
</description>
</method>
<method name="_shaped_text_get_selection" qualifiers="virtual const">
@@ -1256,12 +1607,16 @@
<param index="1" name="start" type="int" />
<param index="2" name="end" type="int" />
<description>
+ [b]Optional.[/b]
+ Returns selection rectangles for the specified character range.
</description>
</method>
<method name="_shaped_text_get_size" qualifiers="virtual const">
<return type="Vector2" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns size of the text.
</description>
</method>
<method name="_shaped_text_get_spacing" qualifiers="virtual const">
@@ -1269,30 +1624,40 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="spacing" type="int" enum="TextServer.SpacingType" />
<description>
+ [b]Optional.[/b]
+ Returns extra spacing added between glyphs or lines in pixels.
</description>
</method>
<method name="_shaped_text_get_trim_pos" qualifiers="virtual const">
<return type="int" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns the position of the overrun trim.
</description>
</method>
<method name="_shaped_text_get_underline_position" qualifiers="virtual const">
<return type="float" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns pixel offset of the underline below the baseline.
</description>
</method>
<method name="_shaped_text_get_underline_thickness" qualifiers="virtual const">
<return type="float" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns thickness of the underline.
</description>
</method>
<method name="_shaped_text_get_width" qualifiers="virtual const">
<return type="float" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns width (for horizontal layout) or height (for vertical) of the text.
</description>
</method>
<method name="_shaped_text_get_word_breaks" qualifiers="virtual const">
@@ -1300,6 +1665,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="grapheme_flags" type="int" enum="TextServer.GraphemeFlag" is_bitfield="true" />
<description>
+ [b]Optional.[/b]
+ Breaks text into words and returns array of character ranges. Use [param grapheme_flags] to set what characters are used for breaking (see [enum TextServer.GraphemeFlag]).
</description>
</method>
<method name="_shaped_text_hit_test_grapheme" qualifiers="virtual const">
@@ -1307,6 +1674,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="coord" type="float" />
<description>
+ [b]Optional.[/b]
+ Returns grapheme index at the specified pixel offset at the baseline, or [code]-1[/code] if none is found.
</description>
</method>
<method name="_shaped_text_hit_test_position" qualifiers="virtual const">
@@ -1314,12 +1683,16 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="coord" type="float" />
<description>
+ [b]Optional.[/b]
+ Returns caret character offset at the specified pixel offset at the baseline. This function always returns a valid position.
</description>
</method>
<method name="_shaped_text_is_ready" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns [code]true[/code] if buffer is successfully shaped.
</description>
</method>
<method name="_shaped_text_next_character_pos" qualifiers="virtual const">
@@ -1327,6 +1700,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="pos" type="int" />
<description>
+ [b]Optional.[/b]
+ Returns composite character end position closest to the [param pos].
</description>
</method>
<method name="_shaped_text_next_grapheme_pos" qualifiers="virtual const">
@@ -1334,6 +1709,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="pos" type="int" />
<description>
+ [b]Optional.[/b]
+ Returns grapheme end position closest to the [param pos].
</description>
</method>
<method name="_shaped_text_overrun_trim_to_width" qualifiers="virtual">
@@ -1342,6 +1719,8 @@
<param index="1" name="width" type="float" />
<param index="2" name="trim_flags" type="int" enum="TextServer.TextOverrunFlag" is_bitfield="true" />
<description>
+ [b]Optional.[/b]
+ Trims text if it exceeds the given width.
</description>
</method>
<method name="_shaped_text_prev_character_pos" qualifiers="virtual const">
@@ -1349,6 +1728,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="pos" type="int" />
<description>
+ [b]Optional.[/b]
+ Returns composite character start position closest to the [param pos].
</description>
</method>
<method name="_shaped_text_prev_grapheme_pos" qualifiers="virtual const">
@@ -1356,6 +1737,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="pos" type="int" />
<description>
+ [b]Optional.[/b]
+ Returns grapheme start position closest to the [param pos].
</description>
</method>
<method name="_shaped_text_resize_object" qualifiers="virtual">
@@ -1366,6 +1749,8 @@
<param index="3" name="inline_align" type="int" enum="InlineAlignment" />
<param index="4" name="baseline" type="float" />
<description>
+ [b]Required.[/b]
+ Sets new size and alignment of embedded object.
</description>
</method>
<method name="_shaped_text_set_bidi_override" qualifiers="virtual">
@@ -1373,6 +1758,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="override" type="Array" />
<description>
+ [b]Optional.[/b]
+ Overrides BiDi for the structured text.
</description>
</method>
<method name="_shaped_text_set_custom_ellipsis" qualifiers="virtual">
@@ -1380,6 +1767,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="char" type="int" />
<description>
+ [b]Optional.[/b]
+ Sets ellipsis character used for text clipping.
</description>
</method>
<method name="_shaped_text_set_custom_punctuation" qualifiers="virtual">
@@ -1387,6 +1776,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="punct" type="String" />
<description>
+ [b]Optional.[/b]
+ Sets custom punctuation character list, used for word breaking. If set to empty string, server defaults are used.
</description>
</method>
<method name="_shaped_text_set_direction" qualifiers="virtual">
@@ -1394,6 +1785,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="direction" type="int" enum="TextServer.Direction" />
<description>
+ [b]Optional.[/b]
+ Sets desired text direction. If set to [constant TextServer.DIRECTION_AUTO], direction will be detected based on the buffer contents and current locale.
</description>
</method>
<method name="_shaped_text_set_orientation" qualifiers="virtual">
@@ -1401,6 +1794,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="orientation" type="int" enum="TextServer.Orientation" />
<description>
+ [b]Optional.[/b]
+ Sets desired text orientation.
</description>
</method>
<method name="_shaped_text_set_preserve_control" qualifiers="virtual">
@@ -1408,6 +1803,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="enabled" type="bool" />
<description>
+ [b]Optional.[/b]
+ If set to [code]true[/code] text buffer will display control characters.
</description>
</method>
<method name="_shaped_text_set_preserve_invalid" qualifiers="virtual">
@@ -1415,6 +1812,8 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="enabled" type="bool" />
<description>
+ [b]Optional.[/b]
+ If set to [code]true[/code] text buffer will display invalid characters as hexadecimal codes, otherwise nothing is displayed.
</description>
</method>
<method name="_shaped_text_set_spacing" qualifiers="virtual">
@@ -1423,18 +1822,24 @@
<param index="1" name="spacing" type="int" enum="TextServer.SpacingType" />
<param index="2" name="value" type="int" />
<description>
+ [b]Optional.[/b]
+ Sets extra spacing added between glyphs or lines in pixels.
</description>
</method>
<method name="_shaped_text_shape" qualifiers="virtual">
<return type="bool" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Shapes buffer if it's not shaped. Returns [code]true[/code] if the string is shaped successfully.
</description>
</method>
<method name="_shaped_text_sort_logical" qualifiers="virtual">
<return type="const Glyph*" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Required.[/b]
+ Returns text glyphs in the logical order.
</description>
</method>
<method name="_shaped_text_substr" qualifiers="virtual const">
@@ -1443,6 +1848,8 @@
<param index="1" name="start" type="int" />
<param index="2" name="length" type="int" />
<description>
+ [b]Required.[/b]
+ Returns text buffer for the substring of the text in the [param shaped] text buffer (including inline objects).
</description>
</method>
<method name="_shaped_text_tab_align" qualifiers="virtual">
@@ -1450,24 +1857,32 @@
<param index="0" name="shaped" type="RID" />
<param index="1" name="tab_stops" type="PackedFloat32Array" />
<description>
+ [b]Optional.[/b]
+ Aligns shaped text to the given tab-stops.
</description>
</method>
<method name="_shaped_text_update_breaks" qualifiers="virtual">
<return type="bool" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Optional.[/b]
+ Updates break points in the shaped text. This method is called by default implementation of text breaking functions.
</description>
</method>
<method name="_shaped_text_update_justification_ops" qualifiers="virtual">
<return type="bool" />
<param index="0" name="shaped" type="RID" />
<description>
+ [b]Optional.[/b]
+ Updates justification points in the shaped text. This method is called by default implementation of text justification functions.
</description>
</method>
<method name="_spoof_check" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="string" type="String" />
<description>
+ [b]Optional.[/b]
+ Returns [code]true[/code] if [param string] is likely to be an attempt at confusing the reader.
</description>
</method>
<method name="_string_get_character_breaks" qualifiers="virtual const">
@@ -1475,6 +1890,8 @@
<param index="0" name="string" type="String" />
<param index="1" name="language" type="String" />
<description>
+ [b]Optional.[/b]
+ Returns array of the composite character boundaries.
</description>
</method>
<method name="_string_get_word_breaks" qualifiers="virtual const">
@@ -1483,6 +1900,8 @@
<param index="1" name="language" type="String" />
<param index="2" name="chars_per_line" type="int" />
<description>
+ [b]Optional.[/b]
+ Returns an array of the word break boundaries. Elements in the returned array are the offsets of the start and end of words. Therefore the length of the array is always even.
</description>
</method>
<method name="_string_to_lower" qualifiers="virtual const">
@@ -1490,6 +1909,8 @@
<param index="0" name="string" type="String" />
<param index="1" name="language" type="String" />
<description>
+ [b]Optional.[/b]
+ Returns the string converted to lowercase.
</description>
</method>
<method name="_string_to_upper" qualifiers="virtual const">
@@ -1497,18 +1918,24 @@
<param index="0" name="string" type="String" />
<param index="1" name="language" type="String" />
<description>
+ [b]Optional.[/b]
+ Returns the string converted to uppercase.
</description>
</method>
<method name="_strip_diacritics" qualifiers="virtual const">
<return type="String" />
<param index="0" name="string" type="String" />
<description>
+ [b]Optional.[/b]
+ Strips diacritics from the string.
</description>
</method>
<method name="_tag_to_name" qualifiers="virtual const">
<return type="String" />
<param index="0" name="tag" type="int" />
<description>
+ [b]Optional.[/b]
+ Converts OpenType tag to readable feature, variation, script, or language name.
</description>
</method>
</methods>
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 82bc8d82cb..13d84d96d6 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -368,7 +368,7 @@
In some cases, debanding may introduce a slightly noticeable dithering pattern. It's recommended to enable debanding only when actually needed since the dithering pattern will make lossless-compressed screenshots larger.
</member>
<member name="use_hdr_2d" type="bool" setter="set_use_hdr_2d" getter="is_using_hdr_2d" default="false">
- If [code]true[/code], 2D rendering will use an high dynamic range (HDR) format framebuffer matching the bit depth of the 3D framebuffer. When using the Forward+ renderer this will be a [code]RGBA16[/code] framebuffer, while when using the Mobile renderer it will be a [code]RGB10_A2[/code] framebuffer. Additionally, 2D rendering will take place in linear color space and will be converted to sRGB space immediately before blitting to the screen (if the Viewport is attached to the screen). Practically speaking, this means that the end result of the Viewport will not be clamped into the [code]0-1[/code] range and can be used in 3D rendering without color space adjustments. This allows 2D rendering to take advantage of effects requiring high dynamic range (e.g. 2D glow) as well as substantially improves the appearance of effects requiring highly detailed gradients.
+ If [code]true[/code], 2D rendering will use an high dynamic range (HDR) format framebuffer matching the bit depth of the 3D framebuffer. When using the Forward+ renderer this will be an [code]RGBA16[/code] framebuffer, while when using the Mobile renderer it will be an [code]RGB10_A2[/code] framebuffer. Additionally, 2D rendering will take place in linear color space and will be converted to sRGB space immediately before blitting to the screen (if the Viewport is attached to the screen). Practically speaking, this means that the end result of the Viewport will not be clamped into the [code]0-1[/code] range and can be used in 3D rendering without color space adjustments. This allows 2D rendering to take advantage of effects requiring high dynamic range (e.g. 2D glow) as well as substantially improves the appearance of effects requiring highly detailed gradients.
[b]Note:[/b] This setting will have no effect when using the GL Compatibility renderer as the GL Compatibility renderer always renders in low dynamic range for performance reasons.
</member>
<member name="use_occlusion_culling" type="bool" setter="set_use_occlusion_culling" getter="is_using_occlusion_culling" default="false">
diff --git a/doc/classes/XMLParser.xml b/doc/classes/XMLParser.xml
index b6dd7a74f8..2b67ff6fbb 100644
--- a/doc/classes/XMLParser.xml
+++ b/doc/classes/XMLParser.xml
@@ -6,7 +6,7 @@
<description>
Provides a low-level interface for creating parsers for [url=https://en.wikipedia.org/wiki/XML]XML[/url] files. This class can serve as base to make custom XML parsers.
To parse XML, you must open a file with the [method open] method or a buffer with the [method open_buffer] method. Then, the [method read] method must be called to parse the next nodes. Most of the methods take into consideration the currently parsed node.
- Here is an example of using [XMLParser] to parse a SVG file (which is based on XML), printing each element and its attributes as a dictionary:
+ Here is an example of using [XMLParser] to parse an SVG file (which is based on XML), printing each element and its attributes as a dictionary:
[codeblocks]
[gdscript]
var parser = XMLParser.new()
diff --git a/drivers/d3d12/rendering_context_driver_d3d12.h b/drivers/d3d12/rendering_context_driver_d3d12.h
index f74105ed3d..2e286b6927 100644
--- a/drivers/d3d12/rendering_context_driver_d3d12.h
+++ b/drivers/d3d12/rendering_context_driver_d3d12.h
@@ -100,7 +100,7 @@ public:
// D3D12-only methods.
struct Surface {
- HWND hwnd = NULL;
+ HWND hwnd = nullptr;
uint32_t width = 0;
uint32_t height = 0;
DisplayServer::VSyncMode vsync_mode = DisplayServer::VSYNC_ENABLED;
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp
index 49ab4f179f..fc7aa62aae 100644
--- a/drivers/d3d12/rendering_device_driver_d3d12.cpp
+++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp
@@ -5999,7 +5999,7 @@ RenderingDeviceDriverD3D12::~RenderingDeviceDriverD3D12() {
}
bool RenderingDeviceDriverD3D12::is_in_developer_mode() {
- HKEY hkey = NULL;
+ HKEY hkey = nullptr;
LSTATUS result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModelUnlock", 0, KEY_READ, &hkey);
if (result != ERROR_SUCCESS) {
return false;
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h
index 852cb9db0e..61da9a5169 100644
--- a/drivers/d3d12/rendering_device_driver_d3d12.h
+++ b/drivers/d3d12/rendering_device_driver_d3d12.h
@@ -379,7 +379,7 @@ private:
struct FenceInfo {
ComPtr<ID3D12Fence> d3d_fence = nullptr;
- HANDLE event_handle = NULL;
+ HANDLE event_handle = nullptr;
UINT64 fence_value = 0;
};
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index de990a4222..304dc9e328 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -1287,7 +1287,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index, Ren
uint32_t range_start = state.canvas_instance_batches[p_index].start * sizeof(InstanceData);
_enable_attributes(range_start, false);
- glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0, state.canvas_instance_batches[p_index].instance_count);
+ glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr, state.canvas_instance_batches[p_index].instance_count);
glBindVertexArray(0);
if (r_render_info) {
@@ -1490,7 +1490,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index, Ren
uint32_t vertex_count = mesh_storage->mesh_surface_get_vertices_drawn_count(surface);
if (use_index_buffer) {
- glDrawElementsInstanced(primitive_gl, vertex_count, mesh_storage->mesh_surface_get_index_type(surface), 0, instance_count);
+ glDrawElementsInstanced(primitive_gl, vertex_count, mesh_storage->mesh_surface_get_index_type(surface), nullptr, instance_count);
} else {
glDrawArraysInstanced(primitive_gl, 0, vertex_count, instance_count);
}
@@ -1701,7 +1701,7 @@ void RasterizerCanvasGLES3::light_update_shadow(RID p_rid, int p_shadow_index, c
}
glBindVertexArray(co->vertex_array);
- glDrawElements(GL_TRIANGLES, 3 * co->line_point_count, GL_UNSIGNED_SHORT, 0);
+ glDrawElements(GL_TRIANGLES, 3 * co->line_point_count, GL_UNSIGNED_SHORT, nullptr);
instance = instance->next;
}
@@ -1804,7 +1804,7 @@ void RasterizerCanvasGLES3::light_update_directional_shadow(RID p_rid, int p_sha
}
glBindVertexArray(co->vertex_array);
- glDrawElements(GL_TRIANGLES, 3 * co->line_point_count, GL_UNSIGNED_SHORT, 0);
+ glDrawElements(GL_TRIANGLES, 3 * co->line_point_count, GL_UNSIGNED_SHORT, nullptr);
instance = instance->next;
}
@@ -1923,7 +1923,7 @@ void RasterizerCanvasGLES3::render_sdf(RID p_render_target, LightOccluderInstanc
shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW2, modelview.columns[0][1], modelview.columns[1][1], 0, modelview.columns[2][1], shadow_render.shader_version, variant);
glBindVertexArray(oc->sdf_vertex_array);
- glDrawElements(oc->sdf_is_lines ? GL_LINES : GL_TRIANGLES, oc->sdf_index_count, GL_UNSIGNED_INT, 0);
+ glDrawElements(oc->sdf_is_lines ? GL_LINES : GL_TRIANGLES, oc->sdf_index_count, GL_UNSIGNED_INT, nullptr);
instance = instance->next;
}
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 73ee277074..cee4f93b3d 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -307,7 +307,7 @@ RasterizerGLES3::RasterizerGLES3() {
if (callback) {
print_line("godot: ENABLING GL DEBUG");
glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
- callback((DEBUGPROCARB)_gl_debug_print, NULL);
+ callback((DEBUGPROCARB)_gl_debug_print, nullptr);
glEnable(_EXT_DEBUG_OUTPUT);
}
}
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 09edc12112..29cfa251d6 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -3462,10 +3462,10 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
if (use_wireframe) {
- glDrawElementsInstanced(GL_LINES, count, GL_UNSIGNED_INT, 0, inst->instance_count);
+ glDrawElementsInstanced(GL_LINES, count, GL_UNSIGNED_INT, nullptr, inst->instance_count);
} else {
if (use_index_buffer) {
- glDrawElementsInstanced(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0, inst->instance_count);
+ glDrawElementsInstanced(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), nullptr, inst->instance_count);
} else {
glDrawArraysInstanced(primitive_gl, 0, count, inst->instance_count);
}
@@ -3473,10 +3473,10 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
} else {
// Using regular Mesh.
if (use_wireframe) {
- glDrawElements(GL_LINES, count, GL_UNSIGNED_INT, 0);
+ glDrawElements(GL_LINES, count, GL_UNSIGNED_INT, nullptr);
} else {
if (use_index_buffer) {
- glDrawElements(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0);
+ glDrawElements(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), nullptr);
} else {
glDrawArrays(primitive_gl, 0, count);
}
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index ce0876972a..71cd152520 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -144,7 +144,7 @@ private:
RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
uint64_t scene_pass = 0;
- template <class T>
+ template <typename T>
struct InstanceSort {
float depth;
T *instance = nullptr;
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index 43b146152d..876309d22c 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/drivers/gles3/shader_gles3.cpp
@@ -540,7 +540,7 @@ bool ShaderGLES3::_load_from_cache(Version *p_version) {
return false;
#else
#if !defined(ANDROID_ENABLED) && !defined(IOS_ENABLED)
- if (RasterizerGLES3::is_gles_over_gl() && (glProgramBinary == NULL)) { // ARB_get_program_binary extension not available.
+ if (RasterizerGLES3::is_gles_over_gl() && (glProgramBinary == nullptr)) { // ARB_get_program_binary extension not available.
return false;
}
#endif
@@ -627,7 +627,7 @@ void ShaderGLES3::_save_to_cache(Version *p_version) {
#else
ERR_FAIL_COND(!shader_cache_dir_valid);
#if !defined(ANDROID_ENABLED) && !defined(IOS_ENABLED)
- if (RasterizerGLES3::is_gles_over_gl() && (glGetProgramBinary == NULL)) { // ARB_get_program_binary extension not available.
+ if (RasterizerGLES3::is_gles_over_gl() && (glGetProgramBinary == nullptr)) { // ARB_get_program_binary extension not available.
return;
}
#endif
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index 5d2bc44377..a032535827 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -1067,7 +1067,7 @@ Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer);
glBindTexture(GL_TEXTURE_2D, temp_color_texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -1139,7 +1139,7 @@ Ref<Image> TextureStorage::texture_2d_layer_get(RID p_texture, int p_layer) cons
glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer);
glBindTexture(GL_TEXTURE_2D, temp_color_texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -1248,7 +1248,7 @@ Vector<Ref<Image>> TextureStorage::texture_3d_get(RID p_texture) const {
glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer);
glBindTexture(GL_TEXTURE_2D, temp_color_texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
diff --git a/editor/editor_data.h b/editor/editor_data.h
index d71a2b3ed3..42b2d2ed0c 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -300,7 +300,7 @@ public:
void remove_node(Node *p_node);
bool is_selected(Node *p_node) const;
- template <class T>
+ template <typename T>
T *get_node_editor_data(Node *p_node) {
if (!selection.has(p_node)) {
return nullptr;
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 83e71292a3..ff42b82435 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -439,7 +439,7 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
}
}
- if (importer_name == "keep") {
+ if (importer_name == "keep" || importer_name == "skip") {
return false; //keep mode, do not reimport
}
@@ -1859,7 +1859,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
source_file_options[p_files[i]] = HashMap<StringName, Variant>();
importer_name = file_importer_name;
- if (importer_name == "keep") {
+ if (importer_name == "keep" || importer_name == "skip") {
continue; //do nothing
}
@@ -1885,7 +1885,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
base_paths[p_files[i]] = ResourceFormatImporter::get_singleton()->get_import_base_path(p_files[i]);
}
- if (importer_name == "keep") {
+ if (importer_name == "keep" || importer_name == "skip") {
return OK; // (do nothing)
}
@@ -2078,7 +2078,7 @@ Error EditorFileSystem::_reimport_file(const String &p_file, const HashMap<Strin
}
}
- if (importer_name == "keep") {
+ if (importer_name == "keep" || importer_name == "skip") {
//keep files, do nothing.
fs->files[cpos]->modified_time = FileAccess::get_modified_time(p_file);
fs->files[cpos]->import_modified_time = FileAccess::get_modified_time(p_file + ".import");
diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h
index 003b98adf0..39ffc2f71b 100644
--- a/editor/editor_help_search.h
+++ b/editor/editor_help_search.h
@@ -117,7 +117,7 @@ class EditorHelpSearch::Runner : public RefCounted {
};
int phase = 0;
- template <class T>
+ template <typename T>
struct MemberMatch {
T *doc = nullptr;
bool name = false;
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 7c28818b2f..f45a512b89 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -264,7 +264,7 @@ class EditorPlugins {
static EditorPluginCreateFunc creation_funcs[MAX_CREATE_FUNCS];
static int creation_func_count;
- template <class T>
+ template <typename T>
static EditorPlugin *creator() {
return memnew(T);
}
@@ -276,7 +276,7 @@ public:
return creation_funcs[p_idx]();
}
- template <class T>
+ template <typename T>
static void add_by_type() {
add_create_func(creator<T>);
}
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index c212bdb84f..d2a187bcfd 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -1196,6 +1196,11 @@ Error EditorExportPlatform::export_project_files(bool p_main_pack, const Ref<Edi
String importer_type = config->get_value("remap", "importer");
+ if (importer_type == "skip") {
+ // Skip file.
+ continue;
+ }
+
if (importer_type == "keep") {
// Just keep file as-is.
Vector<uint8_t> array = FileAccess::get_file_as_bytes(path);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 88fed16db1..0f83e109fa 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -173,14 +173,48 @@ FileSystemList::FileSystemList() {
FileSystemDock *FileSystemDock::singleton = nullptr;
-Ref<Texture2D> FileSystemDock::_get_tree_item_icon(bool p_is_valid, const String &p_file_type) {
- Ref<Texture2D> file_icon;
+Ref<Texture2D> FileSystemDock::_get_tree_item_icon(bool p_is_valid, const String &p_file_type, const String &p_icon_path) {
+ if (!p_icon_path.is_empty()) {
+ Ref<Texture2D> icon = ResourceLoader::load(p_icon_path);
+ if (icon.is_valid()) {
+ return icon;
+ }
+ }
+
if (!p_is_valid) {
- file_icon = get_editor_theme_icon(SNAME("ImportFail"));
+ return get_editor_theme_icon(SNAME("ImportFail"));
+ } else if (has_theme_icon(p_file_type, EditorStringName(EditorIcons))) {
+ return get_editor_theme_icon(p_file_type);
} else {
- file_icon = (has_theme_icon(p_file_type, EditorStringName(EditorIcons))) ? get_editor_theme_icon(p_file_type) : get_editor_theme_icon(SNAME("File"));
+ return get_editor_theme_icon(SNAME("File"));
}
- return file_icon;
+}
+
+String FileSystemDock::_get_entry_script_icon(const EditorFileSystemDirectory *p_dir, int p_file) {
+ const PackedStringArray &deps = p_dir->get_file_deps(p_file);
+ if (deps.is_empty()) {
+ return String();
+ }
+
+ const String &script_path = deps[0]; // Assuming the first dependency is a script.
+ if (script_path.is_empty() || !ClassDB::is_parent_class(ResourceLoader::get_resource_type(script_path), SNAME("Script"))) {
+ return String();
+ }
+
+ String *cached = icon_cache.getptr(script_path);
+ if (cached) {
+ return *cached;
+ }
+
+ HashMap<String, String>::Iterator I;
+ int script_file;
+ EditorFileSystemDirectory *efsd = EditorFileSystem::get_singleton()->find_file(script_path, &script_file);
+ if (efsd) {
+ I = icon_cache.insert(script_path, efsd->get_file_script_class_icon_path(script_file));
+ } else {
+ I = icon_cache.insert(script_path, String());
+ }
+ return I->value;
}
bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path) {
@@ -272,6 +306,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
FileInfo fi;
fi.name = p_dir->get_file(i);
fi.type = p_dir->get_file_type(i);
+ fi.icon_path = _get_entry_script_icon(p_dir, i);
fi.import_broken = !p_dir->get_file_import_is_valid(i);
fi.modified_time = p_dir->get_file_modified_time(i);
@@ -282,18 +317,21 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
_sort_file_info_list(file_list);
// Build the tree.
+ const int icon_size = get_theme_constant(SNAME("class_icon_size"), SNAME("Editor"));
+
for (const FileInfo &fi : file_list) {
TreeItem *file_item = tree->create_item(subdirectory_item);
+ const String file_metadata = lpath.path_join(fi.name);
file_item->set_text(0, fi.name);
file_item->set_structured_text_bidi_override(0, TextServer::STRUCTURED_TEXT_FILE);
- file_item->set_icon(0, _get_tree_item_icon(!fi.import_broken, fi.type));
+ file_item->set_icon(0, _get_tree_item_icon(!fi.import_broken, fi.type, fi.icon_path));
+ file_item->set_icon_max_width(0, icon_size);
Color parent_bg_color = subdirectory_item->get_custom_bg_color(0);
if (has_custom_color) {
file_item->set_custom_bg_color(0, parent_bg_color.darkened(0.3));
} else if (parent_bg_color != Color()) {
file_item->set_custom_bg_color(0, parent_bg_color);
}
- String file_metadata = lpath.path_join(fi.name);
file_item->set_metadata(0, file_metadata);
if (!p_select_in_favorites && current_path == file_metadata) {
file_item->select(0);
@@ -366,6 +404,8 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
updating_tree = true;
TreeItem *root = tree->create_item();
+ icon_cache.clear();
+
// Handles the favorites.
TreeItem *favorites_item = tree->create_item(root);
favorites_item->set_icon(0, get_editor_theme_icon(SNAME("Favorites")));
@@ -413,7 +453,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
int index;
EditorFileSystemDirectory *dir = EditorFileSystem::get_singleton()->find_file(favorite, &index);
if (dir) {
- icon = _get_tree_item_icon(dir->get_file_import_is_valid(index), dir->get_file_type(index));
+ icon = _get_tree_item_icon(dir->get_file_import_is_valid(index), dir->get_file_path(index), dir->get_file_type(index));
} else {
icon = get_editor_theme_icon(SNAME("File"));
}
@@ -1160,7 +1200,7 @@ void FileSystemDock::_select_file(const String &p_path, bool p_select_in_favorit
if (err == OK) {
if (config->has_section_key("remap", "importer")) {
String importer = config->get_value("remap", "importer");
- if (importer == "keep") {
+ if (importer == "keep" || importer == "skip") {
EditorNode::get_singleton()->show_warning(TTR("Importing has been disabled for this file, so it can't be opened for editing."));
return;
}
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index acb7ca017b..15a43dc6f2 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -139,6 +139,7 @@ private:
FILE_NEW_SCENE,
};
+ HashMap<String, String> icon_cache;
HashMap<String, Color> folder_colors;
Dictionary assigned_folder_colors;
@@ -245,7 +246,8 @@ private:
void _tree_mouse_exited();
void _reselect_items_selected_on_drag_begin(bool reset = false);
- Ref<Texture2D> _get_tree_item_icon(bool p_is_valid, const String &p_file_type);
+ Ref<Texture2D> _get_tree_item_icon(bool p_is_valid, const String &p_file_type, const String &p_icon_path);
+ String _get_entry_script_icon(const EditorFileSystemDirectory *p_dir, int p_file);
bool _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path = false);
void _update_tree(const Vector<String> &p_uncollapsed_paths = Vector<String>(), bool p_uncollapse_root = false, bool p_select_in_favorites = false, bool p_unfold_path = false);
void _navigate_to_path(const String &p_path, bool p_select_in_favorites = false);
@@ -323,6 +325,7 @@ private:
struct FileInfo {
String name;
String path;
+ String icon_path;
StringName type;
Vector<String> sources;
bool import_broken = false;
diff --git a/editor/icons/FadeCross.svg b/editor/icons/FadeCross.svg
new file mode 100644
index 0000000000..2d4f058838
--- /dev/null
+++ b/editor/icons/FadeCross.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 1v2h2.586l-3.586 3.586-4.293-4.293-1.414 1.414 4.293 4.293-4.293 4.293 1.414 1.414 4.293-4.293 3.586 3.586h-2.586v2h5a1 1 0 0 0 1-1v-5h-2v2.586l-3.586-3.586 3.586-3.586v2.586h2v-5a1 1 0 0 0 -1-1z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/FadeDisabled.svg b/editor/icons/FadeDisabled.svg
new file mode 100644
index 0000000000..2333335dcd
--- /dev/null
+++ b/editor/icons/FadeDisabled.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m11.032091 3.1108593-1.4142134 1.4142136 1.8285784 1.8285781h-9.8600786v1.999698h9.8600786l-1.8285784 1.828578 1.4142134 1.414214 3.535534-3.5355342c.390524-.3905243.390525-1.0236891 0-1.4142136z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/FadeIn.svg b/editor/icons/FadeIn.svg
new file mode 100644
index 0000000000..3144e07d23
--- /dev/null
+++ b/editor/icons/FadeIn.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 1v2h2.586c-9.293 9.293-.896067.8960673-9.293 9.293l1.414 1.414c9.293-9.293 3.7072139-3.7072139 9.293-9.293v2.586h2v-5c0-.5522847-.447715-1-1-1z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/FadeOut.svg b/editor/icons/FadeOut.svg
new file mode 100644
index 0000000000..4ce90b58aa
--- /dev/null
+++ b/editor/icons/FadeOut.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.707 2.293-1.414 1.414c9.293 9.293 1.4503342 1.4503342 9.293 9.293h-2.586v2h5c.552285 0 1-.447715 1-1v-5h-2v2.586c-9.293-9.293-2.832166-2.8321664-9.293-9.293z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/import/3d/resource_importer_scene.h b/editor/import/3d/resource_importer_scene.h
index 2e682350bc..17fa9ef0e2 100644
--- a/editor/import/3d/resource_importer_scene.h
+++ b/editor/import/3d/resource_importer_scene.h
@@ -303,10 +303,10 @@ public:
ResourceImporterScene(bool p_animation_import = false, bool p_singleton = false);
~ResourceImporterScene();
- template <class M>
+ template <typename M>
static Vector<Ref<Shape3D>> get_collision_shapes(const Ref<ImporterMesh> &p_mesh, const M &p_options, float p_applied_root_scale);
- template <class M>
+ template <typename M>
static Transform3D get_collision_shapes_transform(const M &p_options);
};
@@ -319,7 +319,7 @@ public:
virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr) override;
};
-template <class M>
+template <typename M>
Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<ImporterMesh> &p_mesh, const M &p_options, float p_applied_root_scale) {
ERR_FAIL_COND_V(p_mesh.is_null(), Vector<Ref<Shape3D>>());
ShapeType generate_shape_type = SHAPE_TYPE_DECOMPOSE_CONVEX;
@@ -476,7 +476,7 @@ Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Impor
return Vector<Ref<Shape3D>>();
}
-template <class M>
+template <typename M>
Transform3D ResourceImporterScene::get_collision_shapes_transform(const M &p_options) {
Transform3D transform;
diff --git a/editor/import/resource_importer_bmfont.cpp b/editor/import/resource_importer_bmfont.cpp
index a2cb306c94..085ca1362d 100644
--- a/editor/import/resource_importer_bmfont.cpp
+++ b/editor/import/resource_importer_bmfont.cpp
@@ -30,6 +30,7 @@
#include "resource_importer_bmfont.h"
+#include "core/io/config_file.h"
#include "core/io/resource_saver.h"
String ResourceImporterBMFont::get_importer_name() const {
@@ -75,9 +76,24 @@ Error ResourceImporterBMFont::import(const String &p_source_file, const String &
Ref<FontFile> font;
font.instantiate();
- Error err = font->load_bitmap_font(p_source_file);
+ List<String> image_files;
+ Error err = font->_load_bitmap_font(p_source_file, &image_files);
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot load font to file \"" + p_source_file + "\".");
+ // Update import settings for the image files used by font.
+ for (List<String>::Element *E = image_files.front(); E; E = E->next()) {
+ Ref<ConfigFile> config;
+ config.instantiate();
+
+ err = config->load(E->get() + ".import");
+ if (err == OK) {
+ config->clear();
+ config->set_value("remap", "importer", "skip");
+
+ config->save(E->get() + ".import");
+ }
+ }
+
font->set_allow_system_fallback(false);
font->set_fallbacks(fallbacks);
font->set_fixed_size_scale_mode(smode);
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index 47572a991c..6f4a376496 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -48,7 +48,8 @@ public:
Ref<ResourceImporter> importer;
Vector<String> paths;
HashSet<StringName> checked;
- bool checking;
+ bool checking = false;
+ bool skip = false;
String base_options_path;
bool _set(const StringName &p_name, const Variant &p_value) {
@@ -91,10 +92,6 @@ public:
void update() {
notify_property_list_changed();
}
-
- ImportDockParameters() {
- checking = false;
- }
};
ImportDock *ImportDock::singleton = nullptr;
@@ -109,8 +106,16 @@ void ImportDock::set_edit_path(const String &p_path) {
}
String importer_name = config->get_value("remap", "importer");
-
- params->importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
+ if (importer_name == "keep") {
+ params->importer.unref();
+ params->skip = false;
+ } else if (importer_name == "skip") {
+ params->importer.unref();
+ params->skip = true;
+ } else {
+ params->importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
+ params->skip = false;
+ }
params->paths.clear();
params->paths.push_back(p_path);
@@ -152,9 +157,13 @@ void ImportDock::set_edit_path(const String &p_path) {
void ImportDock::_add_keep_import_option(const String &p_importer_name) {
import_as->add_separator();
- import_as->add_item(TTR("Keep File (No Import)"));
+ import_as->add_item(TTR("Keep File (exported as is)"));
import_as->set_item_metadata(-1, "keep");
+ import_as->add_item(TTR("Skip File (not exported)"));
+ import_as->set_item_metadata(-1, "skip");
if (p_importer_name == "keep") {
+ import_as->select(import_as->get_item_count() - 2);
+ } else if (p_importer_name == "skip") {
import_as->select(import_as->get_item_count() - 1);
}
}
@@ -163,7 +172,7 @@ void ImportDock::_update_options(const String &p_path, const Ref<ConfigFile> &p_
// Set the importer class to fetch the correct class in the XML class reference.
// This allows tooltips to display when hovering properties.
if (params->importer != nullptr) {
- // Null check to avoid crashing if the "Keep File (No Import)" mode is selected.
+ // Null check to avoid crashing if the "Keep File (exported as is)" mode is selected.
import_opts->set_object_class(params->importer->get_class_name());
}
@@ -215,7 +224,17 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) {
ERR_CONTINUE(err != OK);
if (i == 0) {
- params->importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(config->get_value("remap", "importer"));
+ String importer_name = config->get_value("remap", "importer");
+ if (importer_name == "keep") {
+ params->importer.unref();
+ params->skip = false;
+ } else if (importer_name == "skip") {
+ params->importer.unref();
+ params->skip = true;
+ } else {
+ params->importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
+ params->skip = false;
+ }
if (params->importer.is_null()) {
clear();
return;
@@ -372,12 +391,18 @@ void ImportDock::_importer_selected(int i_idx) {
String name = import_as->get_selected_metadata();
if (name == "keep") {
params->importer.unref();
+ params->skip = false;
+ _update_options(params->base_options_path, Ref<ConfigFile>());
+ } else if (name == "skip") {
+ params->importer.unref();
+ params->skip = true;
_update_options(params->base_options_path, Ref<ConfigFile>());
} else {
Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(name);
ERR_FAIL_COND(importer.is_null());
params->importer = importer;
+ params->skip = false;
Ref<ConfigFile> config;
if (params->paths.size()) {
String path = params->paths[0];
@@ -490,7 +515,11 @@ void ImportDock::_reimport_attempt() {
if (params->importer.is_valid()) {
importer_name = params->importer->get_importer_name();
} else {
- importer_name = "keep";
+ if (params->skip) {
+ importer_name = "skip";
+ } else {
+ importer_name = "keep";
+ }
}
for (int i = 0; i < params->paths.size(); i++) {
Ref<ConfigFile> config;
@@ -566,6 +595,7 @@ void ImportDock::_advanced_options() {
params->importer->show_advanced_options(params->paths[0]);
}
}
+
void ImportDock::_reimport() {
for (int i = 0; i < params->paths.size(); i++) {
Ref<ConfigFile> config;
@@ -611,7 +641,11 @@ void ImportDock::_reimport() {
} else {
//set to no import
config->clear();
- config->set_value("remap", "importer", "keep");
+ if (params->skip) {
+ config->set_value("remap", "importer", "skip");
+ } else {
+ config->set_value("remap", "importer", "keep");
+ }
}
config->save(params->paths[i] + ".import");
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index 5845ddbb6e..597fd7393f 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -946,8 +946,10 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() {
button_center_view = memnew(Button);
button_center_view->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT, Control::PRESET_MODE_MINSIZE, 5);
+ button_center_view->set_grow_direction_preset(Control::PRESET_TOP_RIGHT);
button_center_view->connect("pressed", callable_mp(this, &GenericTilePolygonEditor::_center_view));
button_center_view->set_theme_type_variation("FlatButton");
+ button_center_view->set_tooltip_text(TTR("Center View"));
button_center_view->set_disabled(true);
root->add_child(button_center_view);
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index d5aba35a8f..f9efc62f03 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -2683,10 +2683,8 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
help_label = memnew(Label(TTR("Hold Shift to create big tiles.")));
tile_create_help->add_child(help_label);
- tile_create_help->set_anchors_and_offsets_preset(Control::PRESET_BOTTOM_LEFT, Control::PRESET_MODE_MINSIZE);
- Vector2 pos = tile_create_help->get_position();
- pos.y -= 8 * EDSCALE;
- tile_create_help->set_position(pos);
+ tile_create_help->set_anchors_and_offsets_preset(Control::PRESET_BOTTOM_LEFT, Control::PRESET_MODE_MINSIZE, 8);
+ tile_create_help->set_grow_direction_preset(Control::PRESET_BOTTOM_LEFT);
base_tile_popup_menu = memnew(PopupMenu);
base_tile_popup_menu->add_shortcut(ED_SHORTCUT("tiles_editor/delete", TTR("Delete"), Key::KEY_DELETE), TILE_DELETE);
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index a54ffd4ee8..9460f9fef2 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -464,7 +464,7 @@ void VersionControlEditorPlugin::_force_push() {
void VersionControlEditorPlugin::_update_opened_tabs() {
Vector<EditorData::EditedScene> open_scenes = EditorNode::get_editor_data().get_edited_scenes();
for (int i = 0; i < open_scenes.size(); i++) {
- if (open_scenes[i].root == NULL) {
+ if (open_scenes[i].root == nullptr) {
continue;
}
EditorNode::get_singleton()->reload_scene(open_scenes[i].path);
diff --git a/main/main.cpp b/main/main.cpp
index 15f55fe180..9215f2e848 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -74,14 +74,15 @@
#include "servers/navigation_server_3d.h"
#include "servers/navigation_server_3d_dummy.h"
#include "servers/physics_server_2d.h"
-#ifndef _3D_DISABLED
-#include "servers/physics_server_3d.h"
-#endif // _3D_DISABLED
#include "servers/register_server_types.h"
#include "servers/rendering/rendering_server_default.h"
#include "servers/text/text_server_dummy.h"
#include "servers/text_server.h"
+
+#ifndef _3D_DISABLED
+#include "servers/physics_server_3d.h"
#include "servers/xr_server.h"
+#endif // _3D_DISABLED
#ifdef TESTS_ENABLED
#include "tests/test_main.h"
@@ -144,17 +145,17 @@ static AudioServer *audio_server = nullptr;
static DisplayServer *display_server = nullptr;
static RenderingServer *rendering_server = nullptr;
static CameraServer *camera_server = nullptr;
-static XRServer *xr_server = nullptr;
static TextServerManager *tsman = nullptr;
-#ifndef _3D_DISABLED
-static PhysicsServer3DManager *physics_server_3d_manager = nullptr;
-static PhysicsServer3D *physics_server_3d = nullptr;
-#endif // _3D_DISABLED
static PhysicsServer2DManager *physics_server_2d_manager = nullptr;
static PhysicsServer2D *physics_server_2d = nullptr;
static NavigationServer3D *navigation_server_3d = nullptr;
static NavigationServer2D *navigation_server_2d = nullptr;
static ThemeDB *theme_db = nullptr;
+#ifndef _3D_DISABLED
+static PhysicsServer3DManager *physics_server_3d_manager = nullptr;
+static PhysicsServer3D *physics_server_3d = nullptr;
+static XRServer *xr_server = nullptr;
+#endif // _3D_DISABLED
// We error out if setup2() doesn't turn this true
static bool _start_success = false;
@@ -1646,6 +1647,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->disable_crash_handler();
} else if (I->get() == "--skip-breakpoints") {
skip_breakpoints = true;
+#ifndef _3D_DISABLED
} else if (I->get() == "--xr-mode") {
if (I->next()) {
String xr_mode = I->next()->get().to_lower();
@@ -1664,7 +1666,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->print("Missing --xr-mode argument, aborting.\n");
goto error;
}
-
+#endif // _3D_DISABLED
} else if (I->get() == "--benchmark") {
OS::get_singleton()->set_use_benchmark(true);
} else if (I->get() == "--benchmark-file") {
@@ -2788,6 +2790,7 @@ Error Main::setup2() {
OS::get_singleton()->benchmark_end_measure("Servers", "Audio");
}
+#ifndef _3D_DISABLED
/* Initialize XR Server */
{
@@ -2797,6 +2800,7 @@ Error Main::setup2() {
OS::get_singleton()->benchmark_end_measure("Servers", "XR");
}
+#endif // _3D_DISABLED
OS::get_singleton()->benchmark_end_measure("Startup", "Servers");
@@ -3942,7 +3946,9 @@ bool Main::iteration() {
bool exit = false;
// process all our active interfaces
+#ifndef _3D_DISABLED
XRServer::get_singleton()->_process();
+#endif // _3D_DISABLED
NavigationServer2D::get_singleton()->sync();
NavigationServer3D::get_singleton()->sync();
@@ -4161,11 +4167,13 @@ void Main::cleanup(bool p_force) {
//clear global shader variables before scene and other graphics stuff are deinitialized.
rendering_server->global_shader_parameters_clear();
+#ifndef _3D_DISABLED
if (xr_server) {
// Now that we're unregistering properly in plugins we need to keep access to xr_server for a little longer
// We do however unset our primary interface
xr_server->set_primary_interface(Ref<XRInterface>());
}
+#endif // _3D_DISABLED
#ifdef TOOLS_ENABLED
GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_EDITOR);
@@ -4195,9 +4203,11 @@ void Main::cleanup(bool p_force) {
EngineDebugger::deinitialize();
+#ifndef _3D_DISABLED
if (xr_server) {
memdelete(xr_server);
}
+#endif // _3D_DISABLED
if (audio_server) {
audio_server->finish();
diff --git a/main/main.h b/main/main.h
index 062af73d57..755c7d841a 100644
--- a/main/main.h
+++ b/main/main.h
@@ -35,7 +35,7 @@
#include "core/os/thread.h"
#include "core/typedefs.h"
-template <class T>
+template <typename T>
class Vector;
class Main {
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 94aa077014..8e74de4242 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -354,6 +354,21 @@ bool GDScript::has_static_method(const StringName &p_method) const {
return member_functions.has(p_method) && member_functions[p_method]->is_static();
}
+int GDScript::get_script_method_argument_count(const StringName &p_method, bool *r_is_valid) const {
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = member_functions.find(p_method);
+ if (!E) {
+ if (r_is_valid) {
+ *r_is_valid = false;
+ }
+ return 0;
+ }
+
+ if (r_is_valid) {
+ *r_is_valid = true;
+ }
+ return E->value->get_argument_count();
+}
+
MethodInfo GDScript::get_method_info(const StringName &p_method) const {
HashMap<StringName, GDScriptFunction *>::ConstIterator E = member_functions.find(p_method);
if (!E) {
@@ -1916,6 +1931,25 @@ bool GDScriptInstance::has_method(const StringName &p_method) const {
return false;
}
+int GDScriptInstance::get_method_argument_count(const StringName &p_method, bool *r_is_valid) const {
+ const GDScript *sptr = script.ptr();
+ while (sptr) {
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(p_method);
+ if (E) {
+ if (r_is_valid) {
+ *r_is_valid = true;
+ }
+ return E->value->get_argument_count();
+ }
+ sptr = sptr->_base;
+ }
+
+ if (r_is_valid) {
+ *r_is_valid = false;
+ }
+ return 0;
+}
+
Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
GDScript *sptr = script.ptr();
if (unlikely(p_method == SNAME("_ready"))) {
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 7c471c285b..fd5ad837f9 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -312,6 +312,9 @@ public:
virtual void get_script_method_list(List<MethodInfo> *p_list) const override;
virtual bool has_method(const StringName &p_method) const override;
virtual bool has_static_method(const StringName &p_method) const override;
+
+ virtual int get_script_method_argument_count(const StringName &p_method, bool *r_is_valid = nullptr) const override;
+
virtual MethodInfo get_method_info(const StringName &p_method) const override;
virtual void get_script_property_list(List<PropertyInfo> *p_list) const override;
@@ -376,6 +379,9 @@ public:
virtual void get_method_list(List<MethodInfo> *p_list) const;
virtual bool has_method(const StringName &p_method) const;
+
+ virtual int get_method_argument_count(const StringName &p_method, bool *r_is_valid = nullptr) const;
+
virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
Variant debug_get_member_by_index(int p_idx) const { return members[p_idx]; }
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 3ec5098c21..6af6460b31 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -562,6 +562,12 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
class_type.native_type = result.native_type;
p_class->set_datatype(class_type);
+ // Apply annotations.
+ for (GDScriptParser::AnnotationNode *&E : p_class->annotations) {
+ resolve_annotation(E);
+ E->apply(parser, p_class, p_class->outer);
+ }
+
parser->current_class = previous_class;
return OK;
@@ -912,7 +918,6 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class,
{
#ifdef DEBUG_ENABLED
- HashSet<GDScriptWarning::Code> previously_ignored_warnings = parser->ignored_warnings;
GDScriptParser::Node *member_node = member.get_source_node();
if (member_node && member_node->type != GDScriptParser::Node::ANNOTATION) {
// Apply @warning_ignore annotations before resolving member.
@@ -922,9 +927,6 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class,
E->apply(parser, member.variable, p_class);
}
}
- for (GDScriptWarning::Code ignored_warning : member_node->ignored_warnings) {
- parser->ignored_warnings.insert(ignored_warning);
- }
}
#endif
switch (member.type) {
@@ -1061,6 +1063,13 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class,
enum_type.enum_values[element.identifier->name] = element.value;
dictionary[String(element.identifier->name)] = element.value;
+
+#ifdef DEBUG_ENABLED
+ // Named enum identifiers do not shadow anything since you can only access them with `NamedEnum.ENUM_VALUE`.
+ if (member.m_enum->identifier->name == StringName()) {
+ is_shadowing(element.identifier, "enum member", false);
+ }
+#endif
}
current_enum = prev_enum;
@@ -1133,9 +1142,6 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class,
ERR_PRINT("Trying to resolve undefined member.");
break;
}
-#ifdef DEBUG_ENABLED
- parser->ignored_warnings = previously_ignored_warnings;
-#endif
}
parser->current_class = previous_class;
@@ -1146,11 +1152,11 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
p_source = p_class;
}
+ if (!p_class->resolved_interface) {
#ifdef DEBUG_ENABLED
- bool has_static_data = p_class->has_static_data;
+ bool has_static_data = p_class->has_static_data;
#endif
- if (!p_class->resolved_interface) {
if (!parser->has_class(p_class)) {
String script_path = p_class->get_datatype().script_path;
Ref<GDScriptParserRef> parser_ref = get_parser_for(script_path);
@@ -1178,6 +1184,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
return;
}
+
p_class->resolved_interface = true;
if (resolve_class_inheritance(p_class) != OK) {
@@ -1319,10 +1326,6 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class, co
GDScriptParser::ClassNode::Member member = p_class->members[i];
if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) {
#ifdef DEBUG_ENABLED
- HashSet<GDScriptWarning::Code> previously_ignored_warnings = parser->ignored_warnings;
- for (GDScriptWarning::Code ignored_warning : member.variable->ignored_warnings) {
- parser->ignored_warnings.insert(ignored_warning);
- }
if (member.variable->usages == 0 && String(member.variable->identifier->name).begins_with("_")) {
parser->push_warning(member.variable->identifier, GDScriptWarning::UNUSED_PRIVATE_CLASS_VARIABLE, member.variable->identifier->name);
}
@@ -1396,10 +1399,12 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class, co
}
}
}
-
+ } else if (member.type == GDScriptParser::ClassNode::Member::SIGNAL) {
#ifdef DEBUG_ENABLED
- parser->ignored_warnings = previously_ignored_warnings;
-#endif // DEBUG_ENABLED
+ if (member.signal->usages == 0) {
+ parser->push_warning(member.signal->identifier, GDScriptWarning::UNUSED_SIGNAL, member.signal->identifier->name);
+ }
+#endif
}
}
@@ -1431,6 +1436,7 @@ void GDScriptAnalyzer::resolve_node(GDScriptParser::Node *p_node, bool p_is_root
case GDScriptParser::Node::NONE:
break; // Unreachable.
case GDScriptParser::Node::CLASS:
+ // NOTE: Currently this route is never executed, `resolve_class_*()` is called directly.
if (OK == resolve_class_inheritance(static_cast<GDScriptParser::ClassNode *>(p_node), true)) {
resolve_class_interface(static_cast<GDScriptParser::ClassNode *>(p_node), true);
resolve_class_body(static_cast<GDScriptParser::ClassNode *>(p_node), true);
@@ -1584,13 +1590,6 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
}
p_function->resolved_signature = true;
-#ifdef DEBUG_ENABLED
- HashSet<GDScriptWarning::Code> previously_ignored_warnings = parser->ignored_warnings;
- for (GDScriptWarning::Code ignored_warning : p_function->ignored_warnings) {
- parser->ignored_warnings.insert(ignored_warning);
- }
-#endif
-
GDScriptParser::FunctionNode *previous_function = parser->current_function;
parser->current_function = p_function;
bool previous_static_context = static_context;
@@ -1775,9 +1774,6 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
p_function->set_datatype(prev_datatype);
}
-#ifdef DEBUG_ENABLED
- parser->ignored_warnings = previously_ignored_warnings;
-#endif
parser->current_function = previous_function;
static_context = previous_static_context;
}
@@ -1788,13 +1784,6 @@ void GDScriptAnalyzer::resolve_function_body(GDScriptParser::FunctionNode *p_fun
}
p_function->resolved_body = true;
-#ifdef DEBUG_ENABLED
- HashSet<GDScriptWarning::Code> previously_ignored_warnings = parser->ignored_warnings;
- for (GDScriptWarning::Code ignored_warning : p_function->ignored_warnings) {
- parser->ignored_warnings.insert(ignored_warning);
- }
-#endif
-
GDScriptParser::FunctionNode *previous_function = parser->current_function;
parser->current_function = p_function;
@@ -1812,9 +1801,6 @@ void GDScriptAnalyzer::resolve_function_body(GDScriptParser::FunctionNode *p_fun
}
}
-#ifdef DEBUG_ENABLED
- parser->ignored_warnings = previously_ignored_warnings;
-#endif
parser->current_function = previous_function;
static_context = previous_static_context;
}
@@ -1852,23 +1838,11 @@ void GDScriptAnalyzer::resolve_suite(GDScriptParser::SuiteNode *p_suite) {
// Apply annotations.
for (GDScriptParser::AnnotationNode *&E : stmt->annotations) {
resolve_annotation(E);
- E->apply(parser, stmt, nullptr);
+ E->apply(parser, stmt, nullptr); // TODO: Provide `p_class`.
}
-#ifdef DEBUG_ENABLED
- HashSet<GDScriptWarning::Code> previously_ignored_warnings = parser->ignored_warnings;
- for (GDScriptWarning::Code ignored_warning : stmt->ignored_warnings) {
- parser->ignored_warnings.insert(ignored_warning);
- }
-#endif // DEBUG_ENABLED
-
resolve_node(stmt);
resolve_pending_lambda_bodies();
-
-#ifdef DEBUG_ENABLED
- parser->ignored_warnings = previously_ignored_warnings;
-#endif // DEBUG_ENABLED
-
decide_suite_type(p_suite, stmt);
}
}
@@ -2257,6 +2231,12 @@ void GDScriptAnalyzer::resolve_match(GDScriptParser::MatchNode *p_match) {
}
void GDScriptAnalyzer::resolve_match_branch(GDScriptParser::MatchBranchNode *p_match_branch, GDScriptParser::ExpressionNode *p_match_test) {
+ // Apply annotations.
+ for (GDScriptParser::AnnotationNode *&E : p_match_branch->annotations) {
+ resolve_annotation(E);
+ E->apply(parser, p_match_branch, nullptr); // TODO: Provide `p_class`.
+ }
+
for (int i = 0; i < p_match_branch->patterns.size(); i++) {
resolve_match_pattern(p_match_branch->patterns[i], p_match_test);
}
@@ -3746,6 +3726,8 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
if (is_base && !base.is_meta_type) {
p_identifier->set_datatype(member.get_datatype());
p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_SIGNAL;
+ p_identifier->signal_source = member.signal;
+ member.signal->usages += 1;
return;
}
} break;
@@ -3930,6 +3912,8 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
found_source = true;
break;
case GDScriptParser::IdentifierNode::MEMBER_SIGNAL:
+ p_identifier->signal_source->usages++;
+ [[fallthrough]];
case GDScriptParser::IdentifierNode::INHERITED_VARIABLE:
mark_lambda_use_self();
break;
@@ -5636,21 +5620,20 @@ Error GDScriptAnalyzer::resolve_dependencies() {
Error GDScriptAnalyzer::analyze() {
parser->errors.clear();
- Error err = OK;
- err = resolve_inheritance();
+ Error err = resolve_inheritance();
if (err) {
return err;
}
- // Apply annotations.
- for (GDScriptParser::AnnotationNode *&E : parser->head->annotations) {
- resolve_annotation(E);
- E->apply(parser, parser->head, nullptr);
- }
-
resolve_interface();
resolve_body();
+
+#ifdef DEBUG_ENABLED
+ // Apply here, after all `@warning_ignore`s have been resolved and applied.
+ parser->apply_pending_warnings();
+#endif
+
if (!parser->errors.is_empty()) {
return ERR_PARSE_ERROR;
}
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index 177c68533e..002fc159fa 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -511,6 +511,7 @@ public:
_FORCE_INLINE_ GDScript *get_script() const { return _script; }
_FORCE_INLINE_ bool is_static() const { return _static; }
_FORCE_INLINE_ MethodInfo get_method_info() const { return method_info; }
+ _FORCE_INLINE_ int get_argument_count() const { return _argument_count; }
_FORCE_INLINE_ Variant get_rpc_config() const { return rpc_config; }
_FORCE_INLINE_ int get_max_stack_size() const { return _stack_size; }
diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp
index f6fa17c84f..626ef6ccb0 100644
--- a/modules/gdscript/gdscript_lambda_callable.cpp
+++ b/modules/gdscript/gdscript_lambda_callable.cpp
@@ -78,6 +78,15 @@ StringName GDScriptLambdaCallable::get_method() const {
return function->get_name();
}
+int GDScriptLambdaCallable::get_argument_count(bool &r_is_valid) const {
+ if (function == nullptr) {
+ r_is_valid = false;
+ return 0;
+ }
+ r_is_valid = true;
+ return function->get_argument_count();
+}
+
void GDScriptLambdaCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
int captures_amount = captures.size();
@@ -189,6 +198,15 @@ ObjectID GDScriptLambdaSelfCallable::get_object() const {
return object->get_instance_id();
}
+int GDScriptLambdaSelfCallable::get_argument_count(bool &r_is_valid) const {
+ if (function == nullptr) {
+ r_is_valid = false;
+ return 0;
+ }
+ r_is_valid = true;
+ return function->get_argument_count();
+}
+
void GDScriptLambdaSelfCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
#ifdef DEBUG_ENABLED
if (object->get_script_instance() == nullptr || object->get_script_instance()->get_language() != GDScriptLanguage::get_singleton()) {
diff --git a/modules/gdscript/gdscript_lambda_callable.h b/modules/gdscript/gdscript_lambda_callable.h
index 2c5d01aa16..45c0235913 100644
--- a/modules/gdscript/gdscript_lambda_callable.h
+++ b/modules/gdscript/gdscript_lambda_callable.h
@@ -59,6 +59,7 @@ public:
CompareLessFunc get_compare_less_func() const override;
ObjectID get_object() const override;
StringName get_method() const override;
+ int get_argument_count(bool &r_is_valid) const override;
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
GDScriptLambdaCallable(GDScriptLambdaCallable &) = delete;
@@ -86,6 +87,7 @@ public:
CompareEqualFunc get_compare_equal_func() const override;
CompareLessFunc get_compare_less_func() const override;
ObjectID get_object() const override;
+ int get_argument_count(bool &r_is_valid) const override;
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
GDScriptLambdaSelfCallable(GDScriptLambdaSelfCallable &) = delete;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 49341cb670..d706f4e9a3 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -127,7 +127,7 @@ GDScriptParser::GDScriptParser() {
register_annotation(MethodInfo("@export_group", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "prefix")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_GROUP>, varray(""));
register_annotation(MethodInfo("@export_subgroup", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "prefix")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_SUBGROUP>, varray(""));
// Warning annotations.
- register_annotation(MethodInfo("@warning_ignore", PropertyInfo(Variant::STRING, "warning")), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, varray(), true);
+ register_annotation(MethodInfo("@warning_ignore", PropertyInfo(Variant::STRING, "warning")), AnnotationInfo::CLASS_LEVEL | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, varray(), true);
// Networking.
register_annotation(MethodInfo("@rpc", PropertyInfo(Variant::STRING, "mode"), PropertyInfo(Variant::STRING, "sync"), PropertyInfo(Variant::STRING, "transfer_mode"), PropertyInfo(Variant::INT, "transfer_channel")), AnnotationInfo::FUNCTION, &GDScriptParser::rpc_annotation, varray("authority", "call_remote", "unreliable", 0));
}
@@ -181,47 +181,62 @@ void GDScriptParser::push_error(const String &p_message, const Node *p_origin) {
#ifdef DEBUG_ENABLED
void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_code, const Vector<String> &p_symbols) {
ERR_FAIL_NULL(p_source);
+ ERR_FAIL_INDEX(p_code, GDScriptWarning::WARNING_MAX);
+
if (is_ignoring_warnings) {
return;
}
if (GLOBAL_GET("debug/gdscript/warnings/exclude_addons").booleanize() && script_path.begins_with("res://addons/")) {
return;
}
-
- if (ignored_warnings.has(p_code)) {
+ GDScriptWarning::WarnLevel warn_level = (GDScriptWarning::WarnLevel)(int)GLOBAL_GET(GDScriptWarning::get_settings_path_from_code(p_code));
+ if (warn_level == GDScriptWarning::IGNORE) {
return;
}
- int warn_level = (int)GLOBAL_GET(GDScriptWarning::get_settings_path_from_code(p_code));
- if (!warn_level) {
- return;
- }
+ PendingWarning pw;
+ pw.source = p_source;
+ pw.code = p_code;
+ pw.treated_as_error = warn_level == GDScriptWarning::ERROR;
+ pw.symbols = p_symbols;
- GDScriptWarning warning;
- warning.code = p_code;
- warning.symbols = p_symbols;
- warning.start_line = p_source->start_line;
- warning.end_line = p_source->end_line;
- warning.leftmost_column = p_source->leftmost_column;
- warning.rightmost_column = p_source->rightmost_column;
+ pending_warnings.push_back(pw);
+}
- if (warn_level == GDScriptWarning::WarnLevel::ERROR) {
- push_error(warning.get_message() + String(" (Warning treated as error.)"), p_source);
- return;
- }
+void GDScriptParser::apply_pending_warnings() {
+ for (const PendingWarning &pw : pending_warnings) {
+ if (warning_ignored_lines[pw.code].has(pw.source->start_line)) {
+ continue;
+ }
- List<GDScriptWarning>::Element *before = nullptr;
- for (List<GDScriptWarning>::Element *E = warnings.front(); E; E = E->next()) {
- if (E->get().start_line > warning.start_line) {
- break;
+ GDScriptWarning warning;
+ warning.code = pw.code;
+ warning.symbols = pw.symbols;
+ warning.start_line = pw.source->start_line;
+ warning.end_line = pw.source->end_line;
+ warning.leftmost_column = pw.source->leftmost_column;
+ warning.rightmost_column = pw.source->rightmost_column;
+
+ if (pw.treated_as_error) {
+ push_error(warning.get_message() + String(" (Warning treated as error.)"), pw.source);
+ continue;
+ }
+
+ List<GDScriptWarning>::Element *before = nullptr;
+ for (List<GDScriptWarning>::Element *E = warnings.front(); E; E = E->next()) {
+ if (E->get().start_line > warning.start_line) {
+ break;
+ }
+ before = E;
+ }
+ if (before) {
+ warnings.insert_after(before, warning);
+ } else {
+ warnings.push_front(warning);
}
- before = E;
- }
- if (before) {
- warnings.insert_after(before, warning);
- } else {
- warnings.push_front(warning);
}
+
+ pending_warnings.clear();
}
#endif
@@ -553,25 +568,53 @@ void GDScriptParser::end_statement(const String &p_context) {
void GDScriptParser::parse_program() {
head = alloc_node<ClassNode>();
+ head->start_line = 1;
+ head->end_line = 1;
head->fqcn = GDScript::canonicalize_path(script_path);
current_class = head;
bool can_have_class_or_extends = true;
+#define PUSH_PENDING_ANNOTATIONS_TO_HEAD \
+ if (!annotation_stack.is_empty()) { \
+ for (AnnotationNode * annot : annotation_stack) { \
+ head->annotations.push_back(annot); \
+ } \
+ annotation_stack.clear(); \
+ }
+
while (!check(GDScriptTokenizer::Token::TK_EOF)) {
if (match(GDScriptTokenizer::Token::ANNOTATION)) {
- AnnotationNode *annotation = parse_annotation(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE | AnnotationInfo::CLASS_LEVEL);
+ AnnotationNode *annotation = parse_annotation(AnnotationInfo::SCRIPT | AnnotationInfo::CLASS_LEVEL | AnnotationInfo::STANDALONE);
if (annotation != nullptr) {
- if (annotation->applies_to(AnnotationInfo::SCRIPT)) {
- // `@icon` needs to be applied in the parser. See GH-72444.
- if (annotation->name == SNAME("@icon")) {
- annotation->apply(this, head, nullptr);
+ if (annotation->applies_to(AnnotationInfo::CLASS)) {
+ // We do not know in advance what the annotation will be applied to: the `head` class or the subsequent inner class.
+ // If we encounter `class_name`, `extends` or pure `SCRIPT` annotation, then it's `head`, otherwise it's an inner class.
+ annotation_stack.push_back(annotation);
+ } else if (annotation->applies_to(AnnotationInfo::SCRIPT)) {
+ PUSH_PENDING_ANNOTATIONS_TO_HEAD;
+ if (annotation->name == SNAME("@tool") || annotation->name == SNAME("@icon")) {
+ // Some annotations need to be resolved in the parser.
+ annotation->apply(this, head, nullptr); // `head->outer == nullptr`.
} else {
head->annotations.push_back(annotation);
}
+ } else if (annotation->applies_to(AnnotationInfo::STANDALONE)) {
+ if (previous.type != GDScriptTokenizer::Token::NEWLINE) {
+ push_error(R"(Expected newline after a standalone annotation.)");
+ }
+ if (annotation->name == SNAME("@export_category") || annotation->name == SNAME("@export_group") || annotation->name == SNAME("@export_subgroup")) {
+ head->add_member_group(annotation);
+ // This annotation must appear after script-level annotations and `class_name`/`extends`,
+ // so we stop looking for script-level stuff.
+ can_have_class_or_extends = false;
+ break;
+ } else {
+ // For potential non-group standalone annotations.
+ push_error(R"(Unexpected standalone annotation.)");
+ }
} else {
annotation_stack.push_back(annotation);
- // This annotation must appear after script-level annotations
- // and class_name/extends (ex: could be @onready or @export),
+ // This annotation must appear after script-level annotations and `class_name`/`extends`,
// so we stop looking for script-level stuff.
can_have_class_or_extends = false;
break;
@@ -592,6 +635,10 @@ void GDScriptParser::parse_program() {
// Order here doesn't matter, but there should be only one of each at most.
switch (current.type) {
case GDScriptTokenizer::Token::CLASS_NAME:
+ PUSH_PENDING_ANNOTATIONS_TO_HEAD;
+ if (head->start_line == 1) {
+ reset_extents(head, current);
+ }
advance();
if (head->identifier != nullptr) {
push_error(R"("class_name" can only be used once.)");
@@ -600,6 +647,10 @@ void GDScriptParser::parse_program() {
}
break;
case GDScriptTokenizer::Token::EXTENDS:
+ PUSH_PENDING_ANNOTATIONS_TO_HEAD;
+ if (head->start_line == 1) {
+ reset_extents(head, current);
+ }
advance();
if (head->extends_used) {
push_error(R"("extends" can only be used once.)");
@@ -608,6 +659,10 @@ void GDScriptParser::parse_program() {
end_statement("superclass");
}
break;
+ case GDScriptTokenizer::Token::TK_EOF:
+ PUSH_PENDING_ANNOTATIONS_TO_HEAD;
+ can_have_class_or_extends = false;
+ break;
case GDScriptTokenizer::Token::LITERAL:
if (current.literal.get_type() == Variant::STRING) {
// Allow strings in class body as multiline comments.
@@ -629,6 +684,8 @@ void GDScriptParser::parse_program() {
}
}
+#undef PUSH_PENDING_ANNOTATIONS_TO_HEAD
+
parse_class_body(true);
complete_extents(head);
@@ -799,7 +856,7 @@ void GDScriptParser::parse_extends() {
}
}
-template <class T>
+template <typename T>
void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)(bool), AnnotationInfo::TargetKind p_target, const String &p_member_kind, bool p_is_static) {
advance();
@@ -907,8 +964,8 @@ void GDScriptParser::parse_class_body(bool p_is_multiline) {
case GDScriptTokenizer::Token::ANNOTATION: {
advance();
- // Check for standalone and class-level annotations.
- AnnotationNode *annotation = parse_annotation(AnnotationInfo::STANDALONE | AnnotationInfo::CLASS_LEVEL);
+ // Check for class-level and standalone annotations.
+ AnnotationNode *annotation = parse_annotation(AnnotationInfo::CLASS_LEVEL | AnnotationInfo::STANDALONE);
if (annotation != nullptr) {
if (annotation->applies_to(AnnotationInfo::STANDALONE)) {
if (previous.type != GDScriptTokenizer::Token::NEWLINE) {
@@ -918,9 +975,9 @@ void GDScriptParser::parse_class_body(bool p_is_multiline) {
current_class->add_member_group(annotation);
} else {
// For potential non-group standalone annotations.
- push_error(R"(Unexpected standalone annotation in class body.)");
+ push_error(R"(Unexpected standalone annotation.)");
}
- } else {
+ } else { // `AnnotationInfo::CLASS_LEVEL`.
annotation_stack.push_back(annotation);
}
}
@@ -1342,22 +1399,9 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum(bool p_is_static) {
break; // Allow trailing comma.
}
if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected identifier for enum key.)")) {
- EnumNode::Value item;
GDScriptParser::IdentifierNode *identifier = parse_identifier();
-#ifdef DEBUG_ENABLED
- if (!named) { // Named enum identifiers do not shadow anything since you can only access them with NamedEnum.ENUM_VALUE
- for (MethodInfo &info : gdscript_funcs) {
- if (info.name == identifier->name) {
- push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "enum member", identifier->name, "built-in function");
- }
- }
- if (Variant::has_utility_function(identifier->name)) {
- push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "enum member", identifier->name, "built-in function");
- } else if (ClassDB::class_exists(identifier->name)) {
- push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "enum member", identifier->name, "global class");
- }
- }
-#endif
+
+ EnumNode::Value item;
item.identifier = identifier;
item.parent_enum = enum_node;
item.line = previous.start_line;
@@ -1701,7 +1745,19 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
bool unreachable = current_suite->has_return && !current_suite->has_unreachable_code;
#endif
- bool is_annotation = false;
+ List<AnnotationNode *> annotations;
+ if (current.type != GDScriptTokenizer::Token::ANNOTATION) {
+ while (!annotation_stack.is_empty()) {
+ AnnotationNode *last_annotation = annotation_stack.back()->get();
+ if (last_annotation->applies_to(AnnotationInfo::STATEMENT)) {
+ annotations.push_front(last_annotation);
+ annotation_stack.pop_back();
+ } else {
+ push_error(vformat(R"(Annotation "%s" cannot be applied to a statement.)", last_annotation->name));
+ clear_unused_annotations();
+ }
+ }
+ }
switch (current.type) {
case GDScriptTokenizer::Token::PASS:
@@ -1775,7 +1831,6 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
break;
case GDScriptTokenizer::Token::ANNOTATION: {
advance();
- is_annotation = true;
AnnotationNode *annotation = parse_annotation(AnnotationInfo::STATEMENT);
if (annotation != nullptr) {
annotation_stack.push_back(annotation);
@@ -1804,10 +1859,9 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
#ifdef DEBUG_ENABLED
if (expression != nullptr) {
switch (expression->type) {
- case Node::CALL:
case Node::ASSIGNMENT:
case Node::AWAIT:
- case Node::TERNARY_OPERATOR:
+ case Node::CALL:
// Fine.
break;
case Node::LAMBDA:
@@ -1815,11 +1869,14 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
push_error("Standalone lambdas cannot be accessed. Consider assigning it to a variable.", expression);
break;
case Node::LITERAL:
- if (static_cast<GDScriptParser::LiteralNode *>(expression)->value.get_type() == Variant::STRING) {
- // Allow strings as multiline comments.
- break;
+ // Allow strings as multiline comments.
+ if (static_cast<GDScriptParser::LiteralNode *>(expression)->value.get_type() != Variant::STRING) {
+ push_warning(expression, GDScriptWarning::STANDALONE_EXPRESSION);
}
- [[fallthrough]];
+ break;
+ case Node::TERNARY_OPERATOR:
+ push_warning(expression, GDScriptWarning::STANDALONE_TERNARY);
+ break;
default:
push_warning(expression, GDScriptWarning::STANDALONE_EXPRESSION);
}
@@ -1829,14 +1886,9 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
}
}
- while (!is_annotation && result != nullptr && !annotation_stack.is_empty()) {
- AnnotationNode *last_annotation = annotation_stack.back()->get();
- if (last_annotation->applies_to(AnnotationInfo::STATEMENT)) {
- result->annotations.push_front(last_annotation);
- annotation_stack.pop_back();
- } else {
- push_error(vformat(R"(Annotation "%s" cannot be applied to a statement.)", last_annotation->name));
- clear_unused_annotations();
+ if (result != nullptr && !annotations.is_empty()) {
+ for (AnnotationNode *&annotation : annotations) {
+ result->annotations.push_back(annotation);
}
}
@@ -2017,10 +2069,10 @@ GDScriptParser::IfNode *GDScriptParser::parse_if(const String &p_token) {
}
GDScriptParser::MatchNode *GDScriptParser::parse_match() {
- MatchNode *match = alloc_node<MatchNode>();
+ MatchNode *match_node = alloc_node<MatchNode>();
- match->test = parse_expression(false);
- if (match->test == nullptr) {
+ match_node->test = parse_expression(false);
+ if (match_node->test == nullptr) {
push_error(R"(Expected expression to test after "match".)");
}
@@ -2028,20 +2080,45 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() {
consume(GDScriptTokenizer::Token::NEWLINE, R"(Expected a newline after "match" statement.)");
if (!consume(GDScriptTokenizer::Token::INDENT, R"(Expected an indented block after "match" statement.)")) {
- complete_extents(match);
- return match;
+ complete_extents(match_node);
+ return match_node;
}
bool all_have_return = true;
bool have_wildcard = false;
+ List<AnnotationNode *> match_branch_annotation_stack;
+
while (!check(GDScriptTokenizer::Token::DEDENT) && !is_at_end()) {
+ if (match(GDScriptTokenizer::Token::PASS)) {
+ consume(GDScriptTokenizer::Token::NEWLINE, R"(Expected newline after "pass".)");
+ continue;
+ }
+
+ if (match(GDScriptTokenizer::Token::ANNOTATION)) {
+ AnnotationNode *annotation = parse_annotation(AnnotationInfo::STATEMENT);
+ if (annotation == nullptr) {
+ continue;
+ }
+ if (annotation->name != SNAME("@warning_ignore")) {
+ push_error(vformat(R"(Annotation "%s" is not allowed in this level.)", annotation->name), annotation);
+ continue;
+ }
+ match_branch_annotation_stack.push_back(annotation);
+ continue;
+ }
+
MatchBranchNode *branch = parse_match_branch();
if (branch == nullptr) {
advance();
continue;
}
+ for (AnnotationNode *annotation : match_branch_annotation_stack) {
+ branch->annotations.push_back(annotation);
+ }
+ match_branch_annotation_stack.clear();
+
#ifdef DEBUG_ENABLED
if (have_wildcard && !branch->patterns.is_empty()) {
push_warning(branch->patterns[0], GDScriptWarning::UNREACHABLE_PATTERN);
@@ -2050,9 +2127,9 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() {
have_wildcard = have_wildcard || branch->has_wildcard;
all_have_return = all_have_return && branch->block->has_return;
- match->branches.push_back(branch);
+ match_node->branches.push_back(branch);
}
- complete_extents(match);
+ complete_extents(match_node);
consume(GDScriptTokenizer::Token::DEDENT, R"(Expected an indented block after "match" statement.)");
@@ -2060,7 +2137,12 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() {
current_suite->has_return = true;
}
- return match;
+ for (const AnnotationNode *annotation : match_branch_annotation_stack) {
+ push_error(vformat(R"(Annotation "%s" does not precede a valid target, so it will have no effect.)", annotation->name), annotation);
+ }
+ match_branch_annotation_stack.clear();
+
+ return match_node;
}
GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() {
@@ -2378,7 +2460,7 @@ GDScriptParser::IdentifierNode *GDScriptParser::parse_identifier() {
IdentifierNode *identifier = static_cast<IdentifierNode *>(parse_identifier(nullptr, false));
#ifdef DEBUG_ENABLED
// Check for spoofing here (if available in TextServer) since this isn't called inside expressions. This is only relevant for declarations.
- if (identifier && TS->has_feature(TextServer::FEATURE_UNICODE_SECURITY) && TS->spoof_check(identifier->name.operator String())) {
+ if (identifier && TS->has_feature(TextServer::FEATURE_UNICODE_SECURITY) && TS->spoof_check(identifier->name)) {
push_warning(identifier, GDScriptWarning::CONFUSABLE_IDENTIFIER, identifier->name.operator String());
}
#endif
@@ -3161,6 +3243,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_get_node(ExpressionNode *p
complete_extents(get_node);
return nullptr;
}
+
get_node->full_path += "%";
path_state = PATH_STATE_PERCENT;
@@ -3204,6 +3287,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_get_node(ExpressionNode *p
path_state = PATH_STATE_NODE_NAME;
} else if (current.is_node_name()) {
advance();
+
String identifier = previous.get_identifier();
#ifdef DEBUG_ENABLED
// Check spoofing.
@@ -3934,7 +4018,7 @@ bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation)
return false;
}
- // `@icon`'s argument needs to be resolved in the parser. See GH-72444.
+ // Some annotations need to be resolved in the parser.
if (p_annotation->name == SNAME("@icon")) {
ExpressionNode *argument = p_annotation->arguments[0];
@@ -4401,23 +4485,77 @@ bool GDScriptParser::export_group_annotations(const AnnotationNode *p_annotation
}
bool GDScriptParser::warning_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
-#ifdef DEBUG_ENABLED
+#ifndef DEBUG_ENABLED
+ // Only available in debug builds.
+ return true;
+#else // DEBUG_ENABLED
+ if (is_ignoring_warnings) {
+ return true; // We already ignore all warnings, let's optimize it.
+ }
+
bool has_error = false;
for (const Variant &warning_name : p_annotation->resolved_arguments) {
- GDScriptWarning::Code warning = GDScriptWarning::get_code_from_name(String(warning_name).to_upper());
- if (warning == GDScriptWarning::WARNING_MAX) {
+ GDScriptWarning::Code warning_code = GDScriptWarning::get_code_from_name(String(warning_name).to_upper());
+ if (warning_code == GDScriptWarning::WARNING_MAX) {
push_error(vformat(R"(Invalid warning name: "%s".)", warning_name), p_annotation);
has_error = true;
} else {
- p_target->ignored_warnings.push_back(warning);
+ int start_line = p_annotation->start_line;
+ int end_line = p_target->end_line;
+
+ switch (p_target->type) {
+#define SIMPLE_CASE(m_type, m_class, m_property) \
+ case m_type: { \
+ m_class *node = static_cast<m_class *>(p_target); \
+ if (node->m_property == nullptr) { \
+ end_line = node->start_line; \
+ } else { \
+ end_line = node->m_property->end_line; \
+ } \
+ } break;
+
+ // Can contain properties (set/get).
+ SIMPLE_CASE(Node::VARIABLE, VariableNode, initializer)
+
+ // Contain bodies.
+ SIMPLE_CASE(Node::FOR, ForNode, list)
+ SIMPLE_CASE(Node::IF, IfNode, condition)
+ SIMPLE_CASE(Node::MATCH, MatchNode, test)
+ SIMPLE_CASE(Node::WHILE, WhileNode, condition)
+#undef SIMPLE_CASE
+
+ case Node::CLASS: {
+ end_line = p_target->start_line;
+ for (const AnnotationNode *annotation : p_target->annotations) {
+ start_line = MIN(start_line, annotation->start_line);
+ end_line = MAX(end_line, annotation->end_line);
+ }
+ } break;
+
+ case Node::FUNCTION: {
+ // `@warning_ignore` on function has a controversial feature that is used in tests.
+ // It's better not to remove it for now, while there is no way to mass-ignore warnings.
+ } break;
+
+ case Node::MATCH_BRANCH: {
+ MatchBranchNode *branch = static_cast<MatchBranchNode *>(p_target);
+ end_line = branch->start_line;
+ for (int i = 0; i < branch->patterns.size(); i++) {
+ end_line = MAX(end_line, branch->patterns[i]->end_line);
+ }
+ } break;
+
+ default: {
+ } break;
+ }
+
+ end_line = MAX(start_line, end_line); // Prevent infinite loop.
+ for (int line = start_line; line <= end_line; line++) {
+ warning_ignored_lines[warning_code].insert(line);
+ }
}
}
-
return !has_error;
-
-#else // ! DEBUG_ENABLED
- // Only available in debug builds.
- return true;
#endif // DEBUG_ENABLED
}
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 45ab3f3e38..ea67f1eaff 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -338,9 +338,6 @@ public:
int leftmost_column = 0, rightmost_column = 0;
Node *next = nullptr;
List<AnnotationNode *> annotations;
-#ifdef DEBUG_ENABLED
- Vector<GDScriptWarning::Code> ignored_warnings;
-#endif
DataType datatype;
@@ -777,7 +774,7 @@ public:
bool has_function(const StringName &p_name) const {
return has_member(p_name) && members[members_indices[p_name]].type == Member::FUNCTION;
}
- template <class T>
+ template <typename T>
void add_member(T *p_member_node) {
members_indices[p_member_node->identifier->name] = members.size();
members.push_back(Member(p_member_node));
@@ -900,9 +897,10 @@ public:
union {
ParameterNode *parameter_source = nullptr;
- ConstantNode *constant_source;
- VariableNode *variable_source;
IdentifierNode *bind_source;
+ VariableNode *variable_source;
+ ConstantNode *constant_source;
+ SignalNode *signal_source;
};
FunctionNode *source_function = nullptr;
@@ -1051,6 +1049,8 @@ public:
MemberDocData doc_data;
#endif // TOOLS_ENABLED
+ int usages = 0;
+
SignalNode() {
type = SIGNAL;
}
@@ -1167,7 +1167,7 @@ public:
bool has_local(const StringName &p_name) const;
const Local &get_local(const StringName &p_name) const;
- template <class T>
+ template <typename T>
void add_local(T *p_local, FunctionNode *p_source_function) {
locals_indices[p_local->identifier->name] = locals.size();
locals.push_back(Local(p_local, p_source_function));
@@ -1334,9 +1334,17 @@ private:
List<ParserError> errors;
#ifdef DEBUG_ENABLED
+ struct PendingWarning {
+ const Node *source = nullptr;
+ GDScriptWarning::Code code = GDScriptWarning::WARNING_MAX;
+ bool treated_as_error = false;
+ Vector<String> symbols;
+ };
+
bool is_ignoring_warnings = false;
List<GDScriptWarning> warnings;
- HashSet<GDScriptWarning::Code> ignored_warnings;
+ List<PendingWarning> pending_warnings;
+ HashSet<int> warning_ignored_lines[GDScriptWarning::WARNING_MAX];
HashSet<int> unsafe_lines;
#endif
@@ -1368,7 +1376,7 @@ private:
FUNCTION = 1 << 5,
STATEMENT = 1 << 6,
STANDALONE = 1 << 7,
- CLASS_LEVEL = CLASS | VARIABLE | FUNCTION,
+ CLASS_LEVEL = CLASS | VARIABLE | CONSTANT | SIGNAL | FUNCTION,
};
uint32_t target_kind = 0; // Flags.
AnnotationAction apply = nullptr;
@@ -1418,7 +1426,7 @@ private:
void reset_extents(Node *p_node, GDScriptTokenizer::Token p_token);
void reset_extents(Node *p_node, Node *p_from);
- template <class T>
+ template <typename T>
T *alloc_node() {
T *node = memnew(T);
@@ -1438,6 +1446,7 @@ private:
void push_warning(const Node *p_source, GDScriptWarning::Code p_code, const Symbols &...p_symbols) {
push_warning(p_source, p_code, Vector<String>{ p_symbols... });
}
+ void apply_pending_warnings();
#endif
void make_completion_context(CompletionType p_type, Node *p_node, int p_argument = -1, bool p_force = false);
@@ -1464,7 +1473,7 @@ private:
void parse_class_name();
void parse_extends();
void parse_class_body(bool p_is_multiline);
- template <class T>
+ template <typename T>
void parse_class_member(T *(GDScriptParser::*p_parse_function)(bool), AnnotationInfo::TargetKind p_target, const String &p_member_kind, bool p_is_static = false);
SignalNode *parse_signal(bool p_is_static);
EnumNode *parse_enum(bool p_is_static);
diff --git a/modules/gdscript/gdscript_rpc_callable.cpp b/modules/gdscript/gdscript_rpc_callable.cpp
index df014d3cfe..3139371eb5 100644
--- a/modules/gdscript/gdscript_rpc_callable.cpp
+++ b/modules/gdscript/gdscript_rpc_callable.cpp
@@ -68,6 +68,10 @@ StringName GDScriptRPCCallable::get_method() const {
return method;
}
+int GDScriptRPCCallable::get_argument_count(bool &r_is_valid) const {
+ return object->get_method_argument_count(method, &r_is_valid);
+}
+
void GDScriptRPCCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
r_return_value = object->callp(method, p_arguments, p_argcount, r_call_error);
}
diff --git a/modules/gdscript/gdscript_rpc_callable.h b/modules/gdscript/gdscript_rpc_callable.h
index 66052157be..2ca6290951 100644
--- a/modules/gdscript/gdscript_rpc_callable.h
+++ b/modules/gdscript/gdscript_rpc_callable.h
@@ -52,6 +52,7 @@ public:
CompareLessFunc get_compare_less_func() const override;
ObjectID get_object() const override;
StringName get_method() const override;
+ int get_argument_count(bool &r_is_valid) const override;
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const override;
diff --git a/modules/gdscript/gdscript_utility_callable.cpp b/modules/gdscript/gdscript_utility_callable.cpp
index 7708a18044..edd7e05b22 100644
--- a/modules/gdscript/gdscript_utility_callable.cpp
+++ b/modules/gdscript/gdscript_utility_callable.cpp
@@ -80,6 +80,21 @@ ObjectID GDScriptUtilityCallable::get_object() const {
return ObjectID();
}
+int GDScriptUtilityCallable::get_argument_count(bool &r_is_valid) const {
+ switch (type) {
+ case TYPE_INVALID:
+ r_is_valid = false;
+ return 0;
+ case TYPE_GLOBAL:
+ r_is_valid = true;
+ return Variant::get_utility_function_argument_count(function_name);
+ case TYPE_GDSCRIPT:
+ r_is_valid = true;
+ return GDScriptUtilityFunctions::get_function_argument_count(function_name);
+ }
+ ERR_FAIL_V_MSG(0, "Invalid type.");
+}
+
void GDScriptUtilityCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
switch (type) {
case TYPE_INVALID:
diff --git a/modules/gdscript/gdscript_utility_callable.h b/modules/gdscript/gdscript_utility_callable.h
index 675bc4ddd9..c5736e815f 100644
--- a/modules/gdscript/gdscript_utility_callable.h
+++ b/modules/gdscript/gdscript_utility_callable.h
@@ -57,6 +57,7 @@ public:
bool is_valid() const override;
StringName get_method() const override;
ObjectID get_object() const override;
+ int get_argument_count(bool &r_is_valid) const override;
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
GDScriptUtilityCallable(const StringName &p_function_name);
diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp
index f8cb460e40..e5b0f55df8 100644
--- a/modules/gdscript/gdscript_utility_functions.cpp
+++ b/modules/gdscript/gdscript_utility_functions.cpp
@@ -759,7 +759,7 @@ Variant::Type GDScriptUtilityFunctions::get_function_argument_type(const StringN
return info->info.arguments[p_arg].type;
}
-int GDScriptUtilityFunctions::get_function_argument_count(const StringName &p_function, int p_arg) {
+int GDScriptUtilityFunctions::get_function_argument_count(const StringName &p_function) {
GDScriptUtilityFunctionInfo *info = utility_function_table.lookup_ptr(p_function);
ERR_FAIL_NULL_V(info, 0);
return info->info.arguments.size();
diff --git a/modules/gdscript/gdscript_utility_functions.h b/modules/gdscript/gdscript_utility_functions.h
index 40e9379a3a..1c4e4452c8 100644
--- a/modules/gdscript/gdscript_utility_functions.h
+++ b/modules/gdscript/gdscript_utility_functions.h
@@ -46,7 +46,7 @@ public:
static Variant::Type get_function_return_type(const StringName &p_function);
static StringName get_function_return_class(const StringName &p_function);
static Variant::Type get_function_argument_type(const StringName &p_function, int p_arg);
- static int get_function_argument_count(const StringName &p_function, int p_arg);
+ static int get_function_argument_count(const StringName &p_function);
static bool is_function_vararg(const StringName &p_function);
static bool is_function_constant(const StringName &p_function);
diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp
index 1fe9b0425c..e7d9787eab 100644
--- a/modules/gdscript/gdscript_warning.cpp
+++ b/modules/gdscript/gdscript_warning.cpp
@@ -52,13 +52,13 @@ String GDScriptWarning::get_message() const {
return vformat(R"(The local constant "%s" is declared but never used in the block. If this is intended, prefix it with an underscore: "_%s".)", symbols[0], symbols[0]);
case UNUSED_PRIVATE_CLASS_VARIABLE:
CHECK_SYMBOLS(1);
- return vformat(R"(The class variable "%s" is declared but never used in the script.)", symbols[0]);
+ return vformat(R"(The class variable "%s" is declared but never used in the class.)", symbols[0]);
case UNUSED_PARAMETER:
CHECK_SYMBOLS(2);
return vformat(R"*(The parameter "%s" is never used in the function "%s()". If this is intended, prefix it with an underscore: "_%s".)*", symbols[1], symbols[0], symbols[1]);
case UNUSED_SIGNAL:
CHECK_SYMBOLS(1);
- return vformat(R"(The signal "%s" is declared but never emitted.)", symbols[0]);
+ return vformat(R"(The signal "%s" is declared but never explicitly used in the class.)", symbols[0]);
case SHADOWED_VARIABLE:
CHECK_SYMBOLS(4);
return vformat(R"(The local %s "%s" is shadowing an already-declared %s at line %s.)", symbols[0], symbols[1], symbols[2], symbols[3]);
@@ -76,18 +76,9 @@ String GDScriptWarning::get_message() const {
case STANDALONE_EXPRESSION:
return "Standalone expression (the line has no effect).";
case STANDALONE_TERNARY:
- return "Standalone ternary conditional operator: the return value is being discarded.";
+ return "Standalone ternary operator: the return value is being discarded.";
case INCOMPATIBLE_TERNARY:
- return "Values of the ternary conditional are not mutually compatible.";
- case PROPERTY_USED_AS_FUNCTION:
- CHECK_SYMBOLS(2);
- return vformat(R"*(The method "%s()" was not found in base "%s" but there's a property with the same name. Did you mean to access it?)*", symbols[0], symbols[1]);
- case CONSTANT_USED_AS_FUNCTION:
- CHECK_SYMBOLS(2);
- return vformat(R"*(The method "%s()" was not found in base "%s" but there's a constant with the same name. Did you mean to access it?)*", symbols[0], symbols[1]);
- case FUNCTION_USED_AS_PROPERTY:
- CHECK_SYMBOLS(2);
- return vformat(R"(The property "%s" was not found in base "%s" but there's a method with the same name. Did you mean to call it?)", symbols[0], symbols[1]);
+ return "Values of the ternary operator are not mutually compatible.";
case UNTYPED_DECLARATION:
CHECK_SYMBOLS(2);
if (symbols[0] == "Function") {
@@ -162,10 +153,17 @@ String GDScriptWarning::get_message() const {
return vformat(R"*(The default value is using "%s" which won't return nodes in the scene tree before "_ready()" is called. Use the "@onready" annotation to solve this.)*", symbols[0]);
case ONREADY_WITH_EXPORT:
return R"("@onready" will set the default value after "@export" takes effect and will override it.)";
+#ifndef DISABLE_DEPRECATED
+ // Never produced. These warnings migrated from 3.x by mistake.
+ case PROPERTY_USED_AS_FUNCTION: // There is already an error.
+ case CONSTANT_USED_AS_FUNCTION: // There is already an error.
+ case FUNCTION_USED_AS_PROPERTY: // This is valid, returns `Callable`.
+ break;
+#endif
case WARNING_MAX:
- break; // Can't happen, but silences warning
+ break; // Can't happen, but silences warning.
}
- ERR_FAIL_V_MSG(String(), "Invalid GDScript warning code: " + get_name_from_code(code) + ".");
+ ERR_FAIL_V_MSG(String(), vformat(R"(Invalid GDScript warning "%s".)", get_name_from_code(code)));
#undef CHECK_SYMBOLS
}
@@ -206,9 +204,6 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"STANDALONE_EXPRESSION",
"STANDALONE_TERNARY",
"INCOMPATIBLE_TERNARY",
- "PROPERTY_USED_AS_FUNCTION",
- "CONSTANT_USED_AS_FUNCTION",
- "FUNCTION_USED_AS_PROPERTY",
"UNTYPED_DECLARATION",
"INFERRED_DECLARATION",
"UNSAFE_PROPERTY_ACCESS",
@@ -236,6 +231,11 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"NATIVE_METHOD_OVERRIDE",
"GET_NODE_DEFAULT_WITHOUT_ONREADY",
"ONREADY_WITH_EXPORT",
+#ifndef DISABLE_DEPRECATED
+ "PROPERTY_USED_AS_FUNCTION",
+ "CONSTANT_USED_AS_FUNCTION",
+ "FUNCTION_USED_AS_PROPERTY",
+#endif
};
static_assert((sizeof(names) / sizeof(*names)) == WARNING_MAX, "Amount of warning types don't match the amount of warning names.");
diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h
index 1aef6fa81b..69cc8c179f 100644
--- a/modules/gdscript/gdscript_warning.h
+++ b/modules/gdscript/gdscript_warning.h
@@ -50,9 +50,9 @@ public:
UNASSIGNED_VARIABLE_OP_ASSIGN, // Variable never assigned but used in an assignment operation (+=, *=, etc).
UNUSED_VARIABLE, // Local variable is declared but never used.
UNUSED_LOCAL_CONSTANT, // Local constant is declared but never used.
- UNUSED_PRIVATE_CLASS_VARIABLE, // Class variable is declared private ("_" prefix) but never used in the file.
+ UNUSED_PRIVATE_CLASS_VARIABLE, // Class variable is declared private ("_" prefix) but never used in the class.
UNUSED_PARAMETER, // Function parameter is never used.
- UNUSED_SIGNAL, // Signal is defined but never emitted.
+ UNUSED_SIGNAL, // Signal is defined but never explicitly used in the class.
SHADOWED_VARIABLE, // Variable name shadowed by other variable in same class.
SHADOWED_VARIABLE_BASE_CLASS, // Variable name shadowed by other variable in some base class.
SHADOWED_GLOBAL_IDENTIFIER, // A global class or function has the same name as variable.
@@ -61,9 +61,6 @@ public:
STANDALONE_EXPRESSION, // Expression not assigned to a variable.
STANDALONE_TERNARY, // Return value of ternary expression is discarded.
INCOMPATIBLE_TERNARY, // Possible values of a ternary if are not mutually compatible.
- PROPERTY_USED_AS_FUNCTION, // Function not found, but there's a property with the same name.
- CONSTANT_USED_AS_FUNCTION, // Function not found, but there's a constant with the same name.
- FUNCTION_USED_AS_PROPERTY, // Property not found, but there's a function with the same name.
UNTYPED_DECLARATION, // Variable/parameter/function has no static type, explicitly specified or implicitly inferred.
INFERRED_DECLARATION, // Variable/constant/parameter has an implicitly inferred static type.
UNSAFE_PROPERTY_ACCESS, // Property not found in the detected type (but can be in subtypes).
@@ -91,6 +88,11 @@ public:
NATIVE_METHOD_OVERRIDE, // The script method overrides a native one, this may not work as intended.
GET_NODE_DEFAULT_WITHOUT_ONREADY, // A class variable uses `get_node()` (or the `$` notation) as its default value, but does not use the @onready annotation.
ONREADY_WITH_EXPORT, // The `@onready` annotation will set the value after `@export` which is likely not intended.
+#ifndef DISABLE_DEPRECATED
+ PROPERTY_USED_AS_FUNCTION, // Function not found, but there's a property with the same name.
+ CONSTANT_USED_AS_FUNCTION, // Function not found, but there's a constant with the same name.
+ FUNCTION_USED_AS_PROPERTY, // Property not found, but there's a function with the same name.
+#endif
WARNING_MAX,
};
@@ -110,9 +112,6 @@ public:
WARN, // STANDALONE_EXPRESSION
WARN, // STANDALONE_TERNARY
WARN, // INCOMPATIBLE_TERNARY
- WARN, // PROPERTY_USED_AS_FUNCTION
- WARN, // CONSTANT_USED_AS_FUNCTION
- WARN, // FUNCTION_USED_AS_PROPERTY
IGNORE, // UNTYPED_DECLARATION // Static typing is optional, we don't want to spam warnings.
IGNORE, // INFERRED_DECLARATION // Static typing is optional, we don't want to spam warnings.
IGNORE, // UNSAFE_PROPERTY_ACCESS // Too common in untyped scenarios.
@@ -140,6 +139,11 @@ public:
ERROR, // NATIVE_METHOD_OVERRIDE // May not work as expected.
ERROR, // GET_NODE_DEFAULT_WITHOUT_ONREADY // May not work as expected.
ERROR, // ONREADY_WITH_EXPORT // May not work as expected.
+#ifndef DISABLE_DEPRECATED
+ WARN, // PROPERTY_USED_AS_FUNCTION
+ WARN, // CONSTANT_USED_AS_FUNCTION
+ WARN, // FUNCTION_USED_AS_PROPERTY
+#endif
};
static_assert((sizeof(default_warning_levels) / sizeof(default_warning_levels[0])) == WARNING_MAX, "Amount of default levels does not match the amount of warnings.");
diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd
deleted file mode 100644
index 292db30bcd..0000000000
--- a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd
+++ /dev/null
@@ -1,15 +0,0 @@
-@warning_ignore("unused_private_class_variable")
-var _unused = 2
-
-@warning_ignore("unused_variable")
-func test():
- print("test")
- var unused = 3
-
- @warning_ignore("redundant_await")
- print(await regular_func())
-
- print("done")
-
-func regular_func() -> int:
- return 0
diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out
deleted file mode 100644
index 42292774a0..0000000000
--- a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out
+++ /dev/null
@@ -1,4 +0,0 @@
-GDTEST_OK
-test
-0
-done
diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_targets.gd b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_targets.gd
new file mode 100644
index 0000000000..10eca33647
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_targets.gd
@@ -0,0 +1,35 @@
+@warning_ignore("confusable_identifier")
+class MyClАss:
+ var my_vАr
+
+@warning_ignore("narrowing_conversion")
+var i: int = f:
+ get:
+ return f
+
+var f: float
+
+@warning_ignore("narrowing_conversion")
+func test_func(_i: int = f):
+ i = f
+
+func test():
+ @warning_ignore("narrowing_conversion")
+ if signi(f): # TODO: Allow `@warning_ignore` before `elif`?
+ i = f
+
+ @warning_ignore("narrowing_conversion")
+ match signi(f):
+ 1:
+ i = f
+ @warning_ignore("confusable_identifier")
+ var my_vАr:
+ var _my_vАr: Variant = my_vАr
+
+ @warning_ignore("narrowing_conversion")
+ for j in signi(f):
+ i = f
+
+ @warning_ignore("narrowing_conversion")
+ while signi(f):
+ i = f
diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_targets.out b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_targets.out
new file mode 100644
index 0000000000..032af0322b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_targets.out
@@ -0,0 +1,29 @@
+GDTEST_OK
+>> WARNING
+>> Line: 3
+>> CONFUSABLE_IDENTIFIER
+>> The identifier "my_vАr" has misleading characters and might be confused with something else.
+>> WARNING
+>> Line: 8
+>> NARROWING_CONVERSION
+>> Narrowing conversion (float is converted to int and loses precision).
+>> WARNING
+>> Line: 19
+>> NARROWING_CONVERSION
+>> Narrowing conversion (float is converted to int and loses precision).
+>> WARNING
+>> Line: 24
+>> NARROWING_CONVERSION
+>> Narrowing conversion (float is converted to int and loses precision).
+>> WARNING
+>> Line: 27
+>> CONFUSABLE_IDENTIFIER
+>> The identifier "_my_vАr" has misleading characters and might be confused with something else.
+>> WARNING
+>> Line: 31
+>> NARROWING_CONVERSION
+>> Narrowing conversion (float is converted to int and loses precision).
+>> WARNING
+>> Line: 35
+>> NARROWING_CONVERSION
+>> Narrowing conversion (float is converted to int and loses precision).
diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_warnings.gd b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_warnings.gd
new file mode 100644
index 0000000000..8a1ab6f406
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_warnings.gd
@@ -0,0 +1,156 @@
+@warning_ignore("redundant_static_unload")
+@static_unload
+extends Node
+
+class A extends Node:
+ static func static_called_on_instance():
+ pass
+
+ @warning_ignore("get_node_default_without_onready")
+ var get_node_default_without_onready = $Node
+
+@warning_ignore("unused_private_class_variable")
+var _unused_private_class_variable
+
+@warning_ignore("onready_with_export")
+@onready @export var onready_with_export = 1
+
+var shadowed_variable
+var confusable_local_usage
+
+@warning_ignore("unused_signal")
+signal unused_signal()
+
+func variant_func() -> Variant:
+ return null
+
+func int_func() -> int:
+ return 1
+
+@warning_ignore("unused_parameter")
+func test_warnings(unused_private_class_variable):
+ var t = 1
+
+ @warning_ignore("unassigned_variable")
+ var unassigned_variable
+ print(unassigned_variable)
+
+ var _unassigned_variable_op_assign
+ @warning_ignore("unassigned_variable_op_assign")
+ _unassigned_variable_op_assign += t
+
+ @warning_ignore("unused_variable")
+ var unused_variable
+
+ @warning_ignore("unused_local_constant")
+ const unused_local_constant = 1
+
+ @warning_ignore("shadowed_variable")
+ var shadowed_variable = 1
+ print(shadowed_variable)
+
+ @warning_ignore("shadowed_variable_base_class")
+ var name = "test"
+ print(name)
+
+ @warning_ignore("shadowed_global_identifier")
+ var var_to_str = 1
+ print(var_to_str)
+
+ @warning_ignore("standalone_expression")
+ 1 + 2
+
+ @warning_ignore("standalone_ternary")
+ 1 if 2 else 3
+
+ @warning_ignore("incompatible_ternary")
+ t = 1 if 2 else false
+
+ @warning_ignore("unsafe_property_access")
+ self.unsafe_property_access = 1
+
+ var node: Node = null
+ @warning_ignore("unsafe_method_access")
+ node.unsafe_method_access()
+
+ @warning_ignore("unsafe_cast")
+ print(variant_func().x as int)
+
+ var key: Variant = "key"
+ @warning_ignore("unsafe_call_argument")
+ set(key, 1)
+
+ variant_func() # No warning (intended?).
+ @warning_ignore("return_value_discarded")
+ int_func()
+
+ var a: A = null
+ @warning_ignore("static_called_on_instance")
+ a.static_called_on_instance()
+
+ @warning_ignore("redundant_await")
+ await 1
+
+ @warning_ignore("assert_always_true")
+ assert(true)
+
+ assert(false) # No warning (intended).
+ @warning_ignore("assert_always_false")
+ assert(false and false)
+
+ @warning_ignore("integer_division")
+ var _integer_division = 5 / 2
+
+ @warning_ignore("narrowing_conversion")
+ var _narrowing_conversion: int = floorf(2.5)
+
+ @warning_ignore("int_as_enum_without_cast")
+ var _int_as_enum_without_cast: Variant.Type = 1
+
+ @warning_ignore("int_as_enum_without_cast", "int_as_enum_without_match")
+ var _int_as_enum_without_match: Variant.Type = 255
+
+ @warning_ignore("confusable_identifier")
+ var _cОnfusable_identifier = 1
+
+ if true:
+ @warning_ignore("confusable_local_declaration")
+ var _confusable_local_declaration = 1
+ var _confusable_local_declaration = 2
+
+ @warning_ignore("confusable_local_usage")
+ print(confusable_local_usage)
+ @warning_ignore("shadowed_variable")
+ var confusable_local_usage = 2
+ print(confusable_local_usage)
+
+ @warning_ignore("inference_on_variant")
+ var _inference_on_variant := variant_func()
+
+func test_unreachable_code():
+ return
+ @warning_ignore("unreachable_code")
+ print(1)
+
+func test_unreachable_pattern():
+ match 1:
+ _:
+ print(0)
+ @warning_ignore("unreachable_pattern")
+ 1:
+ print(1)
+
+func test_unsafe_void_return_variant() -> void:
+ return variant_func() # No warning (intended?).
+
+func test_unsafe_void_return() -> void:
+ @warning_ignore("unsafe_method_access", "unsafe_void_return")
+ return variant_func().f()
+
+@warning_ignore("native_method_override")
+func get_class():
+ pass
+
+# We don't want to execute it because of errors, just analyze.
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_warnings.out b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_warnings.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_warnings.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/unused_private_class_variable.out b/modules/gdscript/tests/scripts/analyzer/warnings/unused_private_class_variable.out
index fd88d23950..c902676a5d 100644
--- a/modules/gdscript/tests/scripts/analyzer/warnings/unused_private_class_variable.out
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/unused_private_class_variable.out
@@ -2,8 +2,8 @@ GDTEST_OK
>> WARNING
>> Line: 3
>> UNUSED_PRIVATE_CLASS_VARIABLE
->> The class variable "_a" is declared but never used in the script.
+>> The class variable "_a" is declared but never used in the class.
>> WARNING
>> Line: 7
>> UNUSED_PRIVATE_CLASS_VARIABLE
->> The class variable "_d" is declared but never used in the script.
+>> The class variable "_d" is declared but never used in the class.
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.gd b/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.gd
new file mode 100644
index 0000000000..d937dfdcfe
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.gd
@@ -0,0 +1,12 @@
+signal s1()
+signal s2()
+signal s3()
+@warning_ignore("unused_signal")
+signal s4()
+
+func no_exec():
+ s1.emit()
+ print(s2)
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.out b/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.out
new file mode 100644
index 0000000000..ff57017830
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+>> WARNING
+>> Line: 3
+>> UNUSED_SIGNAL
+>> The signal "s3" is declared but never explicitly used in the class.
diff --git a/modules/gdscript/tests/scripts/parser/errors/duplicate_tool.out b/modules/gdscript/tests/scripts/parser/errors/duplicate_tool.out
index 26fe23fb78..497d361204 100644
--- a/modules/gdscript/tests/scripts/parser/errors/duplicate_tool.out
+++ b/modules/gdscript/tests/scripts/parser/errors/duplicate_tool.out
@@ -1,2 +1,2 @@
-GDTEST_ANALYZER_ERROR
+GDTEST_PARSER_ERROR
"@tool" annotation can only be used once.
diff --git a/modules/gdscript/tests/scripts/parser/features/class_inheritance_access.gd b/modules/gdscript/tests/scripts/parser/features/class_inheritance_access.gd
index eb392672eb..2e1407237f 100644
--- a/modules/gdscript/tests/scripts/parser/features/class_inheritance_access.gd
+++ b/modules/gdscript/tests/scripts/parser/features/class_inheritance_access.gd
@@ -4,6 +4,7 @@ class Parent:
var parent_variable := 2
+ @warning_ignore("unused_signal")
signal parent_signal
var parent_attribute: int:
diff --git a/modules/gdscript/tests/scripts/parser/features/lambda_ends_with_new_line.gd b/modules/gdscript/tests/scripts/parser/features/lambda_ends_with_new_line.gd
index f16c768f7f..46b6856d22 100644
--- a/modules/gdscript/tests/scripts/parser/features/lambda_ends_with_new_line.gd
+++ b/modules/gdscript/tests/scripts/parser/features/lambda_ends_with_new_line.gd
@@ -14,6 +14,7 @@ func test():
print(v)
print()
+ @warning_ignore("standalone_ternary")
v=func(): print(2) if false else print(3)
@warning_ignore("unsafe_cast")
(v as Callable).call()
diff --git a/modules/gdscript/tests/scripts/parser/features/match.gd b/modules/gdscript/tests/scripts/parser/features/match.gd
index 59b5ba2426..a2e93c64fd 100644
--- a/modules/gdscript/tests/scripts/parser/features/match.gd
+++ b/modules/gdscript/tests/scripts/parser/features/match.gd
@@ -14,3 +14,6 @@ func test():
print("This won't match")
_:
print("This will match")
+
+ match 0:
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd b/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd
index e4d6a72f90..d02f82d417 100644
--- a/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd
+++ b/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd
@@ -1,5 +1,3 @@
-#GDTEST_OK
-
# No parentheses.
signal a
@@ -16,5 +14,15 @@ signal d(
c,
)
+# With type hints.
+signal e(a: int, b: Variant, c: Node)
+
+func no_exec():
+ a.emit()
+ b.emit()
+ c.emit()
+ d.emit()
+ e.emit()
+
func test():
print("Ok")
diff --git a/modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.out b/modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.out
index 7d1558c6fc..ff3e827255 100644
--- a/modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.out
+++ b/modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.out
@@ -2,4 +2,4 @@ GDTEST_OK
>> WARNING
>> Line: 8
>> INCOMPATIBLE_TERNARY
->> Values of the ternary conditional are not mutually compatible.
+>> Values of the ternary operator are not mutually compatible.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/standalone_ternary.gd b/modules/gdscript/tests/scripts/parser/warnings/standalone_ternary.gd
new file mode 100644
index 0000000000..9b296e02e1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/standalone_ternary.gd
@@ -0,0 +1,3 @@
+func test():
+ 1 if true else 2
+ print(1) if true else print(2)
diff --git a/modules/gdscript/tests/scripts/parser/warnings/standalone_ternary.out b/modules/gdscript/tests/scripts/parser/warnings/standalone_ternary.out
new file mode 100644
index 0000000000..477449e0e3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/standalone_ternary.out
@@ -0,0 +1,10 @@
+GDTEST_OK
+>> WARNING
+>> Line: 2
+>> STANDALONE_TERNARY
+>> Standalone ternary operator: the return value is being discarded.
+>> WARNING
+>> Line: 3
+>> STANDALONE_TERNARY
+>> Standalone ternary operator: the return value is being discarded.
+1
diff --git a/modules/gdscript/tests/scripts/runtime/features/argument_count.gd b/modules/gdscript/tests/scripts/runtime/features/argument_count.gd
new file mode 100644
index 0000000000..c67ce25cbe
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/argument_count.gd
@@ -0,0 +1,102 @@
+extends Node
+
+func my_func_1(_foo, _bar):
+ pass
+
+func my_func_2(_foo, _bar, _baz):
+ pass
+
+static func my_static_func_1(_foo, _bar):
+ pass
+
+static func my_static_func_2(_foo, _bar, _baz):
+ pass
+
+@rpc
+func my_rpc_func_1(_foo, _bar):
+ pass
+
+@rpc
+func my_rpc_func_2(_foo, _bar, _baz):
+ pass
+
+func test():
+ # Test built-in methods.
+ var builtin_callable_1 : Callable = add_to_group
+ print(builtin_callable_1.get_argument_count()) # Should print 2.
+ var builtin_callable_2 : Callable = find_child
+ print(builtin_callable_2.get_argument_count()) # Should print 3.
+
+ # Test built-in vararg methods.
+ var builtin_vararg_callable_1 : Callable = call_thread_safe
+ print(builtin_vararg_callable_1.get_argument_count()) # Should print 1.
+ var builtin_vararg_callable_2 : Callable = rpc_id
+ print(builtin_vararg_callable_2.get_argument_count()) # Should print 2.
+
+ # Test plain methods.
+ var callable_1 : Callable = my_func_1
+ print(callable_1.get_argument_count()) # Should print 2.
+ var callable_2 : Callable = my_func_2
+ print(callable_2.get_argument_count()) # Should print 3.
+
+ # Test static methods.
+ var static_callable_1 : Callable = my_static_func_1
+ print(static_callable_1.get_argument_count()) # Should print 2.
+ var static_callable_2 : Callable = my_static_func_2
+ print(static_callable_2.get_argument_count()) # Should print 3.
+
+ # Test rpc methods.
+ var rpc_callable_1 : Callable = my_rpc_func_1
+ print(rpc_callable_1.get_argument_count()) # Should print 2.
+ var rpc_callable_2 : Callable = my_rpc_func_2
+ print(rpc_callable_2.get_argument_count()) # Should print 3.
+
+ # Test lambdas.
+ var lambda_callable_1 : Callable = func(_foo, _bar): pass
+ print(lambda_callable_1.get_argument_count()) # Should print 2.
+ var lambda_callable_2 : Callable = func(_foo, _bar, _baz): pass
+ print(lambda_callable_2.get_argument_count()) # Should print 3.
+
+ # Test lambas with self.
+ var lambda_self_callable_1 : Callable = func(_foo, _bar): return self
+ print(lambda_self_callable_1.get_argument_count()) # Should print 2.
+ var lambda_self_callable_2 : Callable = func(_foo, _bar, _baz): return self
+ print(lambda_self_callable_2.get_argument_count()) # Should print 3.
+
+ # Test bind.
+ var bind_callable_1 : Callable = my_func_2.bind(1)
+ print(bind_callable_1.get_argument_count()) # Should print 2.
+ var bind_callable_2 : Callable = my_func_2.bind(1, 2)
+ print(bind_callable_2.get_argument_count()) # Should print 1.
+
+ # Test unbind.
+ var unbind_callable_1 : Callable = my_func_2.unbind(1)
+ print(unbind_callable_1.get_argument_count()) # Should print 4.
+ var unbind_callable_2 : Callable = my_func_2.unbind(2)
+ print(unbind_callable_2.get_argument_count()) # Should print 5.
+
+ # Test variant callables.
+ var string_tmp := String()
+ var variant_callable_1 : Callable = string_tmp.replace
+ print(variant_callable_1.get_argument_count()) # Should print 2.
+ var variant_callable_2 : Callable = string_tmp.rsplit
+ print(variant_callable_2.get_argument_count()) # Should print 3.
+
+ # Test variant vararg callables.
+ var callable_tmp := Callable()
+ var variant_vararg_callable_1 : Callable = callable_tmp.call
+ print(variant_vararg_callable_1.get_argument_count()) # Should print 0.
+ var variant_vararg_callable_2 : Callable = callable_tmp.rpc_id
+ print(variant_vararg_callable_2.get_argument_count()) # Should print 1.
+
+ # Test global methods.
+ var global_callable_1 = is_equal_approx
+ print(global_callable_1.get_argument_count()) # Should print 2.
+ var global_callable_2 = inverse_lerp
+ print(global_callable_2.get_argument_count()) # Should print 3.
+
+ # Test GDScript methods.
+ var gdscript_callable_1 = char
+ print(gdscript_callable_1.get_argument_count()) # Should print 1.
+ var gdscript_callable_2 = is_instance_of
+ print(gdscript_callable_2.get_argument_count()) # Should print 2.
diff --git a/modules/gdscript/tests/scripts/runtime/features/argument_count.out b/modules/gdscript/tests/scripts/runtime/features/argument_count.out
new file mode 100644
index 0000000000..42c4ece37d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/argument_count.out
@@ -0,0 +1,27 @@
+GDTEST_OK
+2
+3
+1
+2
+2
+3
+2
+3
+2
+3
+2
+3
+2
+3
+2
+1
+4
+5
+2
+3
+0
+1
+2
+3
+1
+2
diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info.gd b/modules/gdscript/tests/scripts/runtime/features/member_info.gd
index 6fe9647b4d..d7485f49e6 100644
--- a/modules/gdscript/tests/scripts/runtime/features/member_info.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/member_info.gd
@@ -56,6 +56,16 @@ signal test_signal_6(a: Resource, b: Array[Resource])
signal test_signal_7(a: TestMemberInfo, b: Array[TestMemberInfo])
signal test_signal_8(a: MyClass, b: Array[MyClass])
+func no_exec():
+ test_signal_1.emit()
+ test_signal_2.emit()
+ test_signal_3.emit()
+ test_signal_4.emit()
+ test_signal_5.emit()
+ test_signal_6.emit()
+ test_signal_7.emit()
+ test_signal_8.emit()
+
func test():
var script: Script = get_script()
for property in script.get_property_list():
diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.gd b/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.gd
index 563c6ce569..ee5c1e1267 100644
--- a/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.gd
@@ -11,7 +11,9 @@ class A:
static func test_static_func_a2(): pass
func test_func_a1(): pass
func test_func_a2(): pass
+ @warning_ignore("unused_signal")
signal test_signal_a1()
+ @warning_ignore("unused_signal")
signal test_signal_a2()
class B extends A:
@@ -23,7 +25,9 @@ class B extends A:
static func test_static_func_b2(): pass
func test_func_b1(): pass
func test_func_b2(): pass
+ @warning_ignore("unused_signal")
signal test_signal_b1()
+ @warning_ignore("unused_signal")
signal test_signal_b2()
func test():
diff --git a/modules/gltf/doc_classes/GLTFMesh.xml b/modules/gltf/doc_classes/GLTFMesh.xml
index 8234ed9eac..b4c3db7618 100644
--- a/modules/gltf/doc_classes/GLTFMesh.xml
+++ b/modules/gltf/doc_classes/GLTFMesh.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GLTFMesh" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
- GLTFMesh represents an GLTF mesh.
+ GLTFMesh represents a GLTF mesh.
</brief_description>
<description>
GLTFMesh handles 3D mesh data imported from GLTF files. It includes properties for blend channels, blend weights, instance materials, and the mesh itself.
diff --git a/modules/gltf/doc_classes/GLTFTexture.xml b/modules/gltf/doc_classes/GLTFTexture.xml
index 50789a0ebf..9ad7c0f4c6 100644
--- a/modules/gltf/doc_classes/GLTFTexture.xml
+++ b/modules/gltf/doc_classes/GLTFTexture.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GLTFTexture" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
- GLTFTexture represents a texture in an GLTF file.
+ GLTFTexture represents a texture in a GLTF file.
</brief_description>
<description>
</description>
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index b53be7f855..b8152749d3 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -5517,7 +5517,7 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> p_state, const GL
}
}
-template <class T>
+template <typename T>
struct SceneFormatImporterGLTFInterpolate {
T lerp(const T &a, const T &b, float c) const {
return a + (b - a) * c;
@@ -5567,7 +5567,7 @@ struct SceneFormatImporterGLTFInterpolate<Quaternion> {
}
};
-template <class T>
+template <typename T>
T GLTFDocument::_interpolate_track(const Vector<real_t> &p_times, const Vector<T> &p_values, const float p_time, const GLTFAnimation::Interpolation p_interp) {
ERR_FAIL_COND_V(p_values.is_empty(), T());
if (p_times.size() != (p_values.size() / (p_interp == GLTFAnimation::INTERP_CUBIC_SPLINE ? 3 : 1))) {
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index 1682e9eeb7..11b29e7268 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -217,7 +217,7 @@ private:
Light3D *_generate_light(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index);
Node3D *_generate_spatial(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index);
void _assign_node_names(Ref<GLTFState> p_state);
- template <class T>
+ template <typename T>
T _interpolate_track(const Vector<real_t> &p_times, const Vector<T> &p_values,
const float p_time,
const GLTFAnimation::Interpolation p_interp);
diff --git a/modules/gltf/gltf_template_convert.h b/modules/gltf/gltf_template_convert.h
index 2743cd8a9b..46f185867a 100644
--- a/modules/gltf/gltf_template_convert.h
+++ b/modules/gltf/gltf_template_convert.h
@@ -37,7 +37,7 @@
#include "core/variant/typed_array.h"
namespace GLTFTemplateConvert {
-template <class T>
+template <typename T>
static Array to_array(const Vector<T> &p_inp) {
Array ret;
for (int i = 0; i < p_inp.size(); i++) {
@@ -46,7 +46,7 @@ static Array to_array(const Vector<T> &p_inp) {
return ret;
}
-template <class T>
+template <typename T>
static TypedArray<T> to_array(const HashSet<T> &p_inp) {
TypedArray<T> ret;
typename HashSet<T>::Iterator elem = p_inp.begin();
@@ -57,7 +57,7 @@ static TypedArray<T> to_array(const HashSet<T> &p_inp) {
return ret;
}
-template <class T>
+template <typename T>
static void set_from_array(Vector<T> &r_out, const Array &p_inp) {
r_out.clear();
for (int i = 0; i < p_inp.size(); i++) {
@@ -65,7 +65,7 @@ static void set_from_array(Vector<T> &r_out, const Array &p_inp) {
}
}
-template <class T>
+template <typename T>
static void set_from_array(HashSet<T> &r_out, const TypedArray<T> &p_inp) {
r_out.clear();
for (int i = 0; i < p_inp.size(); i++) {
@@ -73,7 +73,7 @@ static void set_from_array(HashSet<T> &r_out, const TypedArray<T> &p_inp) {
}
}
-template <class K, class V>
+template <typename K, typename V>
static Dictionary to_dictionary(const HashMap<K, V> &p_inp) {
Dictionary ret;
for (const KeyValue<K, V> &E : p_inp) {
@@ -82,7 +82,7 @@ static Dictionary to_dictionary(const HashMap<K, V> &p_inp) {
return ret;
}
-template <class K, class V>
+template <typename K, typename V>
static void set_from_dictionary(HashMap<K, V> &r_out, const Dictionary &p_inp) {
r_out.clear();
Array keys = p_inp.keys();
diff --git a/modules/gltf/structures/gltf_animation.h b/modules/gltf/structures/gltf_animation.h
index 7f769752c2..afc9784895 100644
--- a/modules/gltf/structures/gltf_animation.h
+++ b/modules/gltf/structures/gltf_animation.h
@@ -47,7 +47,7 @@ public:
INTERP_CUBIC_SPLINE,
};
- template <class T>
+ template <typename T>
struct Channel {
Interpolation interpolation = INTERP_LINEAR;
Vector<real_t> times;
diff --git a/modules/interactive_music/SCsub b/modules/interactive_music/SCsub
new file mode 100644
index 0000000000..2950a30854
--- /dev/null
+++ b/modules/interactive_music/SCsub
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_interactive_music = env_modules.Clone()
+
+# Godot's own source files
+env_interactive_music.add_source_files(env.modules_sources, "*.cpp")
+if env.editor_build:
+ env_interactive_music.add_source_files(env.modules_sources, "editor/*.cpp")
diff --git a/modules/interactive_music/audio_stream_interactive.cpp b/modules/interactive_music/audio_stream_interactive.cpp
new file mode 100644
index 0000000000..01764d66ed
--- /dev/null
+++ b/modules/interactive_music/audio_stream_interactive.cpp
@@ -0,0 +1,1030 @@
+/**************************************************************************/
+/* audio_stream_interactive.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "audio_stream_interactive.h"
+
+#include "core/math/math_funcs.h"
+#include "core/string/print_string.h"
+
+AudioStreamInteractive::AudioStreamInteractive() {
+}
+
+Ref<AudioStreamPlayback> AudioStreamInteractive::instantiate_playback() {
+ Ref<AudioStreamPlaybackInteractive> playback_transitioner;
+ playback_transitioner.instantiate();
+ playback_transitioner->stream = Ref<AudioStreamInteractive>(this);
+ return playback_transitioner;
+}
+
+String AudioStreamInteractive::get_stream_name() const {
+ return "Transitioner";
+}
+
+void AudioStreamInteractive::set_clip_count(int p_count) {
+ ERR_FAIL_COND(p_count < 0 || p_count > MAX_CLIPS);
+
+ AudioServer::get_singleton()->lock();
+
+ if (p_count < clip_count) {
+ // Removing should stop players.
+ version++;
+ }
+
+#ifdef TOOLS_ENABLED
+ stream_name_cache = "";
+ if (p_count < clip_count) {
+ for (int i = 0; i < clip_count; i++) {
+ if (clips[i].auto_advance_next_clip >= p_count) {
+ clips[i].auto_advance_next_clip = 0;
+ clips[i].auto_advance = AUTO_ADVANCE_DISABLED;
+ }
+ }
+
+ for (KeyValue<TransitionKey, Transition> &K : transition_map) {
+ if (K.value.filler_clip >= p_count) {
+ K.value.use_filler_clip = false;
+ K.value.filler_clip = 0;
+ }
+ }
+ if (initial_clip >= p_count) {
+ initial_clip = 0;
+ }
+ }
+#endif
+ clip_count = p_count;
+ AudioServer::get_singleton()->unlock();
+
+ notify_property_list_changed();
+ emit_signal(SNAME("parameter_list_changed"));
+}
+
+void AudioStreamInteractive::set_initial_clip(int p_clip) {
+ ERR_FAIL_INDEX(p_clip, clip_count);
+ initial_clip = p_clip;
+}
+
+int AudioStreamInteractive::get_initial_clip() const {
+ return initial_clip;
+}
+
+int AudioStreamInteractive::get_clip_count() const {
+ return clip_count;
+}
+
+void AudioStreamInteractive::set_clip_name(int p_clip, const StringName &p_name) {
+ ERR_FAIL_INDEX(p_clip, MAX_CLIPS);
+ clips[p_clip].name = p_name;
+}
+
+StringName AudioStreamInteractive::get_clip_name(int p_clip) const {
+ ERR_FAIL_COND_V(p_clip < -1 || p_clip >= MAX_CLIPS, StringName());
+ if (p_clip == CLIP_ANY) {
+ return RTR("All Clips");
+ }
+ return clips[p_clip].name;
+}
+
+void AudioStreamInteractive::set_clip_stream(int p_clip, const Ref<AudioStream> &p_stream) {
+ ERR_FAIL_INDEX(p_clip, MAX_CLIPS);
+ AudioServer::get_singleton()->lock();
+ if (clips[p_clip].stream.is_valid()) {
+ version++;
+ }
+ clips[p_clip].stream = p_stream;
+ AudioServer::get_singleton()->unlock();
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ if (clips[p_clip].name == StringName() && p_stream.is_valid()) {
+ String n;
+ if (!clips[p_clip].stream->get_name().is_empty()) {
+ n = clips[p_clip].stream->get_name().replace(",", " ");
+ } else if (clips[p_clip].stream->get_path().is_resource_file()) {
+ n = clips[p_clip].stream->get_path().get_file().get_basename().replace(",", " ");
+ n = n.capitalize();
+ }
+
+ if (n != "") {
+ clips[p_clip].name = n;
+ }
+ }
+ }
+#endif
+
+#ifdef TOOLS_ENABLED
+ stream_name_cache = "";
+ notify_property_list_changed(); // Hints change if stream changes.
+ emit_signal(SNAME("parameter_list_changed"));
+#endif
+}
+
+Ref<AudioStream> AudioStreamInteractive::get_clip_stream(int p_clip) const {
+ ERR_FAIL_INDEX_V(p_clip, MAX_CLIPS, Ref<AudioStream>());
+ return clips[p_clip].stream;
+}
+
+void AudioStreamInteractive::set_clip_auto_advance(int p_clip, AutoAdvanceMode p_mode) {
+ ERR_FAIL_INDEX(p_clip, MAX_CLIPS);
+ ERR_FAIL_INDEX(p_mode, 3);
+ clips[p_clip].auto_advance = p_mode;
+ notify_property_list_changed();
+}
+
+AudioStreamInteractive::AutoAdvanceMode AudioStreamInteractive::get_clip_auto_advance(int p_clip) const {
+ ERR_FAIL_INDEX_V(p_clip, MAX_CLIPS, AUTO_ADVANCE_DISABLED);
+ return clips[p_clip].auto_advance;
+}
+
+void AudioStreamInteractive::set_clip_auto_advance_next_clip(int p_clip, int p_index) {
+ ERR_FAIL_INDEX(p_clip, MAX_CLIPS);
+ clips[p_clip].auto_advance_next_clip = p_index;
+}
+
+int AudioStreamInteractive::get_clip_auto_advance_next_clip(int p_clip) const {
+ ERR_FAIL_INDEX_V(p_clip, MAX_CLIPS, -1);
+ return clips[p_clip].auto_advance_next_clip;
+}
+
+// TRANSITIONS
+
+void AudioStreamInteractive::_set_transitions(const Dictionary &p_transitions) {
+ List<Variant> keys;
+ p_transitions.get_key_list(&keys);
+ for (const Variant &K : keys) {
+ Vector2i k = K;
+ Dictionary data = p_transitions[K];
+ ERR_CONTINUE(!data.has("from_time"));
+ ERR_CONTINUE(!data.has("to_time"));
+ ERR_CONTINUE(!data.has("fade_mode"));
+ ERR_CONTINUE(!data.has("fade_beats"));
+ bool use_filler_clip = false;
+ int filler_clip = 0;
+ if (data.has("use_filler_clip") && data.has("filler_clip")) {
+ use_filler_clip = data["use_filler_clip"];
+ filler_clip = data["filler_clip"];
+ }
+ bool hold_previous = data.has("hold_previous") ? bool(data["hold_previous"]) : false;
+
+ add_transition(k.x, k.y, TransitionFromTime(int(data["from_time"])), TransitionToTime(int(data["to_time"])), FadeMode(int(data["fade_mode"])), data["fade_beats"], use_filler_clip, filler_clip, hold_previous);
+ }
+}
+
+Dictionary AudioStreamInteractive::_get_transitions() const {
+ Vector<Vector2i> keys;
+
+ for (const KeyValue<TransitionKey, Transition> &K : transition_map) {
+ keys.push_back(Vector2i(K.key.from_clip, K.key.to_clip));
+ }
+ keys.sort();
+ Dictionary ret;
+ for (int i = 0; i < keys.size(); i++) {
+ const Transition &tr = transition_map[TransitionKey(keys[i].x, keys[i].y)];
+ Dictionary data;
+ data["from_time"] = tr.from_time;
+ data["to_time"] = tr.to_time;
+ data["fade_mode"] = tr.fade_mode;
+ data["fade_beats"] = tr.fade_beats;
+ if (tr.use_filler_clip) {
+ data["use_filler_clip"] = true;
+ data["filler_clip"] = tr.filler_clip;
+ }
+ if (tr.hold_previous) {
+ data["hold_previous"] = true;
+ }
+
+ ret[keys[i]] = data;
+ }
+ return ret;
+}
+
+bool AudioStreamInteractive::has_transition(int p_from_clip, int p_to_clip) const {
+ TransitionKey tk(p_from_clip, p_to_clip);
+ return transition_map.has(tk);
+}
+
+void AudioStreamInteractive::erase_transition(int p_from_clip, int p_to_clip) {
+ TransitionKey tk(p_from_clip, p_to_clip);
+ ERR_FAIL_COND(!transition_map.has(tk));
+ AudioDriver::get_singleton()->lock();
+ transition_map.erase(tk);
+ AudioDriver::get_singleton()->unlock();
+}
+
+PackedInt32Array AudioStreamInteractive::get_transition_list() const {
+ PackedInt32Array ret;
+
+ for (const KeyValue<TransitionKey, Transition> &K : transition_map) {
+ ret.push_back(K.key.from_clip);
+ ret.push_back(K.key.to_clip);
+ }
+ return ret;
+}
+
+void AudioStreamInteractive::add_transition(int p_from_clip, int p_to_clip, TransitionFromTime p_from_time, TransitionToTime p_to_time, FadeMode p_fade_mode, float p_fade_beats, bool p_use_filler_flip, int p_filler_clip, bool p_hold_previous) {
+ ERR_FAIL_COND(p_from_clip < CLIP_ANY || p_from_clip >= clip_count);
+ ERR_FAIL_COND(p_to_clip < CLIP_ANY || p_to_clip >= clip_count);
+ ERR_FAIL_UNSIGNED_INDEX(p_from_time, TRANSITION_FROM_TIME_MAX);
+ ERR_FAIL_UNSIGNED_INDEX(p_to_time, TRANSITION_TO_TIME_MAX);
+ ERR_FAIL_UNSIGNED_INDEX(p_fade_mode, FADE_MAX);
+
+ Transition tr;
+ tr.from_time = p_from_time;
+ tr.to_time = p_to_time;
+ tr.fade_mode = p_fade_mode;
+ tr.fade_beats = p_fade_beats;
+ tr.use_filler_clip = p_use_filler_flip;
+ tr.filler_clip = p_filler_clip;
+ tr.hold_previous = p_hold_previous;
+
+ TransitionKey tk(p_from_clip, p_to_clip);
+
+ AudioDriver::get_singleton()->lock();
+ transition_map[tk] = tr;
+ AudioDriver::get_singleton()->unlock();
+}
+
+AudioStreamInteractive::TransitionFromTime AudioStreamInteractive::get_transition_from_time(int p_from_clip, int p_to_clip) const {
+ TransitionKey tk(p_from_clip, p_to_clip);
+ ERR_FAIL_COND_V(!transition_map.has(tk), TRANSITION_FROM_TIME_END);
+ return transition_map[tk].from_time;
+}
+
+AudioStreamInteractive::TransitionToTime AudioStreamInteractive::get_transition_to_time(int p_from_clip, int p_to_clip) const {
+ TransitionKey tk(p_from_clip, p_to_clip);
+ ERR_FAIL_COND_V(!transition_map.has(tk), TRANSITION_TO_TIME_START);
+ return transition_map[tk].to_time;
+}
+
+AudioStreamInteractive::FadeMode AudioStreamInteractive::get_transition_fade_mode(int p_from_clip, int p_to_clip) const {
+ TransitionKey tk(p_from_clip, p_to_clip);
+ ERR_FAIL_COND_V(!transition_map.has(tk), FADE_DISABLED);
+ return transition_map[tk].fade_mode;
+}
+
+float AudioStreamInteractive::get_transition_fade_beats(int p_from_clip, int p_to_clip) const {
+ TransitionKey tk(p_from_clip, p_to_clip);
+ ERR_FAIL_COND_V(!transition_map.has(tk), -1);
+ return transition_map[tk].fade_beats;
+}
+
+bool AudioStreamInteractive::is_transition_using_filler_clip(int p_from_clip, int p_to_clip) const {
+ TransitionKey tk(p_from_clip, p_to_clip);
+ ERR_FAIL_COND_V(!transition_map.has(tk), false);
+ return transition_map[tk].use_filler_clip;
+}
+
+int AudioStreamInteractive::get_transition_filler_clip(int p_from_clip, int p_to_clip) const {
+ TransitionKey tk(p_from_clip, p_to_clip);
+ ERR_FAIL_COND_V(!transition_map.has(tk), -1);
+ return transition_map[tk].filler_clip;
+}
+
+bool AudioStreamInteractive::is_transition_holding_previous(int p_from_clip, int p_to_clip) const {
+ TransitionKey tk(p_from_clip, p_to_clip);
+ ERR_FAIL_COND_V(!transition_map.has(tk), false);
+ return transition_map[tk].hold_previous;
+}
+
+#ifdef TOOLS_ENABLED
+
+PackedStringArray AudioStreamInteractive::_get_linked_undo_properties(const String &p_property, const Variant &p_new_value) const {
+ PackedStringArray ret;
+
+ if (p_property.begins_with("clip_") && p_property.ends_with("/stream")) {
+ int clip = p_property.get_slicec('_', 1).to_int();
+ if (clip < clip_count) {
+ ret.push_back("clip_" + itos(clip) + "/name");
+ }
+ }
+
+ if (p_property == "clip_count") {
+ int new_clip_count = p_new_value;
+
+ if (new_clip_count < clip_count) {
+ for (int i = 0; i < clip_count; i++) {
+ if (clips[i].auto_advance_next_clip >= new_clip_count) {
+ ret.push_back("clip_" + itos(i) + "/auto_advance");
+ ret.push_back("clip_" + itos(i) + "/next_clip");
+ }
+ }
+
+ ret.push_back("_transitions");
+ if (initial_clip >= new_clip_count) {
+ ret.push_back("initial_clip");
+ }
+ }
+ }
+ return ret;
+}
+
+template <class T>
+static void _test_and_swap(T &p_elem, uint32_t p_a, uint32_t p_b) {
+ if ((uint32_t)p_elem == p_a) {
+ p_elem = p_b;
+ } else if (uint32_t(p_elem) == p_b) {
+ p_elem = p_a;
+ }
+}
+
+void AudioStreamInteractive::_inspector_array_swap_clip(uint32_t p_item_a, uint32_t p_item_b) {
+ ERR_FAIL_UNSIGNED_INDEX(p_item_a, (uint32_t)clip_count);
+ ERR_FAIL_UNSIGNED_INDEX(p_item_b, (uint32_t)clip_count);
+
+ for (int i = 0; i < clip_count; i++) {
+ _test_and_swap(clips[i].auto_advance_next_clip, p_item_a, p_item_b);
+ }
+
+ Vector<TransitionKey> to_remove;
+ HashMap<TransitionKey, Transition, TransitionKeyHasher> to_add;
+
+ for (KeyValue<TransitionKey, Transition> &K : transition_map) {
+ if (K.key.from_clip == p_item_a || K.key.from_clip == p_item_b || K.key.to_clip == p_item_a || K.key.to_clip == p_item_b) {
+ to_remove.push_back(K.key);
+ TransitionKey new_key = K.key;
+ _test_and_swap(new_key.from_clip, p_item_a, p_item_b);
+ _test_and_swap(new_key.to_clip, p_item_a, p_item_b);
+ to_add[new_key] = K.value;
+ }
+ }
+
+ for (int i = 0; i < to_remove.size(); i++) {
+ transition_map.erase(to_remove[i]);
+ }
+
+ for (KeyValue<TransitionKey, Transition> &K : to_add) {
+ transition_map.insert(K.key, K.value);
+ }
+
+ SWAP(clips[p_item_a], clips[p_item_b]);
+
+ stream_name_cache = "";
+
+ notify_property_list_changed();
+ emit_signal(SNAME("parameter_list_changed"));
+}
+
+String AudioStreamInteractive::_get_streams_hint() const {
+ if (!stream_name_cache.is_empty()) {
+ return stream_name_cache;
+ }
+
+ for (int i = 0; i < clip_count; i++) {
+ if (i > 0) {
+ stream_name_cache += ",";
+ }
+ String n = String(clips[i].name).replace(",", " ");
+
+ if (n == "" && clips[i].stream.is_valid()) {
+ if (!clips[i].stream->get_name().is_empty()) {
+ n = clips[i].stream->get_name().replace(",", " ");
+ } else if (clips[i].stream->get_path().is_resource_file()) {
+ n = clips[i].stream->get_path().get_file().replace(",", " ");
+ }
+ }
+
+ if (n == "") {
+ n = "Clip " + itos(i);
+ }
+
+ stream_name_cache += n;
+ }
+
+ return stream_name_cache;
+}
+
+#endif
+void AudioStreamInteractive::_validate_property(PropertyInfo &r_property) const {
+ String prop = r_property.name;
+
+#ifdef TOOLS_ENABLED
+ if (prop == "switch_to") {
+ r_property.hint_string = _get_streams_hint();
+ return;
+ }
+#endif
+
+ if (prop == "initial_clip") {
+#ifdef TOOLS_ENABLED
+ r_property.hint_string = _get_streams_hint();
+#endif
+ } else if (prop.begins_with("clip_") && prop != "clip_count") {
+ int clip = prop.get_slicec('_', 1).to_int();
+ if (clip >= clip_count) {
+ r_property.usage = PROPERTY_USAGE_INTERNAL;
+ } else if (prop == "clip_" + itos(clip) + "/next_clip") {
+ if (clips[clip].auto_advance != AUTO_ADVANCE_ENABLED) {
+ r_property.usage = 0;
+ } else {
+#ifdef TOOLS_ENABLED
+ r_property.hint_string = _get_streams_hint();
+#endif
+ }
+ }
+ }
+}
+
+void AudioStreamInteractive::get_parameter_list(List<Parameter> *r_parameters) {
+ String clip_names;
+ for (int i = 0; i < clip_count; i++) {
+ clip_names += ",";
+ clip_names += clips[i].name;
+ }
+ r_parameters->push_back(Parameter(PropertyInfo(Variant::STRING, "switch_to_clip", PROPERTY_HINT_ENUM, clip_names, PROPERTY_USAGE_EDITOR), ""));
+}
+
+void AudioStreamInteractive::_bind_methods() {
+#ifdef TOOLS_ENABLED
+ ClassDB::bind_method(D_METHOD("_get_linked_undo_properties", "for_property", "for_value"), &AudioStreamInteractive::_get_linked_undo_properties);
+ ClassDB::bind_method(D_METHOD("_inspector_array_swap_clip", "a", "b"), &AudioStreamInteractive::_inspector_array_swap_clip);
+#endif
+
+ // CLIPS
+
+ ClassDB::bind_method(D_METHOD("set_clip_count", "clip_count"), &AudioStreamInteractive::set_clip_count);
+ ClassDB::bind_method(D_METHOD("get_clip_count"), &AudioStreamInteractive::get_clip_count);
+
+ ClassDB::bind_method(D_METHOD("set_initial_clip", "clip_index"), &AudioStreamInteractive::set_initial_clip);
+ ClassDB::bind_method(D_METHOD("get_initial_clip"), &AudioStreamInteractive::get_initial_clip);
+
+ ClassDB::bind_method(D_METHOD("set_clip_name", "clip_index", "name"), &AudioStreamInteractive::set_clip_name);
+ ClassDB::bind_method(D_METHOD("get_clip_name", "clip_index"), &AudioStreamInteractive::get_clip_name);
+
+ ClassDB::bind_method(D_METHOD("set_clip_stream", "clip_index", "stream"), &AudioStreamInteractive::set_clip_stream);
+ ClassDB::bind_method(D_METHOD("get_clip_stream", "clip_index"), &AudioStreamInteractive::get_clip_stream);
+
+ ClassDB::bind_method(D_METHOD("set_clip_auto_advance", "clip_index", "mode"), &AudioStreamInteractive::set_clip_auto_advance);
+ ClassDB::bind_method(D_METHOD("get_clip_auto_advance", "clip_index"), &AudioStreamInteractive::get_clip_auto_advance);
+
+ ClassDB::bind_method(D_METHOD("set_clip_auto_advance_next_clip", "clip_index", "auto_advance_next_clip"), &AudioStreamInteractive::set_clip_auto_advance_next_clip);
+ ClassDB::bind_method(D_METHOD("get_clip_auto_advance_next_clip", "clip_index"), &AudioStreamInteractive::get_clip_auto_advance_next_clip);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "initial_clip", PROPERTY_HINT_ENUM, "", PROPERTY_USAGE_DEFAULT), "set_initial_clip", "get_initial_clip");
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "clip_count", PROPERTY_HINT_RANGE, "1," + itos(MAX_CLIPS), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Clips,clip_,page_size=999,unfoldable,numbered,swap_method=_inspector_array_swap_clip,add_button_text=" + String(RTR("Add Clip"))), "set_clip_count", "get_clip_count");
+ for (int i = 0; i < MAX_CLIPS; i++) {
+ ADD_PROPERTYI(PropertyInfo(Variant::STRING_NAME, "clip_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_clip_name", "get_clip_name", i);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "clip_" + itos(i) + "/stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_clip_stream", "get_clip_stream", i);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "clip_" + itos(i) + "/auto_advance", PROPERTY_HINT_ENUM, "Disabled,Enabled,ReturnToHold", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_clip_auto_advance", "get_clip_auto_advance", i);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "clip_" + itos(i) + "/next_clip", PROPERTY_HINT_ENUM, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_clip_auto_advance_next_clip", "get_clip_auto_advance_next_clip", i);
+ }
+
+ // TRANSITIONS
+
+ ClassDB::bind_method(D_METHOD("add_transition", "from_clip", "to_clip", "from_time", "to_time", "fade_mode", "fade_beats", "use_filler_clip", "filler_clip", "hold_previous"), &AudioStreamInteractive::add_transition, DEFVAL(false), DEFVAL(-1), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("has_transition", "from_clip", "to_clip"), &AudioStreamInteractive::has_transition);
+ ClassDB::bind_method(D_METHOD("erase_transition", "from_clip", "to_clip"), &AudioStreamInteractive::erase_transition);
+ ClassDB::bind_method(D_METHOD("get_transition_list"), &AudioStreamInteractive::get_transition_list);
+
+ ClassDB::bind_method(D_METHOD("get_transition_from_time", "from_clip", "to_clip"), &AudioStreamInteractive::get_transition_from_time);
+ ClassDB::bind_method(D_METHOD("get_transition_to_time", "from_clip", "to_clip"), &AudioStreamInteractive::get_transition_to_time);
+ ClassDB::bind_method(D_METHOD("get_transition_fade_mode", "from_clip", "to_clip"), &AudioStreamInteractive::get_transition_fade_mode);
+ ClassDB::bind_method(D_METHOD("get_transition_fade_beats", "from_clip", "to_clip"), &AudioStreamInteractive::get_transition_fade_beats);
+ ClassDB::bind_method(D_METHOD("is_transition_using_filler_clip", "from_clip", "to_clip"), &AudioStreamInteractive::is_transition_using_filler_clip);
+ ClassDB::bind_method(D_METHOD("get_transition_filler_clip", "from_clip", "to_clip"), &AudioStreamInteractive::get_transition_filler_clip);
+ ClassDB::bind_method(D_METHOD("is_transition_holding_previous", "from_clip", "to_clip"), &AudioStreamInteractive::is_transition_holding_previous);
+
+ ClassDB::bind_method(D_METHOD("_set_transitions", "transitions"), &AudioStreamInteractive::_set_transitions);
+ ClassDB::bind_method(D_METHOD("_get_transitions"), &AudioStreamInteractive::_get_transitions);
+
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_transitions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_transitions", "_get_transitions");
+
+ BIND_ENUM_CONSTANT(TRANSITION_FROM_TIME_IMMEDIATE);
+ BIND_ENUM_CONSTANT(TRANSITION_FROM_TIME_NEXT_BEAT);
+ BIND_ENUM_CONSTANT(TRANSITION_FROM_TIME_NEXT_BAR);
+ BIND_ENUM_CONSTANT(TRANSITION_FROM_TIME_END);
+
+ BIND_ENUM_CONSTANT(TRANSITION_TO_TIME_SAME_POSITION);
+ BIND_ENUM_CONSTANT(TRANSITION_TO_TIME_START);
+
+ BIND_ENUM_CONSTANT(FADE_DISABLED);
+ BIND_ENUM_CONSTANT(FADE_IN);
+ BIND_ENUM_CONSTANT(FADE_OUT);
+ BIND_ENUM_CONSTANT(FADE_CROSS);
+ BIND_ENUM_CONSTANT(FADE_AUTOMATIC);
+
+ BIND_ENUM_CONSTANT(AUTO_ADVANCE_DISABLED);
+ BIND_ENUM_CONSTANT(AUTO_ADVANCE_ENABLED);
+ BIND_ENUM_CONSTANT(AUTO_ADVANCE_RETURN_TO_HOLD);
+
+ BIND_CONSTANT(CLIP_ANY);
+}
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+AudioStreamPlaybackInteractive::AudioStreamPlaybackInteractive() {
+}
+
+AudioStreamPlaybackInteractive::~AudioStreamPlaybackInteractive() {
+}
+
+void AudioStreamPlaybackInteractive::stop() {
+ if (!active) {
+ return;
+ }
+
+ active = false;
+
+ for (int i = 0; i < AudioStreamInteractive::MAX_CLIPS; i++) {
+ if (states[i].playback.is_valid()) {
+ states[i].playback->stop();
+ }
+ states[i].fade_speed = 0.0;
+ states[i].fade_volume = 0.0;
+ states[i].fade_wait = 0.0;
+ states[i].reset_fade();
+ states[i].active = false;
+ states[i].auto_advance = -1;
+ states[i].first_mix = true;
+ }
+}
+
+void AudioStreamPlaybackInteractive::start(double p_from_pos) {
+ if (active) {
+ stop();
+ }
+
+ if (version != stream->version) {
+ for (int i = 0; i < AudioStreamInteractive::MAX_CLIPS; i++) {
+ Ref<AudioStream> src_stream;
+ if (i < stream->clip_count) {
+ src_stream = stream->clips[i].stream;
+ }
+ if (states[i].stream != src_stream) {
+ states[i].stream.unref();
+ states[i].playback.unref();
+
+ states[i].stream = src_stream;
+ states[i].playback = src_stream->instantiate_playback();
+ }
+ }
+
+ version = stream->version;
+ }
+
+ int current = stream->initial_clip;
+ if (current < 0 || current >= stream->clip_count) {
+ return; // No playback possible.
+ }
+ if (!states[current].playback.is_valid()) {
+ return; //no playback possible
+ }
+ active = true;
+
+ _queue(current, false);
+}
+
+void AudioStreamPlaybackInteractive::_queue(int p_to_clip_index, bool p_is_auto_advance) {
+ ERR_FAIL_INDEX(p_to_clip_index, stream->clip_count);
+ ERR_FAIL_COND(states[p_to_clip_index].playback.is_null());
+
+ if (playback_current == -1) {
+ // Nothing to do, start.
+ int current = p_to_clip_index;
+ State &state = states[current];
+ state.active = true;
+ state.fade_wait = 0;
+ state.fade_volume = 1.0;
+ state.fade_speed = 0;
+ state.first_mix = true;
+
+ state.playback->start(0);
+
+ playback_current = current;
+
+ if (stream->clips[current].auto_advance == AudioStreamInteractive::AUTO_ADVANCE_ENABLED && stream->clips[current].auto_advance_next_clip >= 0 && stream->clips[current].auto_advance_next_clip < stream->clip_count && stream->clips[current].auto_advance_next_clip != current) {
+ //prepare auto advance
+ state.auto_advance = stream->clips[current].auto_advance_next_clip;
+ }
+ return;
+ }
+
+ for (int i = 0; i < stream->clip_count; i++) {
+ if (i == playback_current || i == p_to_clip_index) {
+ continue;
+ }
+ if (states[i].active && states[i].fade_wait > 0) { // Waiting to kick in, terminate because change of plans.
+ states[i].playback->stop();
+ states[i].reset_fade();
+ states[i].active = false;
+ }
+ }
+
+ State &from_state = states[playback_current];
+ State &to_state = states[p_to_clip_index];
+
+ AudioStreamInteractive::Transition transition; // Use an empty transition by default
+
+ AudioStreamInteractive::TransitionKey tkeys[4] = {
+ AudioStreamInteractive::TransitionKey(playback_current, p_to_clip_index),
+ AudioStreamInteractive::TransitionKey(playback_current, AudioStreamInteractive::CLIP_ANY),
+ AudioStreamInteractive::TransitionKey(AudioStreamInteractive::CLIP_ANY, p_to_clip_index),
+ AudioStreamInteractive::TransitionKey(AudioStreamInteractive::CLIP_ANY, AudioStreamInteractive::CLIP_ANY)
+ };
+
+ for (int i = 0; i < 4; i++) {
+ if (stream->transition_map.has(tkeys[i])) {
+ transition = stream->transition_map[tkeys[i]];
+ break;
+ }
+ }
+
+ if (transition.fade_mode == AudioStreamInteractive::FADE_AUTOMATIC) {
+ // Adjust automatic mode based on context.
+ if (transition.to_time == AudioStreamInteractive::TRANSITION_TO_TIME_START) {
+ transition.fade_mode = AudioStreamInteractive::FADE_OUT;
+ } else {
+ transition.fade_mode = AudioStreamInteractive::FADE_CROSS;
+ }
+ }
+
+ if (p_is_auto_advance) {
+ transition.from_time = AudioStreamInteractive::TRANSITION_FROM_TIME_END;
+ if (transition.to_time == AudioStreamInteractive::TRANSITION_TO_TIME_SAME_POSITION) {
+ transition.to_time = AudioStreamInteractive::TRANSITION_TO_TIME_START;
+ }
+ }
+
+ // Prepare the fadeout
+ float current_pos = from_state.playback->get_playback_position();
+
+ float src_fade_wait = 0;
+ float dst_seek_to = 0;
+ float fade_speed = 0;
+ bool src_no_loop = false;
+
+ if (from_state.stream->get_bpm()) {
+ // Check if source speed has BPM, if so, transition syncs to BPM
+ float beat_sec = 60 / float(from_state.stream->get_bpm());
+ switch (transition.from_time) {
+ case AudioStreamInteractive::TRANSITION_FROM_TIME_IMMEDIATE: {
+ src_fade_wait = 0;
+ } break;
+ case AudioStreamInteractive::TRANSITION_FROM_TIME_NEXT_BEAT: {
+ float remainder = Math::fmod(current_pos, beat_sec);
+ src_fade_wait = beat_sec - remainder;
+ } break;
+ case AudioStreamInteractive::TRANSITION_FROM_TIME_NEXT_BAR: {
+ float bar_sec = beat_sec * from_state.stream->get_bar_beats();
+ float remainder = Math::fmod(current_pos, bar_sec);
+ src_fade_wait = bar_sec - remainder;
+ } break;
+ case AudioStreamInteractive::TRANSITION_FROM_TIME_END: {
+ float end = from_state.stream->get_beat_count() > 0 ? float(from_state.stream->get_beat_count() * beat_sec) : from_state.stream->get_length();
+ if (end == 0) {
+ // Stream does not have a length.
+ src_fade_wait = 0;
+ } else {
+ src_fade_wait = end - current_pos;
+ }
+
+ if (!from_state.stream->has_loop()) {
+ src_no_loop = true;
+ }
+
+ } break;
+ default: {
+ }
+ }
+ // Fade speed also aligned to BPM
+ fade_speed = 1.0 / (transition.fade_beats * beat_sec);
+ } else {
+ // Source has no BPM, so just simple transition.
+ if (transition.from_time == AudioStreamInteractive::TRANSITION_FROM_TIME_END && from_state.stream->get_length() > 0) {
+ float end = from_state.stream->get_length();
+ src_fade_wait = end - current_pos;
+ if (!from_state.stream->has_loop()) {
+ src_no_loop = true;
+ }
+ } else {
+ src_fade_wait = 0;
+ }
+ fade_speed = 1.0 / transition.fade_beats;
+ }
+
+ if (transition.to_time == AudioStreamInteractive::TRANSITION_TO_TIME_PREVIOUS_POSITION && to_state.stream->get_length() > 0.0) {
+ dst_seek_to = to_state.previous_position;
+ } else if (transition.to_time == AudioStreamInteractive::TRANSITION_TO_TIME_SAME_POSITION && transition.from_time != AudioStreamInteractive::TRANSITION_FROM_TIME_END && to_state.stream->get_length() > 0.0) {
+ // Seeking to basically same position as when we start fading.
+ dst_seek_to = current_pos + src_fade_wait;
+ float end;
+ if (to_state.stream->get_bpm() > 0 && to_state.stream->get_beat_count()) {
+ float beat_sec = 60 / float(to_state.stream->get_bpm());
+ end = to_state.stream->get_beat_count() * beat_sec;
+ } else {
+ end = to_state.stream->get_length();
+ }
+
+ if (dst_seek_to > end) {
+ // Seeking too far away.
+ dst_seek_to = 0; //past end, loop to beginning.
+ }
+
+ } else {
+ // Seek to Start
+ dst_seek_to = 0.0;
+ }
+
+ if (transition.fade_mode == AudioStreamInteractive::FADE_DISABLED || transition.fade_mode == AudioStreamInteractive::FADE_IN) {
+ if (src_no_loop) {
+ // If there is no fade in the source stream, then let it continue until it ends.
+ from_state.fade_wait = 0;
+ from_state.fade_speed = 0;
+ } else {
+ // Otherwise force a very quick fade to avoid clicks
+ from_state.fade_wait = src_fade_wait;
+ from_state.fade_speed = 1.0 / -0.001;
+ }
+ } else {
+ // Regular fade.
+ from_state.fade_wait = src_fade_wait;
+ from_state.fade_speed = -fade_speed;
+ }
+ // keep volume, since it may have been fading in from something else.
+
+ to_state.playback->start(dst_seek_to);
+ to_state.active = true;
+ to_state.fade_volume = 0.0;
+ to_state.first_mix = true;
+
+ int auto_advance_to = -1;
+
+ if (stream->clips[p_to_clip_index].auto_advance == AudioStreamInteractive::AUTO_ADVANCE_ENABLED) {
+ int next_clip = stream->clips[p_to_clip_index].auto_advance_next_clip;
+ if (next_clip >= 0 && next_clip < (int)stream->clip_count && states[next_clip].playback.is_valid() && next_clip != p_to_clip_index && next_clip != playback_current && (!transition.use_filler_clip || next_clip != transition.filler_clip)) {
+ auto_advance_to = next_clip;
+ }
+ }
+
+ if (return_memory != -1 && stream->clips[p_to_clip_index].auto_advance == AudioStreamInteractive::AUTO_ADVANCE_RETURN_TO_HOLD) {
+ auto_advance_to = return_memory;
+ return_memory = -1;
+ }
+
+ if (transition.hold_previous) {
+ return_memory = playback_current;
+ }
+
+ if (transition.use_filler_clip && transition.filler_clip >= 0 && transition.filler_clip < (int)stream->clip_count && states[transition.filler_clip].playback.is_valid() && playback_current != transition.filler_clip && p_to_clip_index != transition.filler_clip) {
+ State &filler_state = states[transition.filler_clip];
+
+ filler_state.playback->start(0);
+ filler_state.active = true;
+
+ // Filler state does not fade (bake fade in the audio clip if you want fading.
+ filler_state.fade_volume = 1.0;
+ filler_state.fade_speed = 0.0;
+
+ filler_state.fade_wait = src_fade_wait;
+ filler_state.first_mix = true;
+
+ float filler_end;
+ if (filler_state.stream->get_bpm() > 0 && filler_state.stream->get_beat_count() > 0) {
+ float filler_beat_sec = 60 / float(filler_state.stream->get_bpm());
+ filler_end = filler_beat_sec * filler_state.stream->get_beat_count();
+ } else {
+ filler_end = filler_state.stream->get_length();
+ }
+
+ if (!filler_state.stream->has_loop()) {
+ src_no_loop = true;
+ }
+
+ if (transition.fade_mode == AudioStreamInteractive::FADE_DISABLED || transition.fade_mode == AudioStreamInteractive::FADE_OUT) {
+ // No fading, immediately start at full volume.
+ to_state.fade_volume = 0.0;
+ to_state.fade_speed = 1.0; //start at full volume, as filler is meant as a transition.
+ } else {
+ // Fade enable, prepare fade.
+ to_state.fade_volume = 0.0;
+ to_state.fade_speed = fade_speed;
+ }
+
+ to_state.fade_wait = src_fade_wait + filler_end;
+
+ } else {
+ to_state.fade_wait = src_fade_wait;
+
+ if (transition.fade_mode == AudioStreamInteractive::FADE_DISABLED || transition.fade_mode == AudioStreamInteractive::FADE_OUT) {
+ to_state.fade_volume = 1.0;
+ to_state.fade_speed = 0.0;
+ } else {
+ to_state.fade_volume = 0.0;
+ to_state.fade_speed = fade_speed;
+ }
+
+ to_state.auto_advance = auto_advance_to;
+ }
+}
+
+void AudioStreamPlaybackInteractive::seek(double p_time) {
+ // Seek not supported
+}
+
+int AudioStreamPlaybackInteractive::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
+ if (active && version != stream->version) {
+ stop();
+ }
+
+ if (switch_request != -1) {
+ _queue(switch_request, false);
+ switch_request = -1;
+ }
+
+ if (!active) {
+ for (int i = 0; i < p_frames; i++) {
+ p_buffer[i] = AudioFrame(0.0, 0.0);
+ }
+ return p_frames;
+ }
+
+ int todo = p_frames;
+
+ while (todo) {
+ int to_mix = MIN(todo, BUFFER_SIZE);
+ _mix_internal(to_mix);
+ for (int i = 0; i < to_mix; i++) {
+ p_buffer[i] = mix_buffer[i];
+ }
+ p_buffer += to_mix;
+ todo -= to_mix;
+ }
+
+ return p_frames;
+}
+
+void AudioStreamPlaybackInteractive::_mix_internal(int p_frames) {
+ for (int i = 0; i < p_frames; i++) {
+ mix_buffer[i] = AudioFrame(0, 0);
+ }
+
+ for (int i = 0; i < stream->clip_count; i++) {
+ if (!states[i].active) {
+ continue;
+ }
+
+ _mix_internal_state(i, p_frames);
+ }
+}
+
+void AudioStreamPlaybackInteractive::_mix_internal_state(int p_state_idx, int p_frames) {
+ State &state = states[p_state_idx];
+ double mix_rate = double(AudioServer::get_singleton()->get_mix_rate());
+ double frame_inc = 1.0 / mix_rate;
+
+ int from_frame = 0;
+ int queue_next = -1;
+
+ if (state.first_mix) {
+ // Did not start mixing yet, wait.
+ double mix_time = p_frames * frame_inc;
+ if (state.fade_wait < mix_time) {
+ // time to start!
+ from_frame = state.fade_wait * mix_rate;
+ state.fade_wait = 0;
+ queue_next = state.auto_advance;
+ playback_current = p_state_idx;
+ state.first_mix = false;
+ } else {
+ // This is for fade in of new stream.
+ state.fade_wait -= mix_time;
+ return; // Nothing to do
+ }
+ }
+
+ state.previous_position = state.playback->get_playback_position();
+ state.playback->mix(temp_buffer + from_frame, 1.0, p_frames - from_frame);
+
+ double frame_fade_inc = state.fade_speed * frame_inc;
+
+ for (int i = from_frame; i < p_frames; i++) {
+ if (state.fade_wait) {
+ // This is for fade out of existing stream;
+ state.fade_wait -= frame_inc;
+ if (state.fade_wait < 0.0) {
+ state.fade_wait = 0.0;
+ }
+ } else if (frame_fade_inc > 0) {
+ state.fade_volume += frame_fade_inc;
+ if (state.fade_volume >= 1.0) {
+ state.fade_speed = 0.0;
+ frame_fade_inc = 0.0;
+ state.fade_volume = 1.0;
+ }
+ } else if (frame_fade_inc < 0.0) {
+ state.fade_volume += frame_fade_inc;
+ if (state.fade_volume <= 0.0) {
+ state.fade_speed = 0.0;
+ frame_fade_inc = 0.0;
+ state.fade_volume = 0.0;
+ state.playback->stop(); // Stop playback and break, no point to continue mixing
+ break;
+ }
+ }
+
+ mix_buffer[i] += temp_buffer[i] * state.fade_volume;
+ state.previous_position += frame_inc;
+ }
+
+ if (!state.playback->is_playing()) {
+ // It finished because it either reached end or faded out, so deactivate and continue.
+ state.active = false;
+ }
+ if (queue_next != -1) {
+ _queue(queue_next, true);
+ }
+}
+
+void AudioStreamPlaybackInteractive::tag_used_streams() {
+ for (int i = 0; i < stream->clip_count; i++) {
+ if (states[i].active && !states[i].first_mix && states[i].playback->is_playing()) {
+ states[i].stream->tag_used(states[i].playback->get_playback_position());
+ }
+ }
+ stream->tag_used(0);
+}
+
+void AudioStreamPlaybackInteractive::switch_to_clip_by_name(const StringName &p_name) {
+ if (p_name == StringName()) {
+ switch_request = -1;
+ return;
+ }
+
+ for (int i = 0; i < stream->get_clip_count(); i++) {
+ if (stream->get_clip_name(i) == p_name) {
+ switch_request = i;
+ return;
+ }
+ }
+ ERR_FAIL_MSG("Clip not found: " + String(p_name));
+}
+
+void AudioStreamPlaybackInteractive::set_parameter(const StringName &p_name, const Variant &p_value) {
+ if (p_name == SNAME("switch_to_clip")) {
+ switch_to_clip_by_name(p_value);
+ }
+}
+
+Variant AudioStreamPlaybackInteractive::get_parameter(const StringName &p_name) const {
+ if (p_name == SNAME("switch_to_clip")) {
+ for (int i = 0; i < stream->get_clip_count(); i++) {
+ if (switch_request != -1) {
+ if (switch_request == i) {
+ return String(stream->get_clip_name(i));
+ }
+ } else if (playback_current == i) {
+ return String(stream->get_clip_name(i));
+ }
+ }
+ return "";
+ }
+
+ return Variant();
+}
+
+void AudioStreamPlaybackInteractive::switch_to_clip(int p_index) {
+ switch_request = p_index;
+}
+
+int AudioStreamPlaybackInteractive::get_loop_count() const {
+ return 0; // Looping not supported
+}
+
+double AudioStreamPlaybackInteractive::get_playback_position() const {
+ return 0.0;
+}
+
+bool AudioStreamPlaybackInteractive::is_playing() const {
+ return active;
+}
+
+void AudioStreamPlaybackInteractive::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("switch_to_clip_by_name", "clip_name"), &AudioStreamPlaybackInteractive::switch_to_clip_by_name);
+ ClassDB::bind_method(D_METHOD("switch_to_clip", "clip_index"), &AudioStreamPlaybackInteractive::switch_to_clip);
+}
diff --git a/modules/interactive_music/audio_stream_interactive.h b/modules/interactive_music/audio_stream_interactive.h
new file mode 100644
index 0000000000..12d3ce8aad
--- /dev/null
+++ b/modules/interactive_music/audio_stream_interactive.h
@@ -0,0 +1,270 @@
+/**************************************************************************/
+/* audio_stream_interactive.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 AUDIO_STREAM_INTERACTIVE_H
+#define AUDIO_STREAM_INTERACTIVE_H
+
+#include "servers/audio/audio_stream.h"
+
+class AudioStreamPlaybackInteractive;
+
+class AudioStreamInteractive : public AudioStream {
+ GDCLASS(AudioStreamInteractive, AudioStream)
+ OBJ_SAVE_TYPE(AudioStream)
+public:
+ enum TransitionFromTime {
+ TRANSITION_FROM_TIME_IMMEDIATE,
+ TRANSITION_FROM_TIME_NEXT_BEAT,
+ TRANSITION_FROM_TIME_NEXT_BAR,
+ TRANSITION_FROM_TIME_END,
+ TRANSITION_FROM_TIME_MAX
+ };
+
+ enum TransitionToTime {
+ TRANSITION_TO_TIME_SAME_POSITION,
+ TRANSITION_TO_TIME_START,
+ TRANSITION_TO_TIME_PREVIOUS_POSITION,
+ TRANSITION_TO_TIME_MAX,
+ };
+
+ enum FadeMode {
+ FADE_DISABLED,
+ FADE_IN,
+ FADE_OUT,
+ FADE_CROSS,
+ FADE_AUTOMATIC,
+ FADE_MAX
+ };
+
+ enum AutoAdvanceMode {
+ AUTO_ADVANCE_DISABLED,
+ AUTO_ADVANCE_ENABLED,
+ AUTO_ADVANCE_RETURN_TO_HOLD,
+ };
+
+ enum {
+ CLIP_ANY = -1
+ };
+
+private:
+ friend class AudioStreamPlaybackInteractive;
+ int sample_rate = 44100;
+ bool stereo = true;
+ int initial_clip = 0;
+
+ double time = 0;
+
+ enum {
+ MAX_CLIPS = 63, // Because we use bitmasks for transition matching.
+ MAX_TRANSITIONS = 63,
+ };
+
+ struct Clip {
+ StringName name;
+ Ref<AudioStream> stream;
+
+ AutoAdvanceMode auto_advance = AUTO_ADVANCE_DISABLED;
+ int auto_advance_next_clip = 0;
+ };
+
+ Clip clips[MAX_CLIPS];
+
+ struct Transition {
+ TransitionFromTime from_time = TRANSITION_FROM_TIME_NEXT_BEAT;
+ TransitionToTime to_time = TRANSITION_TO_TIME_START;
+ FadeMode fade_mode = FADE_AUTOMATIC;
+ int fade_beats = 1;
+ bool use_filler_clip = false;
+ int filler_clip = 0;
+ bool hold_previous = false;
+ };
+
+ struct TransitionKey {
+ uint32_t from_clip;
+ uint32_t to_clip;
+ bool operator==(const TransitionKey &p_key) const {
+ return from_clip == p_key.from_clip && to_clip == p_key.to_clip;
+ }
+ TransitionKey(uint32_t p_from_clip = 0, uint32_t p_to_clip = 0) {
+ from_clip = p_from_clip;
+ to_clip = p_to_clip;
+ }
+ };
+
+ struct TransitionKeyHasher {
+ static _FORCE_INLINE_ uint32_t hash(const TransitionKey &p_key) {
+ uint32_t h = hash_murmur3_one_32(p_key.from_clip);
+ return hash_murmur3_one_32(p_key.to_clip, h);
+ }
+ };
+
+ HashMap<TransitionKey, Transition, TransitionKeyHasher> transition_map;
+
+ uint64_t version = 1; // Used to stop playback instances for incompatibility.
+ int clip_count = 0;
+
+ HashSet<AudioStreamPlaybackInteractive *> playbacks;
+
+#ifdef TOOLS_ENABLED
+
+ mutable String stream_name_cache;
+ String _get_streams_hint() const;
+ PackedStringArray _get_linked_undo_properties(const String &p_property, const Variant &p_new_value) const;
+ void _inspector_array_swap_clip(uint32_t p_item_a, uint32_t p_item_b);
+
+#endif
+
+ void _set_transitions(const Dictionary &p_transitions);
+ Dictionary _get_transitions() const;
+
+public:
+ // CLIPS
+ void set_clip_count(int p_count);
+ int get_clip_count() const;
+
+ void set_initial_clip(int p_clip);
+ int get_initial_clip() const;
+
+ void set_clip_name(int p_clip, const StringName &p_name);
+ StringName get_clip_name(int p_clip) const;
+
+ void set_clip_stream(int p_clip, const Ref<AudioStream> &p_stream);
+ Ref<AudioStream> get_clip_stream(int p_clip) const;
+
+ void set_clip_auto_advance(int p_clip, AutoAdvanceMode p_mode);
+ AutoAdvanceMode get_clip_auto_advance(int p_clip) const;
+
+ void set_clip_auto_advance_next_clip(int p_clip, int p_index);
+ int get_clip_auto_advance_next_clip(int p_clip) const;
+
+ // TRANSITIONS
+
+ void add_transition(int p_from_clip, int p_to_clip, TransitionFromTime p_from_time, TransitionToTime p_to_time, FadeMode p_fade_mode, float p_fade_beats, bool p_use_filler_flip = false, int p_filler_clip = -1, bool p_hold_previous = false);
+ TransitionFromTime get_transition_from_time(int p_from_clip, int p_to_clip) const;
+ TransitionToTime get_transition_to_time(int p_from_clip, int p_to_clip) const;
+ FadeMode get_transition_fade_mode(int p_from_clip, int p_to_clip) const;
+ float get_transition_fade_beats(int p_from_clip, int p_to_clip) const;
+ bool is_transition_using_filler_clip(int p_from_clip, int p_to_clip) const;
+ int get_transition_filler_clip(int p_from_clip, int p_to_clip) const;
+ bool is_transition_holding_previous(int p_from_clip, int p_to_clip) const;
+
+ bool has_transition(int p_from_clip, int p_to_clip) const;
+ void erase_transition(int p_from_clip, int p_to_clip);
+
+ PackedInt32Array get_transition_list() const;
+
+ virtual Ref<AudioStreamPlayback> instantiate_playback() override;
+ virtual String get_stream_name() const override;
+ virtual double get_length() const override { return 0; }
+ AudioStreamInteractive();
+
+protected:
+ virtual void get_parameter_list(List<Parameter> *r_parameters) override;
+
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &r_property) const;
+};
+
+VARIANT_ENUM_CAST(AudioStreamInteractive::TransitionFromTime)
+VARIANT_ENUM_CAST(AudioStreamInteractive::TransitionToTime)
+VARIANT_ENUM_CAST(AudioStreamInteractive::AutoAdvanceMode)
+VARIANT_ENUM_CAST(AudioStreamInteractive::FadeMode)
+
+class AudioStreamPlaybackInteractive : public AudioStreamPlayback {
+ GDCLASS(AudioStreamPlaybackInteractive, AudioStreamPlayback)
+ friend class AudioStreamInteractive;
+
+private:
+ Ref<AudioStreamInteractive> stream;
+ uint64_t version = 0;
+
+ enum {
+ BUFFER_SIZE = 1024
+ };
+
+ AudioFrame mix_buffer[BUFFER_SIZE];
+ AudioFrame temp_buffer[BUFFER_SIZE];
+
+ struct State {
+ Ref<AudioStream> stream;
+ Ref<AudioStreamPlayback> playback;
+ bool active = false;
+ double fade_wait = 0; // Time to wait until fade kicks-in
+ double fade_volume = 1.0;
+ double fade_speed = 0; // Fade speed, negative or positive
+ int auto_advance = -1;
+ bool first_mix = true;
+ double previous_position = 0;
+
+ void reset_fade() {
+ fade_wait = 0;
+ fade_volume = 1.0;
+ fade_speed = 0;
+ }
+ };
+
+ State states[AudioStreamInteractive::MAX_CLIPS];
+ int playback_current = -1;
+
+ bool active = false;
+ int return_memory = -1;
+
+ void _mix_internal(int p_frames);
+ void _mix_internal_state(int p_state_idx, int p_frames);
+
+ void _queue(int p_to_clip_index, bool p_is_auto_advance);
+
+ int switch_request = -1;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual void start(double p_from_pos = 0.0) override;
+ virtual void stop() override;
+ virtual bool is_playing() const override;
+ virtual int get_loop_count() const override; // times it looped
+ virtual double get_playback_position() const override;
+ virtual void seek(double p_time) override;
+ virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override;
+
+ virtual void tag_used_streams() override;
+
+ void switch_to_clip_by_name(const StringName &p_name);
+ void switch_to_clip(int p_index);
+
+ virtual void set_parameter(const StringName &p_name, const Variant &p_value) override;
+ virtual Variant get_parameter(const StringName &p_name) const override;
+
+ AudioStreamPlaybackInteractive();
+ ~AudioStreamPlaybackInteractive();
+};
+
+#endif // AUDIO_STREAM_INTERACTIVE_H
diff --git a/modules/interactive_music/audio_stream_playlist.cpp b/modules/interactive_music/audio_stream_playlist.cpp
new file mode 100644
index 0000000000..f47035b30c
--- /dev/null
+++ b/modules/interactive_music/audio_stream_playlist.cpp
@@ -0,0 +1,406 @@
+/**************************************************************************/
+/* audio_stream_playlist.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "audio_stream_playlist.h"
+
+#include "core/math/math_funcs.h"
+#include "core/string/print_string.h"
+
+Ref<AudioStreamPlayback> AudioStreamPlaylist::instantiate_playback() {
+ Ref<AudioStreamPlaybackPlaylist> playback_playlist;
+ playback_playlist.instantiate();
+ playback_playlist->playlist = Ref<AudioStreamPlaylist>(this);
+ playback_playlist->_update_playback_instances();
+ playbacks.insert(playback_playlist.operator->());
+ return playback_playlist;
+}
+
+String AudioStreamPlaylist::get_stream_name() const {
+ return "Playlist";
+}
+
+void AudioStreamPlaylist::set_list_stream(int p_stream_index, Ref<AudioStream> p_stream) {
+ ERR_FAIL_COND(p_stream == this);
+ ERR_FAIL_INDEX(p_stream_index, MAX_STREAMS);
+
+ AudioServer::get_singleton()->lock();
+ audio_streams[p_stream_index] = p_stream;
+ for (AudioStreamPlaybackPlaylist *E : playbacks) {
+ E->_update_playback_instances();
+ }
+ AudioServer::get_singleton()->unlock();
+}
+
+Ref<AudioStream> AudioStreamPlaylist::get_list_stream(int p_stream_index) const {
+ ERR_FAIL_INDEX_V(p_stream_index, MAX_STREAMS, Ref<AudioStream>());
+
+ return audio_streams[p_stream_index];
+}
+
+double AudioStreamPlaylist::get_bpm() const {
+ for (int i = 0; i < stream_count; i++) {
+ if (audio_streams[i].is_valid()) {
+ double bpm = audio_streams[i]->get_bpm();
+ if (bpm != 0.0) {
+ return bpm;
+ }
+ }
+ }
+ return 0.0;
+}
+
+double AudioStreamPlaylist::get_length() const {
+ double total_length = 0.0;
+ for (int i = 0; i < stream_count; i++) {
+ if (audio_streams[i].is_valid()) {
+ double bpm = audio_streams[i]->get_bpm();
+ int beat_count = audio_streams[i]->get_beat_count();
+ if (bpm > 0.0 && beat_count > 0) {
+ total_length += beat_count * 60.0 / bpm;
+ } else {
+ total_length += audio_streams[i]->get_length();
+ }
+ }
+ }
+ return total_length;
+}
+
+void AudioStreamPlaylist::set_stream_count(int p_count) {
+ ERR_FAIL_COND(p_count < 0 || p_count > MAX_STREAMS);
+ AudioServer::get_singleton()->lock();
+ stream_count = p_count;
+ AudioServer::get_singleton()->unlock();
+ notify_property_list_changed();
+}
+
+int AudioStreamPlaylist::get_stream_count() const {
+ return stream_count;
+}
+
+void AudioStreamPlaylist::set_fade_time(float p_time) {
+ fade_time = p_time;
+}
+
+float AudioStreamPlaylist::get_fade_time() const {
+ return fade_time;
+}
+
+void AudioStreamPlaylist::set_shuffle(bool p_shuffle) {
+ shuffle = p_shuffle;
+}
+
+bool AudioStreamPlaylist::get_shuffle() const {
+ return shuffle;
+}
+
+void AudioStreamPlaylist::set_loop(bool p_loop) {
+ loop = p_loop;
+}
+
+bool AudioStreamPlaylist::has_loop() const {
+ return loop;
+}
+
+void AudioStreamPlaylist::_validate_property(PropertyInfo &r_property) const {
+ String prop = r_property.name;
+ if (prop != "stream_count" && prop.begins_with("stream_")) {
+ int stream = prop.get_slicec('/', 0).get_slicec('_', 1).to_int();
+ if (stream >= stream_count) {
+ r_property.usage = PROPERTY_USAGE_INTERNAL;
+ }
+ }
+}
+
+void AudioStreamPlaylist::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_stream_count", "stream_count"), &AudioStreamPlaylist::set_stream_count);
+ ClassDB::bind_method(D_METHOD("get_stream_count"), &AudioStreamPlaylist::get_stream_count);
+
+ ClassDB::bind_method(D_METHOD("get_bpm"), &AudioStreamPlaylist::get_bpm);
+
+ ClassDB::bind_method(D_METHOD("set_list_stream", "stream_index", "audio_stream"), &AudioStreamPlaylist::set_list_stream);
+ ClassDB::bind_method(D_METHOD("get_list_stream", "stream_index"), &AudioStreamPlaylist::get_list_stream);
+
+ ClassDB::bind_method(D_METHOD("set_shuffle", "shuffle"), &AudioStreamPlaylist::set_shuffle);
+ ClassDB::bind_method(D_METHOD("get_shuffle"), &AudioStreamPlaylist::get_shuffle);
+
+ ClassDB::bind_method(D_METHOD("set_fade_time", "dec"), &AudioStreamPlaylist::set_fade_time);
+ ClassDB::bind_method(D_METHOD("get_fade_time"), &AudioStreamPlaylist::get_fade_time);
+
+ ClassDB::bind_method(D_METHOD("set_loop", "loop"), &AudioStreamPlaylist::set_loop);
+ ClassDB::bind_method(D_METHOD("has_loop"), &AudioStreamPlaylist::has_loop);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shuffle"), "set_shuffle", "get_shuffle");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fade_time", PROPERTY_HINT_RANGE, "0,1,0.01,suffix:s"), "set_fade_time", "get_fade_time");
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "stream_count", PROPERTY_HINT_RANGE, "0," + itos(MAX_STREAMS), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Streams,stream_,unfoldable,page_size=999,add_button_text=" + String(RTR("Add Stream"))), "set_stream_count", "get_stream_count");
+
+ for (int i = 0; i < MAX_STREAMS; i++) {
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "stream_" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "AudioStream", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_list_stream", "get_list_stream", i);
+ }
+
+ BIND_CONSTANT(MAX_STREAMS);
+}
+
+//////////////////////
+//////////////////////
+
+AudioStreamPlaybackPlaylist::~AudioStreamPlaybackPlaylist() {
+ if (playlist.is_valid()) {
+ playlist->playbacks.erase(this);
+ }
+}
+
+void AudioStreamPlaybackPlaylist::stop() {
+ active = false;
+ for (int i = 0; i < playlist->stream_count; i++) {
+ if (playback[i].is_valid()) {
+ playback[i]->stop();
+ }
+ }
+}
+
+void AudioStreamPlaybackPlaylist::_update_order() {
+ for (int i = 0; i < playlist->stream_count; i++) {
+ play_order[i] = i;
+ }
+
+ if (playlist->shuffle) {
+ for (int i = 0; i < playlist->stream_count; i++) {
+ int swap_with = Math::rand() % uint32_t(playlist->stream_count);
+ SWAP(play_order[i], play_order[swap_with]);
+ }
+ }
+}
+
+void AudioStreamPlaybackPlaylist::start(double p_from_pos) {
+ if (active) {
+ stop();
+ }
+
+ p_from_pos = MAX(0, p_from_pos);
+
+ float pl_length = playlist->get_length();
+ if (p_from_pos >= pl_length) {
+ if (!playlist->loop) {
+ return; // No loop, end.
+ }
+ p_from_pos = Math::fmod((float)p_from_pos, (float)pl_length);
+ }
+
+ _update_order();
+
+ play_index = -1;
+
+ double play_ofs = p_from_pos;
+ for (int i = 0; i < playlist->stream_count; i++) {
+ int idx = play_order[i];
+ if (playlist->audio_streams[idx].is_valid()) {
+ double bpm = playlist->audio_streams[idx]->get_bpm();
+ int beat_count = playlist->audio_streams[idx]->get_beat_count();
+ double length;
+ if (bpm > 0.0 && beat_count > 0) {
+ length = beat_count * 60.0 / bpm;
+ } else {
+ length = playlist->audio_streams[idx]->get_length();
+ }
+ if (play_ofs < length) {
+ play_index = i;
+ stream_todo = length - play_ofs;
+ break;
+ } else {
+ play_ofs -= length;
+ }
+ }
+ }
+
+ if (play_index == -1) {
+ return;
+ }
+
+ playback[play_order[play_index]]->start(play_ofs);
+ fade_index = -1;
+ loop_count = 0;
+
+ active = true;
+}
+
+void AudioStreamPlaybackPlaylist::seek(double p_time) {
+ stop();
+ start(p_time);
+}
+
+int AudioStreamPlaybackPlaylist::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
+ if (!active) {
+ for (int i = 0; i < p_frames; i++) {
+ p_buffer[i] = AudioFrame(0.0, 0.0);
+ }
+ return p_frames;
+ }
+
+ double time_dec = (1.0 / AudioServer::get_singleton()->get_mix_rate());
+ double fade_dec = (1.0 / playlist->fade_time) / AudioServer::get_singleton()->get_mix_rate();
+
+ int todo = p_frames;
+
+ while (todo) {
+ int to_mix = MIN(todo, MIX_BUFFER_SIZE);
+
+ playback[play_order[play_index]]->mix(mix_buffer, 1.0, to_mix);
+ if (fade_index != -1) {
+ playback[fade_index]->mix(fade_buffer, 1.0, to_mix);
+ }
+
+ offset += time_dec * to_mix;
+
+ for (int i = 0; i < to_mix; i++) {
+ *p_buffer = mix_buffer[i];
+ stream_todo -= time_dec;
+ if (stream_todo < 0) {
+ //find next stream.
+ int prev = play_order[play_index];
+
+ for (int j = 0; j < playlist->stream_count; j++) {
+ play_index++;
+ if (play_index >= playlist->stream_count) {
+ // No loop, exit.
+ if (!playlist->loop) {
+ for (int k = i; k < todo - i; k++) {
+ p_buffer[k] = AudioFrame(0, 0);
+ }
+ todo = to_mix;
+ active = false;
+ break;
+ }
+
+ _update_order();
+ play_index = 0;
+ loop_count++;
+ offset = time_dec * (to_mix - i);
+ }
+ if (playback[play_order[play_index]].is_valid()) {
+ break;
+ }
+ }
+
+ if (!active) {
+ break;
+ }
+
+ if (!playback[play_order[play_index]].is_valid()) {
+ todo = to_mix; // Weird error.
+ active = false;
+ break;
+ }
+
+ bool restart = true;
+ if (prev == play_order[play_index]) {
+ // Went back to the same one, continue loop (if it loops) or restart if it does not.
+ if (playlist->audio_streams[prev]->has_loop()) {
+ restart = false;
+ }
+ fade_index = -1;
+ } else {
+ // Move current mixed data to fade buffer.
+ for (int j = i; j < to_mix; j++) {
+ fade_buffer[j] = mix_buffer[j];
+ }
+
+ fade_index = prev;
+ fade_volume = 1.0;
+ }
+
+ int idx = play_order[play_index];
+
+ if (restart) {
+ playback[idx]->start(0); // No loop, just cold-restart.
+ playback[idx]->mix(mix_buffer + i, 1.0, to_mix - i); // Fill rest of mix buffer
+ }
+
+ // Update fade todo.
+ double bpm = playlist->audio_streams[idx]->get_bpm();
+ int beat_count = playlist->audio_streams[idx]->get_beat_count();
+
+ if (bpm > 0.0 && beat_count > 0) {
+ stream_todo = beat_count * 60.0 / bpm;
+ } else {
+ stream_todo = playlist->audio_streams[idx]->get_length();
+ }
+ }
+
+ if (fade_index != -1) {
+ *p_buffer += fade_buffer[i] * fade_volume;
+ fade_volume -= fade_dec;
+ if (fade_volume <= 0.0) {
+ playback[fade_index]->stop();
+ fade_index = -1;
+ }
+ }
+
+ p_buffer++;
+ }
+
+ todo -= to_mix;
+ }
+
+ return p_frames;
+}
+
+void AudioStreamPlaybackPlaylist::tag_used_streams() {
+ if (active) {
+ playlist->audio_streams[play_order[play_index]]->tag_used(playback[play_order[play_index]]->get_playback_position());
+ }
+
+ playlist->tag_used(0);
+}
+
+int AudioStreamPlaybackPlaylist::get_loop_count() const {
+ return loop_count;
+}
+
+double AudioStreamPlaybackPlaylist::get_playback_position() const {
+ return offset;
+}
+
+bool AudioStreamPlaybackPlaylist::is_playing() const {
+ return active;
+}
+
+void AudioStreamPlaybackPlaylist::_update_playback_instances() {
+ stop();
+
+ for (int i = 0; i < playlist->stream_count; i++) {
+ if (playlist->audio_streams[i].is_valid()) {
+ playback[i] = playlist->audio_streams[i]->instantiate_playback();
+ } else {
+ playback[i].unref();
+ }
+ }
+}
diff --git a/modules/interactive_music/audio_stream_playlist.h b/modules/interactive_music/audio_stream_playlist.h
new file mode 100644
index 0000000000..a30f97b7af
--- /dev/null
+++ b/modules/interactive_music/audio_stream_playlist.h
@@ -0,0 +1,125 @@
+/**************************************************************************/
+/* audio_stream_playlist.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 AUDIO_STREAM_PLAYLIST_H
+#define AUDIO_STREAM_PLAYLIST_H
+
+#include "servers/audio/audio_stream.h"
+
+class AudioStreamPlaybackPlaylist;
+
+class AudioStreamPlaylist : public AudioStream {
+ GDCLASS(AudioStreamPlaylist, AudioStream)
+ OBJ_SAVE_TYPE(AudioStream)
+
+private:
+ friend class AudioStreamPlaybackPlaylist;
+
+ enum {
+ MAX_STREAMS = 64
+ };
+
+ bool shuffle = false;
+ bool loop = true;
+ double fade_time = 0.3;
+
+ int stream_count = 0;
+ Ref<AudioStream> audio_streams[MAX_STREAMS];
+ HashSet<AudioStreamPlaybackPlaylist *> playbacks;
+
+public:
+ virtual double get_bpm() const override;
+ void set_stream_count(int p_count);
+ int get_stream_count() const;
+ void set_fade_time(float p_time);
+ float get_fade_time() const;
+ void set_shuffle(bool p_shuffle);
+ bool get_shuffle() const;
+ void set_loop(bool p_loop);
+ virtual bool has_loop() const override;
+ void set_list_stream(int p_stream_index, Ref<AudioStream> p_stream);
+ Ref<AudioStream> get_list_stream(int p_stream_index) const;
+
+ virtual Ref<AudioStreamPlayback> instantiate_playback() override;
+ virtual String get_stream_name() const override;
+ virtual double get_length() const override;
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &r_property) const;
+};
+
+///////////////////////////////////////
+
+class AudioStreamPlaybackPlaylist : public AudioStreamPlayback {
+ GDCLASS(AudioStreamPlaybackPlaylist, AudioStreamPlayback)
+ friend class AudioStreamPlaylist;
+
+private:
+ enum {
+ MIX_BUFFER_SIZE = 128
+ };
+ AudioFrame mix_buffer[MIX_BUFFER_SIZE];
+ AudioFrame fade_buffer[MIX_BUFFER_SIZE];
+
+ Ref<AudioStreamPlaylist> playlist;
+ Ref<AudioStreamPlayback> playback[AudioStreamPlaylist::MAX_STREAMS];
+
+ int play_order[AudioStreamPlaylist::MAX_STREAMS] = {};
+
+ double stream_todo = 0.0;
+ int fade_index = -1;
+ double fade_volume = 1.0;
+ int play_index = 0;
+ double offset = 0.0;
+
+ int loop_count = 0;
+
+ bool active = false;
+
+ void _update_order();
+
+ void _update_playback_instances();
+
+public:
+ virtual void start(double p_from_pos = 0.0) override;
+ virtual void stop() override;
+ virtual bool is_playing() const override;
+ virtual int get_loop_count() const override; // times it looped
+ virtual double get_playback_position() const override;
+ virtual void seek(double p_time) override;
+ virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override;
+
+ virtual void tag_used_streams() override;
+
+ ~AudioStreamPlaybackPlaylist();
+};
+
+#endif // AUDIO_STREAM_PLAYLIST_H
diff --git a/modules/interactive_music/audio_stream_synchronized.cpp b/modules/interactive_music/audio_stream_synchronized.cpp
new file mode 100644
index 0000000000..d0d58fac16
--- /dev/null
+++ b/modules/interactive_music/audio_stream_synchronized.cpp
@@ -0,0 +1,312 @@
+/**************************************************************************/
+/* audio_stream_synchronized.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "audio_stream_synchronized.h"
+
+#include "core/math/math_funcs.h"
+#include "core/string/print_string.h"
+
+AudioStreamSynchronized::AudioStreamSynchronized() {
+}
+
+Ref<AudioStreamPlayback> AudioStreamSynchronized::instantiate_playback() {
+ Ref<AudioStreamPlaybackSynchronized> playback_playlist;
+ playback_playlist.instantiate();
+ playback_playlist->stream = Ref<AudioStreamSynchronized>(this);
+ playback_playlist->_update_playback_instances();
+ playbacks.insert(playback_playlist.operator->());
+ return playback_playlist;
+}
+
+String AudioStreamSynchronized::get_stream_name() const {
+ return "Synchronized";
+}
+
+void AudioStreamSynchronized::set_sync_stream(int p_stream_index, Ref<AudioStream> p_stream) {
+ ERR_FAIL_COND(p_stream == this);
+ ERR_FAIL_INDEX(p_stream_index, MAX_STREAMS);
+
+ AudioServer::get_singleton()->lock();
+ audio_streams[p_stream_index] = p_stream;
+ for (AudioStreamPlaybackSynchronized *E : playbacks) {
+ E->_update_playback_instances();
+ }
+ AudioServer::get_singleton()->unlock();
+}
+
+Ref<AudioStream> AudioStreamSynchronized::get_sync_stream(int p_stream_index) const {
+ ERR_FAIL_INDEX_V(p_stream_index, MAX_STREAMS, Ref<AudioStream>());
+
+ return audio_streams[p_stream_index];
+}
+
+void AudioStreamSynchronized::set_sync_stream_volume(int p_stream_index, float p_db) {
+ ERR_FAIL_INDEX(p_stream_index, MAX_STREAMS);
+ audio_stream_volume_db[p_stream_index] = p_db;
+}
+
+float AudioStreamSynchronized::get_sync_stream_volume(int p_stream_index) const {
+ ERR_FAIL_INDEX_V(p_stream_index, MAX_STREAMS, 0);
+ return audio_stream_volume_db[p_stream_index];
+}
+
+double AudioStreamSynchronized::get_bpm() const {
+ for (int i = 0; i < stream_count; i++) {
+ if (audio_streams[i].is_valid()) {
+ double bpm = audio_streams[i]->get_bpm();
+ if (bpm != 0.0) {
+ return bpm;
+ }
+ }
+ }
+ return 0.0;
+}
+
+int AudioStreamSynchronized::get_beat_count() const {
+ int max_beats = 0;
+ for (int i = 0; i < stream_count; i++) {
+ if (audio_streams[i].is_valid()) {
+ max_beats = MAX(max_beats, audio_streams[i]->get_beat_count());
+ }
+ }
+ return max_beats;
+}
+
+bool AudioStreamSynchronized::has_loop() const {
+ for (int i = 0; i < stream_count; i++) {
+ if (audio_streams[i].is_valid()) {
+ if (audio_streams[i]->has_loop()) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+double AudioStreamSynchronized::get_length() const {
+ double max_length = 0.0;
+ for (int i = 0; i < stream_count; i++) {
+ if (audio_streams[i].is_valid()) {
+ max_length = MAX(max_length, audio_streams[i]->get_length());
+ }
+ }
+ return max_length;
+}
+
+void AudioStreamSynchronized::set_stream_count(int p_count) {
+ ERR_FAIL_COND(p_count < 0 || p_count > MAX_STREAMS);
+ AudioServer::get_singleton()->lock();
+ stream_count = p_count;
+ AudioServer::get_singleton()->unlock();
+ notify_property_list_changed();
+}
+
+int AudioStreamSynchronized::get_stream_count() const {
+ return stream_count;
+}
+
+void AudioStreamSynchronized::_validate_property(PropertyInfo &property) const {
+ String prop = property.name;
+ if (prop != "stream_count" && prop.begins_with("stream_")) {
+ int stream = prop.get_slicec('/', 0).get_slicec('_', 1).to_int();
+ if (stream >= stream_count) {
+ property.usage = PROPERTY_USAGE_INTERNAL;
+ }
+ }
+}
+
+void AudioStreamSynchronized::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_stream_count", "stream_count"), &AudioStreamSynchronized::set_stream_count);
+ ClassDB::bind_method(D_METHOD("get_stream_count"), &AudioStreamSynchronized::get_stream_count);
+
+ ClassDB::bind_method(D_METHOD("set_sync_stream", "stream_index", "audio_stream"), &AudioStreamSynchronized::set_sync_stream);
+ ClassDB::bind_method(D_METHOD("get_sync_stream", "stream_index"), &AudioStreamSynchronized::get_sync_stream);
+ ClassDB::bind_method(D_METHOD("set_sync_stream_volume", "stream_index", "volume_db"), &AudioStreamSynchronized::set_sync_stream_volume);
+ ClassDB::bind_method(D_METHOD("get_sync_stream_volume", "stream_index"), &AudioStreamSynchronized::get_sync_stream_volume);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "stream_count", PROPERTY_HINT_RANGE, "0," + itos(MAX_STREAMS), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Streams,stream_,unfoldable,page_size=999,add_button_text=" + String(RTR("Add Stream"))), "set_stream_count", "get_stream_count");
+
+ for (int i = 0; i < MAX_STREAMS; i++) {
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "stream_" + itos(i) + "/stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_sync_stream", "get_sync_stream", i);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "stream_" + itos(i) + "/volume", PROPERTY_HINT_RANGE, "-60,12,0.01,suffix:db", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_sync_stream_volume", "get_sync_stream_volume", i);
+ }
+
+ BIND_CONSTANT(MAX_STREAMS);
+}
+
+//////////////////////
+//////////////////////
+
+AudioStreamPlaybackSynchronized::AudioStreamPlaybackSynchronized() {
+}
+
+AudioStreamPlaybackSynchronized::~AudioStreamPlaybackSynchronized() {
+ if (stream.is_valid()) {
+ stream->playbacks.erase(this);
+ }
+}
+
+void AudioStreamPlaybackSynchronized::stop() {
+ active = false;
+ for (int i = 0; i < stream->stream_count; i++) {
+ if (playback[i].is_valid()) {
+ playback[i]->stop();
+ }
+ }
+}
+
+void AudioStreamPlaybackSynchronized::start(double p_from_pos) {
+ if (active) {
+ stop();
+ }
+
+ for (int i = 0; i < stream->stream_count; i++) {
+ if (playback[i].is_valid()) {
+ playback[i]->start(p_from_pos);
+ active = true;
+ }
+ }
+}
+
+void AudioStreamPlaybackSynchronized::seek(double p_time) {
+ for (int i = 0; i < stream->stream_count; i++) {
+ if (playback[i].is_valid()) {
+ playback[i]->seek(p_time);
+ }
+ }
+}
+
+int AudioStreamPlaybackSynchronized::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
+ if (active != true) {
+ for (int i = 0; i < p_frames; i++) {
+ p_buffer[i] = AudioFrame(0.0, 0.0);
+ }
+ return p_frames;
+ }
+
+ int todo = p_frames;
+
+ bool any_active = false;
+ while (todo) {
+ int to_mix = MIN(todo, MIX_BUFFER_SIZE);
+
+ bool first = true;
+ for (int i = 0; i < stream->stream_count; i++) {
+ if (playback[i].is_valid() && playback[i]->is_playing()) {
+ float volume = Math::db_to_linear(stream->audio_stream_volume_db[i]);
+ if (first) {
+ playback[i]->mix(p_buffer, p_rate_scale, to_mix);
+ for (int j = 0; j < to_mix; j++) {
+ p_buffer[j] *= volume;
+ }
+ first = false;
+ any_active = true;
+ } else {
+ playback[i]->mix(mix_buffer, p_rate_scale, to_mix);
+ for (int j = 0; j < to_mix; j++) {
+ p_buffer[j] += mix_buffer[j] * volume;
+ }
+ }
+ }
+ }
+
+ if (first) {
+ // Nothing mixed, put zeroes.
+ for (int j = 0; j < to_mix; j++) {
+ p_buffer[j] = AudioFrame(0, 0);
+ }
+ }
+
+ p_buffer += to_mix;
+ todo -= to_mix;
+ }
+
+ if (!any_active) {
+ active = false;
+ }
+ return p_frames;
+}
+
+void AudioStreamPlaybackSynchronized::tag_used_streams() {
+ if (active) {
+ for (int i = 0; i < stream->stream_count; i++) {
+ if (playback[i].is_valid() && playback[i]->is_playing()) {
+ stream->audio_streams[i]->tag_used(playback[i]->get_playback_position());
+ }
+ }
+ stream->tag_used(0);
+ }
+}
+
+int AudioStreamPlaybackSynchronized::get_loop_count() const {
+ int min_loops = 0;
+ bool min_loops_found = false;
+ for (int i = 0; i < stream->stream_count; i++) {
+ if (playback[i].is_valid() && playback[i]->is_playing()) {
+ int loops = playback[i]->get_loop_count();
+ if (!min_loops_found || loops < min_loops) {
+ min_loops = loops;
+ min_loops_found = true;
+ }
+ }
+ }
+ return min_loops;
+}
+
+double AudioStreamPlaybackSynchronized::get_playback_position() const {
+ float max_pos = 0;
+ bool pos_found = false;
+ for (int i = 0; i < stream->stream_count; i++) {
+ if (playback[i].is_valid() && playback[i]->is_playing()) {
+ float pos = playback[i]->get_playback_position();
+ if (!pos_found || pos > max_pos) {
+ max_pos = pos;
+ pos_found = true;
+ }
+ }
+ }
+ return max_pos;
+}
+
+bool AudioStreamPlaybackSynchronized::is_playing() const {
+ return active;
+}
+
+void AudioStreamPlaybackSynchronized::_update_playback_instances() {
+ stop();
+
+ for (int i = 0; i < stream->stream_count; i++) {
+ if (stream->audio_streams[i].is_valid()) {
+ playback[i] = stream->audio_streams[i]->instantiate_playback();
+ } else {
+ playback[i].unref();
+ }
+ }
+}
diff --git a/modules/interactive_music/audio_stream_synchronized.h b/modules/interactive_music/audio_stream_synchronized.h
new file mode 100644
index 0000000000..a2d8c55404
--- /dev/null
+++ b/modules/interactive_music/audio_stream_synchronized.h
@@ -0,0 +1,119 @@
+/**************************************************************************/
+/* audio_stream_synchronized.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 AUDIO_STREAM_SYNCHRONIZED_H
+#define AUDIO_STREAM_SYNCHRONIZED_H
+
+#include "servers/audio/audio_stream.h"
+
+class AudioStreamPlaybackSynchronized;
+
+class AudioStreamSynchronized : public AudioStream {
+ GDCLASS(AudioStreamSynchronized, AudioStream)
+ OBJ_SAVE_TYPE(AudioStream)
+
+private:
+ friend class AudioStreamPlaybackSynchronized;
+
+ enum {
+ MAX_STREAMS = 32
+ };
+
+ int stream_count = 0;
+ Ref<AudioStream> audio_streams[MAX_STREAMS];
+ float audio_stream_volume_db[MAX_STREAMS] = {};
+ HashSet<AudioStreamPlaybackSynchronized *> playbacks;
+
+public:
+ virtual double get_bpm() const override;
+ virtual int get_beat_count() const override;
+ virtual bool has_loop() const override;
+ void set_stream_count(int p_count);
+ int get_stream_count() const;
+ void set_sync_stream(int p_stream_index, Ref<AudioStream> p_stream);
+ Ref<AudioStream> get_sync_stream(int p_stream_index) const;
+ void set_sync_stream_volume(int p_stream_index, float p_db);
+ float get_sync_stream_volume(int p_stream_index) const;
+
+ virtual Ref<AudioStreamPlayback> instantiate_playback() override;
+ virtual String get_stream_name() const override;
+ virtual double get_length() const override;
+ AudioStreamSynchronized();
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const;
+};
+
+///////////////////////////////////////
+
+class AudioStreamPlaybackSynchronized : public AudioStreamPlayback {
+ GDCLASS(AudioStreamPlaybackSynchronized, AudioStreamPlayback)
+ friend class AudioStreamSynchronized;
+
+private:
+ enum {
+ MIX_BUFFER_SIZE = 128
+ };
+ AudioFrame mix_buffer[MIX_BUFFER_SIZE];
+
+ Ref<AudioStreamSynchronized> stream;
+ Ref<AudioStreamPlayback> playback[AudioStreamSynchronized::MAX_STREAMS];
+
+ int play_order[AudioStreamSynchronized::MAX_STREAMS];
+
+ double stream_todo = 0.0;
+ int fade_index = -1;
+ double fade_volume = 1.0;
+ int play_index = 0;
+ double offset = 0.0;
+
+ int loop_count = 0;
+
+ bool active = false;
+
+ void _update_playback_instances();
+
+public:
+ virtual void start(double p_from_pos = 0.0) override;
+ virtual void stop() override;
+ virtual bool is_playing() const override;
+ virtual int get_loop_count() const override; // times it looped
+ virtual double get_playback_position() const override;
+ virtual void seek(double p_time) override;
+ virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override;
+
+ virtual void tag_used_streams() override;
+
+ AudioStreamPlaybackSynchronized();
+ ~AudioStreamPlaybackSynchronized();
+};
+
+#endif // AUDIO_STREAM_SYNCHRONIZED_H
diff --git a/modules/interactive_music/config.py b/modules/interactive_music/config.py
new file mode 100644
index 0000000000..fb327f1372
--- /dev/null
+++ b/modules/interactive_music/config.py
@@ -0,0 +1,21 @@
+def can_build(env, platform):
+ return True
+
+
+def configure(env):
+ pass
+
+
+def get_doc_classes():
+ return [
+ "AudioStreamPlaylist",
+ "AudioStreamPlaybackPlaylist",
+ "AudioStreamInteractive",
+ "AudioStreamPlaybackInteractive",
+ "AudioStreamSynchronized",
+ "AudioStreamPlaybackSynchronized",
+ ]
+
+
+def get_doc_path():
+ return "doc_classes"
diff --git a/modules/interactive_music/doc_classes/AudioStreamInteractive.xml b/modules/interactive_music/doc_classes/AudioStreamInteractive.xml
new file mode 100644
index 0000000000..e8f8e7b760
--- /dev/null
+++ b/modules/interactive_music/doc_classes/AudioStreamInteractive.xml
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="AudioStreamInteractive" inherits="AudioStream" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ Audio stream that can playback music interactively, combining clips and a transition table.
+ </brief_description>
+ <description>
+ This is an audio stream that can playback music interactively, combining clips and a transition table. Clips must be added first, and the transition rules via the [method add_transition]. Additionally, this stream export a property parameter to control the playback via [AudioStreamPlayer], [AudioStreamPlayer2D], or [AudioStreamPlayer3D].
+ The way this is used is by filling a number of clips, then configuring the transition table. From there, clips are selected for playback and the music will smoothly go from the current to the new one while using the corresponding transition rule defined in the transition table.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="add_transition">
+ <return type="void" />
+ <param index="0" name="from_clip" type="int" />
+ <param index="1" name="to_clip" type="int" />
+ <param index="2" name="from_time" type="int" enum="AudioStreamInteractive.TransitionFromTime" />
+ <param index="3" name="to_time" type="int" enum="AudioStreamInteractive.TransitionToTime" />
+ <param index="4" name="fade_mode" type="int" enum="AudioStreamInteractive.FadeMode" />
+ <param index="5" name="fade_beats" type="float" />
+ <param index="6" name="use_filler_clip" type="bool" default="false" />
+ <param index="7" name="filler_clip" type="int" default="-1" />
+ <param index="8" name="hold_previous" type="bool" default="false" />
+ <description>
+ Add a transition between two clips. Provide the indices of the source and destination clips, or use the [constant CLIP_ANY] constant to indicate that transition happens to/from any clip to this one.
+ * [param from_time] indicates the moment in the current clip the transition will begin after triggered.
+ * [param to_time] indicates the time in the next clip that the playback will start from.
+ * [param fade_mode] indicates how the fade will happen between clips. If unsure, just use [constant FADE_AUTOMATIC] which uses the most common type of fade for each situation.
+ * [param fade_beats] indicates how many beats the fade will take. Using decimals is allowed.
+ * [param use_filler_clip] indicates that there will be a filler clip used between the source and destination clips.
+ * [param filler_clip] the index of the filler clip.
+ * If [param hold_previous] is used, then this clip will be remembered. This can be used together with [constant AUTO_ADVANCE_RETURN_TO_HOLD] to return to this clip after another is done playing.
+ </description>
+ </method>
+ <method name="erase_transition">
+ <return type="void" />
+ <param index="0" name="from_clip" type="int" />
+ <param index="1" name="to_clip" type="int" />
+ <description>
+ Erase a transition by providing [param from_clip] and [param to_clip] clip indices. [constant CLIP_ANY] can be used for either argument or both.
+ </description>
+ </method>
+ <method name="get_clip_auto_advance" qualifiers="const">
+ <return type="int" enum="AudioStreamInteractive.AutoAdvanceMode" />
+ <param index="0" name="clip_index" type="int" />
+ <description>
+ Return whether a clip has auto-advance enabled. See [method set_clip_auto_advance].
+ </description>
+ </method>
+ <method name="get_clip_auto_advance_next_clip" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="clip_index" type="int" />
+ <description>
+ Return the clip towards which the clip referenced by [param clip_index] will auto-advance to.
+ </description>
+ </method>
+ <method name="get_clip_name" qualifiers="const">
+ <return type="StringName" />
+ <param index="0" name="clip_index" type="int" />
+ <description>
+ Return the name of a clip.
+ </description>
+ </method>
+ <method name="get_clip_stream" qualifiers="const">
+ <return type="AudioStream" />
+ <param index="0" name="clip_index" type="int" />
+ <description>
+ Return the [AudioStream] associated with a clip.
+ </description>
+ </method>
+ <method name="get_transition_fade_beats" qualifiers="const">
+ <return type="float" />
+ <param index="0" name="from_clip" type="int" />
+ <param index="1" name="to_clip" type="int" />
+ <description>
+ Return the time (in beats) for a transition (see [method add_transition]).
+ </description>
+ </method>
+ <method name="get_transition_fade_mode" qualifiers="const">
+ <return type="int" enum="AudioStreamInteractive.FadeMode" />
+ <param index="0" name="from_clip" type="int" />
+ <param index="1" name="to_clip" type="int" />
+ <description>
+ Return the mode for a transition (see [method add_transition]).
+ </description>
+ </method>
+ <method name="get_transition_filler_clip" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="from_clip" type="int" />
+ <param index="1" name="to_clip" type="int" />
+ <description>
+ Return the filler clip for a transition (see [method add_transition]).
+ </description>
+ </method>
+ <method name="get_transition_from_time" qualifiers="const">
+ <return type="int" enum="AudioStreamInteractive.TransitionFromTime" />
+ <param index="0" name="from_clip" type="int" />
+ <param index="1" name="to_clip" type="int" />
+ <description>
+ Return the source time position for a transition (see [method add_transition]).
+ </description>
+ </method>
+ <method name="get_transition_list" qualifiers="const">
+ <return type="PackedInt32Array" />
+ <description>
+ Return the list of transitions (from, to interleaved).
+ </description>
+ </method>
+ <method name="get_transition_to_time" qualifiers="const">
+ <return type="int" enum="AudioStreamInteractive.TransitionToTime" />
+ <param index="0" name="from_clip" type="int" />
+ <param index="1" name="to_clip" type="int" />
+ <description>
+ Return the destination time position for a transition (see [method add_transition]).
+ </description>
+ </method>
+ <method name="has_transition" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="from_clip" type="int" />
+ <param index="1" name="to_clip" type="int" />
+ <description>
+ Return true if a given transition exists (was added via [method add_transition]).
+ </description>
+ </method>
+ <method name="is_transition_holding_previous" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="from_clip" type="int" />
+ <param index="1" name="to_clip" type="int" />
+ <description>
+ Return whether a transition uses the [i]hold previous[/i] functionality (see [method add_transition]).
+ </description>
+ </method>
+ <method name="is_transition_using_filler_clip" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="from_clip" type="int" />
+ <param index="1" name="to_clip" type="int" />
+ <description>
+ Return whether a transition uses the [i]filler clip[/i] functionality (see [method add_transition]).
+ </description>
+ </method>
+ <method name="set_clip_auto_advance">
+ <return type="void" />
+ <param index="0" name="clip_index" type="int" />
+ <param index="1" name="mode" type="int" enum="AudioStreamInteractive.AutoAdvanceMode" />
+ <description>
+ Set whether a clip will auto-advance by changing the auto-advance mode.
+ </description>
+ </method>
+ <method name="set_clip_auto_advance_next_clip">
+ <return type="void" />
+ <param index="0" name="clip_index" type="int" />
+ <param index="1" name="auto_advance_next_clip" type="int" />
+ <description>
+ Set the index of the next clip towards which this clip will auto advance to when finished. If the clip being played loops, then auto-advance will be ignored.
+ </description>
+ </method>
+ <method name="set_clip_name">
+ <return type="void" />
+ <param index="0" name="clip_index" type="int" />
+ <param index="1" name="name" type="StringName" />
+ <description>
+ Set the name of the current clip (for easier identification).
+ </description>
+ </method>
+ <method name="set_clip_stream">
+ <return type="void" />
+ <param index="0" name="clip_index" type="int" />
+ <param index="1" name="stream" type="AudioStream" />
+ <description>
+ Set the [AudioStream] associated with the current clip.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="clip_count" type="int" setter="set_clip_count" getter="get_clip_count" default="0">
+ Amount of clips contained in this interactive player.
+ </member>
+ <member name="initial_clip" type="int" setter="set_initial_clip" getter="get_initial_clip" default="0">
+ Index of the initial clip, which will be played first when this stream is played.
+ </member>
+ </members>
+ <constants>
+ <constant name="TRANSITION_FROM_TIME_IMMEDIATE" value="0" enum="TransitionFromTime">
+ Start transition as soon as possible, don't wait for any specific time position.
+ </constant>
+ <constant name="TRANSITION_FROM_TIME_NEXT_BEAT" value="1" enum="TransitionFromTime">
+ Transition when the clip playback position reaches the next beat.
+ </constant>
+ <constant name="TRANSITION_FROM_TIME_NEXT_BAR" value="2" enum="TransitionFromTime">
+ Transition when the clip playback position reaches the next bar.
+ </constant>
+ <constant name="TRANSITION_FROM_TIME_END" value="3" enum="TransitionFromTime">
+ Transition when the current clip finished playing.
+ </constant>
+ <constant name="TRANSITION_TO_TIME_SAME_POSITION" value="0" enum="TransitionToTime">
+ Transition to the same position in the destination clip. This is useful when both clips have exactly the same length and the music should fade between them.
+ </constant>
+ <constant name="TRANSITION_TO_TIME_START" value="1" enum="TransitionToTime">
+ Transition to the start of the destination clip.
+ </constant>
+ <constant name="FADE_DISABLED" value="0" enum="FadeMode">
+ Do not use fade for the transition. This is useful when transitioning from a clip-end to clip-beginning, and each clip has their begin/end.
+ </constant>
+ <constant name="FADE_IN" value="1" enum="FadeMode">
+ Use a fade-in in the next clip, let the current clip finish.
+ </constant>
+ <constant name="FADE_OUT" value="2" enum="FadeMode">
+ Use a fade-out in the current clip, the next clip will start by itself.
+ </constant>
+ <constant name="FADE_CROSS" value="3" enum="FadeMode">
+ Use a cross-fade between clips.
+ </constant>
+ <constant name="FADE_AUTOMATIC" value="4" enum="FadeMode">
+ Use automatic fade logic depending on the transition from/to. It is recommended to use this by default.
+ </constant>
+ <constant name="AUTO_ADVANCE_DISABLED" value="0" enum="AutoAdvanceMode">
+ Disable auto-advance (default).
+ </constant>
+ <constant name="AUTO_ADVANCE_ENABLED" value="1" enum="AutoAdvanceMode">
+ Enable auto-advance, a clip must be specified.
+ </constant>
+ <constant name="AUTO_ADVANCE_RETURN_TO_HOLD" value="2" enum="AutoAdvanceMode">
+ Enable auto-advance, but instead of specifying a clip, the playback will return to hold (see [method add_transition]).
+ </constant>
+ <constant name="CLIP_ANY" value="-1">
+ This constant describes that any clip is valid for a specific transition as either source or destination.
+ </constant>
+ </constants>
+</class>
diff --git a/modules/interactive_music/doc_classes/AudioStreamPlaybackInteractive.xml b/modules/interactive_music/doc_classes/AudioStreamPlaybackInteractive.xml
new file mode 100644
index 0000000000..c87d7c8fcb
--- /dev/null
+++ b/modules/interactive_music/doc_classes/AudioStreamPlaybackInteractive.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="AudioStreamPlaybackInteractive" inherits="AudioStreamPlayback" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ Playback component of [AudioStreamInteractive].
+ </brief_description>
+ <description>
+ Playback component of [AudioStreamInteractive]. Contains functions to change the currently played clip.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="switch_to_clip">
+ <return type="void" />
+ <param index="0" name="clip_index" type="int" />
+ <description>
+ Switch to a clip (by index).
+ </description>
+ </method>
+ <method name="switch_to_clip_by_name">
+ <return type="void" />
+ <param index="0" name="clip_name" type="StringName" />
+ <description>
+ Switch to a clip (by name).
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/modules/interactive_music/doc_classes/AudioStreamPlaybackPlaylist.xml b/modules/interactive_music/doc_classes/AudioStreamPlaybackPlaylist.xml
new file mode 100644
index 0000000000..2553563071
--- /dev/null
+++ b/modules/interactive_music/doc_classes/AudioStreamPlaybackPlaylist.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="AudioStreamPlaybackPlaylist" inherits="AudioStreamPlayback" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ Playback class used for [AudioStreamPlaylist].
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/modules/interactive_music/doc_classes/AudioStreamPlaybackSynchronized.xml b/modules/interactive_music/doc_classes/AudioStreamPlaybackSynchronized.xml
new file mode 100644
index 0000000000..adaae0fef9
--- /dev/null
+++ b/modules/interactive_music/doc_classes/AudioStreamPlaybackSynchronized.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="AudioStreamPlaybackSynchronized" inherits="AudioStreamPlayback" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/modules/interactive_music/doc_classes/AudioStreamPlaylist.xml b/modules/interactive_music/doc_classes/AudioStreamPlaylist.xml
new file mode 100644
index 0000000000..1d429a932f
--- /dev/null
+++ b/modules/interactive_music/doc_classes/AudioStreamPlaylist.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="AudioStreamPlaylist" inherits="AudioStream" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ [AudioStream] that includes sub-streams and plays them back like a playslit.
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_bpm" qualifiers="const">
+ <return type="float" />
+ <description>
+ Return the bpm of the playlist, which can vary depending on the clip being played.
+ </description>
+ </method>
+ <method name="get_list_stream" qualifiers="const">
+ <return type="AudioStream" />
+ <param index="0" name="stream_index" type="int" />
+ <description>
+ Get the stream at playback position index.
+ </description>
+ </method>
+ <method name="set_list_stream">
+ <return type="void" />
+ <param index="0" name="stream_index" type="int" />
+ <param index="1" name="audio_stream" type="AudioStream" />
+ <description>
+ Set the stream at playback position index.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="fade_time" type="float" setter="set_fade_time" getter="get_fade_time" default="0.3">
+ Fade time used when a stream ends, when going to the next one. Streams are expected to have an extra bit of audio after the end to help with fading.
+ </member>
+ <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="true">
+ If true, the playlist will loop, otherwise the playlist when end when the last stream is played.
+ </member>
+ <member name="shuffle" type="bool" setter="set_shuffle" getter="get_shuffle" default="false">
+ Shuffle the playlist. Streams are played in random order.
+ </member>
+ <member name="stream_count" type="int" setter="set_stream_count" getter="get_stream_count" default="0">
+ Amount of streams in the playlist.
+ </member>
+ </members>
+ <constants>
+ <constant name="MAX_STREAMS" value="64">
+ Maximum amount of streams supported in the playlist.
+ </constant>
+ </constants>
+</class>
diff --git a/modules/interactive_music/doc_classes/AudioStreamSynchronized.xml b/modules/interactive_music/doc_classes/AudioStreamSynchronized.xml
new file mode 100644
index 0000000000..ea914715a3
--- /dev/null
+++ b/modules/interactive_music/doc_classes/AudioStreamSynchronized.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="AudioStreamSynchronized" inherits="AudioStream" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ Stream that can be fitted with sub-streams, which will be played in-sync.
+ </brief_description>
+ <description>
+ This is a stream that can be fitted with sub-streams, which will be played in-sync. The streams being at exactly the same time when play is pressed, and will end when the last of them ends. If one of the sub-streams loops, then playback will continue.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_sync_stream" qualifiers="const">
+ <return type="AudioStream" />
+ <param index="0" name="stream_index" type="int" />
+ <description>
+ Get one of the synchronized streams, by index.
+ </description>
+ </method>
+ <method name="get_sync_stream_volume" qualifiers="const">
+ <return type="float" />
+ <param index="0" name="stream_index" type="int" />
+ <description>
+ Get the volume of one of the synchronized streams, by index.
+ </description>
+ </method>
+ <method name="set_sync_stream">
+ <return type="void" />
+ <param index="0" name="stream_index" type="int" />
+ <param index="1" name="audio_stream" type="AudioStream" />
+ <description>
+ Set one of the synchronized streams, by index.
+ </description>
+ </method>
+ <method name="set_sync_stream_volume">
+ <return type="void" />
+ <param index="0" name="stream_index" type="int" />
+ <param index="1" name="volume_db" type="float" />
+ <description>
+ Set the volume of one of the synchronized streams, by index.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="stream_count" type="int" setter="set_stream_count" getter="get_stream_count" default="0">
+ Set the total amount of streams that will be played back synchronized.
+ </member>
+ </members>
+ <constants>
+ <constant name="MAX_STREAMS" value="32">
+ Maximum amount of streams that can be synchrohized.
+ </constant>
+ </constants>
+</class>
diff --git a/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.cpp b/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.cpp
new file mode 100644
index 0000000000..9960c4e07c
--- /dev/null
+++ b/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.cpp
@@ -0,0 +1,416 @@
+/**************************************************************************/
+/* audio_stream_interactive_editor_plugin.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "audio_stream_interactive_editor_plugin.h"
+
+#include "../audio_stream_interactive.h"
+#include "core/input/input.h"
+#include "core/os/keyboard.h"
+#include "editor/editor_node.h"
+#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
+#include "editor/editor_undo_redo_manager.h"
+#include "editor/themes/editor_scale.h"
+#include "scene/gui/check_box.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/spin_box.h"
+#include "scene/gui/split_container.h"
+#include "scene/gui/tree.h"
+
+void AudioStreamInteractiveTransitionEditor::_notification(int p_what) {
+ if (p_what == NOTIFICATION_READY || p_what == NOTIFICATION_THEME_CHANGED) {
+ fade_mode->clear();
+ fade_mode->add_icon_item(get_editor_theme_icon(SNAME("FadeDisabled")), TTR("Disabled"), AudioStreamInteractive::FADE_DISABLED);
+ fade_mode->add_icon_item(get_editor_theme_icon(SNAME("FadeIn")), TTR("Fade-In"), AudioStreamInteractive::FADE_IN);
+ fade_mode->add_icon_item(get_editor_theme_icon(SNAME("FadeOut")), TTR("Fade-Out"), AudioStreamInteractive::FADE_OUT);
+ fade_mode->add_icon_item(get_editor_theme_icon(SNAME("FadeCross")), TTR("Cross-Fade"), AudioStreamInteractive::FADE_CROSS);
+ fade_mode->add_icon_item(get_editor_theme_icon(SNAME("AutoPlay")), TTR("Automatic"), AudioStreamInteractive::FADE_AUTOMATIC);
+ }
+}
+
+void AudioStreamInteractiveTransitionEditor::_bind_methods() {
+ ClassDB::bind_method("_update_transitions", &AudioStreamInteractiveTransitionEditor::_update_transitions);
+}
+
+void AudioStreamInteractiveTransitionEditor::_edited() {
+ if (updating) {
+ return;
+ }
+
+ bool enabled = transition_enabled->is_pressed();
+ AudioStreamInteractive::TransitionFromTime from = AudioStreamInteractive::TransitionFromTime(transition_from->get_selected());
+ AudioStreamInteractive::TransitionToTime to = AudioStreamInteractive::TransitionToTime(transition_to->get_selected());
+ AudioStreamInteractive::FadeMode fade = AudioStreamInteractive::FadeMode(fade_mode->get_selected());
+ float beats = fade_beats->get_value();
+ bool use_filler = filler_clip->get_selected() > 0;
+ int filler = use_filler ? filler_clip->get_selected() - 1 : 0;
+ bool hold = hold_previous->is_pressed();
+
+ EditorUndoRedoManager::get_singleton()->create_action("Edit Transitions");
+ for (int i = 0; i < selected.size(); i++) {
+ if (!enabled) {
+ if (audio_stream_interactive->has_transition(selected[i].x, selected[i].y)) {
+ EditorUndoRedoManager::get_singleton()->add_do_method(audio_stream_interactive, "erase_transition", selected[i].x, selected[i].y);
+ }
+ } else {
+ EditorUndoRedoManager::get_singleton()->add_do_method(audio_stream_interactive, "add_transition", selected[i].x, selected[i].y, from, to, fade, beats, use_filler, filler, hold);
+ }
+ }
+ EditorUndoRedoManager::get_singleton()->add_undo_property(audio_stream_interactive, "_transitions", audio_stream_interactive->get("_transitions"));
+ EditorUndoRedoManager::get_singleton()->add_do_method(this, "_update_transitions");
+ EditorUndoRedoManager::get_singleton()->add_undo_method(this, "_update_transitions");
+ EditorUndoRedoManager::get_singleton()->commit_action();
+}
+
+void AudioStreamInteractiveTransitionEditor::_update_selection() {
+ updating_selection = false;
+ int clip_count = audio_stream_interactive->get_clip_count();
+ selected.clear();
+ Vector2i editing;
+ int editing_order = -1;
+ for (int i = 0; i <= clip_count; i++) {
+ for (int j = 0; j <= clip_count; j++) {
+ if (rows[i]->is_selected(j)) {
+ Vector2i meta = rows[i]->get_metadata(j);
+ if (selection_order.has(meta)) {
+ int order = selection_order[meta];
+ if (order > editing_order) {
+ editing = meta;
+ }
+ }
+ selected.push_back(meta);
+ }
+ }
+ }
+
+ transition_enabled->set_disabled(selected.is_empty());
+ transition_from->set_disabled(selected.is_empty());
+ transition_to->set_disabled(selected.is_empty());
+ fade_mode->set_disabled(selected.is_empty());
+ fade_beats->set_editable(!selected.is_empty());
+ filler_clip->set_disabled(selected.is_empty());
+ hold_previous->set_disabled(selected.is_empty());
+
+ if (selected.size() == 0) {
+ return;
+ }
+
+ updating = true;
+ if (!audio_stream_interactive->has_transition(editing.x, editing.y)) {
+ transition_enabled->set_pressed(false);
+ transition_from->select(0);
+ transition_to->select(0);
+ fade_mode->select(AudioStreamInteractive::FADE_AUTOMATIC);
+ fade_beats->set_value(1.0);
+ filler_clip->select(0);
+ hold_previous->set_pressed(false);
+ } else {
+ transition_enabled->set_pressed(true);
+ transition_from->select(audio_stream_interactive->get_transition_from_time(editing.x, editing.y));
+ transition_to->select(audio_stream_interactive->get_transition_to_time(editing.x, editing.y));
+ fade_mode->select(audio_stream_interactive->get_transition_fade_mode(editing.x, editing.y));
+ fade_beats->set_value(audio_stream_interactive->get_transition_fade_beats(editing.x, editing.y));
+ if (audio_stream_interactive->is_transition_using_filler_clip(editing.x, editing.y)) {
+ filler_clip->select(audio_stream_interactive->get_transition_filler_clip(editing.x, editing.y) + 1);
+ } else {
+ filler_clip->select(0);
+ }
+ hold_previous->set_pressed(audio_stream_interactive->is_transition_holding_previous(editing.x, editing.y));
+ }
+ updating = false;
+}
+
+void AudioStreamInteractiveTransitionEditor::_cell_selected(TreeItem *p_item, int p_column, bool p_selected) {
+ int to = p_item->get_meta("to");
+ int from = p_column == audio_stream_interactive->get_clip_count() ? AudioStreamInteractive::CLIP_ANY : p_column;
+ if (p_selected) {
+ selection_order[Vector2i(from, to)] = order_counter++;
+ }
+
+ if (!updating_selection) {
+ MessageQueue::get_singleton()->push_callable(callable_mp(this, &AudioStreamInteractiveTransitionEditor::_update_selection));
+ updating_selection = true;
+ }
+}
+
+void AudioStreamInteractiveTransitionEditor::_update_transitions() {
+ if (!is_visible()) {
+ return;
+ }
+ int clip_count = audio_stream_interactive->get_clip_count();
+ Color font_color = tree->get_theme_color("font_color", "Tree");
+ Color font_color_default = font_color;
+ font_color_default.a *= 0.5;
+ Ref<Texture> fade_icons[5] = {
+ get_editor_theme_icon(SNAME("FadeDisabled")),
+ get_editor_theme_icon(SNAME("FadeIn")),
+ get_editor_theme_icon(SNAME("FadeOut")),
+ get_editor_theme_icon(SNAME("FadeCross")),
+ get_editor_theme_icon(SNAME("AutoPlay"))
+ };
+ for (int i = 0; i <= clip_count; i++) {
+ for (int j = 0; j <= clip_count; j++) {
+ String txt;
+ int from = i == clip_count ? AudioStreamInteractive::CLIP_ANY : i;
+ int to = j == clip_count ? AudioStreamInteractive::CLIP_ANY : j;
+
+ bool exists = audio_stream_interactive->has_transition(from, to);
+ String tooltip;
+ Ref<Texture> icon;
+ if (!exists) {
+ if (audio_stream_interactive->has_transition(AudioStreamInteractive::CLIP_ANY, to)) {
+ from = AudioStreamInteractive::CLIP_ANY;
+ tooltip = "Using Any Clip -> " + audio_stream_interactive->get_clip_name(to) + ".";
+ } else if (audio_stream_interactive->has_transition(from, AudioStreamInteractive::CLIP_ANY)) {
+ to = AudioStreamInteractive::CLIP_ANY;
+ tooltip = "Using " + audio_stream_interactive->get_clip_name(from) + " -> Any Clip.";
+ } else if (audio_stream_interactive->has_transition(AudioStreamInteractive::CLIP_ANY, AudioStreamInteractive::CLIP_ANY)) {
+ from = to = AudioStreamInteractive::CLIP_ANY;
+ tooltip = "Using All CLips -> Any Clip.";
+ } else {
+ tooltip = "No transition available.";
+ }
+ }
+
+ if (audio_stream_interactive->has_transition(from, to)) {
+ icon = fade_icons[audio_stream_interactive->get_transition_fade_mode(from, to)];
+ switch (audio_stream_interactive->get_transition_from_time(from, to)) {
+ case AudioStreamInteractive::TRANSITION_FROM_TIME_IMMEDIATE: {
+ txt += TTR("Immediate");
+ } break;
+ case AudioStreamInteractive::TRANSITION_FROM_TIME_NEXT_BEAT: {
+ txt += TTR("Next Beat");
+ } break;
+ case AudioStreamInteractive::TRANSITION_FROM_TIME_NEXT_BAR: {
+ txt += TTR("Next Bar");
+ } break;
+ case AudioStreamInteractive::TRANSITION_FROM_TIME_END: {
+ txt += TTR("Clip End");
+ } break;
+ default: {
+ }
+ }
+
+ switch (audio_stream_interactive->get_transition_to_time(from, to)) {
+ case AudioStreamInteractive::TRANSITION_TO_TIME_SAME_POSITION: {
+ txt += TTR(L"⮕ Same");
+ } break;
+ case AudioStreamInteractive::TRANSITION_TO_TIME_START: {
+ txt += TTR(L"⮕ Start");
+ } break;
+ case AudioStreamInteractive::TRANSITION_TO_TIME_PREVIOUS_POSITION: {
+ txt += TTR(L"⮕ Prev");
+ } break;
+ default: {
+ }
+ }
+ }
+
+ rows[j]->set_icon(i, icon);
+ rows[j]->set_text(i, txt);
+ rows[j]->set_tooltip_text(i, tooltip);
+ if (exists) {
+ rows[j]->set_custom_color(i, font_color);
+ rows[j]->set_icon_modulate(i, Color(1, 1, 1, 1));
+ } else {
+ rows[j]->set_custom_color(i, font_color_default);
+ rows[j]->set_icon_modulate(i, Color(1, 1, 1, 0.5));
+ }
+ }
+ }
+}
+
+void AudioStreamInteractiveTransitionEditor::edit(Object *p_obj) {
+ audio_stream_interactive = Object::cast_to<AudioStreamInteractive>(p_obj);
+ if (!audio_stream_interactive) {
+ return;
+ }
+
+ Ref<Font> header_font = get_theme_font("bold", "EditorFonts");
+ int header_font_size = get_theme_font_size("bold_size", "EditorFonts");
+
+ tree->clear();
+ rows.clear();
+ selection_order.clear();
+ selected.clear();
+
+ int clip_count = audio_stream_interactive->get_clip_count();
+ tree->set_columns(clip_count + 2);
+ TreeItem *root = tree->create_item();
+ TreeItem *header = tree->create_item(root); // Header
+ int header_index = clip_count + 1;
+ header->set_text(header_index, TTR("From / To"));
+ header->set_editable(0, false);
+
+ filler_clip->clear();
+ filler_clip->add_item("Disabled", -1);
+
+ Color header_color = get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor));
+
+ int max_w = 0;
+
+ updating = true;
+ for (int i = 0; i <= clip_count; i++) {
+ int cell_index = i;
+ int clip_i = i == clip_count ? AudioStreamInteractive::CLIP_ANY : i;
+ header->set_editable(cell_index, false);
+ header->set_selectable(cell_index, false);
+ header->set_custom_font(cell_index, header_font);
+ header->set_custom_font_size(cell_index, header_font_size);
+ header->set_custom_bg_color(cell_index, header_color);
+
+ String name;
+ if (i == clip_count) {
+ name = TTR("Any Clip");
+ } else {
+ name = audio_stream_interactive->get_clip_name(i);
+ }
+
+ int min_w = header_font->get_string_size(name + "XX").width;
+ tree->set_column_expand(cell_index, false);
+ tree->set_column_custom_minimum_width(cell_index, min_w);
+ max_w = MAX(max_w, min_w);
+
+ header->set_text(cell_index, name);
+
+ TreeItem *row = tree->create_item(root);
+ row->set_text(header_index, name);
+ row->set_selectable(header_index, false);
+ row->set_custom_font(header_index, header_font);
+ row->set_custom_font_size(header_index, header_font_size);
+ row->set_custom_bg_color(header_index, header_color);
+ row->set_meta("to", clip_i);
+ for (int j = 0; j <= clip_count; j++) {
+ int clip_j = j == clip_count ? AudioStreamInteractive::CLIP_ANY : j;
+ row->set_metadata(j, Vector2i(clip_j, clip_i));
+ }
+ rows.push_back(row);
+
+ if (i < clip_count) {
+ filler_clip->add_item(name, i);
+ }
+ }
+
+ tree->set_column_expand(header_index, false);
+ tree->set_column_custom_minimum_width(header_index, max_w);
+ selection_order.clear();
+ _update_selection();
+ popup_centered_ratio(0.6);
+ updating = false;
+ _update_transitions();
+}
+
+AudioStreamInteractiveTransitionEditor::AudioStreamInteractiveTransitionEditor() {
+ set_title(TTR("AudioStreamInteractive Transition Editor"));
+ split = memnew(HSplitContainer);
+ add_child(split);
+ tree = memnew(Tree);
+ tree->set_hide_root(true);
+ tree->add_theme_constant_override("draw_guides", 1);
+ tree->set_select_mode(Tree::SELECT_MULTI);
+ split->add_child(tree);
+
+ tree->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ tree->connect("multi_selected", callable_mp(this, &AudioStreamInteractiveTransitionEditor::_cell_selected));
+ VBoxContainer *edit_vb = memnew(VBoxContainer);
+ split->add_child(edit_vb);
+
+ transition_enabled = memnew(CheckBox);
+ transition_enabled->set_text(TTR("Use Transition"));
+ edit_vb->add_margin_child(TTR("Transition Enabled:"), transition_enabled);
+ transition_enabled->connect("pressed", callable_mp(this, &AudioStreamInteractiveTransitionEditor::_edited));
+
+ transition_from = memnew(OptionButton);
+ edit_vb->add_margin_child(TTR("Transition From:"), transition_from);
+ transition_from->add_item(TTR("Immediate"), AudioStreamInteractive::TRANSITION_FROM_TIME_IMMEDIATE);
+ transition_from->add_item(TTR("Next Beat"), AudioStreamInteractive::TRANSITION_FROM_TIME_NEXT_BEAT);
+ transition_from->add_item(TTR("Next Bar"), AudioStreamInteractive::TRANSITION_FROM_TIME_NEXT_BAR);
+ transition_from->add_item(TTR("Clip End"), AudioStreamInteractive::TRANSITION_FROM_TIME_END);
+
+ transition_from->connect("item_selected", callable_mp(this, &AudioStreamInteractiveTransitionEditor::_edited).unbind(1));
+
+ transition_to = memnew(OptionButton);
+ edit_vb->add_margin_child(TTR("Transition To:"), transition_to);
+ transition_to->add_item(TTR("Same Position"), AudioStreamInteractive::TRANSITION_TO_TIME_SAME_POSITION);
+ transition_to->add_item(TTR("Clip Start"), AudioStreamInteractive::TRANSITION_TO_TIME_START);
+ transition_to->add_item(TTR("Prev Position"), AudioStreamInteractive::TRANSITION_TO_TIME_PREVIOUS_POSITION);
+ transition_to->connect("item_selected", callable_mp(this, &AudioStreamInteractiveTransitionEditor::_edited).unbind(1));
+
+ fade_mode = memnew(OptionButton);
+ edit_vb->add_margin_child(TTR("Fade Mode:"), fade_mode);
+ fade_mode->connect("item_selected", callable_mp(this, &AudioStreamInteractiveTransitionEditor::_edited).unbind(1));
+
+ fade_beats = memnew(SpinBox);
+ edit_vb->add_margin_child(TTR("Fade Beats:"), fade_beats);
+ fade_beats->set_max(16);
+ fade_beats->set_step(0.1);
+ fade_beats->connect("value_changed", callable_mp(this, &AudioStreamInteractiveTransitionEditor::_edited).unbind(1));
+
+ filler_clip = memnew(OptionButton);
+ edit_vb->add_margin_child(TTR("Filler Clip:"), filler_clip);
+ filler_clip->connect("item_selected", callable_mp(this, &AudioStreamInteractiveTransitionEditor::_edited).unbind(1));
+
+ hold_previous = memnew(CheckBox);
+ hold_previous->set_text(TTR("Enabled"));
+ hold_previous->connect("pressed", callable_mp(this, &AudioStreamInteractiveTransitionEditor::_edited));
+ edit_vb->add_margin_child(TTR("Hold Previous:"), hold_previous);
+
+ set_exclusive(true);
+}
+
+////////////////////////
+
+bool EditorInspectorPluginAudioStreamInteractive::can_handle(Object *p_object) {
+ return Object::cast_to<AudioStreamInteractive>(p_object);
+}
+
+void EditorInspectorPluginAudioStreamInteractive::_edit(Object *p_object) {
+ audio_stream_interactive_transition_editor->edit(p_object);
+}
+
+void EditorInspectorPluginAudioStreamInteractive::parse_end(Object *p_object) {
+ if (Object::cast_to<AudioStreamInteractive>(p_object)) {
+ Button *button = EditorInspector::create_inspector_action_button(TTR("Edit Transitions"));
+ button->set_icon(audio_stream_interactive_transition_editor->get_editor_theme_icon(SNAME("Blend")));
+ button->connect("pressed", callable_mp(this, &EditorInspectorPluginAudioStreamInteractive::_edit).bind(p_object));
+ add_custom_control(button);
+ }
+}
+
+EditorInspectorPluginAudioStreamInteractive::EditorInspectorPluginAudioStreamInteractive() {
+ audio_stream_interactive_transition_editor = memnew(AudioStreamInteractiveTransitionEditor);
+ EditorNode::get_singleton()->get_gui_base()->add_child(audio_stream_interactive_transition_editor);
+}
+
+AudioStreamInteractiveEditorPlugin::AudioStreamInteractiveEditorPlugin() {
+ Ref<EditorInspectorPluginAudioStreamInteractive> inspector_plugin;
+ inspector_plugin.instantiate();
+ add_inspector_plugin(inspector_plugin);
+}
diff --git a/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.h b/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.h
new file mode 100644
index 0000000000..730d1ca83b
--- /dev/null
+++ b/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.h
@@ -0,0 +1,110 @@
+/**************************************************************************/
+/* audio_stream_interactive_editor_plugin.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 AUDIO_STREAM_INTERACTIVE_EDITOR_PLUGIN_H
+#define AUDIO_STREAM_INTERACTIVE_EDITOR_PLUGIN_H
+
+#include "editor/editor_inspector.h"
+#include "editor/editor_plugin.h"
+#include "scene/gui/dialogs.h"
+
+class CheckBox;
+class HSplitContainer;
+class VSplitContainer;
+class Tree;
+class TreeItem;
+class AudioStreamInteractive;
+
+class AudioStreamInteractiveTransitionEditor : public AcceptDialog {
+ GDCLASS(AudioStreamInteractiveTransitionEditor, AcceptDialog);
+
+ AudioStreamInteractive *audio_stream_interactive = nullptr;
+
+ HSplitContainer *split = nullptr;
+ Tree *tree = nullptr;
+
+ Vector<TreeItem *> rows;
+
+ CheckBox *transition_enabled = nullptr;
+ OptionButton *transition_from = nullptr;
+ OptionButton *transition_to = nullptr;
+ OptionButton *fade_mode = nullptr;
+ SpinBox *fade_beats = nullptr;
+ OptionButton *filler_clip = nullptr;
+ CheckBox *hold_previous = nullptr;
+
+ bool updating_selection = false;
+ int order_counter = 0;
+ HashMap<Vector2i, int> selection_order;
+
+ Vector<Vector2i> selected;
+ bool updating = false;
+ void _cell_selected(TreeItem *p_item, int p_column, bool p_selected);
+ void _update_transitions();
+
+ void _update_selection();
+ void _edited();
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void edit(Object *p_obj);
+
+ AudioStreamInteractiveTransitionEditor();
+};
+
+//
+
+class EditorInspectorPluginAudioStreamInteractive : public EditorInspectorPlugin {
+ GDCLASS(EditorInspectorPluginAudioStreamInteractive, EditorInspectorPlugin);
+
+ AudioStreamInteractiveTransitionEditor *audio_stream_interactive_transition_editor = nullptr;
+
+ void _edit(Object *p_object);
+
+public:
+ virtual bool can_handle(Object *p_object) override;
+ virtual void parse_end(Object *p_object) override;
+
+ EditorInspectorPluginAudioStreamInteractive();
+};
+
+class AudioStreamInteractiveEditorPlugin : public EditorPlugin {
+ GDCLASS(AudioStreamInteractiveEditorPlugin, EditorPlugin);
+
+public:
+ virtual String get_name() const override { return "AudioStreamInteractive"; }
+
+ AudioStreamInteractiveEditorPlugin();
+};
+
+#endif // AUDIO_STREAM_INTERACTIVE_EDITOR_PLUGIN_H
diff --git a/modules/interactive_music/register_types.cpp b/modules/interactive_music/register_types.cpp
new file mode 100644
index 0000000000..5baea13f81
--- /dev/null
+++ b/modules/interactive_music/register_types.cpp
@@ -0,0 +1,60 @@
+/**************************************************************************/
+/* register_types.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "register_types.h"
+
+#include "audio_stream_interactive.h"
+#include "audio_stream_playlist.h"
+#include "audio_stream_synchronized.h"
+#include "core/object/class_db.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/audio_stream_interactive_editor_plugin.h"
+#endif
+
+void initialize_interactive_music_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
+ GDREGISTER_CLASS(AudioStreamPlaylist);
+ GDREGISTER_VIRTUAL_CLASS(AudioStreamPlaybackPlaylist);
+ GDREGISTER_CLASS(AudioStreamInteractive);
+ GDREGISTER_VIRTUAL_CLASS(AudioStreamPlaybackInteractive);
+ GDREGISTER_CLASS(AudioStreamSynchronized);
+ GDREGISTER_VIRTUAL_CLASS(AudioStreamPlaybackSynchronized);
+ }
+#ifdef TOOLS_ENABLED
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ EditorPlugins::add_by_type<AudioStreamInteractiveEditorPlugin>();
+ }
+#endif
+}
+
+void uninitialize_interactive_music_module(ModuleInitializationLevel p_level) {
+ // Nothing to do here.
+}
diff --git a/modules/interactive_music/register_types.h b/modules/interactive_music/register_types.h
new file mode 100644
index 0000000000..5625e28b64
--- /dev/null
+++ b/modules/interactive_music/register_types.h
@@ -0,0 +1,39 @@
+/**************************************************************************/
+/* register_types.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 INTERACTIVE_MUSIC_REGISTER_TYPES_H
+#define INTERACTIVE_MUSIC_REGISTER_TYPES_H
+
+#include "modules/register_module_types.h"
+
+void initialize_interactive_music_module(ModuleInitializationLevel p_level);
+void uninitialize_interactive_music_module(ModuleInitializationLevel p_level);
+
+#endif // INTERACTIVE_MUSIC_REGISTER_TYPES_H
diff --git a/modules/ktx/texture_loader_ktx.cpp b/modules/ktx/texture_loader_ktx.cpp
index 026c0ce510..7c73f9cb8a 100644
--- a/modules/ktx/texture_loader_ktx.cpp
+++ b/modules/ktx/texture_loader_ktx.cpp
@@ -90,7 +90,7 @@ static Ref<Image> load_from_file_access(Ref<FileAccess> f, Error *r_error) {
ktx_stream.destruct = ktx_destruct;
ktx_stream.type = eStreamTypeCustom;
ktx_stream.data.custom_ptr.address = &f;
- ktx_stream.data.custom_ptr.allocatorAddress = NULL;
+ ktx_stream.data.custom_ptr.allocatorAddress = nullptr;
ktx_stream.data.custom_ptr.size = 0;
ktx_stream.readpos = 0;
ktx_stream.closeOnDestruct = false;
diff --git a/modules/minimp3/doc_classes/ResourceImporterMP3.xml b/modules/minimp3/doc_classes/ResourceImporterMP3.xml
index a84c51cf68..72868623c7 100644
--- a/modules/minimp3/doc_classes/ResourceImporterMP3.xml
+++ b/modules/minimp3/doc_classes/ResourceImporterMP3.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="ResourceImporterMP3" inherits="ResourceImporter" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
- Imports a MP3 audio file for playback.
+ Imports an MP3 audio file for playback.
</brief_description>
<description>
MP3 is a lossy audio format, with worse audio quality compared to [ResourceImporterOggVorbis] at a given bitrate.
- In most cases, it's recommended to use Ogg Vorbis over MP3. However, if you're using a MP3 sound source with no higher quality source available, then it's recommended to use the MP3 file directly to avoid double lossy compression.
+ In most cases, it's recommended to use Ogg Vorbis over MP3. However, if you're using an MP3 sound source with no higher quality source available, then it's recommended to use the MP3 file directly to avoid double lossy compression.
MP3 requires more CPU to decode than [ResourceImporterWAV]. If you need to play a lot of simultaneous sounds, it's recommended to use WAV for those sounds instead, especially if targeting low-end devices.
</description>
<tutorials>
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 93fb5f1dc6..858d1d3e4e 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -1735,6 +1735,34 @@ bool CSharpInstance::has_method(const StringName &p_method) const {
gchandle.get_intptr(), &p_method);
}
+int CSharpInstance::get_method_argument_count(const StringName &p_method, bool *r_is_valid) const {
+ if (!script->is_valid() || !script->valid) {
+ if (r_is_valid) {
+ *r_is_valid = false;
+ }
+ return 0;
+ }
+
+ const CSharpScript *top = script.ptr();
+ while (top != nullptr) {
+ for (const CSharpScript::CSharpMethodInfo &E : top->methods) {
+ if (E.name == p_method) {
+ if (r_is_valid) {
+ *r_is_valid = true;
+ }
+ return E.method_info.arguments.size();
+ }
+ }
+
+ top = top->base_script.ptr();
+ }
+
+ if (r_is_valid) {
+ *r_is_valid = false;
+ }
+ return 0;
+}
+
Variant CSharpInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
ERR_FAIL_COND_V(!script.is_valid(), Variant());
@@ -2579,6 +2607,29 @@ bool CSharpScript::has_method(const StringName &p_method) const {
return false;
}
+int CSharpScript::get_script_method_argument_count(const StringName &p_method, bool *r_is_valid) const {
+ if (!valid) {
+ if (r_is_valid) {
+ *r_is_valid = false;
+ }
+ return 0;
+ }
+
+ for (const CSharpMethodInfo &E : methods) {
+ if (E.name == p_method) {
+ if (r_is_valid) {
+ *r_is_valid = true;
+ }
+ return E.method_info.arguments.size();
+ }
+ }
+
+ if (r_is_valid) {
+ *r_is_valid = false;
+ }
+ return 0;
+}
+
MethodInfo CSharpScript::get_method_info(const StringName &p_method) const {
if (!valid) {
return MethodInfo();
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 7821420620..06d526f494 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -278,6 +278,7 @@ public:
void get_script_method_list(List<MethodInfo> *p_list) const override;
bool has_method(const StringName &p_method) const override;
+ virtual int get_script_method_argument_count(const StringName &p_method, bool *r_is_valid = nullptr) const override;
MethodInfo get_method_info(const StringName &p_method) const override;
Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
@@ -346,6 +347,7 @@ public:
void get_method_list(List<MethodInfo> *p_list) const override;
bool has_method(const StringName &p_method) const override;
+ virtual int get_method_argument_count(const StringName &p_method, bool *r_is_valid = nullptr) const override;
Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
void mono_object_disposed(GCHandleIntPtr p_gchandle_to_free);
diff --git a/modules/mono/editor/hostfxr_resolver.cpp b/modules/mono/editor/hostfxr_resolver.cpp
index 4f15335c1e..7fa482969e 100644
--- a/modules/mono/editor/hostfxr_resolver.cpp
+++ b/modules/mono/editor/hostfxr_resolver.cpp
@@ -239,7 +239,7 @@ bool get_dotnet_self_registered_dir(String &r_dotnet_root) {
String sub_key = "SOFTWARE\\dotnet\\Setup\\InstalledVersions\\" + get_dotnet_arch();
Char16String value = String("InstallLocation").utf16();
- HKEY hkey = NULL;
+ HKEY hkey = nullptr;
LSTATUS result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, (LPCWSTR)(sub_key.utf16().get_data()), 0, KEY_READ | KEY_WOW64_32KEY, &hkey);
if (result != ERROR_SUCCESS) {
return false;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
index 6c34d7c29d..c7be0464b6 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
@@ -12,6 +12,7 @@ namespace Godot.Bridge
public delegate* unmanaged<IntPtr, void*, godot_variant**, int, godot_variant*, void> DelegateUtils_InvokeWithVariantArgs;
public delegate* unmanaged<IntPtr, IntPtr, godot_bool> DelegateUtils_DelegateEquals;
public delegate* unmanaged<IntPtr, int> DelegateUtils_DelegateHash;
+ public delegate* unmanaged<IntPtr, godot_bool*, int> DelegateUtils_GetArgumentCount;
public delegate* unmanaged<IntPtr, godot_array*, godot_bool> DelegateUtils_TrySerializeDelegateWithGCHandle;
public delegate* unmanaged<godot_array*, IntPtr*, godot_bool> DelegateUtils_TryDeserializeDelegateWithGCHandle;
public delegate* unmanaged<void> ScriptManagerBridge_FrameCallback;
@@ -55,6 +56,7 @@ namespace Godot.Bridge
DelegateUtils_InvokeWithVariantArgs = &DelegateUtils.InvokeWithVariantArgs,
DelegateUtils_DelegateEquals = &DelegateUtils.DelegateEquals,
DelegateUtils_DelegateHash = &DelegateUtils.DelegateHash,
+ DelegateUtils_GetArgumentCount = &DelegateUtils.GetArgumentCount,
DelegateUtils_TrySerializeDelegateWithGCHandle = &DelegateUtils.TrySerializeDelegateWithGCHandle,
DelegateUtils_TryDeserializeDelegateWithGCHandle = &DelegateUtils.TryDeserializeDelegateWithGCHandle,
ScriptManagerBridge_FrameCallback = &ScriptManagerBridge.FrameCallback,
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
index c680142638..ef3c9c79d4 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
@@ -46,6 +46,29 @@ namespace Godot
}
[UnmanagedCallersOnly]
+ internal static unsafe int GetArgumentCount(IntPtr delegateGCHandle, godot_bool* outIsValid)
+ {
+ try
+ {
+ var @delegate = (Delegate?)GCHandle.FromIntPtr(delegateGCHandle).Target;
+ int? argCount = @delegate?.Method?.GetParameters().Length;
+ if (argCount is null)
+ {
+ *outIsValid = godot_bool.False;
+ return 0;
+ }
+ *outIsValid = godot_bool.True;
+ return argCount.Value;
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ *outIsValid = godot_bool.False;
+ return 0;
+ }
+ }
+
+ [UnmanagedCallersOnly]
internal static unsafe void InvokeWithVariantArgs(IntPtr delegateGCHandle, void* trampoline,
godot_variant** args, int argc, godot_variant* outRet)
{
diff --git a/modules/mono/managed_callable.cpp b/modules/mono/managed_callable.cpp
index c55c5d8111..7c48110199 100644
--- a/modules/mono/managed_callable.cpp
+++ b/modules/mono/managed_callable.cpp
@@ -85,6 +85,10 @@ ObjectID ManagedCallable::get_object() const {
return CSharpLanguage::get_singleton()->get_managed_callable_middleman()->get_instance_id();
}
+int ManagedCallable::get_argument_count(bool &r_is_valid) const {
+ return GDMonoCache::managed_callbacks.DelegateUtils_GetArgumentCount(delegate_handle, &r_is_valid);
+}
+
void ManagedCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // Can't find anything better
r_return_value = Variant();
diff --git a/modules/mono/managed_callable.h b/modules/mono/managed_callable.h
index 290d49be14..388c321d5d 100644
--- a/modules/mono/managed_callable.h
+++ b/modules/mono/managed_callable.h
@@ -56,6 +56,7 @@ public:
CompareEqualFunc get_compare_equal_func() const override;
CompareLessFunc get_compare_less_func() const override;
ObjectID get_object() const override;
+ int get_argument_count(bool &r_is_valid) const override;
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
_FORCE_INLINE_ GCHandleIntPtr get_delegate() const { return delegate_handle; }
diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp
index 145f4cee90..5292bcd1ea 100644
--- a/modules/mono/mono_gd/gd_mono_cache.cpp
+++ b/modules/mono/mono_gd/gd_mono_cache.cpp
@@ -53,6 +53,7 @@ void update_godot_api_cache(const ManagedCallbacks &p_managed_callbacks) {
CHECK_CALLBACK_NOT_NULL(DelegateUtils, InvokeWithVariantArgs);
CHECK_CALLBACK_NOT_NULL(DelegateUtils, DelegateEquals);
CHECK_CALLBACK_NOT_NULL(DelegateUtils, DelegateHash);
+ CHECK_CALLBACK_NOT_NULL(DelegateUtils, GetArgumentCount);
CHECK_CALLBACK_NOT_NULL(DelegateUtils, TrySerializeDelegateWithGCHandle);
CHECK_CALLBACK_NOT_NULL(DelegateUtils, TryDeserializeDelegateWithGCHandle);
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, FrameCallback);
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index 46e9ab10cb..7c24f28b3a 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -78,6 +78,7 @@ struct ManagedCallbacks {
using FuncDelegateUtils_InvokeWithVariantArgs = void(GD_CLR_STDCALL *)(GCHandleIntPtr, void *, const Variant **, int32_t, const Variant *);
using FuncDelegateUtils_DelegateEquals = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, GCHandleIntPtr);
using FuncDelegateUtils_DelegateHash = int32_t(GD_CLR_STDCALL *)(GCHandleIntPtr);
+ using FuncDelegateUtils_GetArgumentCount = int32_t(GD_CLR_STDCALL *)(GCHandleIntPtr, bool *);
using FuncDelegateUtils_TrySerializeDelegateWithGCHandle = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const Array *);
using FuncDelegateUtils_TryDeserializeDelegateWithGCHandle = bool(GD_CLR_STDCALL *)(const Array *, GCHandleIntPtr *);
using FuncScriptManagerBridge_FrameCallback = void(GD_CLR_STDCALL *)();
@@ -115,6 +116,7 @@ struct ManagedCallbacks {
FuncDelegateUtils_InvokeWithVariantArgs DelegateUtils_InvokeWithVariantArgs;
FuncDelegateUtils_DelegateEquals DelegateUtils_DelegateEquals;
FuncDelegateUtils_DelegateHash DelegateUtils_DelegateHash;
+ FuncDelegateUtils_GetArgumentCount DelegateUtils_GetArgumentCount;
FuncDelegateUtils_TrySerializeDelegateWithGCHandle DelegateUtils_TrySerializeDelegateWithGCHandle;
FuncDelegateUtils_TryDeserializeDelegateWithGCHandle DelegateUtils_TryDeserializeDelegateWithGCHandle;
FuncScriptManagerBridge_FrameCallback ScriptManagerBridge_FrameCallback;
diff --git a/modules/msdfgen/SCsub b/modules/msdfgen/SCsub
index 0c269bc7f4..f4316a74e7 100644
--- a/modules/msdfgen/SCsub
+++ b/modules/msdfgen/SCsub
@@ -20,8 +20,6 @@ if env["builtin_msdfgen"]:
"core/Projection.cpp",
"core/Scanline.cpp",
"core/Shape.cpp",
- "core/SignedDistance.cpp",
- "core/Vector2.cpp",
"core/contour-combiners.cpp",
"core/edge-coloring.cpp",
"core/edge-segments.cpp",
@@ -36,6 +34,7 @@ if env["builtin_msdfgen"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+ env_msdfgen.Append(CPPDEFINES=[("MSDFGEN_PUBLIC", "")])
env_msdfgen.Prepend(CPPPATH=["#thirdparty/freetype/include", "#thirdparty/msdfgen", "#thirdparty/nanosvg"])
lib = env_msdfgen.add_library("msdfgen_builtin", thirdparty_sources)
diff --git a/modules/multiplayer/scene_replication_interface.h b/modules/multiplayer/scene_replication_interface.h
index 31211bb108..cb582a2caf 100644
--- a/modules/multiplayer/scene_replication_interface.h
+++ b/modules/multiplayer/scene_replication_interface.h
@@ -112,7 +112,7 @@ private:
Error _update_spawn_visibility(int p_peer, const ObjectID &p_oid);
void _free_remotes(const PeerInfo &p_info);
- template <class T>
+ template <typename T>
static T *get_id_as(const ObjectID &p_id) {
return p_id.is_valid() ? Object::cast_to<T>(ObjectDB::get_instance(p_id)) : nullptr;
}
diff --git a/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml b/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml
index ee2aa33108..20ce1c42bf 100644
--- a/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml
+++ b/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml
@@ -12,7 +12,7 @@
<method name="_get_composition_layer" qualifiers="virtual">
<return type="int" />
<description>
- Returns a pointer to a [code]XrCompositionLayerBaseHeader[/code] struct to provide a composition layer. This will only be called if the extension previously registered itself with [method OpenXRAPIExtension.register_composition_layer_provider].
+ Returns a pointer to an [code]XrCompositionLayerBaseHeader[/code] struct to provide a composition layer. This will only be called if the extension previously registered itself with [method OpenXRAPIExtension.register_composition_layer_provider].
</description>
</method>
<method name="_get_requested_extensions" qualifiers="virtual">
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index d3e6eb01ce..e1a04a0796 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -118,7 +118,7 @@ private:
XrSession session = XR_NULL_HANDLE;
XrSessionState session_state = XR_SESSION_STATE_UNKNOWN;
bool running = false;
- XrFrameState frame_state = { XR_TYPE_FRAME_STATE, NULL, 0, 0, false };
+ XrFrameState frame_state = { XR_TYPE_FRAME_STATE, nullptr, 0, 0, false };
double render_target_size_multiplier = 1.0;
OpenXRGraphicsExtensionWrapper *graphics_extension = nullptr;
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index 6b53353ec9..b04ad77bc9 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -531,6 +531,7 @@ module_obj = []
if env["builtin_msdfgen"] and msdfgen_enabled:
# Treat msdfgen headers as system headers to avoid raising warnings. Not supported on MSVC.
+ env_text_server_adv.Append(CPPDEFINES=[("MSDFGEN_PUBLIC", "")])
if not env.msvc:
env_text_server_adv.Append(CPPFLAGS=["-isystem", Dir("#thirdparty/msdfgen").path])
else:
diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct
index cd4331b60e..1f27f5ade9 100644
--- a/modules/text_server_adv/gdextension_build/SConstruct
+++ b/modules/text_server_adv/gdextension_build/SConstruct
@@ -133,8 +133,6 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
"core/Projection.cpp",
"core/Scanline.cpp",
"core/Shape.cpp",
- "core/SignedDistance.cpp",
- "core/Vector2.cpp",
"core/contour-combiners.cpp",
"core/edge-coloring.cpp",
"core/edge-segments.cpp",
@@ -149,8 +147,10 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
]
thirdparty_msdfgen_sources = [thirdparty_msdfgen_dir + file for file in thirdparty_msdfgen_sources]
+ env_msdfgen.Append(CPPDEFINES=[("MSDFGEN_PUBLIC", "")])
env_msdfgen.Append(CPPPATH=["../../../thirdparty/freetype/include", "../../../thirdparty/msdfgen"])
env.Append(CPPPATH=["../../../thirdparty/msdfgen"])
+ env.Append(CPPDEFINES=[("MSDFGEN_PUBLIC", "")])
env.Append(CPPDEFINES=["MODULE_MSDFGEN_ENABLED"])
lib = env_msdfgen.Library(
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index bb198c9c2b..fc06e24bee 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -67,10 +67,16 @@ using namespace godot;
// Thirdparty headers.
#ifdef MODULE_MSDFGEN_ENABLED
+#ifdef _MSC_VER
+#pragma warning(disable : 4458)
+#endif
#include <core/ShapeDistanceFinder.h>
#include <core/contour-combiners.h>
#include <core/edge-selectors.h>
#include <msdfgen.h>
+#ifdef _MSC_VER
+#pragma warning(default : 4458)
+#endif
#endif
#ifdef MODULE_SVG_ENABLED
@@ -6820,13 +6826,13 @@ int64_t TextServerAdvanced::_is_confusable(const String &p_string, const PackedS
}
for (int i = 0; i < p_dict.size(); i++) {
Char16String word = p_dict[i].utf16();
- int32_t len = uspoof_getSkeleton(sc_conf, 0, word.get_data(), -1, NULL, 0, &status);
+ int32_t len = uspoof_getSkeleton(sc_conf, 0, word.get_data(), -1, nullptr, 0, &status);
skeletons.write[i] = (UChar *)memalloc(++len * sizeof(UChar));
status = U_ZERO_ERROR;
uspoof_getSkeleton(sc_conf, 0, word.get_data(), -1, skeletons.write[i], len, &status);
}
- int32_t len = uspoof_getSkeleton(sc_conf, 0, utf16.get_data(), -1, NULL, 0, &status);
+ int32_t len = uspoof_getSkeleton(sc_conf, 0, utf16.get_data(), -1, nullptr, 0, &status);
UChar *skel = (UChar *)memalloc(++len * sizeof(UChar));
status = U_ZERO_ERROR;
uspoof_getSkeleton(sc_conf, 0, utf16.get_data(), -1, skel, len, &status);
@@ -6867,7 +6873,7 @@ bool TextServerAdvanced::_spoof_check(const String &p_string) const {
uspoof_setRestrictionLevel(sc_spoof, USPOOF_MODERATELY_RESTRICTIVE);
}
- int32_t bitmask = uspoof_check(sc_spoof, utf16.get_data(), -1, NULL, &status);
+ int32_t bitmask = uspoof_check(sc_spoof, utf16.get_data(), -1, nullptr, &status);
ERR_FAIL_COND_V_MSG(U_FAILURE(status), false, u_errorName(status));
return (bitmask != 0);
diff --git a/modules/text_server_fb/SCsub b/modules/text_server_fb/SCsub
index e808864512..fc0a8727c6 100644
--- a/modules/text_server_fb/SCsub
+++ b/modules/text_server_fb/SCsub
@@ -17,6 +17,7 @@ if "svg" in env.module_list:
if env["builtin_msdfgen"] and msdfgen_enabled:
# Treat msdfgen headers as system headers to avoid raising warnings. Not supported on MSVC.
+ env_text_server_fb.Append(CPPDEFINES=[("MSDFGEN_PUBLIC", "")])
if not env.msvc:
env_text_server_fb.Append(CPPFLAGS=["-isystem", Dir("#thirdparty/msdfgen").path])
else:
diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct
index 0efced0bfc..29801ede8e 100644
--- a/modules/text_server_fb/gdextension_build/SConstruct
+++ b/modules/text_server_fb/gdextension_build/SConstruct
@@ -144,8 +144,10 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
]
thirdparty_msdfgen_sources = [thirdparty_msdfgen_dir + file for file in thirdparty_msdfgen_sources]
+ env_msdfgen.Append(CPPDEFINES=[("MSDFGEN_PUBLIC", "")])
env_msdfgen.Append(CPPPATH=["../../../thirdparty/freetype/include", "../../../thirdparty/msdfgen"])
env.Append(CPPPATH=["../../../thirdparty/msdfgen"])
+ env.Append(CPPDEFINES=[("MSDFGEN_PUBLIC", "")])
env.Append(CPPDEFINES=["MODULE_MSDFGEN_ENABLED"])
lib = env_msdfgen.Library(
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 1a63e5ac42..4c0ed084d8 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -59,10 +59,16 @@ using namespace godot;
// Thirdparty headers.
#ifdef MODULE_MSDFGEN_ENABLED
+#ifdef _MSC_VER
+#pragma warning(disable : 4458)
+#endif
#include <core/ShapeDistanceFinder.h>
#include <core/contour-combiners.h>
#include <core/edge-selectors.h>
#include <msdfgen.h>
+#ifdef _MSC_VER
+#pragma warning(default : 4458)
+#endif
#endif
#ifdef MODULE_SVG_ENABLED
@@ -73,8 +79,6 @@ using namespace godot;
/*************************************************************************/
-#define OT_TAG(c1, c2, c3, c4) ((int32_t)((((uint32_t)(c1) & 0xff) << 24) | (((uint32_t)(c2) & 0xff) << 16) | (((uint32_t)(c3) & 0xff) << 8) | ((uint32_t)(c4) & 0xff)))
-
bool TextServerFallback::_has_feature(Feature p_feature) const {
switch (p_feature) {
case FEATURE_SIMPLE_LAYOUT:
@@ -907,8 +911,8 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
coords.write[i] = CLAMP(var_value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);
}
- if (p_font_data->variation_coordinates.has(_tag_to_name(var_tag))) {
- var_value = p_font_data->variation_coordinates[_tag_to_name(var_tag)];
+ if (p_font_data->variation_coordinates.has(tag_to_name(var_tag))) {
+ var_value = p_font_data->variation_coordinates[tag_to_name(var_tag)];
coords.write[i] = CLAMP(var_value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);
}
}
@@ -3704,9 +3708,9 @@ RID TextServerFallback::_find_sys_font_for_text(const RID &p_fdef, const String
int font_weight = _font_get_weight(p_fdef);
int font_stretch = _font_get_stretch(p_fdef);
Dictionary dvar = _font_get_variation_coordinates(p_fdef);
- static int64_t wgth_tag = _name_to_tag("weight");
- static int64_t wdth_tag = _name_to_tag("width");
- static int64_t ital_tag = _name_to_tag("italic");
+ static int64_t wgth_tag = name_to_tag("weight");
+ static int64_t wdth_tag = name_to_tag("width");
+ static int64_t ital_tag = name_to_tag("italic");
if (dvar.has(wgth_tag)) {
font_weight = dvar[wgth_tag].operator int();
}
diff --git a/modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml b/modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml
index dd6c181eae..8ae63140f5 100644
--- a/modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml
+++ b/modules/vorbis/doc_classes/ResourceImporterOggVorbis.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Ogg Vorbis is a lossy audio format, with better audio quality compared to [ResourceImporterMP3] at a given bitrate.
- In most cases, it's recommended to use Ogg Vorbis over MP3. However, if you're using a MP3 sound source with no higher quality source available, then it's recommended to use the MP3 file directly to avoid double lossy compression.
+ In most cases, it's recommended to use Ogg Vorbis over MP3. However, if you're using an MP3 sound source with no higher quality source available, then it's recommended to use the MP3 file directly to avoid double lossy compression.
Ogg Vorbis requires more CPU to decode than [ResourceImporterWAV]. If you need to play a lot of simultaneous sounds, it's recommended to use WAV for those sounds instead, especially if targeting low-end devices.
</description>
<tutorials>
diff --git a/modules/websocket/packet_buffer.h b/modules/websocket/packet_buffer.h
index 25e1b1f15a..f98ee12ef9 100644
--- a/modules/websocket/packet_buffer.h
+++ b/modules/websocket/packet_buffer.h
@@ -33,7 +33,7 @@
#include "core/templates/ring_buffer.h"
-template <class T>
+template <typename T>
class PacketBuffer {
private:
typedef struct {
diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm
index 23614af366..ac13a4d457 100644
--- a/platform/ios/os_ios.mm
+++ b/platform/ios/os_ios.mm
@@ -361,7 +361,7 @@ String OS_IOS::get_unique_id() const {
String OS_IOS::get_processor_name() const {
char buffer[256];
size_t buffer_len = 256;
- if (sysctlbyname("machdep.cpu.brand_string", &buffer, &buffer_len, NULL, 0) == 0) {
+ if (sysctlbyname("machdep.cpu.brand_string", &buffer, &buffer_len, nullptr, 0) == 0) {
return String::utf8(buffer, buffer_len);
}
ERR_FAIL_V_MSG("", String("Couldn't get the CPU model name. Returning an empty string."));
diff --git a/platform/linuxbsd/wayland/detect_prime_egl.cpp b/platform/linuxbsd/wayland/detect_prime_egl.cpp
index 4bee32ae3a..4c97a80039 100644
--- a/platform/linuxbsd/wayland/detect_prime_egl.cpp
+++ b/platform/linuxbsd/wayland/detect_prime_egl.cpp
@@ -69,7 +69,7 @@ void DetectPrimeEGL::create_context() {
EGLConfig egl_config;
EGLContext egl_context = EGL_NO_CONTEXT;
- eglInitialize(egl_display, NULL, NULL);
+ eglInitialize(egl_display, nullptr, nullptr);
#if defined(GLAD_ENABLED)
if (!gladLoaderLoadEGL(egl_display)) {
diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp
index 0216ad862c..5040f5dd45 100644
--- a/platform/linuxbsd/wayland/wayland_thread.cpp
+++ b/platform/linuxbsd/wayland/wayland_thread.cpp
@@ -1724,7 +1724,7 @@ void WaylandThread::_wl_keyboard_on_keymap(void *data, struct wl_keyboard *wl_ke
ss->keymap_buffer = nullptr;
}
- ss->keymap_buffer = (const char *)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+ ss->keymap_buffer = (const char *)mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
ss->keymap_buffer_size = size;
xkb_keymap_unref(ss->xkb_keymap);
@@ -2854,7 +2854,7 @@ void WaylandThread::seat_state_lock_pointer(SeatState *p_ss) {
ERR_FAIL_NULL(locked_surface);
- p_ss->wp_locked_pointer = zwp_pointer_constraints_v1_lock_pointer(registry.wp_pointer_constraints, locked_surface, p_ss->wl_pointer, NULL, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+ p_ss->wp_locked_pointer = zwp_pointer_constraints_v1_lock_pointer(registry.wp_pointer_constraints, locked_surface, p_ss->wl_pointer, nullptr, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
}
}
@@ -2886,7 +2886,7 @@ void WaylandThread::seat_state_confine_pointer(SeatState *p_ss) {
ERR_FAIL_NULL(confined_surface);
- p_ss->wp_confined_pointer = zwp_pointer_constraints_v1_confine_pointer(registry.wp_pointer_constraints, confined_surface, p_ss->wl_pointer, NULL, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+ p_ss->wp_confined_pointer = zwp_pointer_constraints_v1_confine_pointer(registry.wp_pointer_constraints, confined_surface, p_ss->wl_pointer, nullptr, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
}
}
@@ -3660,7 +3660,7 @@ void WaylandThread::cursor_shape_set_custom_image(DisplayServer::CursorShape p_c
munmap(cursor.buffer_data, cursor.buffer_data_size);
}
- cursor.buffer_data = (uint32_t *)mmap(NULL, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ cursor.buffer_data = (uint32_t *)mmap(nullptr, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (cursor.wl_buffer) {
// Clean up the old Wayland buffer.
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 29bc60bd2a..c52ed00b3d 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -515,7 +515,7 @@ void DisplayServerMacOS::_keyboard_layout_changed(CFNotificationCenterRef center
NSImage *DisplayServerMacOS::_convert_to_nsimg(Ref<Image> &p_image) const {
p_image->convert(Image::FORMAT_RGBA8);
NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
- initWithBitmapDataPlanes:NULL
+ initWithBitmapDataPlanes:nullptr
pixelsWide:p_image->get_width()
pixelsHigh:p_image->get_height()
bitsPerSample:8
diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm
index c5c95c9a70..d9ad8f937a 100644
--- a/platform/macos/os_macos.mm
+++ b/platform/macos/os_macos.mm
@@ -70,7 +70,7 @@ void OS_MacOS::initialize() {
String OS_MacOS::get_processor_name() const {
char buffer[256];
size_t buffer_len = 256;
- if (sysctlbyname("machdep.cpu.brand_string", &buffer, &buffer_len, NULL, 0) == 0) {
+ if (sysctlbyname("machdep.cpu.brand_string", &buffer, &buffer_len, nullptr, 0) == 0) {
return String::utf8(buffer, buffer_len);
}
ERR_FAIL_V_MSG("", String("Couldn't get the CPU model name. Returning an empty string."));
diff --git a/platform/web/doc_classes/EditorExportPlatformWeb.xml b/platform/web/doc_classes/EditorExportPlatformWeb.xml
index c759701d2f..755308de9a 100644
--- a/platform/web/doc_classes/EditorExportPlatformWeb.xml
+++ b/platform/web/doc_classes/EditorExportPlatformWeb.xml
@@ -84,7 +84,7 @@
</member>
<member name="variant/thread_support" type="bool" setter="" getter="">
If [code]true[/code], the exported game will support threads. It requires [url=https://web.dev/articles/coop-coep]a "cross-origin isolated" website[/url], which may be difficult to set up and is limited for security reasons (such as not being able to communicate with third-party websites).
- If [code]false[/code], the exported game will not support threads. As a result, it is more prone to performance and audio issues, but will only require to be run on a HTTPS website.
+ If [code]false[/code], the exported game will not support threads. As a result, it is more prone to performance and audio issues, but will only require to be run on an HTTPS website.
</member>
<member name="vram_texture_compression/for_desktop" type="bool" setter="" getter="">
If [code]true[/code], allows textures to be optimized for desktop through the S3TC algorithm.
diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp
index e32fbd47dd..133d36aa0d 100644
--- a/platform/windows/crash_handler_windows.cpp
+++ b/platform/windows/crash_handler_windows.cpp
@@ -109,7 +109,7 @@ public:
ret.module_name = temp;
std::vector<char> img(ret.image_name.begin(), ret.image_name.end());
std::vector<char> mod(ret.module_name.begin(), ret.module_name.end());
- SymLoadModule64(process, 0, &img[0], &mod[0], (DWORD64)ret.base_address, ret.load_size);
+ SymLoadModule64(process, nullptr, &img[0], &mod[0], (DWORD64)ret.base_address, ret.load_size);
return ret;
}
};
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index b810043495..2093f552ce 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -202,8 +202,8 @@ void DisplayServerWindows::_register_raw_input_devices(WindowID p_target_window)
rid[1].hwndTarget = windows[p_target_window].hWnd;
} else {
// Follow the keyboard focus
- rid[0].hwndTarget = 0;
- rid[1].hwndTarget = 0;
+ rid[0].hwndTarget = nullptr;
+ rid[1].hwndTarget = nullptr;
}
if (RegisterRawInputDevices(rid, 2, sizeof(rid[0])) == FALSE) {
@@ -272,7 +272,7 @@ public:
QITABENT(FileDialogEventHandler, IFileDialogEvents),
QITABENT(FileDialogEventHandler, IFileDialogControlEvents),
#endif
- { 0, 0 },
+ { nullptr, 0 },
};
return QISearch(this, qit, riid, ppv);
}
@@ -762,15 +762,15 @@ Ref<Image> DisplayServerWindows::clipboard_get_image() const {
}
} else if (IsClipboardFormatAvailable(CF_DIB)) {
HGLOBAL mem = GetClipboardData(CF_DIB);
- if (mem != NULL) {
+ if (mem != nullptr) {
BITMAPINFO *ptr = static_cast<BITMAPINFO *>(GlobalLock(mem));
- if (ptr != NULL) {
+ if (ptr != nullptr) {
BITMAPINFOHEADER *info = &ptr->bmiHeader;
void *dib_bits = (void *)(ptr->bmiColors);
// Draw DIB image to temporary DC surface and read it back as BGRA8.
- HDC dc = GetDC(0);
+ HDC dc = GetDC(nullptr);
if (dc) {
HDC hdc = CreateCompatibleDC(dc);
if (hdc) {
@@ -804,7 +804,7 @@ Ref<Image> DisplayServerWindows::clipboard_get_image() const {
}
DeleteDC(hdc);
}
- ReleaseDC(NULL, dc);
+ ReleaseDC(nullptr, dc);
}
GlobalUnlock(mem);
}
@@ -868,7 +868,7 @@ int DisplayServerWindows::get_screen_count() const {
}
int DisplayServerWindows::get_primary_screen() const {
- EnumScreenData data = { 0, 0, 0 };
+ EnumScreenData data = { 0, 0, nullptr };
EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcPrim, (LPARAM)&data);
return data.screen;
}
@@ -1116,16 +1116,16 @@ Color DisplayServerWindows::screen_get_pixel(const Point2i &p_position) const {
p.x = pos.x;
p.y = pos.y;
if (win81p_LogicalToPhysicalPointForPerMonitorDPI) {
- win81p_LogicalToPhysicalPointForPerMonitorDPI(0, &p);
+ win81p_LogicalToPhysicalPointForPerMonitorDPI(nullptr, &p);
}
- HDC dc = GetDC(0);
+ HDC dc = GetDC(nullptr);
if (dc) {
COLORREF col = GetPixel(dc, p.x, p.y);
if (col != CLR_INVALID) {
- ReleaseDC(NULL, dc);
+ ReleaseDC(nullptr, dc);
return Color(float(col & 0x000000FF) / 255.0f, float((col & 0x0000FF00) >> 8) / 255.0f, float((col & 0x00FF0000) >> 16) / 255.0f, 1.0f);
}
- ReleaseDC(NULL, dc);
+ ReleaseDC(nullptr, dc);
}
return Color();
@@ -1156,12 +1156,12 @@ Ref<Image> DisplayServerWindows::screen_get_image(int p_screen) const {
p2.x = pos.x + size.x;
p2.y = pos.y + size.y;
if (win81p_LogicalToPhysicalPointForPerMonitorDPI) {
- win81p_LogicalToPhysicalPointForPerMonitorDPI(0, &p1);
- win81p_LogicalToPhysicalPointForPerMonitorDPI(0, &p2);
+ win81p_LogicalToPhysicalPointForPerMonitorDPI(nullptr, &p1);
+ win81p_LogicalToPhysicalPointForPerMonitorDPI(nullptr, &p2);
}
Ref<Image> img;
- HDC dc = GetDC(0);
+ HDC dc = GetDC(nullptr);
if (dc) {
HDC hdc = CreateCompatibleDC(dc);
int width = p2.x - p1.x;
@@ -1194,7 +1194,7 @@ Ref<Image> DisplayServerWindows::screen_get_image(int p_screen) const {
}
DeleteDC(hdc);
}
- ReleaseDC(NULL, dc);
+ ReleaseDC(nullptr, dc);
}
return img;
@@ -1420,7 +1420,7 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[p_window].wtctx) {
wintab_WTClose(windows[p_window].wtctx);
- windows[p_window].wtctx = 0;
+ windows[p_window].wtctx = nullptr;
}
DestroyWindow(windows[p_window].hWnd);
windows.erase(p_window);
@@ -1541,7 +1541,7 @@ Size2i DisplayServerWindows::window_get_title_size(const String &p_title, Window
return size;
}
- HDC hdc = GetDCEx(wd.hWnd, NULL, DCX_WINDOW);
+ HDC hdc = GetDCEx(wd.hWnd, nullptr, DCX_WINDOW);
if (hdc) {
Char16String s = p_title.utf16();
SIZE text_size;
@@ -1559,8 +1559,8 @@ Size2i DisplayServerWindows::window_get_title_size(const String &p_title, Window
ClientToScreen(wd.hWnd, (POINT *)&rect.right);
if (win81p_PhysicalToLogicalPointForPerMonitorDPI) {
- win81p_PhysicalToLogicalPointForPerMonitorDPI(0, (POINT *)&rect.left);
- win81p_PhysicalToLogicalPointForPerMonitorDPI(0, (POINT *)&rect.right);
+ win81p_PhysicalToLogicalPointForPerMonitorDPI(nullptr, (POINT *)&rect.left);
+ win81p_PhysicalToLogicalPointForPerMonitorDPI(nullptr, (POINT *)&rect.right);
}
size.x += (rect.right - rect.left);
@@ -1991,7 +1991,7 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window)
MoveWindow(wd.hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
if (restore_mouse_trails > 1) {
- SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, 0, 0);
+ SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, nullptr, 0);
restore_mouse_trails = 0;
}
}
@@ -2048,7 +2048,7 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window)
// Save number of trails so we can restore when exiting, then turn off mouse trails
SystemParametersInfoA(SPI_GETMOUSETRAILS, 0, &restore_mouse_trails, 0);
if (restore_mouse_trails > 1) {
- SystemParametersInfoA(SPI_SETMOUSETRAILS, 0, 0, 0);
+ SystemParametersInfoA(SPI_SETMOUSETRAILS, 0, nullptr, 0);
}
}
}
@@ -2303,10 +2303,10 @@ void DisplayServerWindows::window_set_ime_active(const bool p_active, WindowID p
if (p_active) {
wd.ime_active = true;
ImmAssociateContext(wd.hWnd, wd.im_himc);
- CreateCaret(wd.hWnd, NULL, 1, 1);
+ CreateCaret(wd.hWnd, nullptr, 1, 1);
window_set_ime_position(wd.im_position, p_window);
} else {
- ImmAssociateContext(wd.hWnd, (HIMC)0);
+ ImmAssociateContext(wd.hWnd, (HIMC) nullptr);
DestroyCaret();
wd.ime_active = false;
}
@@ -2321,7 +2321,7 @@ void DisplayServerWindows::window_set_ime_position(const Point2i &p_pos, WindowI
wd.im_position = p_pos;
HIMC himc = ImmGetContext(wd.hWnd);
- if (himc == (HIMC)0) {
+ if (himc == (HIMC) nullptr) {
return;
}
@@ -5015,7 +5015,7 @@ void DisplayServerWindows::_update_tablet_ctx(const String &p_old_driver, const
if ((p_old_driver == "wintab") && wintab_available && wd.wtctx) {
wintab_WTEnable(wd.wtctx, false);
wintab_WTClose(wd.wtctx);
- wd.wtctx = 0;
+ wd.wtctx = nullptr;
}
if ((p_new_driver == "wintab") && wintab_available) {
wintab_WTInfo(WTI_DEFSYSCTX, 0, &wd.wtlc);
@@ -5104,8 +5104,6 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
dwExStyle,
L"Engine", L"",
dwStyle,
- // (GetSystemMetrics(SM_CXSCREEN) - WindowRect.right) / 2,
- // (GetSystemMetrics(SM_CYSCREEN) - WindowRect.bottom) / 2,
WindowRect.left,
WindowRect.top,
WindowRect.right - WindowRect.left,
@@ -5223,7 +5221,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
print_verbose("WinTab context creation failed.");
}
} else {
- wd.wtctx = 0;
+ wd.wtctx = nullptr;
}
if (p_mode == WINDOW_MODE_MAXIMIZED) {
@@ -5269,7 +5267,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
// IME.
wd.im_himc = ImmGetContext(wd.hWnd);
- ImmAssociateContext(wd.hWnd, (HIMC)0);
+ ImmAssociateContext(wd.hWnd, (HIMC) nullptr);
wd.im_position = Vector2();
@@ -5324,17 +5322,17 @@ Vector2i _get_device_ids(const String &p_device_name) {
REFCLSID clsid = CLSID_WbemLocator; // Unmarshaler CLSID
REFIID uuid = IID_IWbemLocator; // Interface UUID
- IWbemLocator *wbemLocator = NULL; // to get the services
- IWbemServices *wbemServices = NULL; // to get the class
- IEnumWbemClassObject *iter = NULL;
+ IWbemLocator *wbemLocator = nullptr; // to get the services
+ IWbemServices *wbemServices = nullptr; // to get the class
+ IEnumWbemClassObject *iter = nullptr;
IWbemClassObject *pnpSDriverObject[1]; // contains driver name, version, etc.
- HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, uuid, (LPVOID *)&wbemLocator);
+ HRESULT hr = CoCreateInstance(clsid, nullptr, CLSCTX_INPROC_SERVER, uuid, (LPVOID *)&wbemLocator);
if (hr != S_OK) {
return Vector2i();
}
BSTR resource_name = SysAllocString(L"root\\CIMV2");
- hr = wbemLocator->ConnectServer(resource_name, NULL, NULL, NULL, 0, NULL, NULL, &wbemServices);
+ hr = wbemLocator->ConnectServer(resource_name, nullptr, nullptr, nullptr, 0, nullptr, nullptr, &wbemServices);
SysFreeString(resource_name);
SAFE_RELEASE(wbemLocator) // from now on, use `wbemServices`
@@ -5348,7 +5346,7 @@ Vector2i _get_device_ids(const String &p_device_name) {
const String gpu_device_class_query = vformat("SELECT * FROM Win32_PnPSignedDriver WHERE DeviceName = \"%s\"", p_device_name);
BSTR query = SysAllocString((const WCHAR *)gpu_device_class_query.utf16().get_data());
BSTR query_lang = SysAllocString(L"WQL");
- hr = wbemServices->ExecQuery(query_lang, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &iter);
+ hr = wbemServices->ExecQuery(query_lang, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, nullptr, &iter);
SysFreeString(query_lang);
SysFreeString(query);
if (hr == S_OK) {
@@ -5359,7 +5357,7 @@ Vector2i _get_device_ids(const String &p_device_name) {
VARIANT did;
VariantInit(&did);
BSTR object_name = SysAllocString(L"DeviceID");
- hr = pnpSDriverObject[0]->Get(object_name, 0, &did, NULL, NULL);
+ hr = pnpSDriverObject[0]->Get(object_name, 0, &did, nullptr, nullptr);
SysFreeString(object_name);
if (hr == S_OK) {
String device_id = String(V_BSTR(&did));
@@ -5872,7 +5870,7 @@ DisplayServerWindows::~DisplayServerWindows() {
#endif
if (wintab_available && windows[MAIN_WINDOW_ID].wtctx) {
wintab_WTClose(windows[MAIN_WINDOW_ID].wtctx);
- windows[MAIN_WINDOW_ID].wtctx = 0;
+ windows[MAIN_WINDOW_ID].wtctx = nullptr;
}
DestroyWindow(windows[MAIN_WINDOW_ID].hWnd);
}
@@ -5890,7 +5888,7 @@ DisplayServerWindows::~DisplayServerWindows() {
#endif
if (restore_mouse_trails > 1) {
- SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, 0, 0);
+ SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, nullptr, 0);
}
#ifdef GLES3_ENABLED
if (gl_manager_angle) {
diff --git a/platform/windows/gl_manager_windows_native.cpp b/platform/windows/gl_manager_windows_native.cpp
index 8af32395b7..da837b3f94 100644
--- a/platform/windows/gl_manager_windows_native.cpp
+++ b/platform/windows/gl_manager_windows_native.cpp
@@ -107,22 +107,22 @@ static bool nvapi_err_check(const char *msg, int status) {
// to avoid stuttering, see https://stackoverflow.com/questions/36959508/nvidia-graphics-driver-causing-noticeable-frame-stuttering/37632948
// also see https://github.com/Ryujinx/Ryujinx/blob/master/src/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs
void GLManagerNative_Windows::_nvapi_disable_threaded_optimization() {
- HMODULE nvapi = 0;
+ HMODULE nvapi = nullptr;
#ifdef _WIN64
nvapi = LoadLibraryA("nvapi64.dll");
#else
nvapi = LoadLibraryA("nvapi.dll");
#endif
- if (nvapi == NULL) {
+ if (nvapi == nullptr) {
return;
}
- void *(__cdecl * NvAPI_QueryInterface)(unsigned int interface_id) = 0;
+ void *(__cdecl * NvAPI_QueryInterface)(unsigned int interface_id) = nullptr;
NvAPI_QueryInterface = (void *(__cdecl *)(unsigned int))(void *)GetProcAddress(nvapi, "nvapi_QueryInterface");
- if (NvAPI_QueryInterface == NULL) {
+ if (NvAPI_QueryInterface == nullptr) {
print_verbose("Error getting NVAPI NvAPI_QueryInterface");
return;
}
@@ -176,7 +176,7 @@ void GLManagerNative_Windows::_nvapi_disable_threaded_optimization() {
Char16String app_executable_name_u16 = app_executable_name.utf16();
Char16String app_friendly_name_u16 = app_friendly_name.utf16();
- NvDRSProfileHandle profile_handle = 0;
+ NvDRSProfileHandle profile_handle = nullptr;
int profile_status = NvAPI_DRS_FindProfileByName(session_handle, (NvU16 *)(app_profile_name_u16.ptrw()), &profile_handle);
@@ -195,7 +195,7 @@ void GLManagerNative_Windows::_nvapi_disable_threaded_optimization() {
}
}
- NvDRSProfileHandle app_profile_handle = 0;
+ NvDRSProfileHandle app_profile_handle = nullptr;
NVDRS_APPLICATION_V4 app;
app.version = NVDRS_APPLICATION_VER_V4;
@@ -362,14 +362,14 @@ Error GLManagerNative_Windows::_create_context(GLWindow &win, GLDisplay &gl_disp
if (wglCreateContextAttribsARB == nullptr) //OpenGL 3.0 is not supported
{
gd_wglDeleteContext(gl_display.hRC);
- gl_display.hRC = 0;
+ gl_display.hRC = nullptr;
return ERR_CANT_CREATE;
}
- HGLRC new_hRC = wglCreateContextAttribsARB(win.hDC, 0, attribs);
+ HGLRC new_hRC = wglCreateContextAttribsARB(win.hDC, nullptr, attribs);
if (!new_hRC) {
gd_wglDeleteContext(gl_display.hRC);
- gl_display.hRC = 0;
+ gl_display.hRC = nullptr;
return ERR_CANT_CREATE;
}
@@ -384,7 +384,7 @@ Error GLManagerNative_Windows::_create_context(GLWindow &win, GLDisplay &gl_disp
{
ERR_PRINT("Could not attach OpenGL context to newly created window with replaced OpenGL context: " + format_error_message(GetLastError()));
gd_wglDeleteContext(gl_display.hRC);
- gl_display.hRC = 0;
+ gl_display.hRC = nullptr;
return ERR_CANT_CREATE;
}
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 93d1ffeac1..152b9ac10f 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -329,7 +329,7 @@ void debug_dynamic_library_check_dependencies(const String &p_root_path, const S
if (import_desc) {
for (; import_desc->Name && import_desc->FirstThunk; import_desc++) {
char16_t full_name_wc[MAX_PATH];
- const char *name_cs = (const char *)ImageRvaToVa(loaded_image.FileHeader, loaded_image.MappedAddress, import_desc->Name, 0);
+ const char *name_cs = (const char *)ImageRvaToVa(loaded_image.FileHeader, loaded_image.MappedAddress, import_desc->Name, nullptr);
String name = String(name_cs);
if (name.begins_with("api-ms-win-")) {
r_checked.insert(name);
@@ -463,9 +463,9 @@ Vector<String> OS_Windows::get_video_adapter_driver_info() const {
REFCLSID clsid = CLSID_WbemLocator; // Unmarshaler CLSID
REFIID uuid = IID_IWbemLocator; // Interface UUID
- IWbemLocator *wbemLocator = NULL; // to get the services
- IWbemServices *wbemServices = NULL; // to get the class
- IEnumWbemClassObject *iter = NULL;
+ IWbemLocator *wbemLocator = nullptr; // to get the services
+ IWbemServices *wbemServices = nullptr; // to get the class
+ IEnumWbemClassObject *iter = nullptr;
IWbemClassObject *pnpSDriverObject[1]; // contains driver name, version, etc.
String driver_name;
String driver_version;
@@ -475,12 +475,12 @@ Vector<String> OS_Windows::get_video_adapter_driver_info() const {
return Vector<String>();
}
- HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, uuid, (LPVOID *)&wbemLocator);
+ HRESULT hr = CoCreateInstance(clsid, nullptr, CLSCTX_INPROC_SERVER, uuid, (LPVOID *)&wbemLocator);
if (hr != S_OK) {
return Vector<String>();
}
BSTR resource_name = SysAllocString(L"root\\CIMV2");
- hr = wbemLocator->ConnectServer(resource_name, NULL, NULL, NULL, 0, NULL, NULL, &wbemServices);
+ hr = wbemLocator->ConnectServer(resource_name, nullptr, nullptr, nullptr, 0, nullptr, nullptr, &wbemServices);
SysFreeString(resource_name);
SAFE_RELEASE(wbemLocator) // from now on, use `wbemServices`
@@ -492,7 +492,7 @@ Vector<String> OS_Windows::get_video_adapter_driver_info() const {
const String gpu_device_class_query = vformat("SELECT * FROM Win32_PnPSignedDriver WHERE DeviceName = \"%s\"", device_name);
BSTR query = SysAllocString((const WCHAR *)gpu_device_class_query.utf16().get_data());
BSTR query_lang = SysAllocString(L"WQL");
- hr = wbemServices->ExecQuery(query_lang, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &iter);
+ hr = wbemServices->ExecQuery(query_lang, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, nullptr, &iter);
SysFreeString(query_lang);
SysFreeString(query);
if (hr == S_OK) {
@@ -504,13 +504,13 @@ Vector<String> OS_Windows::get_video_adapter_driver_info() const {
VariantInit(&dn);
BSTR object_name = SysAllocString(L"DriverName");
- hr = pnpSDriverObject[0]->Get(object_name, 0, &dn, NULL, NULL);
+ hr = pnpSDriverObject[0]->Get(object_name, 0, &dn, nullptr, nullptr);
SysFreeString(object_name);
if (hr == S_OK) {
String d_name = String(V_BSTR(&dn));
if (d_name.is_empty()) {
object_name = SysAllocString(L"DriverProviderName");
- hr = pnpSDriverObject[0]->Get(object_name, 0, &dn, NULL, NULL);
+ hr = pnpSDriverObject[0]->Get(object_name, 0, &dn, nullptr, nullptr);
SysFreeString(object_name);
if (hr == S_OK) {
driver_name = String(V_BSTR(&dn));
@@ -520,7 +520,7 @@ Vector<String> OS_Windows::get_video_adapter_driver_info() const {
}
} else {
object_name = SysAllocString(L"DriverProviderName");
- hr = pnpSDriverObject[0]->Get(object_name, 0, &dn, NULL, NULL);
+ hr = pnpSDriverObject[0]->Get(object_name, 0, &dn, nullptr, nullptr);
SysFreeString(object_name);
if (hr == S_OK) {
driver_name = String(V_BSTR(&dn));
@@ -530,7 +530,7 @@ Vector<String> OS_Windows::get_video_adapter_driver_info() const {
VARIANT dv;
VariantInit(&dv);
object_name = SysAllocString(L"DriverVersion");
- hr = pnpSDriverObject[0]->Get(object_name, 0, &dv, NULL, NULL);
+ hr = pnpSDriverObject[0]->Get(object_name, 0, &dv, nullptr, nullptr);
SysFreeString(object_name);
if (hr == S_OK) {
driver_version = String(V_BSTR(&dv));
@@ -783,7 +783,7 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
DWORD read = 0;
for (;;) { // Read StdOut and StdErr from pipe.
bytes.resize(bytes_in_buffer + CHUNK_SIZE);
- const bool success = ReadFile(pipe[0], bytes.ptr() + bytes_in_buffer, CHUNK_SIZE, &read, NULL);
+ const bool success = ReadFile(pipe[0], bytes.ptr() + bytes_in_buffer, CHUNK_SIZE, &read, nullptr);
if (!success || read == 0) {
break;
}
@@ -873,7 +873,7 @@ Error OS_Windows::kill(const ProcessID &p_pid) {
CloseHandle(pi.hThread);
} else {
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, false, (DWORD)p_pid);
- if (hProcess != NULL) {
+ if (hProcess != nullptr) {
ret = TerminateProcess(hProcess, 0);
CloseHandle(hProcess);
@@ -1455,7 +1455,7 @@ String OS_Windows::get_processor_name() const {
WCHAR buffer[256];
DWORD buffer_len = 256;
DWORD vtype = REG_SZ;
- if (RegQueryValueExW(hkey, L"ProcessorNameString", NULL, &vtype, (LPBYTE)buffer, &buffer_len) == ERROR_SUCCESS) {
+ if (RegQueryValueExW(hkey, L"ProcessorNameString", nullptr, &vtype, (LPBYTE)buffer, &buffer_len) == ERROR_SUCCESS) {
RegCloseKey(hkey);
return String::utf16((const char16_t *)buffer, buffer_len).strip_edges();
} else {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 7e7d23a2a8..351cb32c9b 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -69,7 +69,7 @@
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4
#endif
-template <class T>
+template <typename T>
class ComAutoreleaseRef {
public:
T *reference = nullptr;
diff --git a/platform/windows/tts_windows.cpp b/platform/windows/tts_windows.cpp
index 11d63d85ee..39a8f3e120 100644
--- a/platform/windows/tts_windows.cpp
+++ b/platform/windows/tts_windows.cpp
@@ -35,7 +35,7 @@ TTS_Windows *TTS_Windows::singleton = nullptr;
void __stdcall TTS_Windows::speech_event_callback(WPARAM wParam, LPARAM lParam) {
TTS_Windows *tts = TTS_Windows::get_singleton();
SPEVENT event;
- while (tts->synth->GetEvents(1, &event, NULL) == S_OK) {
+ while (tts->synth->GetEvents(1, &event, nullptr) == S_OK) {
uint32_t stream_num = (uint32_t)event.ulStreamNum;
if (tts->ids.has(stream_num)) {
if (event.eEventId == SPEI_START_INPUT_STREAM) {
@@ -82,7 +82,7 @@ void TTS_Windows::_update_tts() {
if (SUCCEEDED(hr)) {
hr = cpEnum->GetCount(&ulCount);
while (SUCCEEDED(hr) && ulCount--) {
- wchar_t *w_id = 0L;
+ wchar_t *w_id = nullptr;
hr = cpEnum->Next(1, &cpVoiceToken, nullptr);
cpVoiceToken->GetId(&w_id);
if (String::utf16((const char16_t *)w_id) == message.voice) {
diff --git a/platform/windows/wgl_detect_version.cpp b/platform/windows/wgl_detect_version.cpp
index 49da4b58c7..12dd6f6ee6 100644
--- a/platform/windows/wgl_detect_version.cpp
+++ b/platform/windows/wgl_detect_version.cpp
@@ -140,7 +140,7 @@ Dictionary detect_wgl() {
PFNWGLCREATECONTEXTATTRIBSARBPROC gd_wglCreateContextAttribsARB = nullptr;
gd_wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)gd_wglGetProcAddress("wglCreateContextAttribsARB");
if (gd_wglCreateContextAttribsARB) {
- HGLRC new_hRC = gd_wglCreateContextAttribsARB(hDC, 0, attribs);
+ HGLRC new_hRC = gd_wglCreateContextAttribsARB(hDC, nullptr, attribs);
if (new_hRC) {
if (gd_wglMakeCurrent(hDC, new_hRC)) {
PFNWGLGETSTRINGPROC gd_wglGetString = (PFNWGLGETSTRINGPROC)GetProcAddress(module, "glGetString");
diff --git a/scene/main/node.h b/scene/main/node.h
index 7cc0f7b370..57a7278e73 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -57,7 +57,7 @@ protected:
MTFlag() :
mt{} {}
};
- template <class T>
+ template <typename T>
union MTNumeric {
SafeNumeric<T> mt;
T st;
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 079101f679..cd530f100e 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -1041,7 +1041,7 @@ bool Animation::track_get_interpolation_loop_wrap(int p_track) const {
return tracks[p_track]->loop_wrap;
}
-template <class T, class V>
+template <typename T, typename V>
int Animation::_insert(double p_time, T &p_keys, const V &p_value) {
int idx = p_keys.size();
@@ -1065,7 +1065,7 @@ int Animation::_insert(double p_time, T &p_keys, const V &p_value) {
return -1;
}
-template <class T>
+template <typename T>
void Animation::_clear(T &p_keys) {
p_keys.clear();
}
@@ -2331,7 +2331,7 @@ void Animation::track_set_key_transition(int p_track, int p_key_idx, real_t p_tr
emit_changed();
}
-template <class K>
+template <typename K>
int Animation::_find(const Vector<K> &p_keys, double p_time, bool p_backward, bool p_limit) const {
int len = p_keys.size();
if (len == 0) {
@@ -2451,7 +2451,7 @@ Variant Animation::_cubic_interpolate_angle_in_time(const Variant &p_pre_a, cons
return _cubic_interpolate_in_time(p_pre_a, p_a, p_b, p_post_b, p_c, p_pre_a_t, p_b_t, p_post_b_t);
}
-template <class T>
+template <typename T>
T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool p_backward) const {
int len = _find(p_keys, length) + 1; // try to find last key (there may be more past the end)
@@ -2693,7 +2693,7 @@ Animation::UpdateMode Animation::value_track_get_update_mode(int p_track) const
return vt->update_mode;
}
-template <class T>
+template <typename T>
void Animation::_track_get_key_indices_in_range(const Vector<T> &p_array, double from_time, double to_time, List<int> *p_indices, bool p_is_backward) const {
int len = p_array.size();
if (len == 0) {
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 5b27958005..d3df8d03e5 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -120,7 +120,7 @@ private:
};
// Transform key holds either Vector3 or Quaternion.
- template <class T>
+ template <typename T>
struct TKey : public Key {
T value;
};
@@ -235,13 +235,13 @@ private:
Vector<Track *> tracks;
- template <class T>
+ template <typename T>
void _clear(T &p_keys);
- template <class T, class V>
+ template <typename T, typename V>
int _insert(double p_time, T &p_keys, const V &p_value);
- template <class K>
+ template <typename K>
inline int _find(const Vector<K> &p_keys, double p_time, bool p_backward = false, bool p_limit = false) const;
@@ -257,10 +257,10 @@ private:
_FORCE_INLINE_ real_t _cubic_interpolate_in_time(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
_FORCE_INLINE_ Variant _cubic_interpolate_angle_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
- template <class T>
+ template <typename T>
_FORCE_INLINE_ T _interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool p_backward = false) const;
- template <class T>
+ template <typename T>
_FORCE_INLINE_ void _track_get_key_indices_in_range(const Vector<T> &p_array, double from_time, double to_time, List<int> *p_indices, bool p_is_backward) const;
double length = 1.0;
diff --git a/scene/resources/audio_stream_wav.cpp b/scene/resources/audio_stream_wav.cpp
index b6e6493b68..0185c6ef85 100644
--- a/scene/resources/audio_stream_wav.cpp
+++ b/scene/resources/audio_stream_wav.cpp
@@ -86,7 +86,7 @@ void AudioStreamPlaybackWAV::seek(double p_time) {
offset = uint64_t(p_time * base->mix_rate) << MIX_FRAC_BITS;
}
-template <class Depth, bool is_stereo, bool is_ima_adpcm>
+template <typename Depth, bool is_stereo, bool is_ima_adpcm>
void AudioStreamPlaybackWAV::do_resample(const Depth *p_src, AudioFrame *p_dst, int64_t &p_offset, int32_t &p_increment, uint32_t p_amount, IMA_ADPCM_State *p_ima_adpcm) {
// this function will be compiled branchless by any decent compiler
diff --git a/scene/resources/audio_stream_wav.h b/scene/resources/audio_stream_wav.h
index f150a17d21..959d1ceca0 100644
--- a/scene/resources/audio_stream_wav.h
+++ b/scene/resources/audio_stream_wav.h
@@ -60,7 +60,7 @@ class AudioStreamPlaybackWAV : public AudioStreamPlayback {
friend class AudioStreamWAV;
Ref<AudioStreamWAV> base;
- template <class Depth, bool is_stereo, bool is_ima_adpcm>
+ template <typename Depth, bool is_stereo, bool is_ima_adpcm>
void do_resample(const Depth *p_src, AudioFrame *p_dst, int64_t &p_offset, int32_t &p_increment, uint32_t p_amount, IMA_ADPCM_State *p_ima_adpcm);
public:
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index f2efa7fcba..bc8e0b9015 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -1417,6 +1417,10 @@ static const char32_t _oem_to_unicode[][129] = {
};
Error FontFile::load_bitmap_font(const String &p_path) {
+ return _load_bitmap_font(p_path, nullptr);
+}
+
+Error FontFile::_load_bitmap_font(const String &p_path, List<String> *r_image_files) {
reset_state();
antialiasing = TextServer::FONT_ANTIALIASING_NONE;
@@ -1558,6 +1562,9 @@ Error FontFile::load_bitmap_font(const String &p_path) {
img.instantiate();
Error err = ImageLoader::load_image(file, img);
ERR_FAIL_COND_V_MSG(err != OK, ERR_FILE_CANT_READ, vformat("Can't load font texture: %s.", file));
+ if (r_image_files) {
+ r_image_files->push_back(file);
+ }
if (packed) {
if (ch[3] == 0) { // 4 x 8 bit monochrome, no outline
@@ -1849,6 +1856,10 @@ Error FontFile::load_bitmap_font(const String &p_path) {
img.instantiate();
Error err = ImageLoader::load_image(file, img);
ERR_FAIL_COND_V_MSG(err != OK, ERR_FILE_CANT_READ, vformat("Can't load font texture: %s.", file));
+ if (r_image_files) {
+ r_image_files->push_back(file);
+ }
+
if (packed) {
if (ch[3] == 0) { // 4 x 8 bit monochrome, no outline
outline = 0;
diff --git a/scene/resources/font.h b/scene/resources/font.h
index a435d14a02..1878539a3f 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -227,6 +227,8 @@ protected:
virtual void reset_state() override;
public:
+ Error _load_bitmap_font(const String &p_path, List<String> *r_image_files);
+
Error load_bitmap_font(const String &p_path);
Error load_dynamic_font(const String &p_path);
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 44c7d2e0d9..b381096df8 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -661,20 +661,19 @@ void BaseMaterial3D::_update_shader() {
}
if (flags[FLAG_USE_TEXTURE_REPEAT]) {
- texfilter_str += ",repeat_enable";
- texfilter_height_str += ",repeat_enable";
+ texfilter_str += ", repeat_enable";
+ texfilter_height_str += ", repeat_enable";
} else {
- texfilter_str += ",repeat_disable";
- texfilter_height_str += ",repeat_disable";
+ texfilter_str += ", repeat_disable";
+ texfilter_height_str += ", repeat_disable";
}
- //must create a shader!
-
// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
String code = vformat(
"// NOTE: Shader automatically converted from " VERSION_NAME " " VERSION_FULL_CONFIG "'s %s.\n\n",
orm ? "ORMMaterial3D" : "StandardMaterial3D");
+ // Define shader type and render mode based on property values.
code += "shader_type spatial;\nrender_mode ";
switch (blend_mode) {
case BLEND_MODE_MIX:
@@ -700,13 +699,13 @@ void BaseMaterial3D::_update_shader() {
switch (ddm) {
case DEPTH_DRAW_OPAQUE_ONLY:
- code += ",depth_draw_opaque";
+ code += ", depth_draw_opaque";
break;
case DEPTH_DRAW_ALWAYS:
- code += ",depth_draw_always";
+ code += ", depth_draw_always";
break;
case DEPTH_DRAW_DISABLED:
- code += ",depth_draw_never";
+ code += ", depth_draw_never";
break;
case DEPTH_DRAW_MAX:
break; // Internal value, skip.
@@ -714,238 +713,291 @@ void BaseMaterial3D::_update_shader() {
switch (cull_mode) {
case CULL_BACK:
- code += ",cull_back";
+ code += ", cull_back";
break;
case CULL_FRONT:
- code += ",cull_front";
+ code += ", cull_front";
break;
case CULL_DISABLED:
- code += ",cull_disabled";
+ code += ", cull_disabled";
break;
case CULL_MAX:
break; // Internal value, skip.
}
switch (diffuse_mode) {
case DIFFUSE_BURLEY:
- code += ",diffuse_burley";
+ code += ", diffuse_burley";
break;
case DIFFUSE_LAMBERT:
- code += ",diffuse_lambert";
+ code += ", diffuse_lambert";
break;
case DIFFUSE_LAMBERT_WRAP:
- code += ",diffuse_lambert_wrap";
+ code += ", diffuse_lambert_wrap";
break;
case DIFFUSE_TOON:
- code += ",diffuse_toon";
+ code += ", diffuse_toon";
break;
case DIFFUSE_MAX:
break; // Internal value, skip.
}
switch (specular_mode) {
case SPECULAR_SCHLICK_GGX:
- code += ",specular_schlick_ggx";
+ code += ", specular_schlick_ggx";
break;
case SPECULAR_TOON:
- code += ",specular_toon";
+ code += ", specular_toon";
break;
case SPECULAR_DISABLED:
- code += ",specular_disabled";
+ code += ", specular_disabled";
break;
case SPECULAR_MAX:
break; // Internal value, skip.
}
if (features[FEATURE_SUBSURFACE_SCATTERING] && flags[FLAG_SUBSURFACE_MODE_SKIN]) {
- code += ",sss_mode_skin";
+ code += ", sss_mode_skin";
}
if (shading_mode == SHADING_MODE_UNSHADED) {
- code += ",unshaded";
+ code += ", unshaded";
}
if (flags[FLAG_DISABLE_DEPTH_TEST]) {
- code += ",depth_test_disabled";
+ code += ", depth_test_disabled";
}
if (flags[FLAG_PARTICLE_TRAILS_MODE]) {
- code += ",particle_trails";
+ code += ", particle_trails";
}
if (shading_mode == SHADING_MODE_PER_VERTEX) {
- code += ",vertex_lighting";
+ code += ", vertex_lighting";
}
if (flags[FLAG_DONT_RECEIVE_SHADOWS]) {
- code += ",shadows_disabled";
+ code += ", shadows_disabled";
}
if (flags[FLAG_DISABLE_AMBIENT_LIGHT]) {
- code += ",ambient_light_disabled";
+ code += ", ambient_light_disabled";
}
if (flags[FLAG_USE_SHADOW_TO_OPACITY]) {
- code += ",shadow_to_opacity";
+ code += ", shadow_to_opacity";
}
if (flags[FLAG_DISABLE_FOG]) {
- code += ",fog_disabled";
+ code += ", fog_disabled";
}
if (transparency == TRANSPARENCY_ALPHA_DEPTH_PRE_PASS) {
- code += ",depth_prepass_alpha";
+ code += ", depth_prepass_alpha";
}
- // Although its technically possible to do alpha antialiasing without using alpha hash or alpha scissor,
+ // Although it's technically possible to do alpha antialiasing without using alpha hash or alpha scissor,
// it is restricted in the base material because it has no use, and abusing it with regular Alpha blending can
- // saturate the MSAA mask
+ // saturate the MSAA mask.
if (transparency == TRANSPARENCY_ALPHA_HASH || transparency == TRANSPARENCY_ALPHA_SCISSOR) {
- // alpha antialiasing is only useful in ALPHA_HASH or ALPHA_SCISSOR
+ // Alpha antialiasing is only useful with ALPHA_HASH or ALPHA_SCISSOR.
if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) {
- code += ",alpha_to_coverage";
+ code += ", alpha_to_coverage";
} else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) {
- code += ",alpha_to_coverage_and_one";
+ code += ", alpha_to_coverage_and_one";
}
}
code += ";\n";
- code += "uniform vec4 albedo : source_color;\n";
- code += "uniform sampler2D texture_albedo : source_color," + texfilter_str + ";\n";
+ // Generate list of uniforms.
+ code += vformat(R"(
+uniform vec4 albedo : source_color;
+uniform sampler2D texture_albedo : source_color, %s;
+)",
+ texfilter_str);
+
if (grow_enabled) {
- code += "uniform float grow;\n";
+ code += "uniform float grow : hint_range(-16.0, 16.0, 0.001);\n";
}
if (proximity_fade_enabled) {
- code += "uniform float proximity_fade_distance;\n";
+ code += "uniform float proximity_fade_distance : hint_range(0.0, 4096.0, 0.01);\n";
}
if (distance_fade != DISTANCE_FADE_DISABLED) {
- code += "uniform float distance_fade_min;\n";
- code += "uniform float distance_fade_max;\n";
+ code += R"(
+uniform float distance_fade_min : hint_range(0.0, 4096.0, 0.01);
+uniform float distance_fade_max : hint_range(0.0, 4096.0, 0.01);
+)";
}
if (flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
- code += "uniform float msdf_pixel_range;\n";
- code += "uniform float msdf_outline_size;\n";
+ code += R"(
+uniform float msdf_pixel_range : hint_range(1.0, 100.0, 1.0);
+uniform float msdf_outline_size : hint_range(0.0, 250.0, 1.0);
+)";
}
- // alpha scissor is only valid if there is not antialiasing edge
- // alpha hash is valid whenever, but not with alpha scissor
+ // Alpha scissor is only valid if there is no antialiasing edge.
+ // Alpha hash is valid whenever, but not with alpha scissor.
if (transparency == TRANSPARENCY_ALPHA_SCISSOR) {
- code += "uniform float alpha_scissor_threshold;\n";
+ code += "uniform float alpha_scissor_threshold : hint_range(0.0, 1.0, 0.001);\n";
} else if (transparency == TRANSPARENCY_ALPHA_HASH) {
- code += "uniform float alpha_hash_scale;\n";
+ code += "uniform float alpha_hash_scale : hint_range(0.0, 2.0, 0.01);\n";
}
- // if alpha antialiasing isn't off, add in the edge variable
+ // If alpha antialiasing isn't off, add in the edge variable.
if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF &&
(transparency == TRANSPARENCY_ALPHA_SCISSOR || transparency == TRANSPARENCY_ALPHA_HASH)) {
- code += "uniform float alpha_antialiasing_edge;\n";
- code += "uniform ivec2 albedo_texture_size;\n";
+ code += R"(
+uniform float alpha_antialiasing_edge : hint_range(0.0, 1.0, 0.01);
+uniform ivec2 albedo_texture_size;
+)";
}
- code += "uniform float point_size : hint_range(0,128);\n";
+ code += "uniform float point_size : hint_range(0.1, 128.0, 0.1);\n";
- //TODO ALL HINTS
if (!orm) {
- code += "uniform float roughness : hint_range(0,1);\n";
- code += "uniform sampler2D texture_metallic : hint_default_white," + texfilter_str + ";\n";
- code += "uniform vec4 metallic_texture_channel;\n";
+ code += vformat(R"(
+uniform float roughness : hint_range(0.0, 1.0);
+uniform sampler2D texture_metallic : hint_default_white, %s;
+uniform vec4 metallic_texture_channel;
+)",
+ texfilter_str);
switch (roughness_texture_channel) {
case TEXTURE_CHANNEL_RED: {
- code += "uniform sampler2D texture_roughness : hint_roughness_r," + texfilter_str + ";\n";
+ code += vformat("uniform sampler2D texture_roughness : hint_roughness_r, %s;\n", texfilter_str);
} break;
case TEXTURE_CHANNEL_GREEN: {
- code += "uniform sampler2D texture_roughness : hint_roughness_g," + texfilter_str + ";\n";
+ code += vformat("uniform sampler2D texture_roughness : hint_roughness_g, %s;\n", texfilter_str);
} break;
case TEXTURE_CHANNEL_BLUE: {
- code += "uniform sampler2D texture_roughness : hint_roughness_b," + texfilter_str + ";\n";
+ code += vformat("uniform sampler2D texture_roughness : hint_roughness_b, %s;\n", texfilter_str);
} break;
case TEXTURE_CHANNEL_ALPHA: {
- code += "uniform sampler2D texture_roughness : hint_roughness_a," + texfilter_str + ";\n";
+ code += vformat("uniform sampler2D texture_roughness : hint_roughness_a, %s;\n", texfilter_str);
} break;
case TEXTURE_CHANNEL_GRAYSCALE: {
- code += "uniform sampler2D texture_roughness : hint_roughness_gray," + texfilter_str + ";\n";
+ code += vformat("uniform sampler2D texture_roughness : hint_roughness_gray, %s;\n", texfilter_str);
} break;
case TEXTURE_CHANNEL_MAX:
break; // Internal value, skip.
}
- code += "uniform float specular;\n";
- code += "uniform float metallic;\n";
+ code += R"(
+uniform float specular : hint_range(0.0, 1.0, 0.01);
+uniform float metallic : hint_range(0.0, 1.0, 0.01);
+)";
} else {
- code += "uniform sampler2D texture_orm : hint_roughness_g," + texfilter_str + ";\n";
+ code += "uniform sampler2D texture_orm : hint_roughness_g, " + texfilter_str + ";\n";
}
if (billboard_mode == BILLBOARD_PARTICLES) {
- code += "uniform int particles_anim_h_frames;\n";
- code += "uniform int particles_anim_v_frames;\n";
- code += "uniform bool particles_anim_loop;\n";
+ code += R"(
+uniform int particles_anim_h_frames : hint_range(1, 128);
+uniform int particles_anim_v_frames : hint_range(1, 128);
+uniform bool particles_anim_loop;
+)";
}
if (features[FEATURE_EMISSION]) {
- code += "uniform sampler2D texture_emission : source_color, hint_default_black," + texfilter_str + ";\n";
- code += "uniform vec4 emission : source_color;\n";
- code += "uniform float emission_energy;\n";
+ code += vformat(R"(
+uniform sampler2D texture_emission : source_color, hint_default_black, %s;
+uniform vec4 emission : source_color;
+uniform float emission_energy : hint_range(0.0, 100.0, 0.01);
+)",
+ texfilter_str);
}
if (features[FEATURE_REFRACTION]) {
- code += "uniform sampler2D texture_refraction : " + texfilter_str + ";\n";
- code += "uniform float refraction : hint_range(-16,16);\n";
- code += "uniform vec4 refraction_texture_channel;\n";
+ code += vformat(R"(
+uniform sampler2D texture_refraction : %s;
+uniform float refraction : hint_range(-1.0, 1.0, 0.001);
+uniform vec4 refraction_texture_channel;
+)",
+ texfilter_str);
}
if (features[FEATURE_REFRACTION]) {
- code += "uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_linear_mipmap;";
+ code += "uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_linear_mipmap;\n";
}
if (proximity_fade_enabled) {
- code += "uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest;";
+ code += "uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest;\n";
}
if (features[FEATURE_NORMAL_MAPPING]) {
- code += "uniform sampler2D texture_normal : hint_roughness_normal," + texfilter_str + ";\n";
- code += "uniform float normal_scale : hint_range(-16,16);\n";
+ code += vformat(R"(
+uniform sampler2D texture_normal : hint_roughness_normal, %s;
+uniform float normal_scale : hint_range(-16.0, 16.0);
+)",
+ texfilter_str);
}
if (features[FEATURE_RIM]) {
- code += "uniform float rim : hint_range(0,1);\n";
- code += "uniform float rim_tint : hint_range(0,1);\n";
- code += "uniform sampler2D texture_rim : hint_default_white," + texfilter_str + ";\n";
+ code += vformat(R"(
+uniform float rim : hint_range(0.0, 1.0, 0.01);
+uniform float rim_tint : hint_range(0.0, 1.0, 0.01);
+uniform sampler2D texture_rim : hint_default_white, %s;
+)",
+ texfilter_str);
}
if (features[FEATURE_CLEARCOAT]) {
- code += "uniform float clearcoat : hint_range(0,1);\n";
- code += "uniform float clearcoat_roughness : hint_range(0,1);\n";
- code += "uniform sampler2D texture_clearcoat : hint_default_white," + texfilter_str + ";\n";
+ code += vformat(R"(
+uniform float clearcoat : hint_range(0.0, 1.0, 0.01);
+uniform float clearcoat_roughness : hint_range(0.0, 1.0, 0.01);
+uniform sampler2D texture_clearcoat : hint_default_white, %s;
+)",
+ texfilter_str);
}
if (features[FEATURE_ANISOTROPY]) {
- code += "uniform float anisotropy_ratio : hint_range(0,256);\n";
- code += "uniform sampler2D texture_flowmap : hint_anisotropy," + texfilter_str + ";\n";
+ code += vformat(R"(
+uniform float anisotropy_ratio : hint_range(0.0, 1.0, 0.01);
+uniform sampler2D texture_flowmap : hint_anisotropy, %s;
+)",
+ texfilter_str);
}
if (features[FEATURE_AMBIENT_OCCLUSION]) {
- code += "uniform sampler2D texture_ambient_occlusion : hint_default_white, " + texfilter_str + ";\n";
- code += "uniform vec4 ao_texture_channel;\n";
- code += "uniform float ao_light_affect;\n";
+ code += vformat(R"(
+uniform sampler2D texture_ambient_occlusion : hint_default_white, %s;
+uniform vec4 ao_texture_channel;
+uniform float ao_light_affect : hint_range(0.0, 1.0, 0.01);
+)",
+ texfilter_str);
}
if (features[FEATURE_DETAIL]) {
- code += "uniform sampler2D texture_detail_albedo : source_color," + texfilter_str + ";\n";
- code += "uniform sampler2D texture_detail_normal : hint_normal," + texfilter_str + ";\n";
- code += "uniform sampler2D texture_detail_mask : hint_default_white," + texfilter_str + ";\n";
+ code += vformat(R"(
+uniform sampler2D texture_detail_albedo : source_color, %s;
+uniform sampler2D texture_detail_normal : hint_normal, %s;
+uniform sampler2D texture_detail_mask : hint_default_white, %s;
+)",
+ texfilter_str, texfilter_str, texfilter_str);
}
if (features[FEATURE_SUBSURFACE_SCATTERING]) {
- code += "uniform float subsurface_scattering_strength : hint_range(0,1);\n";
- code += "uniform sampler2D texture_subsurface_scattering : hint_default_white," + texfilter_str + ";\n";
+ code += vformat(R"(
+uniform float subsurface_scattering_strength : hint_range(0.0, 1.0, 0.01);
+uniform sampler2D texture_subsurface_scattering : hint_default_white, %s;
+)",
+ texfilter_str);
}
if (features[FEATURE_SUBSURFACE_TRANSMITTANCE]) {
- code += "uniform vec4 transmittance_color : source_color;\n";
- code += "uniform float transmittance_depth;\n";
- code += "uniform sampler2D texture_subsurface_transmittance : hint_default_white," + texfilter_str + ";\n";
- code += "uniform float transmittance_boost;\n";
+ code += vformat(R"(
+uniform vec4 transmittance_color : source_color;
+uniform float transmittance_depth : hint_range(0.001, 8.0, 0.001);
+uniform sampler2D texture_subsurface_transmittance : hint_default_white, %s;
+uniform float transmittance_boost : hint_range(0.0, 1.0, 0.01);
+)",
+ texfilter_str);
}
if (features[FEATURE_BACKLIGHT]) {
- code += "uniform vec4 backlight : source_color;\n";
- code += "uniform sampler2D texture_backlight : hint_default_black," + texfilter_str + ";\n";
+ code += vformat(R"(
+uniform vec4 backlight : source_color;
+uniform sampler2D texture_backlight : hint_default_black, %s;
+)",
+ texfilter_str);
}
if (features[FEATURE_HEIGHT_MAPPING]) {
- code += "uniform sampler2D texture_heightmap : hint_default_black," + texfilter_height_str + ";\n";
- code += "uniform float heightmap_scale;\n";
- code += "uniform int heightmap_min_layers;\n";
- code += "uniform int heightmap_max_layers;\n";
- code += "uniform vec2 heightmap_flip;\n";
+ code += vformat(R"(
+uniform sampler2D texture_heightmap : hint_default_black, %s;
+uniform float heightmap_scale : hint_range(-16.0, 16.0, 0.001);
+uniform int heightmap_min_layers : hint_range(1, 64);
+uniform int heightmap_max_layers : hint_range(1, 64);
+uniform vec2 heightmap_flip;
+)",
+ texfilter_height_str);
}
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
code += "varying vec3 uv1_triplanar_pos;\n";
@@ -954,132 +1006,216 @@ void BaseMaterial3D::_update_shader() {
code += "varying vec3 uv2_triplanar_pos;\n";
}
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += "uniform float uv1_blend_sharpness;\n";
- code += "varying vec3 uv1_power_normal;\n";
+ code += R"(
+uniform float uv1_blend_sharpness : hint_range(0.0, 150.0, 0.001);
+varying vec3 uv1_power_normal;
+)";
}
if (flags[FLAG_UV2_USE_TRIPLANAR]) {
- code += "uniform float uv2_blend_sharpness;\n";
- code += "varying vec3 uv2_power_normal;\n";
+ code += R"(uniform float uv2_blend_sharpness : hint_range(0.0, 150.0, 0.001);
+varying vec3 uv2_power_normal;
+)";
}
- code += "uniform vec3 uv1_scale;\n";
- code += "uniform vec3 uv1_offset;\n";
- code += "uniform vec3 uv2_scale;\n";
- code += "uniform vec3 uv2_offset;\n";
-
- code += "\n\n";
+ code += R"(
+uniform vec3 uv1_scale;
+uniform vec3 uv1_offset;
+uniform vec3 uv2_scale;
+uniform vec3 uv2_offset;
+)";
- code += "void vertex() {\n";
+ // Generate vertex shader.
+ code += R"(
+void vertex() {)";
if (flags[FLAG_SRGB_VERTEX_COLOR]) {
- code += " if (!OUTPUT_IS_SRGB) {\n";
- code += " COLOR.rgb = mix(pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb * (1.0 / 12.92), lessThan(COLOR.rgb, vec3(0.04045)));\n";
- code += " }\n";
+ code += R"(
+ // Vertex Color is sRGB: Enabled
+ if (!OUTPUT_IS_SRGB) {
+ COLOR.rgb = mix(
+ pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)),
+ COLOR.rgb * (1.0 / 12.92),
+ lessThan(COLOR.rgb, vec3(0.04045)));
+ }
+)";
}
if (flags[FLAG_USE_POINT_SIZE]) {
- code += " POINT_SIZE=point_size;\n";
+ code += R"(
+ // Use Point Size: Enabled
+ POINT_SIZE = point_size;
+)";
}
if (shading_mode == SHADING_MODE_PER_VERTEX) {
- code += " ROUGHNESS=roughness;\n";
+ code += R"(
+ // Shading Mode: Per Vertex
+ ROUGHNESS = roughness;
+)";
}
if (!flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " UV=UV*uv1_scale.xy+uv1_offset.xy;\n";
+ code += R"(
+ UV = UV * uv1_scale.xy + uv1_offset.xy;
+)";
+ }
+
+ if (detail_uv == DETAIL_UV_2 && !flags[FLAG_UV2_USE_TRIPLANAR]) {
+ // Don't add a newline if the UV assignment above is already performed,
+ // so that UV1 and UV2 are closer to each other.
+ if (flags[FLAG_UV1_USE_TRIPLANAR]) {
+ code += "\n";
+ }
+ code += R"( // Detail UV Layer: UV2
+ UV2 = UV2 * uv2_scale.xy + uv2_offset.xy;
+)";
}
switch (billboard_mode) {
case BILLBOARD_DISABLED: {
} break;
case BILLBOARD_ENABLED: {
- // MAIN_CAM_INV_VIEW_MATRIX is inverse of the camera, even on shadow passes: this ensures the billboard faces the camera when casting shadows.
- code += " MODELVIEW_MATRIX = VIEW_MATRIX * mat4(MAIN_CAM_INV_VIEW_MATRIX[0], MAIN_CAM_INV_VIEW_MATRIX[1], MAIN_CAM_INV_VIEW_MATRIX[2], MODEL_MATRIX[3]);\n";
-
+ // `MAIN_CAM_INV_VIEW_MATRIX` is inverse of the camera, even on shadow passes.
+ // This ensures the billboard faces the camera when casting shadows.
+ code += R"(
+ // Billboard Mode: Enabled
+ MODELVIEW_MATRIX = VIEW_MATRIX * mat4(
+ MAIN_CAM_INV_VIEW_MATRIX[0],
+ MAIN_CAM_INV_VIEW_MATRIX[1],
+ MAIN_CAM_INV_VIEW_MATRIX[2],
+ MODEL_MATRIX[3]);
+)";
if (flags[FLAG_BILLBOARD_KEEP_SCALE]) {
- code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(MODEL_MATRIX[0].xyz), 0.0, 0.0, 0.0), vec4(0.0, length(MODEL_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, length(MODEL_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
+ code += R"(
+ // Billboard Keep Scale: Enabled
+ MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(
+ vec4(length(MODEL_MATRIX[0].xyz), 0.0, 0.0, 0.0),
+ vec4(0.0, length(MODEL_MATRIX[1].xyz), 0.0, 0.0),
+ vec4(0.0, 0.0, length(MODEL_MATRIX[2].xyz), 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0));
+)";
}
code += " MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);\n";
} break;
case BILLBOARD_FIXED_Y: {
- // MAIN_CAM_INV_VIEW_MATRIX is inverse of the camera, even on shadow passes: this ensures the billboard faces the camera when casting shadows.
- code += " MODELVIEW_MATRIX = VIEW_MATRIX * mat4(vec4(normalize(cross(vec3(0.0, 1.0, 0.0), MAIN_CAM_INV_VIEW_MATRIX[2].xyz)), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(normalize(cross(MAIN_CAM_INV_VIEW_MATRIX[0].xyz, vec3(0.0, 1.0, 0.0))), 0.0), MODEL_MATRIX[3]);\n";
-
+ // `MAIN_CAM_INV_VIEW_MATRIX` is inverse of the camera, even on shadow passes.
+ // This ensures the billboard faces the camera when casting shadows.
+ code += R"(
+ // Billboard Mode: Y-Billboard
+ MODELVIEW_MATRIX = VIEW_MATRIX * mat4(
+ vec4(normalize(cross(vec3(0.0, 1.0, 0.0), MAIN_CAM_INV_VIEW_MATRIX[2].xyz)), 0.0),
+ vec4(0.0, 1.0, 0.0, 0.0),
+ vec4(normalize(cross(MAIN_CAM_INV_VIEW_MATRIX[0].xyz, vec3(0.0, 1.0, 0.0))), 0.0),
+ MODEL_MATRIX[3]);
+)";
if (flags[FLAG_BILLBOARD_KEEP_SCALE]) {
- code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(MODEL_MATRIX[0].xyz), 0.0, 0.0, 0.0), vec4(0.0, length(MODEL_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, length(MODEL_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
+ code += R"(
+ // Billboard Keep Scale: Enabled
+ MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(
+ vec4(length(MODEL_MATRIX[0].xyz), 0.0, 0.0, 0.0),
+ vec4(0.0, length(MODEL_MATRIX[1].xyz), 0.0, 0.0),
+ vec4(0.0, 0.0, length(MODEL_MATRIX[2].xyz), 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0));
+)";
}
code += " MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);\n";
} break;
case BILLBOARD_PARTICLES: {
- //make billboard
- code += " mat4 mat_world = mat4(normalize(INV_VIEW_MATRIX[0]), normalize(INV_VIEW_MATRIX[1]) ,normalize(INV_VIEW_MATRIX[2]), MODEL_MATRIX[3]);\n";
- //rotate by rotation
- code += " mat_world = mat_world * mat4(vec4(cos(INSTANCE_CUSTOM.x), -sin(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
- //set modelview
+ // Make billboard and rotated by rotation.
+ code += R"(
+ // Billboard Mode: Particles
+ mat4 mat_world = mat4(
+ normalize(INV_VIEW_MATRIX[0]),
+ normalize(INV_VIEW_MATRIX[1]),
+ normalize(INV_VIEW_MATRIX[2]),
+ MODEL_MATRIX[3]);
+ mat_world = mat_world * mat4(
+ vec4(cos(INSTANCE_CUSTOM.x), -sin(INSTANCE_CUSTOM.x), 0.0, 0.0),
+ vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0),
+ vec4(0.0, 0.0, 1.0, 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0));
+)";
+ // Set modelview.
code += " MODELVIEW_MATRIX = VIEW_MATRIX * mat_world;\n";
if (flags[FLAG_BILLBOARD_KEEP_SCALE]) {
- code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(MODEL_MATRIX[0].xyz), 0.0, 0.0, 0.0),vec4(0.0, length(MODEL_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, length(MODEL_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
+ code += R"(
+ // Billboard Keep Scale: Enabled
+ MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(
+ vec4(length(MODEL_MATRIX[0].xyz), 0.0, 0.0, 0.0),
+ vec4(0.0, length(MODEL_MATRIX[1].xyz), 0.0, 0.0),
+ vec4(0.0, 0.0, length(MODEL_MATRIX[2].xyz), 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0));
+)";
}
- //set modelview normal
- code += " MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);\n";
-
- //handle animation
- code += " float h_frames = float(particles_anim_h_frames);\n";
- code += " float v_frames = float(particles_anim_v_frames);\n";
- code += " float particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames);\n";
- code += " float particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames));\n";
- code += " if (!particles_anim_loop) {\n";
- code += " particle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);\n";
- code += " } else {\n";
- code += " particle_frame = mod(particle_frame, particle_total_frames);\n";
- code += " }\n";
- code += " UV /= vec2(h_frames, v_frames);\n";
- code += " UV += vec2(mod(particle_frame, h_frames) / h_frames, floor((particle_frame + 0.5) / h_frames) / v_frames);\n";
+ // Set modelview normal and handle animation.
+ code += R"(
+ MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);
+
+ float h_frames = float(particles_anim_h_frames);
+ float v_frames = float(particles_anim_v_frames);
+ float particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames);
+ float particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames));
+ if (!particles_anim_loop) {
+ particle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);
+ } else {
+ particle_frame = mod(particle_frame, particle_total_frames);
+ }
+ UV /= vec2(h_frames, v_frames);
+ UV += vec2(mod(particle_frame, h_frames) / h_frames, floor((particle_frame + 0.5) / h_frames) / v_frames);
+)";
} break;
case BILLBOARD_MAX:
break; // Internal value, skip.
}
if (flags[FLAG_FIXED_SIZE]) {
- code += " if (PROJECTION_MATRIX[3][3] != 0.0) {\n";
- //orthogonal matrix, try to do about the same
- //with viewport size
- code += " float h = abs(1.0 / (2.0 * PROJECTION_MATRIX[1][1]));\n";
- code += " float sc = (h * 2.0); //consistent with Y-fov\n";
- code += " MODELVIEW_MATRIX[0]*=sc;\n";
- code += " MODELVIEW_MATRIX[1]*=sc;\n";
- code += " MODELVIEW_MATRIX[2]*=sc;\n";
- code += " } else {\n";
- //just scale by depth
- code += " float sc = -(MODELVIEW_MATRIX)[3].z;\n";
- code += " MODELVIEW_MATRIX[0]*=sc;\n";
- code += " MODELVIEW_MATRIX[1]*=sc;\n";
- code += " MODELVIEW_MATRIX[2]*=sc;\n";
- code += " }\n";
+ code += R"(
+ // Fixed Size: Enabled
+ if (PROJECTION_MATRIX[3][3] != 0.0) {
+ // Orthogonal matrix; try to do about the same with viewport size.
+ float h = abs(1.0 / (2.0 * PROJECTION_MATRIX[1][1]));
+ // Consistent with vertical FOV (Keep Height).
+ float sc = (h * 2.0);
+ MODELVIEW_MATRIX[0] *= sc;
+ MODELVIEW_MATRIX[1] *= sc;
+ MODELVIEW_MATRIX[2] *= sc;
+ } else {
+ // Scale by depth.
+ float sc = -(MODELVIEW_MATRIX)[3].z;
+ MODELVIEW_MATRIX[0] *= sc;
+ MODELVIEW_MATRIX[1] *= sc;
+ MODELVIEW_MATRIX[2] *= sc;
}
-
- if (detail_uv == DETAIL_UV_2 && !flags[FLAG_UV2_USE_TRIPLANAR]) {
- code += " UV2=UV2*uv2_scale.xy+uv2_offset.xy;\n";
+)";
}
+
if (flags[FLAG_UV1_USE_TRIPLANAR] || flags[FLAG_UV2_USE_TRIPLANAR]) {
- //generate tangent and binormal in world space
+ // Generate tangent and binormal in world space.
if (flags[FLAG_UV1_USE_WORLD_TRIPLANAR]) {
- code += " vec3 normal = MODEL_NORMAL_MATRIX * NORMAL;\n";
+ code += R"(
+ vec3 normal = MODEL_NORMAL_MATRIX * NORMAL;
+)";
} else {
- code += " vec3 normal = NORMAL;\n";
- }
- code += " TANGENT = vec3(0.0,0.0,-1.0) * abs(normal.x);\n";
- code += " TANGENT+= vec3(1.0,0.0,0.0) * abs(normal.y);\n";
- code += " TANGENT+= vec3(1.0,0.0,0.0) * abs(normal.z);\n";
+ code += R"(
+ vec3 normal = NORMAL;
+)";
+ }
+ code += R"(
+ TANGENT = vec3(0.0, 0.0, -1.0) * abs(normal.x);
+ TANGENT += vec3(1.0, 0.0, 0.0) * abs(normal.y);
+ TANGENT += vec3(1.0, 0.0, 0.0) * abs(normal.z);
+)";
if (flags[FLAG_UV1_USE_WORLD_TRIPLANAR]) {
code += " TANGENT = inverse(MODEL_NORMAL_MATRIX) * normalize(TANGENT);\n";
} else {
code += " TANGENT = normalize(TANGENT);\n";
}
- code += " BINORMAL = vec3(0.0,1.0,0.0) * abs(normal.x);\n";
- code += " BINORMAL+= vec3(0.0,0.0,-1.0) * abs(normal.y);\n";
- code += " BINORMAL+= vec3(0.0,1.0,0.0) * abs(normal.z);\n";
+ code += R"(
+ BINORMAL = vec3(0.0, 1.0, 0.0) * abs(normal.x);
+ BINORMAL += vec3(0.0, 0.0, -1.0) * abs(normal.y);
+ BINORMAL += vec3(0.0, 1.0, 0.0) * abs(normal.z);
+)";
if (flags[FLAG_UV1_USE_WORLD_TRIPLANAR]) {
code += " BINORMAL = inverse(MODEL_NORMAL_MATRIX) * normalize(BINORMAL);\n";
} else {
@@ -1089,58 +1225,89 @@ void BaseMaterial3D::_update_shader() {
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
if (flags[FLAG_UV1_USE_WORLD_TRIPLANAR]) {
- code += " uv1_power_normal=pow(abs(normal),vec3(uv1_blend_sharpness));\n";
- code += " uv1_triplanar_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0f)).xyz * uv1_scale + uv1_offset;\n";
+ code += R"(
+ // UV1 Triplanar: Enabled (with World Triplanar)
+ uv1_power_normal = pow(abs(normal), vec3(uv1_blend_sharpness));
+ uv1_triplanar_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz * uv1_scale + uv1_offset;
+)";
} else {
- code += " uv1_power_normal=pow(abs(NORMAL),vec3(uv1_blend_sharpness));\n";
- code += " uv1_triplanar_pos = VERTEX * uv1_scale + uv1_offset;\n";
+ code += R"(
+ // UV1 Triplanar: Enabled
+ uv1_power_normal = pow(abs(NORMAL), vec3(uv1_blend_sharpness));
+ uv1_triplanar_pos = VERTEX * uv1_scale + uv1_offset;
+)";
}
- code += " uv1_power_normal/=dot(uv1_power_normal,vec3(1.0));\n";
- code += " uv1_triplanar_pos *= vec3(1.0,-1.0, 1.0);\n";
+ code += R"( uv1_power_normal /= dot(uv1_power_normal, vec3(1.0));
+ uv1_triplanar_pos *= vec3(1.0, -1.0, 1.0);
+)";
}
if (flags[FLAG_UV2_USE_TRIPLANAR]) {
if (flags[FLAG_UV2_USE_WORLD_TRIPLANAR]) {
- code += " uv2_power_normal=pow(abs(mat3(MODEL_MATRIX) * NORMAL), vec3(uv2_blend_sharpness));\n";
- code += " uv2_triplanar_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0f)).xyz * uv2_scale + uv2_offset;\n";
+ code += R"(
+ // UV2 Triplanar: Enabled (with World Triplanar)
+ uv2_power_normal = pow(abs(mat3(MODEL_MATRIX) * NORMAL), vec3(uv2_blend_sharpness));
+ uv2_triplanar_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz * uv2_scale + uv2_offset;
+)";
} else {
- code += " uv2_power_normal=pow(abs(NORMAL), vec3(uv2_blend_sharpness));\n";
- code += " uv2_triplanar_pos = VERTEX * uv2_scale + uv2_offset;\n";
+ code += R"(
+ // UV2 Triplanar: Enabled
+ uv2_power_normal = pow(abs(NORMAL), vec3(uv2_blend_sharpness));
+ uv2_triplanar_pos = VERTEX * uv2_scale + uv2_offset;
+)";
}
- code += " uv2_power_normal/=dot(uv2_power_normal,vec3(1.0));\n";
- code += " uv2_triplanar_pos *= vec3(1.0,-1.0, 1.0);\n";
+ code += R"( uv2_power_normal /= dot(uv2_power_normal, vec3(1.0));
+ uv2_triplanar_pos *= vec3(1.0, -1.0, 1.0);
+)";
}
if (grow_enabled) {
- code += " VERTEX+=NORMAL*grow;\n";
+ code += R"(
+ // Grow: Enabled
+ VERTEX += NORMAL * grow;
+)";
}
code += "}\n";
- code += "\n\n";
+
if (flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
- code += "float msdf_median(float r, float g, float b, float a) {\n";
- code += " return min(max(min(r, g), min(max(r, g), b)), a);\n";
- code += "}\n";
+ code += R"(
+float msdf_median(float r, float g, float b, float a) {
+ return min(max(min(r, g), min(max(r, g), b)), a);
+}
+)";
}
- code += "\n\n";
+
if (flags[FLAG_UV1_USE_TRIPLANAR] || flags[FLAG_UV2_USE_TRIPLANAR]) {
- code += "vec4 triplanar_texture(sampler2D p_sampler,vec3 p_weights,vec3 p_triplanar_pos) {\n";
- code += " vec4 samp=vec4(0.0);\n";
- code += " samp+= texture(p_sampler,p_triplanar_pos.xy) * p_weights.z;\n";
- code += " samp+= texture(p_sampler,p_triplanar_pos.xz) * p_weights.y;\n";
- code += " samp+= texture(p_sampler,p_triplanar_pos.zy * vec2(-1.0,1.0)) * p_weights.x;\n";
- code += " return samp;\n";
- code += "}\n";
+ code += R"(
+vec4 triplanar_texture(sampler2D p_sampler, vec3 p_weights, vec3 p_triplanar_pos) {
+ vec4 samp = vec4(0.0);
+ samp += texture(p_sampler, p_triplanar_pos.xy) * p_weights.z;
+ samp += texture(p_sampler, p_triplanar_pos.xz) * p_weights.y;
+ samp += texture(p_sampler, p_triplanar_pos.zy * vec2(-1.0, 1.0)) * p_weights.x;
+ return samp;
+}
+)";
}
- code += "\n\n";
- code += "void fragment() {\n";
+
+ // Generate fragment shader.
+ code += R"(
+void fragment() {)";
if (!flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " vec2 base_uv = UV;\n";
+ code += R"(
+ vec2 base_uv = UV;
+)";
}
if ((features[FEATURE_DETAIL] && detail_uv == DETAIL_UV_2) || (features[FEATURE_AMBIENT_OCCLUSION] && flags[FLAG_AO_ON_UV2]) || (features[FEATURE_EMISSION] && flags[FLAG_EMISSION_ON_UV2])) {
- code += " vec2 base_uv2 = UV2;\n";
+ // Don't add a newline if the UV assignment above is already performed,
+ // so that UV1 and UV2 are closer to each other.
+ if (flags[FLAG_UV1_USE_TRIPLANAR]) {
+ code += "\n";
+ }
+ code += R"( vec2 base_uv2 = UV2;
+)";
}
if (features[FEATURE_HEIGHT_MAPPING] && flags[FLAG_UV1_USE_TRIPLANAR]) {
@@ -1157,42 +1324,57 @@ void BaseMaterial3D::_update_shader() {
}
}
- if (!RenderingServer::get_singleton()->is_low_end() && features[FEATURE_HEIGHT_MAPPING] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //heightmap not supported with triplanar
- code += " {\n";
- code += " vec3 view_dir = normalize(normalize(-VERTEX + EYE_OFFSET) * mat3(TANGENT * heightmap_flip.x, -BINORMAL * heightmap_flip.y, NORMAL));\n"; // binormal is negative due to mikktspace, flip 'unflips' it ;-)
+ // Heightmapping isn't supported at the same time as triplanar mapping.
+ if (!RenderingServer::get_singleton()->is_low_end() && features[FEATURE_HEIGHT_MAPPING] && !flags[FLAG_UV1_USE_TRIPLANAR]) {
+ // Binormal is negative due to mikktspace. Flipping it "unflips" it.
+ code += R"(
+ {
+ // Height: Enabled
+ vec3 view_dir = normalize(normalize(-VERTEX + EYE_OFFSET) * mat3(TANGENT * heightmap_flip.x, -BINORMAL * heightmap_flip.y, NORMAL));
+)";
if (deep_parallax) {
- code += " float num_layers = mix(float(heightmap_max_layers),float(heightmap_min_layers), abs(dot(vec3(0.0, 0.0, 1.0), view_dir)));\n";
- code += " float layer_depth = 1.0 / num_layers;\n";
- code += " float current_layer_depth = 0.0;\n";
// Multiply the heightmap scale by 0.01 to improve heightmap scale usability.
- code += " vec2 P = view_dir.xy * heightmap_scale * 0.01;\n";
- code += " vec2 delta = P / num_layers;\n";
- code += " vec2 ofs = base_uv;\n";
+ code += R"(
+ // Height Deep Parallax: Enabled
+ float num_layers = mix(float(heightmap_max_layers), float(heightmap_min_layers), abs(dot(vec3(0.0, 0.0, 1.0), view_dir)));
+ float layer_depth = 1.0 / num_layers;
+ float current_layer_depth = 0.0;
+ vec2 p = view_dir.xy * heightmap_scale * 0.01;
+ vec2 delta = p / num_layers;
+ vec2 ofs = base_uv;
+)";
if (flags[FLAG_INVERT_HEIGHTMAP]) {
code += " float depth = texture(texture_heightmap, ofs).r;\n";
} else {
code += " float depth = 1.0 - texture(texture_heightmap, ofs).r;\n";
}
- code += " float current_depth = 0.0;\n";
- code += " while(current_depth < depth) {\n";
- code += " ofs -= delta;\n";
+ code += R"(
+ float current_depth = 0.0;
+ while (current_depth < depth) {
+ ofs -= delta;
+)";
if (flags[FLAG_INVERT_HEIGHTMAP]) {
code += " depth = texture(texture_heightmap, ofs).r;\n";
} else {
code += " depth = 1.0 - texture(texture_heightmap, ofs).r;\n";
}
- code += " current_depth += layer_depth;\n";
- code += " }\n";
- code += " vec2 prev_ofs = ofs + delta;\n";
- code += " float after_depth = depth - current_depth;\n";
+ code += R"(
+ current_depth += layer_depth;
+ }
+
+ vec2 prev_ofs = ofs + delta;
+ float after_depth = depth - current_depth;
+)";
if (flags[FLAG_INVERT_HEIGHTMAP]) {
code += " float before_depth = texture(texture_heightmap, prev_ofs).r - current_depth + layer_depth;\n";
} else {
- code += " float before_depth = ( 1.0 - texture(texture_heightmap, prev_ofs).r ) - current_depth + layer_depth;\n";
+ code += " float before_depth = (1.0 - texture(texture_heightmap, prev_ofs).r) - current_depth + layer_depth;\n";
}
- code += " float weight = after_depth / (after_depth - before_depth);\n";
- code += " ofs = mix(ofs,prev_ofs,weight);\n";
+ code += R"(
+ float weight = after_depth / (after_depth - before_depth);
+ ofs = mix(ofs, prev_ofs, weight);
+)";
} else {
if (flags[FLAG_INVERT_HEIGHTMAP]) {
@@ -1206,28 +1388,41 @@ void BaseMaterial3D::_update_shader() {
code += " vec2 ofs = base_uv - view_dir.xy * depth * heightmap_scale * 0.01;\n";
}
- code += " base_uv=ofs;\n";
+ code += " base_uv = ofs;\n";
if (features[FEATURE_DETAIL] && detail_uv == DETAIL_UV_2) {
- code += " base_uv2-=ofs;\n";
+ code += " base_uv2 -= ofs;\n";
}
code += " }\n";
}
if (flags[FLAG_USE_POINT_SIZE]) {
- code += " vec4 albedo_tex = texture(texture_albedo,POINT_COORD);\n";
+ code += R"(
+ // Use Point Size: Enabled
+ vec4 albedo_tex = texture(texture_albedo, POINT_COORD);
+)";
} else {
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " vec4 albedo_tex = triplanar_texture(texture_albedo,uv1_power_normal,uv1_triplanar_pos);\n";
+ code += R"(
+ vec4 albedo_tex = triplanar_texture(texture_albedo, uv1_power_normal, uv1_triplanar_pos);
+)";
} else {
- code += " vec4 albedo_tex = texture(texture_albedo,base_uv);\n";
+ code += R"(
+ vec4 albedo_tex = texture(texture_albedo, base_uv);
+)";
}
}
if (flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
- code += " {\n";
- code += " albedo_tex.rgb = mix(vec3(1.0 + 0.055) * pow(albedo_tex.rgb, vec3(1.0 / 2.4)) - vec3(0.055), vec3(12.92) * albedo_tex.rgb.rgb, lessThan(albedo_tex.rgb, vec3(0.0031308)));\n";
- code += " vec2 msdf_size = vec2(msdf_pixel_range) / vec2(textureSize(texture_albedo, 0));\n";
+ code += R"(
+ {
+ // Albedo Texture MSDF: Enabled
+ albedo_tex.rgb = mix(
+ vec3(1.0 + 0.055) * pow(albedo_tex.rgb, vec3(1.0 / 2.4)) - vec3(0.055),
+ vec3(12.92) * albedo_tex.rgb,
+ lessThan(albedo_tex.rgb, vec3(0.0031308)));
+ vec2 msdf_size = vec2(msdf_pixel_range) / vec2(textureSize(texture_albedo, 0));
+)";
if (flags[FLAG_USE_POINT_SIZE]) {
code += " vec2 dest_size = vec2(1.0) / fwidth(POINT_COORD);\n";
} else {
@@ -1237,120 +1432,175 @@ void BaseMaterial3D::_update_shader() {
code += " vec2 dest_size = vec2(1.0) / fwidth(base_uv);\n";
}
}
- code += " float px_size = max(0.5 * dot(msdf_size, dest_size), 1.0);\n";
- code += " float d = msdf_median(albedo_tex.r, albedo_tex.g, albedo_tex.b, albedo_tex.a) - 0.5;\n";
- code += " if (msdf_outline_size > 0.0) {\n";
- code += " float cr = clamp(msdf_outline_size, 0.0, msdf_pixel_range / 2.0) / msdf_pixel_range;\n";
- code += " albedo_tex.a = clamp((d + cr) * px_size, 0.0, 1.0);\n";
- code += " } else {\n";
- code += " albedo_tex.a = clamp(d * px_size + 0.5, 0.0, 1.0);\n";
- code += " }\n";
- code += " albedo_tex.rgb = vec3(1.0);\n";
- code += " }\n";
+ code += R"(
+ float px_size = max(0.5 * dot(msdf_size, dest_size), 1.0);
+ float d = msdf_median(albedo_tex.r, albedo_tex.g, albedo_tex.b, albedo_tex.a) - 0.5;
+ if (msdf_outline_size > 0.0) {
+ float cr = clamp(msdf_outline_size, 0.0, msdf_pixel_range / 2.0) / msdf_pixel_range;
+ albedo_tex.a = clamp((d + cr) * px_size, 0.0, 1.0);
+ } else {
+ albedo_tex.a = clamp(d * px_size + 0.5, 0.0, 1.0);
+ }
+ albedo_tex.rgb = vec3(1.0);
+ }
+)";
} else if (flags[FLAG_ALBEDO_TEXTURE_FORCE_SRGB]) {
- code += " albedo_tex.rgb = mix(pow((albedo_tex.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)),vec3(2.4)),albedo_tex.rgb.rgb * (1.0 / 12.92),lessThan(albedo_tex.rgb,vec3(0.04045)));\n";
+ code += R"(
+ // Albedo Texture Force sRGB: Enabled
+ albedo_tex.rgb = mix(
+ pow((albedo_tex.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)),
+ albedo_tex.rgb.rgb * (1.0 / 12.92),
+ lessThan(albedo_tex.rgb, vec3(0.04045)));
+)";
}
if (flags[FLAG_ALBEDO_FROM_VERTEX_COLOR]) {
- code += " albedo_tex *= COLOR;\n";
+ code += R"(
+ // Vertex Color Use as Albedo: Enabled
+ albedo_tex *= COLOR;
+
+)";
}
code += " ALBEDO = albedo.rgb * albedo_tex.rgb;\n";
if (!orm) {
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " float metallic_tex = dot(triplanar_texture(texture_metallic,uv1_power_normal,uv1_triplanar_pos),metallic_texture_channel);\n";
+ code += R"(
+ float metallic_tex = dot(triplanar_texture(texture_metallic, uv1_power_normal, uv1_triplanar_pos), metallic_texture_channel);
+)";
} else {
- code += " float metallic_tex = dot(texture(texture_metallic,base_uv),metallic_texture_channel);\n";
+ code += R"(
+ float metallic_tex = dot(texture(texture_metallic, base_uv), metallic_texture_channel);
+)";
}
- code += " METALLIC = metallic_tex * metallic;\n";
+ code += R"( METALLIC = metallic_tex * metallic;
+ SPECULAR = specular;
+)";
switch (roughness_texture_channel) {
case TEXTURE_CHANNEL_RED: {
- code += " vec4 roughness_texture_channel = vec4(1.0,0.0,0.0,0.0);\n";
+ code += R"(
+ vec4 roughness_texture_channel = vec4(1.0, 0.0, 0.0, 0.0);
+)";
} break;
case TEXTURE_CHANNEL_GREEN: {
- code += " vec4 roughness_texture_channel = vec4(0.0,1.0,0.0,0.0);\n";
+ code += R"(
+ vec4 roughness_texture_channel = vec4(0.0, 1.0, 0.0, 0.0);
+)";
} break;
case TEXTURE_CHANNEL_BLUE: {
- code += " vec4 roughness_texture_channel = vec4(0.0,0.0,1.0,0.0);\n";
+ code += R"(
+ vec4 roughness_texture_channel = vec4(0.0, 0.0, 1.0, 0.0);
+)";
} break;
case TEXTURE_CHANNEL_ALPHA: {
- code += " vec4 roughness_texture_channel = vec4(0.0,0.0,0.0,1.0);\n";
+ code += R"(
+ vec4 roughness_texture_channel = vec4(0.0, 0.0, 0.0, 1.0);
+)";
} break;
case TEXTURE_CHANNEL_GRAYSCALE: {
- code += " vec4 roughness_texture_channel = vec4(0.333333,0.333333,0.333333,0.0);\n";
+ code += R"(
+ vec4 roughness_texture_channel = vec4(0.333333, 0.333333, 0.333333, 0.0);
+)";
} break;
case TEXTURE_CHANNEL_MAX:
break; // Internal value, skip.
}
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " float roughness_tex = dot(triplanar_texture(texture_roughness,uv1_power_normal,uv1_triplanar_pos),roughness_texture_channel);\n";
+ code += " float roughness_tex = dot(triplanar_texture(texture_roughness, uv1_power_normal, uv1_triplanar_pos), roughness_texture_channel);\n";
} else {
- code += " float roughness_tex = dot(texture(texture_roughness,base_uv),roughness_texture_channel);\n";
+ code += " float roughness_tex = dot(texture(texture_roughness, base_uv), roughness_texture_channel);\n";
}
- code += " ROUGHNESS = roughness_tex * roughness;\n";
- code += " SPECULAR = specular;\n";
+ code += R"( ROUGHNESS = roughness_tex * roughness;
+)";
} else {
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " vec4 orm_tex = triplanar_texture(texture_orm,uv1_power_normal,uv1_triplanar_pos);\n";
+ code += R"(
+ vec4 orm_tex = triplanar_texture(texture_orm, uv1_power_normal, uv1_triplanar_pos);
+)";
} else {
- code += " vec4 orm_tex = texture(texture_orm,base_uv);\n";
+ code += R"(
+ vec4 orm_tex = texture(texture_orm, base_uv);
+)";
}
- code += " ROUGHNESS = orm_tex.g;\n";
- code += " METALLIC = orm_tex.b;\n";
+ code += R"( ROUGHNESS = orm_tex.g;
+ METALLIC = orm_tex.b;
+)";
}
if (features[FEATURE_NORMAL_MAPPING]) {
+ code += R"(
+ // Normal Map: Enabled
+)";
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " NORMAL_MAP = triplanar_texture(texture_normal,uv1_power_normal,uv1_triplanar_pos).rgb;\n";
+ code += " NORMAL_MAP = triplanar_texture(texture_normal, uv1_power_normal, uv1_triplanar_pos).rgb;\n";
} else {
- code += " NORMAL_MAP = texture(texture_normal,base_uv).rgb;\n";
+ code += " NORMAL_MAP = texture(texture_normal, base_uv).rgb;\n";
}
code += " NORMAL_MAP_DEPTH = normal_scale;\n";
}
if (features[FEATURE_EMISSION]) {
+ code += R"(
+ // Emission: Enabled
+)";
if (flags[FLAG_EMISSION_ON_UV2]) {
if (flags[FLAG_UV2_USE_TRIPLANAR]) {
- code += " vec3 emission_tex = triplanar_texture(texture_emission,uv2_power_normal,uv2_triplanar_pos).rgb;\n";
+ code += " vec3 emission_tex = triplanar_texture(texture_emission, uv2_power_normal, uv2_triplanar_pos).rgb;\n";
} else {
- code += " vec3 emission_tex = texture(texture_emission,base_uv2).rgb;\n";
+ code += " vec3 emission_tex = texture(texture_emission, base_uv2).rgb;\n";
}
} else {
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " vec3 emission_tex = triplanar_texture(texture_emission,uv1_power_normal,uv1_triplanar_pos).rgb;\n";
+ code += " vec3 emission_tex = triplanar_texture(texture_emission, uv1_power_normal, uv1_triplanar_pos).rgb;\n";
} else {
- code += " vec3 emission_tex = texture(texture_emission,base_uv).rgb;\n";
+ code += " vec3 emission_tex = texture(texture_emission, base_uv).rgb;\n";
}
}
if (emission_op == EMISSION_OP_ADD) {
- code += " EMISSION = (emission.rgb+emission_tex)*emission_energy;\n";
+ code += R"( // Emission Operator: Add
+ EMISSION = (emission.rgb + emission_tex) * emission_energy;
+)";
} else {
- code += " EMISSION = (emission.rgb*emission_tex)*emission_energy;\n";
+ code += R"( // Emission Operator: Multiply
+ EMISSION = (emission.rgb * emission_tex) * emission_energy;
+)";
}
}
if (features[FEATURE_REFRACTION]) {
if (features[FEATURE_NORMAL_MAPPING]) {
- code += " vec3 unpacked_normal = NORMAL_MAP;\n";
- code += " unpacked_normal.xy = unpacked_normal.xy * 2.0 - 1.0;\n";
- code += " unpacked_normal.z = sqrt(max(0.0, 1.0 - dot(unpacked_normal.xy, unpacked_normal.xy)));\n";
- code += " vec3 ref_normal = normalize( mix(NORMAL,TANGENT * unpacked_normal.x + BINORMAL * unpacked_normal.y + NORMAL * unpacked_normal.z,NORMAL_MAP_DEPTH) );\n";
+ code += R"(
+ // Refraction: Enabled (with normal map texture)
+ vec3 unpacked_normal = NORMAL_MAP;
+ unpacked_normal.xy = unpacked_normal.xy * 2.0 - 1.0;
+ unpacked_normal.z = sqrt(max(0.0, 1.0 - dot(unpacked_normal.xy, unpacked_normal.xy)));
+ vec3 ref_normal = normalize(mix(
+ NORMAL,
+ TANGENT * unpacked_normal.x + BINORMAL * unpacked_normal.y + NORMAL * unpacked_normal.z,
+ NORMAL_MAP_DEPTH));
+)";
} else {
- code += " vec3 ref_normal = NORMAL;\n";
+ code += R"(
+ // Refraction: Enabled
+ vec3 ref_normal = NORMAL;
+)";
}
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " vec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(triplanar_texture(texture_refraction,uv1_power_normal,uv1_triplanar_pos),refraction_texture_channel) * refraction;\n";
+ code += " vec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(triplanar_texture(texture_refraction, uv1_power_normal, uv1_triplanar_pos), refraction_texture_channel) * refraction;\n";
} else {
- code += " vec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(texture(texture_refraction,base_uv),refraction_texture_channel) * refraction;\n";
+ code += " vec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(texture(texture_refraction, base_uv), refraction_texture_channel) * refraction;\n";
}
- code += " float ref_amount = 1.0 - albedo.a * albedo_tex.a;\n";
- code += " EMISSION += textureLod(screen_texture,ref_ofs,ROUGHNESS * 8.0).rgb * ref_amount * EXPOSURE;\n";
- code += " ALBEDO *= 1.0 - ref_amount;\n";
- code += " ALPHA = 1.0;\n";
+ code += R"(
+ float ref_amount = 1.0 - albedo.a * albedo_tex.a;
+ EMISSION += textureLod(screen_texture, ref_ofs, ROUGHNESS * 8.0).rgb * ref_amount * EXPOSURE;
+ ALBEDO *= 1.0 - ref_amount;
+ // Force transparency on the material (required for refraction).
+ ALPHA = 1.0;
+)";
} else if (transparency != TRANSPARENCY_DISABLED || flags[FLAG_USE_SHADOW_TO_OPACITY] || (distance_fade == DISTANCE_FADE_PIXEL_ALPHA) || proximity_fade_enabled) {
code += " ALPHA *= albedo.a * albedo_tex.a;\n";
@@ -1366,10 +1616,13 @@ void BaseMaterial3D::_update_shader() {
}
if (proximity_fade_enabled) {
- code += " float depth_tex = textureLod(depth_texture,SCREEN_UV,0.0).r;\n";
- code += " vec4 world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV*2.0-1.0,depth_tex,1.0);\n";
- code += " world_pos.xyz/=world_pos.w;\n";
- code += " ALPHA*=clamp(1.0-smoothstep(world_pos.z+proximity_fade_distance,world_pos.z,VERTEX.z),0.0,1.0);\n";
+ code += R"(
+ // Proximity Fade: Enabled
+ float depth_tex = textureLod(depth_texture, SCREEN_UV, 0.0).r;
+ vec4 world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, depth_tex, 1.0);
+ world_pos.xyz /= world_pos.w;
+ ALPHA *= clamp(1.0 - smoothstep(world_pos.z + proximity_fade_distance, world_pos.z, VERTEX.z), 0.0, 1.0);
+)";
}
if (distance_fade != DISTANCE_FADE_DISABLED) {
@@ -1377,72 +1630,96 @@ void BaseMaterial3D::_update_shader() {
// (Z distance), so that the fade is always the same regardless of the camera angle.
if ((distance_fade == DISTANCE_FADE_OBJECT_DITHER || distance_fade == DISTANCE_FADE_PIXEL_DITHER)) {
if (!RenderingServer::get_singleton()->is_low_end()) {
- code += " {\n";
+ code += "\n {";
if (distance_fade == DISTANCE_FADE_OBJECT_DITHER) {
- code += " float fade_distance = length((VIEW_MATRIX * MODEL_MATRIX[3]));\n";
+ code += R"(
+ // Distance Fade: Object Dither
+ float fade_distance = length((VIEW_MATRIX * MODEL_MATRIX[3]));
+)";
} else {
- code += " float fade_distance = length(VERTEX);\n";
+ code += R"(
+ // Distance Fade: Pixel Dither
+ float fade_distance = length(VERTEX);
+)";
}
- // Use interleaved gradient noise, which is fast but still looks good.
- code += " const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);";
- code += " float fade = clamp(smoothstep(distance_fade_min, distance_fade_max, fade_distance), 0.0, 1.0);\n";
- // Use a hard cap to prevent a few stray pixels from remaining when past the fade-out distance.
- code += " if (fade < 0.001 || fade < fract(magic.z * fract(dot(FRAGCOORD.xy, magic.xy)))) {\n";
- code += " discard;\n";
- code += " }\n";
-
- code += " }\n\n";
+ code += R"(
+ // Use interleaved gradient noise, which is fast but still looks good.
+ const vec3 magic = vec3(0.06711056, 0.00583715, 52.9829189);
+ float fade = clamp(smoothstep(distance_fade_min, distance_fade_max, fade_distance), 0.0, 1.0);
+ // Use a hard cap to prevent a few stray pixels from remaining when past the fade-out distance.
+ if (fade < 0.001 || fade < fract(magic.z * fract(dot(FRAGCOORD.xy, magic.xy)))) {
+ discard;
+ }
+ }
+)";
}
-
} else {
- code += " ALPHA *= clamp(smoothstep(distance_fade_min, distance_fade_max, length(VERTEX)), 0.0, 1.0);\n";
+ code += R"(
+ // Distance Fade: Pixel Alpha
+ ALPHA *= clamp(smoothstep(distance_fade_min, distance_fade_max, length(VERTEX)), 0.0, 1.0);
+)";
}
}
if (features[FEATURE_RIM]) {
+ code += R"(
+ // Rim: Enabled
+)";
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " vec2 rim_tex = triplanar_texture(texture_rim,uv1_power_normal,uv1_triplanar_pos).xy;\n";
+ code += " vec2 rim_tex = triplanar_texture(texture_rim, uv1_power_normal, uv1_triplanar_pos).xy;\n";
} else {
- code += " vec2 rim_tex = texture(texture_rim,base_uv).xy;\n";
+ code += " vec2 rim_tex = texture(texture_rim, base_uv).xy;\n";
}
- code += " RIM = rim*rim_tex.x;";
- code += " RIM_TINT = rim_tint*rim_tex.y;\n";
+ code += R"( RIM = rim * rim_tex.x;
+ RIM_TINT = rim_tint * rim_tex.y;
+)";
}
if (features[FEATURE_CLEARCOAT]) {
+ code += R"(
+ // Clearcoat: Enabled
+)";
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " vec2 clearcoat_tex = triplanar_texture(texture_clearcoat,uv1_power_normal,uv1_triplanar_pos).xy;\n";
+ code += " vec2 clearcoat_tex = triplanar_texture(texture_clearcoat, uv1_power_normal, uv1_triplanar_pos).xy;\n";
} else {
- code += " vec2 clearcoat_tex = texture(texture_clearcoat,base_uv).xy;\n";
+ code += " vec2 clearcoat_tex = texture(texture_clearcoat, base_uv).xy;\n";
}
- code += " CLEARCOAT = clearcoat*clearcoat_tex.x;";
- code += " CLEARCOAT_ROUGHNESS = clearcoat_roughness*clearcoat_tex.y;\n";
+ code += R"( CLEARCOAT = clearcoat * clearcoat_tex.x;
+ CLEARCOAT_ROUGHNESS = clearcoat_roughness * clearcoat_tex.y;
+)";
}
if (features[FEATURE_ANISOTROPY]) {
+ code += R"(
+ // Anisotropy: Enabled
+)";
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " vec3 anisotropy_tex = triplanar_texture(texture_flowmap,uv1_power_normal,uv1_triplanar_pos).rga;\n";
+ code += " vec3 anisotropy_tex = triplanar_texture(texture_flowmap, uv1_power_normal, uv1_triplanar_pos).rga;\n";
} else {
- code += " vec3 anisotropy_tex = texture(texture_flowmap,base_uv).rga;\n";
+ code += " vec3 anisotropy_tex = texture(texture_flowmap, base_uv).rga;\n";
}
- code += " ANISOTROPY = anisotropy_ratio*anisotropy_tex.b;\n";
- code += " ANISOTROPY_FLOW = anisotropy_tex.rg*2.0-1.0;\n";
+ code += R"( ANISOTROPY = anisotropy_ratio * anisotropy_tex.b;
+ ANISOTROPY_FLOW = anisotropy_tex.rg * 2.0 - 1.0;
+)";
}
if (features[FEATURE_AMBIENT_OCCLUSION]) {
+ code += R"(
+ // Ambient Occlusion: Enabled
+)";
if (!orm) {
if (flags[FLAG_AO_ON_UV2]) {
if (flags[FLAG_UV2_USE_TRIPLANAR]) {
- code += " AO = dot(triplanar_texture(texture_ambient_occlusion,uv2_power_normal,uv2_triplanar_pos),ao_texture_channel);\n";
+ code += " AO = dot(triplanar_texture(texture_ambient_occlusion, uv2_power_normal, uv2_triplanar_pos), ao_texture_channel);\n";
} else {
- code += " AO = dot(texture(texture_ambient_occlusion,base_uv2),ao_texture_channel);\n";
+ code += " AO = dot(texture(texture_ambient_occlusion, base_uv2), ao_texture_channel);\n";
}
} else {
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " AO = dot(triplanar_texture(texture_ambient_occlusion,uv1_power_normal,uv1_triplanar_pos),ao_texture_channel);\n";
+ code += " AO = dot(triplanar_texture(texture_ambient_occlusion, uv1_power_normal, uv1_triplanar_pos), ao_texture_channel);\n";
} else {
- code += " AO = dot(texture(texture_ambient_occlusion,base_uv),ao_texture_channel);\n";
+ code += " AO = dot(texture(texture_ambient_occlusion, base_uv), ao_texture_channel);\n";
}
}
} else {
@@ -1453,75 +1730,103 @@ void BaseMaterial3D::_update_shader() {
}
if (features[FEATURE_SUBSURFACE_SCATTERING]) {
+ code += R"(
+ // Subsurface Scattering: Enabled
+)";
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " float sss_tex = triplanar_texture(texture_subsurface_scattering,uv1_power_normal,uv1_triplanar_pos).r;\n";
+ code += " float sss_tex = triplanar_texture(texture_subsurface_scattering, uv1_power_normal, uv1_triplanar_pos).r;\n";
} else {
- code += " float sss_tex = texture(texture_subsurface_scattering,base_uv).r;\n";
+ code += " float sss_tex = texture(texture_subsurface_scattering, base_uv).r;\n";
}
- code += " SSS_STRENGTH=subsurface_scattering_strength*sss_tex;\n";
+ code += " SSS_STRENGTH = subsurface_scattering_strength * sss_tex;\n";
}
if (features[FEATURE_SUBSURFACE_TRANSMITTANCE]) {
+ code += R"(
+ // Subsurface Scattering Transmittance: Enabled
+)";
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " vec4 trans_color_tex = triplanar_texture(texture_subsurface_transmittance,uv1_power_normal,uv1_triplanar_pos);\n";
+ code += " vec4 trans_color_tex = triplanar_texture(texture_subsurface_transmittance, uv1_power_normal, uv1_triplanar_pos);\n";
} else {
- code += " vec4 trans_color_tex = texture(texture_subsurface_transmittance,base_uv);\n";
+ code += " vec4 trans_color_tex = texture(texture_subsurface_transmittance, base_uv);\n";
}
- code += " SSS_TRANSMITTANCE_COLOR=transmittance_color*trans_color_tex;\n";
+ code += " SSS_TRANSMITTANCE_COLOR = transmittance_color * trans_color_tex;\n";
- code += " SSS_TRANSMITTANCE_DEPTH=transmittance_depth;\n";
- code += " SSS_TRANSMITTANCE_BOOST=transmittance_boost;\n";
+ code += R"( SSS_TRANSMITTANCE_DEPTH = transmittance_depth;
+ SSS_TRANSMITTANCE_BOOST = transmittance_boost;
+)";
}
if (features[FEATURE_BACKLIGHT]) {
+ code += R"(
+ // Backlight: Enabled
+)";
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " vec3 backlight_tex = triplanar_texture(texture_backlight,uv1_power_normal,uv1_triplanar_pos).rgb;\n";
+ code += " vec3 backlight_tex = triplanar_texture(texture_backlight, uv1_power_normal, uv1_triplanar_pos).rgb;\n";
} else {
- code += " vec3 backlight_tex = texture(texture_backlight,base_uv).rgb;\n";
+ code += " vec3 backlight_tex = texture(texture_backlight, base_uv).rgb;\n";
}
- code += " BACKLIGHT = (backlight.rgb+backlight_tex);\n";
+ code += " BACKLIGHT = (backlight.rgb + backlight_tex);\n";
}
if (features[FEATURE_DETAIL]) {
- bool triplanar = (flags[FLAG_UV1_USE_TRIPLANAR] && detail_uv == DETAIL_UV_1) || (flags[FLAG_UV2_USE_TRIPLANAR] && detail_uv == DETAIL_UV_2);
-
+ code += R"(
+ // Detail: Enabled
+)";
+ const bool triplanar = (flags[FLAG_UV1_USE_TRIPLANAR] && detail_uv == DETAIL_UV_1) || (flags[FLAG_UV2_USE_TRIPLANAR] && detail_uv == DETAIL_UV_2);
if (triplanar) {
- String tp_uv = detail_uv == DETAIL_UV_1 ? "uv1" : "uv2";
- code += " vec4 detail_tex = triplanar_texture(texture_detail_albedo," + tp_uv + "_power_normal," + tp_uv + "_triplanar_pos);\n";
- code += " vec4 detail_norm_tex = triplanar_texture(texture_detail_normal," + tp_uv + "_power_normal," + tp_uv + "_triplanar_pos);\n";
-
+ const String tp_uv = detail_uv == DETAIL_UV_1 ? "uv1" : "uv2";
+ code += vformat(R"( vec4 detail_tex = triplanar_texture(texture_detail_albedo, %s_power_normal, %s_triplanar_pos);
+ vec4 detail_norm_tex = triplanar_texture(texture_detail_normal, %s_power_normal, %s_triplanar_pos);
+)",
+ tp_uv, tp_uv, tp_uv, tp_uv);
} else {
- String det_uv = detail_uv == DETAIL_UV_1 ? "base_uv" : "base_uv2";
- code += " vec4 detail_tex = texture(texture_detail_albedo," + det_uv + ");\n";
- code += " vec4 detail_norm_tex = texture(texture_detail_normal," + det_uv + ");\n";
+ const String det_uv = detail_uv == DETAIL_UV_1 ? "base_uv" : "base_uv2";
+ code += vformat(R"( vec4 detail_tex = texture(texture_detail_albedo, %s);
+ vec4 detail_norm_tex = texture(texture_detail_normal, %s);
+)",
+ det_uv, det_uv);
}
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " vec4 detail_mask_tex = triplanar_texture(texture_detail_mask,uv1_power_normal,uv1_triplanar_pos);\n";
+ code += " vec4 detail_mask_tex = triplanar_texture(texture_detail_mask, uv1_power_normal, uv1_triplanar_pos);\n";
} else {
- code += " vec4 detail_mask_tex = texture(texture_detail_mask,base_uv);\n";
+ code += " vec4 detail_mask_tex = texture(texture_detail_mask, base_uv);\n";
}
switch (detail_blend_mode) {
case BLEND_MODE_MIX: {
- code += " vec3 detail = mix(ALBEDO.rgb,detail_tex.rgb,detail_tex.a);\n";
+ code += R"(
+ // Detail Blend Mode: Mix
+ vec3 detail = mix(ALBEDO.rgb, detail_tex.rgb, detail_tex.a);
+)";
} break;
case BLEND_MODE_ADD: {
- code += " vec3 detail = mix(ALBEDO.rgb,ALBEDO.rgb+detail_tex.rgb,detail_tex.a);\n";
+ code += R"(
+ // Detail Blend Mode: Add
+ vec3 detail = mix(ALBEDO.rgb, ALBEDO.rgb + detail_tex.rgb, detail_tex.a);
+)";
} break;
case BLEND_MODE_SUB: {
- code += " vec3 detail = mix(ALBEDO.rgb,ALBEDO.rgb-detail_tex.rgb,detail_tex.a);\n";
+ code += R"(
+ // Detail Blend Mode: Subtract
+ vec3 detail = mix(ALBEDO.rgb, ALBEDO.rgb - detail_tex.rgb, detail_tex.a);
+)";
} break;
case BLEND_MODE_MUL: {
- code += " vec3 detail = mix(ALBEDO.rgb,ALBEDO.rgb*detail_tex.rgb,detail_tex.a);\n";
+ code += R"(
+ // Detail Blend Mode: Multiply
+ vec3 detail = mix(ALBEDO.rgb, ALBEDO.rgb * detail_tex.rgb, detail_tex.a);
+)";
} break;
case BLEND_MODE_MAX:
break; // Internal value, skip.
}
- code += " vec3 detail_norm = mix(NORMAL_MAP,detail_norm_tex.rgb,detail_tex.a);\n";
- code += " NORMAL_MAP = mix(NORMAL_MAP,detail_norm,detail_mask_tex.r);\n";
- code += " ALBEDO.rgb = mix(ALBEDO.rgb,detail,detail_mask_tex.r);\n";
+ code += R"( vec3 detail_norm = mix(NORMAL_MAP, detail_norm_tex.rgb, detail_tex.a);
+ NORMAL_MAP = mix(NORMAL_MAP, detail_norm, detail_mask_tex.r);
+ ALBEDO.rgb = mix(ALBEDO.rgb, detail, detail_mask_tex.r);
+)";
}
code += "}\n";
@@ -2443,8 +2748,8 @@ bool BaseMaterial3D::is_proximity_fade_enabled() const {
}
void BaseMaterial3D::set_proximity_fade_distance(float p_distance) {
- proximity_fade_distance = p_distance;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->proximity_fade_distance, p_distance);
+ proximity_fade_distance = MAX(p_distance, 0.01);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->proximity_fade_distance, proximity_fade_distance);
}
float BaseMaterial3D::get_proximity_fade_distance() const {
@@ -2894,7 +3199,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_particle_trails"), "set_flag", "get_flag", FLAG_PARTICLE_TRAILS_MODE);
ADD_GROUP("Proximity Fade", "proximity_fade_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "proximity_fade_enabled"), "set_proximity_fade_enabled", "is_proximity_fade_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "proximity_fade_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:m"), "set_proximity_fade_distance", "get_proximity_fade_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "proximity_fade_distance", PROPERTY_HINT_RANGE, "0.01,4096,0.01,suffix:m"), "set_proximity_fade_distance", "get_proximity_fade_distance");
ADD_GROUP("MSDF", "msdf_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), "set_msdf_pixel_range", "get_msdf_pixel_range");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "msdf_outline_size", PROPERTY_HINT_RANGE, "0,250,1"), "set_msdf_outline_size", "get_msdf_outline_size");
diff --git a/servers/SCsub b/servers/SCsub
index 3e83657335..2e4430f030 100644
--- a/servers/SCsub
+++ b/servers/SCsub
@@ -15,22 +15,24 @@ env.add_source_files(env.servers_sources, "physics_server_2d_wrap_mt.cpp")
env.add_source_files(env.servers_sources, "register_server_types.cpp")
env.add_source_files(env.servers_sources, "rendering_server.cpp")
env.add_source_files(env.servers_sources, "text_server.cpp")
-env.add_source_files(env.servers_sources, "xr_server.cpp")
-SConscript("xr/SCsub")
-SConscript("camera/SCsub")
-if not env["disable_3d"]:
- SConscript("physics_3d/SCsub")
- env.add_source_files(env.servers_sources, "physics_server_3d.cpp")
- env.add_source_files(env.servers_sources, "physics_server_3d_wrap_mt.cpp")
-SConscript("physics_2d/SCsub")
-SConscript("rendering/SCsub")
SConscript("audio/SCsub")
-SConscript("text/SCsub")
+SConscript("camera/SCsub")
SConscript("debugger/SCsub")
SConscript("extensions/SCsub")
SConscript("movie_writer/SCsub")
SConscript("navigation/SCsub")
+SConscript("rendering/SCsub")
+SConscript("text/SCsub")
+
+SConscript("physics_2d/SCsub")
+
+if not env["disable_3d"]:
+ SConscript("physics_3d/SCsub")
+ env.add_source_files(env.servers_sources, "physics_server_3d.cpp")
+ env.add_source_files(env.servers_sources, "physics_server_3d_wrap_mt.cpp")
+ SConscript("xr/SCsub")
+ env.add_source_files(env.servers_sources, "xr_server.cpp")
lib = env.add_library("servers", env.servers_sources)
diff --git a/servers/camera_server.h b/servers/camera_server.h
index 4e0b75fbf6..e9bcd771d2 100644
--- a/servers/camera_server.h
+++ b/servers/camera_server.h
@@ -71,7 +71,7 @@ protected:
static void _bind_methods();
- template <class T>
+ template <typename T>
static CameraServer *_create_builtin() {
return memnew(T);
}
@@ -79,7 +79,7 @@ protected:
public:
static CameraServer *get_singleton();
- template <class T>
+ template <typename T>
static void make_default() {
create_func = _create_builtin<T>;
}
diff --git a/servers/physics_2d/godot_broad_phase_2d_bvh.h b/servers/physics_2d/godot_broad_phase_2d_bvh.h
index 36fd1223b0..6c1fae5cb2 100644
--- a/servers/physics_2d/godot_broad_phase_2d_bvh.h
+++ b/servers/physics_2d/godot_broad_phase_2d_bvh.h
@@ -38,7 +38,7 @@
#include "core/math/vector2.h"
class GodotBroadPhase2DBVH : public GodotBroadPhase2D {
- template <class T>
+ template <typename T>
class UserPairTestFunction {
public:
static bool user_pair_check(const T *p_a, const T *p_b) {
@@ -47,7 +47,7 @@ class GodotBroadPhase2DBVH : public GodotBroadPhase2D {
}
};
- template <class T>
+ template <typename T>
class UserCullTestFunction {
public:
static bool user_cull_check(const T *p_a, const T *p_b) {
diff --git a/servers/physics_2d/godot_collision_solver_2d_sat.cpp b/servers/physics_2d/godot_collision_solver_2d_sat.cpp
index c85fdc592a..daa9982b2e 100644
--- a/servers/physics_2d/godot_collision_solver_2d_sat.cpp
+++ b/servers/physics_2d/godot_collision_solver_2d_sat.cpp
@@ -171,7 +171,7 @@ static void _generate_contacts_from_supports(const Vector2 *p_points_A, int p_po
contacts_func(points_A, pointcount_A, points_B, pointcount_B, p_collector);
}
-template <class ShapeA, class ShapeB, bool castA = false, bool castB = false, bool withMargin = false>
+template <typename ShapeA, typename ShapeB, bool castA = false, bool castB = false, bool withMargin = false>
class SeparatorAxisTest2D {
const ShapeA *shape_A = nullptr;
const ShapeB *shape_B = nullptr;
diff --git a/servers/physics_3d/godot_broad_phase_3d_bvh.h b/servers/physics_3d/godot_broad_phase_3d_bvh.h
index 6279658ec4..63968dea64 100644
--- a/servers/physics_3d/godot_broad_phase_3d_bvh.h
+++ b/servers/physics_3d/godot_broad_phase_3d_bvh.h
@@ -36,7 +36,7 @@
#include "core/math/bvh.h"
class GodotBroadPhase3DBVH : public GodotBroadPhase3D {
- template <class T>
+ template <typename T>
class UserPairTestFunction {
public:
static bool user_pair_check(const T *p_a, const T *p_b) {
@@ -45,7 +45,7 @@ class GodotBroadPhase3DBVH : public GodotBroadPhase3D {
}
};
- template <class T>
+ template <typename T>
class UserCullTestFunction {
public:
static bool user_cull_check(const T *p_a, const T *p_b) {
diff --git a/servers/physics_3d/godot_collision_solver_3d_sat.cpp b/servers/physics_3d/godot_collision_solver_3d_sat.cpp
index 3aa2f256c1..beaa30eb84 100644
--- a/servers/physics_3d/godot_collision_solver_3d_sat.cpp
+++ b/servers/physics_3d/godot_collision_solver_3d_sat.cpp
@@ -612,7 +612,7 @@ static void _generate_contacts_from_supports(const Vector3 *p_points_A, int p_po
contacts_func(points_A, pointcount_A, points_B, pointcount_B, p_callback);
}
-template <class ShapeA, class ShapeB, bool withMargin = false>
+template <typename ShapeA, typename ShapeB, bool withMargin = false>
class SeparatorAxisTest {
const ShapeA *shape_A = nullptr;
const ShapeB *shape_B = nullptr;
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index 8547ebfad6..4e49129941 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -77,13 +77,6 @@
#include "text/text_server_dummy.h"
#include "text/text_server_extension.h"
#include "text_server.h"
-#include "xr/xr_body_tracker.h"
-#include "xr/xr_face_tracker.h"
-#include "xr/xr_hand_tracker.h"
-#include "xr/xr_interface.h"
-#include "xr/xr_interface_extension.h"
-#include "xr/xr_positional_tracker.h"
-#include "xr_server.h"
// 2D physics and navigation.
#include "navigation_server_2d.h"
@@ -99,6 +92,13 @@
#include "physics_server_3d.h"
#include "physics_server_3d_wrap_mt.h"
#include "servers/extensions/physics_server_3d_extension.h"
+#include "xr/xr_body_tracker.h"
+#include "xr/xr_face_tracker.h"
+#include "xr/xr_hand_tracker.h"
+#include "xr/xr_interface.h"
+#include "xr/xr_interface_extension.h"
+#include "xr/xr_positional_tracker.h"
+#include "xr_server.h"
#endif // _3D_DISABLED
ShaderTypes *shader_types = nullptr;
@@ -165,26 +165,10 @@ void register_server_types() {
GDREGISTER_CLASS(NativeMenu);
- GDREGISTER_ABSTRACT_CLASS(NavigationServer2D);
- GDREGISTER_ABSTRACT_CLASS(NavigationServer3D);
- GDREGISTER_CLASS(NavigationPathQueryParameters2D);
- GDREGISTER_CLASS(NavigationPathQueryParameters3D);
- GDREGISTER_CLASS(NavigationPathQueryResult2D);
- GDREGISTER_CLASS(NavigationPathQueryResult3D);
-
- GDREGISTER_CLASS(XRServer);
GDREGISTER_CLASS(CameraServer);
GDREGISTER_ABSTRACT_CLASS(RenderingDevice);
- GDREGISTER_CLASS(XRBodyTracker);
- GDREGISTER_ABSTRACT_CLASS(XRInterface);
- GDREGISTER_CLASS(XRHandTracker);
- GDREGISTER_CLASS(XRInterfaceExtension); // can't register this as virtual because we need a creation function for our extensions.
- GDREGISTER_CLASS(XRPose);
- GDREGISTER_CLASS(XRPositionalTracker);
- GDREGISTER_CLASS(XRFaceTracker);
-
GDREGISTER_CLASS(AudioStream);
GDREGISTER_CLASS(AudioStreamPlayback);
GDREGISTER_VIRTUAL_CLASS(AudioStreamPlaybackResampled);
@@ -303,6 +287,10 @@ void register_server_types() {
PhysicsServer2DManager::get_singleton()->register_server("GodotPhysics2D", callable_mp_static(_createGodotPhysics2DCallback));
PhysicsServer2DManager::get_singleton()->set_default_server("GodotPhysics2D");
+ GDREGISTER_ABSTRACT_CLASS(NavigationServer2D);
+ GDREGISTER_CLASS(NavigationPathQueryParameters2D);
+ GDREGISTER_CLASS(NavigationPathQueryResult2D);
+
#ifndef _3D_DISABLED
// Physics 3D
GDREGISTER_CLASS(PhysicsServer3DManager);
@@ -332,8 +320,21 @@ void register_server_types() {
PhysicsServer3DManager::get_singleton()->register_server("GodotPhysics3D", callable_mp_static(_createGodotPhysics3DCallback));
PhysicsServer3DManager::get_singleton()->set_default_server("GodotPhysics3D");
+
+ GDREGISTER_ABSTRACT_CLASS(XRInterface);
+ GDREGISTER_CLASS(XRBodyTracker);
+ GDREGISTER_CLASS(XRFaceTracker);
+ GDREGISTER_CLASS(XRHandTracker);
+ GDREGISTER_CLASS(XRInterfaceExtension); // can't register this as virtual because we need a creation function for our extensions.
+ GDREGISTER_CLASS(XRPose);
+ GDREGISTER_CLASS(XRPositionalTracker);
+ GDREGISTER_CLASS(XRServer);
#endif // _3D_DISABLED
+ GDREGISTER_ABSTRACT_CLASS(NavigationServer3D);
+ GDREGISTER_CLASS(NavigationPathQueryParameters3D);
+ GDREGISTER_CLASS(NavigationPathQueryResult3D);
+
writer_mjpeg = memnew(MovieWriterMJPEG);
MovieWriter::add_writer(writer_mjpeg);
@@ -357,18 +358,19 @@ void unregister_server_types() {
void register_server_singletons() {
OS::get_singleton()->benchmark_begin_measure("Servers", "Register Singletons");
+ Engine::get_singleton()->add_singleton(Engine::Singleton("AudioServer", AudioServer::get_singleton(), "AudioServer"));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("CameraServer", CameraServer::get_singleton(), "CameraServer"));
Engine::get_singleton()->add_singleton(Engine::Singleton("DisplayServer", DisplayServer::get_singleton(), "DisplayServer"));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("NativeMenu", NativeMenu::get_singleton(), "NativeMenu"));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer2D", NavigationServer2D::get_singleton(), "NavigationServer2D"));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3D", NavigationServer3D::get_singleton(), "NavigationServer3D"));
Engine::get_singleton()->add_singleton(Engine::Singleton("RenderingServer", RenderingServer::get_singleton(), "RenderingServer"));
- Engine::get_singleton()->add_singleton(Engine::Singleton("AudioServer", AudioServer::get_singleton(), "AudioServer"));
+
Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer2D", PhysicsServer2D::get_singleton(), "PhysicsServer2D"));
#ifndef _3D_DISABLED
Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3D", PhysicsServer3D::get_singleton(), "PhysicsServer3D"));
-#endif // _3D_DISABLED
- Engine::get_singleton()->add_singleton(Engine::Singleton("NativeMenu", NativeMenu::get_singleton(), "NativeMenu"));
- Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer2D", NavigationServer2D::get_singleton(), "NavigationServer2D"));
- Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3D", NavigationServer3D::get_singleton(), "NavigationServer3D"));
Engine::get_singleton()->add_singleton(Engine::Singleton("XRServer", XRServer::get_singleton(), "XRServer"));
- Engine::get_singleton()->add_singleton(Engine::Singleton("CameraServer", CameraServer::get_singleton(), "CameraServer"));
+#endif // _3D_DISABLED
OS::get_singleton()->benchmark_end_measure("Servers", "Register Singletons");
}
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index cd38aa05f3..8e342375f8 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -2162,7 +2162,7 @@ bool RendererCanvasCull::free(RID p_rid) {
return true;
}
-template <class T>
+template <typename T>
void RendererCanvasCull::_free_rids(T &p_owner, const char *p_type) {
List<RID> owned;
p_owner.get_owned_list(&owned);
diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h
index 8d40c2fbaa..d733a7bed2 100644
--- a/servers/rendering/renderer_canvas_cull.h
+++ b/servers/rendering/renderer_canvas_cull.h
@@ -170,7 +170,7 @@ public:
RID_Owner<Item, true> canvas_item_owner;
RID_Owner<RendererCanvasRender::Light, true> canvas_light_owner;
- template <class T>
+ template <typename T>
void _free_rids(T &p_owner, const char *p_type);
bool disable_scale;
diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h
index fd31a40a3e..cf8f6dcb2e 100644
--- a/servers/rendering/renderer_canvas_render.h
+++ b/servers/rendering/renderer_canvas_render.h
@@ -366,7 +366,7 @@ public:
mutable double debug_redraw_time = 0;
#endif
- template <class T>
+ template <typename T>
T *alloc_command() {
T *command = nullptr;
if (commands == nullptr) {
diff --git a/servers/rendering/renderer_compositor.cpp b/servers/rendering/renderer_compositor.cpp
index c36da51e50..d364de5633 100644
--- a/servers/rendering/renderer_compositor.cpp
+++ b/servers/rendering/renderer_compositor.cpp
@@ -49,9 +49,11 @@ bool RendererCompositor::is_xr_enabled() const {
RendererCompositor::RendererCompositor() {
singleton = this;
+#ifndef _3D_DISABLED
if (XRServer::get_xr_mode() == XRServer::XRMODE_DEFAULT) {
xr_enabled = GLOBAL_GET("xr/shaders/enabled");
} else {
xr_enabled = XRServer::get_xr_mode() == XRServer::XRMODE_ON;
}
+#endif // _3D_DISABLED
}
diff --git a/servers/rendering/renderer_rd/effects/vrs.cpp b/servers/rendering/renderer_rd/effects/vrs.cpp
index ce1ac2e929..30c318fb9a 100644
--- a/servers/rendering/renderer_rd/effects/vrs.cpp
+++ b/servers/rendering/renderer_rd/effects/vrs.cpp
@@ -32,7 +32,10 @@
#include "../renderer_compositor_rd.h"
#include "../storage_rd/texture_storage.h"
#include "../uniform_set_cache_rd.h"
+
+#ifndef _3D_DISABLED
#include "servers/xr_server.h"
+#endif // _3D_DISABLED
using namespace RendererRD;
@@ -124,6 +127,7 @@ void VRS::update_vrs_texture(RID p_vrs_fb, RID p_render_target) {
copy_vrs(rd_texture, p_vrs_fb, layers > 1);
}
}
+#ifndef _3D_DISABLED
} else if (vrs_mode == RS::VIEWPORT_VRS_XR) {
Ref<XRInterface> interface = XRServer::get_singleton()->get_primary_interface();
if (interface.is_valid()) {
@@ -138,6 +142,7 @@ void VRS::update_vrs_texture(RID p_vrs_fb, RID p_render_target) {
}
}
}
+#endif // _3D_DISABLED
}
RD::get_singleton()->draw_command_end_label();
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index 86090aa416..341ba0e3b0 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -44,7 +44,10 @@
#include "servers/rendering/rendering_method.h"
#include "servers/rendering/rendering_server_globals.h"
#include "servers/rendering/storage/utilities.h"
+
+#ifndef _3D_DISABLED
#include "servers/xr/xr_interface.h"
+#endif // _3D_DISABLED
class RenderingLightCuller;
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index 445a1b265e..baa198626c 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -220,6 +220,7 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
}
void RendererViewport::_draw_3d(Viewport *p_viewport) {
+#ifndef _3D_DISABLED
RENDER_TIMESTAMP("> Render 3D Scene");
Ref<XRInterface> xr_interface;
@@ -246,6 +247,7 @@ void RendererViewport::_draw_3d(Viewport *p_viewport) {
RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->internal_size, p_viewport->jitter_phase_count, screen_mesh_lod_threshold, p_viewport->shadow_atlas, xr_interface, &p_viewport->render_info);
RENDER_TIMESTAMP("< Render 3D Scene");
+#endif // _3D_DISABLED
}
void RendererViewport::_draw_viewport(Viewport *p_viewport) {
@@ -629,6 +631,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
void RendererViewport::draw_viewports(bool p_swap_buffers) {
timestamp_vp_map.clear();
+#ifndef _3D_DISABLED
// get our xr interface in case we need it
Ref<XRInterface> xr_interface;
XRServer *xr_server = XRServer::get_singleton();
@@ -639,6 +642,7 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
// retrieve the interface responsible for rendering
xr_interface = xr_server->get_primary_interface();
}
+#endif // _3D_DISABLED
if (Engine::get_singleton()->is_editor_hint()) {
set_default_clear_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
@@ -671,6 +675,7 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
bool visible = vp->viewport_to_screen_rect != Rect2();
+#ifndef _3D_DISABLED
if (vp->use_xr) {
if (xr_interface.is_valid()) {
// Ignore update mode we have to commit frames to our XR interface
@@ -684,7 +689,9 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
visible = false;
vp->size = Size2();
}
- } else {
+ } else
+#endif // _3D_DISABLED
+ {
if (vp->update_mode == RS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == RS::VIEWPORT_UPDATE_ONCE) {
visible = true;
}
@@ -722,6 +729,7 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
RENDER_TIMESTAMP("> Render Viewport " + itos(i));
RSG::texture_storage->render_target_set_as_unused(vp->render_target);
+#ifndef _3D_DISABLED
if (vp->use_xr && xr_interface.is_valid()) {
// Inform XR interface we're about to render its viewport,
// if this returns false we don't render.
@@ -758,7 +766,9 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
RSG::rasterizer->end_viewport(p_swap_buffers && blits.size() > 0);
}
}
- } else {
+ } else
+#endif // _3D_DISABLED
+ {
RSG::texture_storage->render_target_set_override(vp->render_target, RID(), RID(), RID());
RSG::scene->set_debug_draw_mode(vp->debug_draw);
diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h
index a0ec9e6318..90c29618b3 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -37,9 +37,12 @@
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_method.h"
#include "servers/rendering_server.h"
-#include "servers/xr/xr_interface.h"
#include "storage/render_scene_buffers.h"
+#ifndef _3D_DISABLED
+#include "servers/xr/xr_interface.h"
+#endif // _3D_DISABLED
+
class RendererViewport {
public:
struct CanvasBase {
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index dc48ddbd56..7dfff0b76f 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -5182,7 +5182,7 @@ void RenderingDevice::_save_pipeline_cache(void *p_data) {
}
}
-template <class T>
+template <typename T>
void RenderingDevice::_free_rids(T &p_owner, const char *p_type) {
List<RID> owned;
p_owner.get_owned_list(&owned);
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 8c88c08950..9a898a2fca 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -1294,7 +1294,7 @@ private:
void _stall_for_previous_frames();
void _flush_and_stall_for_all_frames();
- template <class T>
+ template <typename T>
void _free_rids(T &p_owner, const char *p_type);
#ifdef DEV_ENABLED
diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h
index ee33dc103c..09a0412941 100644
--- a/servers/rendering/rendering_device_driver.h
+++ b/servers/rendering/rendering_device_driver.h
@@ -56,7 +56,7 @@
// This may one day be used in Godot for interoperability between C arrays, Vector and LocalVector.
// (See https://github.com/godotengine/godot-proposals/issues/5144.)
-template <class T>
+template <typename T>
class VectorView {
const T *_ptr = nullptr;
const uint32_t _size = 0;
@@ -97,20 +97,20 @@ public:
#define ENUM_MEMBERS_EQUAL(m_a, m_b) ((int64_t)m_a == (int64_t)m_b)
// This helps using a single paged allocator for many resource types.
-template <class... RESOURCE_TYPES>
+template <typename... RESOURCE_TYPES>
struct VersatileResourceTemplate {
static constexpr size_t RESOURCE_SIZES[] = { sizeof(RESOURCE_TYPES)... };
static constexpr size_t MAX_RESOURCE_SIZE = std::max_element(RESOURCE_SIZES, RESOURCE_SIZES + sizeof...(RESOURCE_TYPES))[0];
uint8_t data[MAX_RESOURCE_SIZE];
- template <class T>
+ template <typename T>
static T *allocate(PagedAllocator<VersatileResourceTemplate> &p_allocator) {
T *obj = (T *)p_allocator.alloc();
memnew_placement(obj, T);
return obj;
}
- template <class T>
+ template <typename T>
static void free(PagedAllocator<VersatileResourceTemplate> &p_allocator, T *p_object) {
p_object->~T();
p_allocator.free((VersatileResourceTemplate *)p_object);
diff --git a/servers/rendering/rendering_method.h b/servers/rendering/rendering_method.h
index 4569846752..aa5e7d83cc 100644
--- a/servers/rendering/rendering_method.h
+++ b/servers/rendering/rendering_method.h
@@ -33,7 +33,14 @@
#include "servers/rendering/storage/render_scene_buffers.h"
#include "servers/rendering_server.h"
+
+#ifdef _3D_DISABLED
+// RendererSceneCull::render_camera is empty when 3D is disabled, but
+// it and RenderingMethod::render_camera have a parameter for XRInterface.
+#define XRInterface RefCounted
+#else // 3D enabled
#include "servers/xr/xr_interface.h"
+#endif // _3D_DISABLED
class RenderingMethod {
public:
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index bf8ab27722..b4c539dcff 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -93,11 +93,13 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
RSG::rasterizer->end_frame(p_swap_buffers);
+#ifndef _3D_DISABLED
XRServer *xr_server = XRServer::get_singleton();
if (xr_server != nullptr) {
// let our XR server know we're done so we can get our frame timing
xr_server->end_frame();
}
+#endif // _3D_DISABLED
RSG::canvas->update_visibility_notifiers();
RSG::scene->update_visibility_notifiers();
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 737545b8ca..816a202b50 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -383,7 +383,7 @@ public:
virtual ~Node() {}
};
- template <class T>
+ template <typename T>
T *alloc_node() {
T *node = memnew(T);
node->next = nodes;
diff --git a/servers/rendering/storage/variant_converters.h b/servers/rendering/storage/variant_converters.h
index 6e3c07237e..7dbdb0f517 100644
--- a/servers/rendering/storage/variant_converters.h
+++ b/servers/rendering/storage/variant_converters.h
@@ -242,10 +242,10 @@ inline bool is_convertible_array(Variant::Type type) {
type == Variant::PACKED_COLOR_ARRAY;
}
-template <class, class = void>
+template <typename, typename = void>
inline constexpr bool is_vector_type_v = false;
-template <class T>
+template <typename T>
inline constexpr bool is_vector_type_v<T, std::void_t<decltype(T::AXIS_COUNT)>> = true;
template <typename T, typename P>
diff --git a/servers/text/text_server_dummy.h b/servers/text/text_server_dummy.h
index 77b6ecf319..a5ab444f55 100644
--- a/servers/text/text_server_dummy.h
+++ b/servers/text/text_server_dummy.h
@@ -40,9 +40,87 @@ class TextServerDummy : public TextServerExtension {
_THREAD_SAFE_CLASS_
public:
- virtual String get_name() const override {
- return "Dummy";
- }
+ virtual bool has_feature(Feature p_feature) const override { return false; }
+ virtual String get_name() const override { return "Dummy"; }
+ virtual int64_t get_features() const override { return 0; }
+ virtual void free_rid(const RID &p_rid) override {}
+ virtual bool has(const RID &p_rid) override { return false; }
+
+ virtual RID create_font() override { return RID(); }
+ virtual void font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) override {}
+ virtual int64_t font_get_fixed_size(const RID &p_font_rid) const override { return 0; }
+ virtual void font_set_fixed_size_scale_mode(const RID &p_font_rid, TextServer::FixedSizeScaleMode p_fixed_size_scale_mode) override {}
+ virtual TextServer::FixedSizeScaleMode font_get_fixed_size_scale_mode(const RID &p_font_rid) const override { return FIXED_SIZE_SCALE_DISABLE; }
+ virtual TypedArray<Vector2i> font_get_size_cache_list(const RID &p_font_rid) const override { return TypedArray<Vector2i>(); }
+ virtual void font_clear_size_cache(const RID &p_font_rid) override {}
+ virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) override {}
+ virtual void font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) override {}
+ virtual double font_get_ascent(const RID &p_font_rid, int64_t p_size) const override { return 0; }
+ virtual void font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) override {}
+ virtual double font_get_descent(const RID &p_font_rid, int64_t p_size) const override { return 0; }
+ virtual void font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) override {}
+ virtual double font_get_underline_position(const RID &p_font_rid, int64_t p_size) const override { return 0; }
+ virtual void font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) override {}
+ virtual double font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const override { return 0; }
+ virtual void font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) override {}
+ virtual double font_get_scale(const RID &p_font_rid, int64_t p_size) const override { return 0; }
+ virtual int64_t font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const override { return 0; }
+ virtual void font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) override {}
+ virtual void font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) override {}
+ virtual void font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) override {}
+ virtual Ref<Image> font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override { return Ref<Image>(); }
+ virtual PackedInt32Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override { return PackedInt32Array(); }
+ virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) override {}
+ virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) override {}
+ virtual Vector2 font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const override { return Vector2(); }
+ virtual void font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) override {}
+ virtual Vector2 font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override { return Vector2(); }
+ virtual void font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) override {}
+ virtual Vector2 font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override { return Vector2(); }
+ virtual void font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) override {}
+ virtual Rect2 font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override { return Rect2(); }
+ virtual void font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) override {}
+ virtual int64_t font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override { return 0; }
+ virtual void font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) override {}
+ virtual RID font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override { return RID(); }
+ virtual Size2 font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override { return Size2(); }
+ virtual int64_t font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const override { return 0; }
+ virtual int64_t font_get_char_from_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_glyph_index) const override { return 0; }
+ virtual bool font_has_char(const RID &p_font_rid, int64_t p_char) const override { return false; }
+ virtual String font_get_supported_chars(const RID &p_font_rid) const override { return String(); }
+ virtual void font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const override {}
+ virtual void font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const override {}
+
+ virtual RID create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) override { return RID(); }
+ virtual void shaped_text_clear(const RID &p_shaped) override {}
+ virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) override { return false; }
+ virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length, double p_baseline) override { return false; }
+ virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, double p_baseline) override { return false; }
+ virtual int64_t shaped_get_span_count(const RID &p_shaped) const override { return 0; }
+ virtual Variant shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const override { return Variant(); }
+ virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) override {}
+ virtual RID shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const override { return RID(); }
+ virtual RID shaped_text_get_parent(const RID &p_shaped) const override { return RID(); }
+ virtual bool shaped_text_shape(const RID &p_shaped) override { return false; }
+ virtual bool shaped_text_is_ready(const RID &p_shaped) const override { return false; }
+ virtual const Glyph *shaped_text_get_glyphs(const RID &p_shaped) const override { return nullptr; }
+ virtual const Glyph *shaped_text_sort_logical(const RID &p_shaped) override { return nullptr; }
+ virtual int64_t shaped_text_get_glyph_count(const RID &p_shaped) const override { return 0; }
+ virtual Vector2i shaped_text_get_range(const RID &p_shaped) const override { return Vector2i(); }
+ virtual int64_t shaped_text_get_trim_pos(const RID &p_shaped) const override { return -1; }
+ virtual int64_t shaped_text_get_ellipsis_pos(const RID &p_shaped) const override { return -1; }
+ virtual const Glyph *shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const override { return nullptr; }
+ virtual int64_t shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const override { return -1; }
+ virtual Array shaped_text_get_objects(const RID &p_shaped) const override { return Array(); }
+ virtual Rect2 shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const override { return Rect2(); }
+ virtual Vector2i shaped_text_get_object_range(const RID &p_shaped, const Variant &p_key) const override { return Vector2i(); }
+ virtual int64_t shaped_text_get_object_glyph(const RID &p_shaped, const Variant &p_key) const override { return -1; }
+ virtual Size2 shaped_text_get_size(const RID &p_shaped) const override { return Size2(); }
+ virtual double shaped_text_get_ascent(const RID &p_shaped) const override { return 0; }
+ virtual double shaped_text_get_descent(const RID &p_shaped) const override { return 0; }
+ virtual double shaped_text_get_width(const RID &p_shaped) const override { return 0; }
+ virtual double shaped_text_get_underline_position(const RID &p_shaped) const override { return 0; }
+ virtual double shaped_text_get_underline_thickness(const RID &p_shaped) const override { return 0; }
};
#endif // TEXT_SERVER_DUMMY_H
diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp
index 113972d20d..eb9f1c1484 100644
--- a/servers/text/text_server_extension.cpp
+++ b/servers/text/text_server_extension.cpp
@@ -326,8 +326,8 @@ void TextServerExtension::_bind_methods() {
GDVIRTUAL_BIND(_shaped_text_prev_character_pos, "shaped", "pos");
GDVIRTUAL_BIND(_shaped_text_closest_character_pos, "shaped", "pos");
- GDVIRTUAL_BIND(_format_number, "string", "language");
- GDVIRTUAL_BIND(_parse_number, "string", "language");
+ GDVIRTUAL_BIND(_format_number, "number", "language");
+ GDVIRTUAL_BIND(_parse_number, "number", "language");
GDVIRTUAL_BIND(_percent_sign, "language");
GDVIRTUAL_BIND(_strip_diacritics, "string");
@@ -349,29 +349,29 @@ void TextServerExtension::_bind_methods() {
bool TextServerExtension::has_feature(Feature p_feature) const {
bool ret = false;
- GDVIRTUAL_CALL(_has_feature, p_feature, ret);
+ GDVIRTUAL_REQUIRED_CALL(_has_feature, p_feature, ret);
return ret;
}
String TextServerExtension::get_name() const {
String ret = "Unknown";
- GDVIRTUAL_CALL(_get_name, ret);
+ GDVIRTUAL_REQUIRED_CALL(_get_name, ret);
return ret;
}
int64_t TextServerExtension::get_features() const {
int64_t ret = 0;
- GDVIRTUAL_CALL(_get_features, ret);
+ GDVIRTUAL_REQUIRED_CALL(_get_features, ret);
return ret;
}
void TextServerExtension::free_rid(const RID &p_rid) {
- GDVIRTUAL_CALL(_free_rid, p_rid);
+ GDVIRTUAL_REQUIRED_CALL(_free_rid, p_rid);
}
bool TextServerExtension::has(const RID &p_rid) {
bool ret = false;
- GDVIRTUAL_CALL(_has, p_rid, ret);
+ GDVIRTUAL_REQUIRED_CALL(_has, p_rid, ret);
return ret;
}
@@ -407,14 +407,18 @@ bool TextServerExtension::is_locale_right_to_left(const String &p_locale) const
int64_t TextServerExtension::name_to_tag(const String &p_name) const {
int64_t ret = 0;
- GDVIRTUAL_CALL(_name_to_tag, p_name, ret);
- return ret;
+ if (GDVIRTUAL_CALL(_name_to_tag, p_name, ret)) {
+ return ret;
+ }
+ return TextServer::name_to_tag(p_name);
}
String TextServerExtension::tag_to_name(int64_t p_tag) const {
String ret;
- GDVIRTUAL_CALL(_tag_to_name, p_tag, ret);
- return ret;
+ if (GDVIRTUAL_CALL(_tag_to_name, p_tag, ret)) {
+ return ret;
+ }
+ return TextServer::tag_to_name(p_tag);
}
/*************************************************************************/
@@ -423,7 +427,7 @@ String TextServerExtension::tag_to_name(int64_t p_tag) const {
RID TextServerExtension::create_font() {
RID ret;
- GDVIRTUAL_CALL(_create_font, ret);
+ GDVIRTUAL_REQUIRED_CALL(_create_font, ret);
return ret;
}
@@ -452,7 +456,7 @@ int64_t TextServerExtension::font_get_face_index(const RID &p_font_rid) const {
}
int64_t TextServerExtension::font_get_face_count(const RID &p_font_rid) const {
- int64_t ret = 0;
+ int64_t ret = 1;
GDVIRTUAL_CALL(_font_get_face_count, p_font_rid, ret);
return ret;
}
@@ -574,22 +578,22 @@ int64_t TextServerExtension::font_get_msdf_size(const RID &p_font_rid) const {
}
void TextServerExtension::font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) {
- GDVIRTUAL_CALL(_font_set_fixed_size, p_font_rid, p_fixed_size);
+ GDVIRTUAL_REQUIRED_CALL(_font_set_fixed_size, p_font_rid, p_fixed_size);
}
int64_t TextServerExtension::font_get_fixed_size(const RID &p_font_rid) const {
int64_t ret = 0;
- GDVIRTUAL_CALL(_font_get_fixed_size, p_font_rid, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_fixed_size, p_font_rid, ret);
return ret;
}
void TextServerExtension::font_set_fixed_size_scale_mode(const RID &p_font_rid, TextServer::FixedSizeScaleMode p_fixed_size_scale_mode) {
- GDVIRTUAL_CALL(_font_set_fixed_size_scale_mode, p_font_rid, p_fixed_size_scale_mode);
+ GDVIRTUAL_REQUIRED_CALL(_font_set_fixed_size_scale_mode, p_font_rid, p_fixed_size_scale_mode);
}
TextServer::FixedSizeScaleMode TextServerExtension::font_get_fixed_size_scale_mode(const RID &p_font_rid) const {
FixedSizeScaleMode ret = FIXED_SIZE_SCALE_DISABLE;
- GDVIRTUAL_CALL(_font_get_fixed_size_scale_mode, p_font_rid, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_fixed_size_scale_mode, p_font_rid, ret);
return ret;
}
@@ -695,89 +699,89 @@ double TextServerExtension::font_get_oversampling(const RID &p_font_rid) const {
TypedArray<Vector2i> TextServerExtension::font_get_size_cache_list(const RID &p_font_rid) const {
TypedArray<Vector2i> ret;
- GDVIRTUAL_CALL(_font_get_size_cache_list, p_font_rid, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_size_cache_list, p_font_rid, ret);
return ret;
}
void TextServerExtension::font_clear_size_cache(const RID &p_font_rid) {
- GDVIRTUAL_CALL(_font_clear_size_cache, p_font_rid);
+ GDVIRTUAL_REQUIRED_CALL(_font_clear_size_cache, p_font_rid);
}
void TextServerExtension::font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) {
- GDVIRTUAL_CALL(_font_remove_size_cache, p_font_rid, p_size);
+ GDVIRTUAL_REQUIRED_CALL(_font_remove_size_cache, p_font_rid, p_size);
}
void TextServerExtension::font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) {
- GDVIRTUAL_CALL(_font_set_ascent, p_font_rid, p_size, p_ascent);
+ GDVIRTUAL_REQUIRED_CALL(_font_set_ascent, p_font_rid, p_size, p_ascent);
}
double TextServerExtension::font_get_ascent(const RID &p_font_rid, int64_t p_size) const {
double ret = 0;
- GDVIRTUAL_CALL(_font_get_ascent, p_font_rid, p_size, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_ascent, p_font_rid, p_size, ret);
return ret;
}
void TextServerExtension::font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) {
- GDVIRTUAL_CALL(_font_set_descent, p_font_rid, p_size, p_descent);
+ GDVIRTUAL_REQUIRED_CALL(_font_set_descent, p_font_rid, p_size, p_descent);
}
double TextServerExtension::font_get_descent(const RID &p_font_rid, int64_t p_size) const {
double ret = 0;
- GDVIRTUAL_CALL(_font_get_descent, p_font_rid, p_size, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_descent, p_font_rid, p_size, ret);
return ret;
}
void TextServerExtension::font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) {
- GDVIRTUAL_CALL(_font_set_underline_position, p_font_rid, p_size, p_underline_position);
+ GDVIRTUAL_REQUIRED_CALL(_font_set_underline_position, p_font_rid, p_size, p_underline_position);
}
double TextServerExtension::font_get_underline_position(const RID &p_font_rid, int64_t p_size) const {
double ret = 0;
- GDVIRTUAL_CALL(_font_get_underline_position, p_font_rid, p_size, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_underline_position, p_font_rid, p_size, ret);
return ret;
}
void TextServerExtension::font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) {
- GDVIRTUAL_CALL(_font_set_underline_thickness, p_font_rid, p_size, p_underline_thickness);
+ GDVIRTUAL_REQUIRED_CALL(_font_set_underline_thickness, p_font_rid, p_size, p_underline_thickness);
}
double TextServerExtension::font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const {
double ret = 0;
- GDVIRTUAL_CALL(_font_get_underline_thickness, p_font_rid, p_size, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_underline_thickness, p_font_rid, p_size, ret);
return ret;
}
void TextServerExtension::font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) {
- GDVIRTUAL_CALL(_font_set_scale, p_font_rid, p_size, p_scale);
+ GDVIRTUAL_REQUIRED_CALL(_font_set_scale, p_font_rid, p_size, p_scale);
}
double TextServerExtension::font_get_scale(const RID &p_font_rid, int64_t p_size) const {
double ret = 0;
- GDVIRTUAL_CALL(_font_get_scale, p_font_rid, p_size, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_scale, p_font_rid, p_size, ret);
return ret;
}
int64_t TextServerExtension::font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const {
int64_t ret = 0;
- GDVIRTUAL_CALL(_font_get_texture_count, p_font_rid, p_size, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_texture_count, p_font_rid, p_size, ret);
return ret;
}
void TextServerExtension::font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) {
- GDVIRTUAL_CALL(_font_clear_textures, p_font_rid, p_size);
+ GDVIRTUAL_REQUIRED_CALL(_font_clear_textures, p_font_rid, p_size);
}
void TextServerExtension::font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) {
- GDVIRTUAL_CALL(_font_remove_texture, p_font_rid, p_size, p_texture_index);
+ GDVIRTUAL_REQUIRED_CALL(_font_remove_texture, p_font_rid, p_size, p_texture_index);
}
void TextServerExtension::font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) {
- GDVIRTUAL_CALL(_font_set_texture_image, p_font_rid, p_size, p_texture_index, p_image);
+ GDVIRTUAL_REQUIRED_CALL(_font_set_texture_image, p_font_rid, p_size, p_texture_index, p_image);
}
Ref<Image> TextServerExtension::font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
Ref<Image> ret;
- GDVIRTUAL_CALL(_font_get_texture_image, p_font_rid, p_size, p_texture_index, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_texture_image, p_font_rid, p_size, p_texture_index, ret);
return ret;
}
@@ -793,77 +797,77 @@ PackedInt32Array TextServerExtension::font_get_texture_offsets(const RID &p_font
PackedInt32Array TextServerExtension::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
PackedInt32Array ret;
- GDVIRTUAL_CALL(_font_get_glyph_list, p_font_rid, p_size, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_list, p_font_rid, p_size, ret);
return ret;
}
void TextServerExtension::font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) {
- GDVIRTUAL_CALL(_font_clear_glyphs, p_font_rid, p_size);
+ GDVIRTUAL_REQUIRED_CALL(_font_clear_glyphs, p_font_rid, p_size);
}
void TextServerExtension::font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) {
- GDVIRTUAL_CALL(_font_remove_glyph, p_font_rid, p_size, p_glyph);
+ GDVIRTUAL_REQUIRED_CALL(_font_remove_glyph, p_font_rid, p_size, p_glyph);
}
Vector2 TextServerExtension::font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const {
Vector2 ret;
- GDVIRTUAL_CALL(_font_get_glyph_advance, p_font_rid, p_size, p_glyph, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_advance, p_font_rid, p_size, p_glyph, ret);
return ret;
}
void TextServerExtension::font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) {
- GDVIRTUAL_CALL(_font_set_glyph_advance, p_font_rid, p_size, p_glyph, p_advance);
+ GDVIRTUAL_REQUIRED_CALL(_font_set_glyph_advance, p_font_rid, p_size, p_glyph, p_advance);
}
Vector2 TextServerExtension::font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
Vector2 ret;
- GDVIRTUAL_CALL(_font_get_glyph_offset, p_font_rid, p_size, p_glyph, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_offset, p_font_rid, p_size, p_glyph, ret);
return ret;
}
void TextServerExtension::font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) {
- GDVIRTUAL_CALL(_font_set_glyph_offset, p_font_rid, p_size, p_glyph, p_offset);
+ GDVIRTUAL_REQUIRED_CALL(_font_set_glyph_offset, p_font_rid, p_size, p_glyph, p_offset);
}
Vector2 TextServerExtension::font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
Vector2 ret;
- GDVIRTUAL_CALL(_font_get_glyph_size, p_font_rid, p_size, p_glyph, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_size, p_font_rid, p_size, p_glyph, ret);
return ret;
}
void TextServerExtension::font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) {
- GDVIRTUAL_CALL(_font_set_glyph_size, p_font_rid, p_size, p_glyph, p_gl_size);
+ GDVIRTUAL_REQUIRED_CALL(_font_set_glyph_size, p_font_rid, p_size, p_glyph, p_gl_size);
}
Rect2 TextServerExtension::font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
Rect2 ret;
- GDVIRTUAL_CALL(_font_get_glyph_uv_rect, p_font_rid, p_size, p_glyph, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_uv_rect, p_font_rid, p_size, p_glyph, ret);
return ret;
}
void TextServerExtension::font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) {
- GDVIRTUAL_CALL(_font_set_glyph_uv_rect, p_font_rid, p_size, p_glyph, p_uv_rect);
+ GDVIRTUAL_REQUIRED_CALL(_font_set_glyph_uv_rect, p_font_rid, p_size, p_glyph, p_uv_rect);
}
int64_t TextServerExtension::font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
int64_t ret = 0;
- GDVIRTUAL_CALL(_font_get_glyph_texture_idx, p_font_rid, p_size, p_glyph, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_texture_idx, p_font_rid, p_size, p_glyph, ret);
return ret;
}
void TextServerExtension::font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) {
- GDVIRTUAL_CALL(_font_set_glyph_texture_idx, p_font_rid, p_size, p_glyph, p_texture_idx);
+ GDVIRTUAL_REQUIRED_CALL(_font_set_glyph_texture_idx, p_font_rid, p_size, p_glyph, p_texture_idx);
}
RID TextServerExtension::font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
RID ret;
- GDVIRTUAL_CALL(_font_get_glyph_texture_rid, p_font_rid, p_size, p_glyph, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_texture_rid, p_font_rid, p_size, p_glyph, ret);
return ret;
}
Size2 TextServerExtension::font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
Size2 ret;
- GDVIRTUAL_CALL(_font_get_glyph_texture_size, p_font_rid, p_size, p_glyph, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_texture_size, p_font_rid, p_size, p_glyph, ret);
return ret;
}
@@ -899,25 +903,25 @@ Vector2 TextServerExtension::font_get_kerning(const RID &p_font_rid, int64_t p_s
int64_t TextServerExtension::font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const {
int64_t ret = 0;
- GDVIRTUAL_CALL(_font_get_glyph_index, p_font_rid, p_size, p_char, p_variation_selector, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_index, p_font_rid, p_size, p_char, p_variation_selector, ret);
return ret;
}
int64_t TextServerExtension::font_get_char_from_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_glyph_index) const {
int64_t ret = 0;
- GDVIRTUAL_CALL(_font_get_char_from_glyph_index, p_font_rid, p_size, p_glyph_index, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_char_from_glyph_index, p_font_rid, p_size, p_glyph_index, ret);
return ret;
}
bool TextServerExtension::font_has_char(const RID &p_font_rid, int64_t p_char) const {
bool ret = false;
- GDVIRTUAL_CALL(_font_has_char, p_font_rid, p_char, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_has_char, p_font_rid, p_char, ret);
return ret;
}
String TextServerExtension::font_get_supported_chars(const RID &p_font_rid) const {
String ret;
- GDVIRTUAL_CALL(_font_get_supported_chars, p_font_rid, ret);
+ GDVIRTUAL_REQUIRED_CALL(_font_get_supported_chars, p_font_rid, ret);
return ret;
}
@@ -930,11 +934,11 @@ void TextServerExtension::font_render_glyph(const RID &p_font_rid, const Vector2
}
void TextServerExtension::font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const {
- GDVIRTUAL_CALL(_font_draw_glyph, p_font_rid, p_canvas, p_size, p_pos, p_index, p_color);
+ GDVIRTUAL_REQUIRED_CALL(_font_draw_glyph, p_font_rid, p_canvas, p_size, p_pos, p_index, p_color);
}
void TextServerExtension::font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const {
- GDVIRTUAL_CALL(_font_draw_glyph_outline, p_font_rid, p_canvas, p_size, p_outline_size, p_pos, p_index, p_color);
+ GDVIRTUAL_REQUIRED_CALL(_font_draw_glyph_outline, p_font_rid, p_canvas, p_size, p_outline_size, p_pos, p_index, p_color);
}
bool TextServerExtension::font_is_language_supported(const RID &p_font_rid, const String &p_language) const {
@@ -1041,12 +1045,12 @@ void TextServerExtension::draw_hex_code_box(const RID &p_canvas, int64_t p_size,
RID TextServerExtension::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
RID ret;
- GDVIRTUAL_CALL(_create_shaped_text, p_direction, p_orientation, ret);
+ GDVIRTUAL_REQUIRED_CALL(_create_shaped_text, p_direction, p_orientation, ret);
return ret;
}
void TextServerExtension::shaped_text_clear(const RID &p_shaped) {
- GDVIRTUAL_CALL(_shaped_text_clear, p_shaped);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_clear, p_shaped);
}
void TextServerExtension::shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
@@ -1131,47 +1135,47 @@ int64_t TextServerExtension::shaped_text_get_spacing(const RID &p_shaped, TextSe
bool TextServerExtension::shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
bool ret = false;
- GDVIRTUAL_CALL(_shaped_text_add_string, p_shaped, p_text, p_fonts, p_size, p_opentype_features, p_language, p_meta, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_add_string, p_shaped, p_text, p_fonts, p_size, p_opentype_features, p_language, p_meta, ret);
return ret;
}
bool TextServerExtension::shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length, double p_baseline) {
bool ret = false;
- GDVIRTUAL_CALL(_shaped_text_add_object, p_shaped, p_key, p_size, p_inline_align, p_length, p_baseline, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_add_object, p_shaped, p_key, p_size, p_inline_align, p_length, p_baseline, ret);
return ret;
}
bool TextServerExtension::shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, double p_baseline) {
bool ret = false;
- GDVIRTUAL_CALL(_shaped_text_resize_object, p_shaped, p_key, p_size, p_inline_align, p_baseline, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_resize_object, p_shaped, p_key, p_size, p_inline_align, p_baseline, ret);
return ret;
}
int64_t TextServerExtension::shaped_get_span_count(const RID &p_shaped) const {
int64_t ret = 0;
- GDVIRTUAL_CALL(_shaped_get_span_count, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_get_span_count, p_shaped, ret);
return ret;
}
Variant TextServerExtension::shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const {
Variant ret = false;
- GDVIRTUAL_CALL(_shaped_get_span_meta, p_shaped, p_index, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_get_span_meta, p_shaped, p_index, ret);
return ret;
}
void TextServerExtension::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) {
- GDVIRTUAL_CALL(_shaped_set_span_update_font, p_shaped, p_index, p_fonts, p_size, p_opentype_features);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_set_span_update_font, p_shaped, p_index, p_fonts, p_size, p_opentype_features);
}
RID TextServerExtension::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {
RID ret;
- GDVIRTUAL_CALL(_shaped_text_substr, p_shaped, p_start, p_length, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_substr, p_shaped, p_start, p_length, ret);
return ret;
}
RID TextServerExtension::shaped_text_get_parent(const RID &p_shaped) const {
RID ret;
- GDVIRTUAL_CALL(_shaped_text_get_parent, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_parent, p_shaped, ret);
return ret;
}
@@ -1189,7 +1193,7 @@ double TextServerExtension::shaped_text_tab_align(const RID &p_shaped, const Pac
bool TextServerExtension::shaped_text_shape(const RID &p_shaped) {
bool ret = false;
- GDVIRTUAL_CALL(_shaped_text_shape, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_shape, p_shaped, ret);
return ret;
}
@@ -1207,31 +1211,31 @@ bool TextServerExtension::shaped_text_update_justification_ops(const RID &p_shap
bool TextServerExtension::shaped_text_is_ready(const RID &p_shaped) const {
bool ret = false;
- GDVIRTUAL_CALL(_shaped_text_is_ready, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_is_ready, p_shaped, ret);
return ret;
}
const Glyph *TextServerExtension::shaped_text_get_glyphs(const RID &p_shaped) const {
GDExtensionConstPtr<const Glyph> ret;
- GDVIRTUAL_CALL(_shaped_text_get_glyphs, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_glyphs, p_shaped, ret);
return ret;
}
const Glyph *TextServerExtension::shaped_text_sort_logical(const RID &p_shaped) {
GDExtensionConstPtr<const Glyph> ret;
- GDVIRTUAL_CALL(_shaped_text_sort_logical, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_sort_logical, p_shaped, ret);
return ret;
}
int64_t TextServerExtension::shaped_text_get_glyph_count(const RID &p_shaped) const {
int64_t ret = 0;
- GDVIRTUAL_CALL(_shaped_text_get_glyph_count, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_glyph_count, p_shaped, ret);
return ret;
}
Vector2i TextServerExtension::shaped_text_get_range(const RID &p_shaped) const {
Vector2i ret;
- GDVIRTUAL_CALL(_shaped_text_get_range, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_range, p_shaped, ret);
return ret;
}
@@ -1261,25 +1265,25 @@ PackedInt32Array TextServerExtension::shaped_text_get_word_breaks(const RID &p_s
int64_t TextServerExtension::shaped_text_get_trim_pos(const RID &p_shaped) const {
int64_t ret = -1;
- GDVIRTUAL_CALL(_shaped_text_get_trim_pos, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_trim_pos, p_shaped, ret);
return ret;
}
int64_t TextServerExtension::shaped_text_get_ellipsis_pos(const RID &p_shaped) const {
int64_t ret = -1;
- GDVIRTUAL_CALL(_shaped_text_get_ellipsis_pos, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_ellipsis_pos, p_shaped, ret);
return ret;
}
const Glyph *TextServerExtension::shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const {
GDExtensionConstPtr<const Glyph> ret;
- GDVIRTUAL_CALL(_shaped_text_get_ellipsis_glyphs, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_ellipsis_glyphs, p_shaped, ret);
return ret;
}
int64_t TextServerExtension::shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const {
int64_t ret = -1;
- GDVIRTUAL_CALL(_shaped_text_get_ellipsis_glyph_count, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_ellipsis_glyph_count, p_shaped, ret);
return ret;
}
@@ -1289,61 +1293,61 @@ void TextServerExtension::shaped_text_overrun_trim_to_width(const RID &p_shaped_
Array TextServerExtension::shaped_text_get_objects(const RID &p_shaped) const {
Array ret;
- GDVIRTUAL_CALL(_shaped_text_get_objects, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_objects, p_shaped, ret);
return ret;
}
Rect2 TextServerExtension::shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const {
Rect2 ret;
- GDVIRTUAL_CALL(_shaped_text_get_object_rect, p_shaped, p_key, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_object_rect, p_shaped, p_key, ret);
return ret;
}
Vector2i TextServerExtension::shaped_text_get_object_range(const RID &p_shaped, const Variant &p_key) const {
Vector2i ret;
- GDVIRTUAL_CALL(_shaped_text_get_object_range, p_shaped, p_key, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_object_range, p_shaped, p_key, ret);
return ret;
}
int64_t TextServerExtension::shaped_text_get_object_glyph(const RID &p_shaped, const Variant &p_key) const {
int64_t ret = -1;
- GDVIRTUAL_CALL(_shaped_text_get_object_glyph, p_shaped, p_key, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_object_glyph, p_shaped, p_key, ret);
return ret;
}
Size2 TextServerExtension::shaped_text_get_size(const RID &p_shaped) const {
Size2 ret;
- GDVIRTUAL_CALL(_shaped_text_get_size, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_size, p_shaped, ret);
return ret;
}
double TextServerExtension::shaped_text_get_ascent(const RID &p_shaped) const {
double ret = 0;
- GDVIRTUAL_CALL(_shaped_text_get_ascent, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_ascent, p_shaped, ret);
return ret;
}
double TextServerExtension::shaped_text_get_descent(const RID &p_shaped) const {
double ret = 0;
- GDVIRTUAL_CALL(_shaped_text_get_descent, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_descent, p_shaped, ret);
return ret;
}
double TextServerExtension::shaped_text_get_width(const RID &p_shaped) const {
double ret = 0;
- GDVIRTUAL_CALL(_shaped_text_get_width, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_width, p_shaped, ret);
return ret;
}
double TextServerExtension::shaped_text_get_underline_position(const RID &p_shaped) const {
double ret = 0;
- GDVIRTUAL_CALL(_shaped_text_get_underline_position, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_underline_position, p_shaped, ret);
return ret;
}
double TextServerExtension::shaped_text_get_underline_thickness(const RID &p_shaped) const {
double ret = 0;
- GDVIRTUAL_CALL(_shaped_text_get_underline_thickness, p_shaped, ret);
+ GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_underline_thickness, p_shaped, ret);
return ret;
}
@@ -1513,8 +1517,10 @@ String TextServerExtension::string_to_lower(const String &p_string, const String
TypedArray<Vector3i> TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
TypedArray<Vector3i> ret;
- GDVIRTUAL_CALL(_parse_structured_text, p_parser_type, p_args, p_text, ret);
- return ret;
+ if (GDVIRTUAL_CALL(_parse_structured_text, p_parser_type, p_args, p_text, ret)) {
+ return ret;
+ }
+ return TextServer::parse_structured_text(p_parser_type, p_args, p_text);
}
PackedInt32Array TextServerExtension::string_get_word_breaks(const String &p_string, const String &p_language, int64_t p_chars_per_line) const {
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index 64c1a2d7dd..078ee27753 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -642,6 +642,48 @@ void TextServer::_bind_methods() {
BIND_ENUM_CONSTANT(FIXED_SIZE_SCALE_ENABLED);
}
+_FORCE_INLINE_ int32_t ot_tag_from_string(const char *p_str, int p_len) {
+ char tag[4];
+ uint32_t i;
+
+ if (!p_str || !p_len || !*p_str) {
+ return OT_TAG(0, 0, 0, 0);
+ }
+
+ if (p_len < 0 || p_len > 4) {
+ p_len = 4;
+ }
+ for (i = 0; i < (uint32_t)p_len && p_str[i]; i++) {
+ tag[i] = p_str[i];
+ }
+
+ for (; i < 4; i++) {
+ tag[i] = ' ';
+ }
+
+ return OT_TAG(tag[0], tag[1], tag[2], tag[3]);
+}
+
+int64_t TextServer::name_to_tag(const String &p_name) const {
+ // No readable name, use tag string.
+ return ot_tag_from_string(p_name.replace("custom_", "").ascii().get_data(), -1);
+}
+
+_FORCE_INLINE_ void ot_tag_to_string(int32_t p_tag, char *p_buf) {
+ p_buf[0] = (char)(uint8_t)(p_tag >> 24);
+ p_buf[1] = (char)(uint8_t)(p_tag >> 16);
+ p_buf[2] = (char)(uint8_t)(p_tag >> 8);
+ p_buf[3] = (char)(uint8_t)(p_tag >> 0);
+}
+
+String TextServer::tag_to_name(int64_t p_tag) const {
+ // No readable name, use tag string.
+ char name[5];
+ memset(name, 0, 5);
+ ot_tag_to_string(p_tag, name);
+ return String("custom_") + String(name);
+}
+
Vector2 TextServer::get_hex_code_box_size(int64_t p_size, int64_t p_index) const {
int w = ((p_index <= 0xFF) ? 1 : ((p_index <= 0xFFFF) ? 2 : 3));
int sp = MAX(0, w - 1);
diff --git a/servers/text_server.h b/servers/text_server.h
index d16a0e0066..4a16ae64e8 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -43,6 +43,8 @@ class TypedArray;
struct Glyph;
struct CaretInfo;
+#define OT_TAG(m_c1, m_c2, m_c3, m_c4) ((int32_t)((((uint32_t)(m_c1) & 0xff) << 24) | (((uint32_t)(m_c2) & 0xff) << 16) | (((uint32_t)(m_c3) & 0xff) << 8) | ((uint32_t)(m_c4) & 0xff)))
+
class TextServer : public RefCounted {
GDCLASS(TextServer, RefCounted);
@@ -239,8 +241,8 @@ public:
virtual bool is_locale_right_to_left(const String &p_locale) const = 0;
- virtual int64_t name_to_tag(const String &p_name) const { return 0; };
- virtual String tag_to_name(int64_t p_tag) const { return ""; };
+ virtual int64_t name_to_tag(const String &p_name) const;
+ virtual String tag_to_name(int64_t p_tag) const;
/* Font interface */
diff --git a/tests/core/object/test_object.h b/tests/core/object/test_object.h
index e5d91db650..3a3013a102 100644
--- a/tests/core/object/test_object.h
+++ b/tests/core/object/test_object.h
@@ -95,6 +95,12 @@ public:
bool has_method(const StringName &p_method) const override {
return false;
}
+ int get_method_argument_count(const StringName &p_method, bool *r_is_valid = nullptr) const override {
+ if (r_is_valid) {
+ *r_is_valid = false;
+ }
+ return 0;
+ }
Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override {
return Variant();
}
diff --git a/tests/core/variant/test_callable.h b/tests/core/variant/test_callable.h
new file mode 100644
index 0000000000..3228e0a583
--- /dev/null
+++ b/tests/core/variant/test_callable.h
@@ -0,0 +1,140 @@
+/**************************************************************************/
+/* test_callable.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 TEST_CALLABLE_H
+#define TEST_CALLABLE_H
+
+#include "core/object/class_db.h"
+#include "core/object/object.h"
+
+#include "tests/test_macros.h"
+
+namespace TestCallable {
+
+class TestClass : public Object {
+ GDCLASS(TestClass, Object);
+
+protected:
+ static void _bind_methods() {
+ ClassDB::bind_method(D_METHOD("test_func_1", "foo", "bar"), &TestClass::test_func_1);
+ ClassDB::bind_method(D_METHOD("test_func_2", "foo", "bar", "baz"), &TestClass::test_func_2);
+ ClassDB::bind_static_method("TestClass", D_METHOD("test_func_5", "foo", "bar"), &TestClass::test_func_5);
+ ClassDB::bind_static_method("TestClass", D_METHOD("test_func_6", "foo", "bar", "baz"), &TestClass::test_func_6);
+
+ {
+ MethodInfo mi;
+ mi.name = "test_func_7";
+ mi.arguments.push_back(PropertyInfo(Variant::INT, "foo"));
+ mi.arguments.push_back(PropertyInfo(Variant::INT, "bar"));
+
+ ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "test_func_7", &TestClass::test_func_7, mi, varray(), false);
+ }
+
+ {
+ MethodInfo mi;
+ mi.name = "test_func_8";
+ mi.arguments.push_back(PropertyInfo(Variant::INT, "foo"));
+ mi.arguments.push_back(PropertyInfo(Variant::INT, "bar"));
+ mi.arguments.push_back(PropertyInfo(Variant::INT, "baz"));
+
+ ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "test_func_8", &TestClass::test_func_8, mi, varray(), false);
+ }
+ }
+
+public:
+ void test_func_1(int p_foo, int p_bar) {}
+ void test_func_2(int p_foo, int p_bar, int p_baz) {}
+
+ int test_func_3(int p_foo, int p_bar) const { return 0; }
+ int test_func_4(int p_foo, int p_bar, int p_baz) const { return 0; }
+
+ static void test_func_5(int p_foo, int p_bar) {}
+ static void test_func_6(int p_foo, int p_bar, int p_baz) {}
+
+ void test_func_7(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {}
+ void test_func_8(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {}
+};
+
+TEST_CASE("[Callable] Argument count") {
+ TestClass *my_test = memnew(TestClass);
+
+ // Bound methods tests.
+
+ // Test simple methods.
+ Callable callable_1 = Callable(my_test, "test_func_1");
+ CHECK_EQ(callable_1.get_argument_count(), 2);
+ Callable callable_2 = Callable(my_test, "test_func_2");
+ CHECK_EQ(callable_2.get_argument_count(), 3);
+ Callable callable_3 = Callable(my_test, "test_func_5");
+ CHECK_EQ(callable_3.get_argument_count(), 2);
+ Callable callable_4 = Callable(my_test, "test_func_6");
+ CHECK_EQ(callable_4.get_argument_count(), 3);
+
+ // Test vararg methods.
+ Callable callable_vararg_1 = Callable(my_test, "test_func_7");
+ CHECK_MESSAGE(callable_vararg_1.get_argument_count() == 2, "vararg Callable should return the number of declared arguments");
+ Callable callable_vararg_2 = Callable(my_test, "test_func_8");
+ CHECK_MESSAGE(callable_vararg_2.get_argument_count() == 3, "vararg Callable should return the number of declared arguments");
+
+ // Callable MP tests.
+
+ // Test simple methods.
+ Callable callable_mp_1 = callable_mp(my_test, &TestClass::test_func_1);
+ CHECK_EQ(callable_mp_1.get_argument_count(), 2);
+ Callable callable_mp_2 = callable_mp(my_test, &TestClass::test_func_2);
+ CHECK_EQ(callable_mp_2.get_argument_count(), 3);
+ Callable callable_mp_3 = callable_mp(my_test, &TestClass::test_func_3);
+ CHECK_EQ(callable_mp_3.get_argument_count(), 2);
+ Callable callable_mp_4 = callable_mp(my_test, &TestClass::test_func_4);
+ CHECK_EQ(callable_mp_4.get_argument_count(), 3);
+
+ // Test static methods.
+ Callable callable_mp_static_1 = callable_mp_static(&TestClass::test_func_5);
+ CHECK_EQ(callable_mp_static_1.get_argument_count(), 2);
+ Callable callable_mp_static_2 = callable_mp_static(&TestClass::test_func_6);
+ CHECK_EQ(callable_mp_static_2.get_argument_count(), 3);
+
+ // Test bind.
+ Callable callable_mp_bind_1 = callable_mp_2.bind(1);
+ CHECK_MESSAGE(callable_mp_bind_1.get_argument_count() == 2, "bind should subtract from the argument count");
+ Callable callable_mp_bind_2 = callable_mp_2.bind(1, 2);
+ CHECK_MESSAGE(callable_mp_bind_2.get_argument_count() == 1, "bind should subtract from the argument count");
+
+ // Test unbind.
+ Callable callable_mp_unbind_1 = callable_mp_2.unbind(1);
+ CHECK_MESSAGE(callable_mp_unbind_1.get_argument_count() == 4, "unbind should add to the argument count");
+ Callable callable_mp_unbind_2 = callable_mp_2.unbind(2);
+ CHECK_MESSAGE(callable_mp_unbind_2.get_argument_count() == 5, "unbind should add to the argument count");
+
+ memdelete(my_test);
+}
+} // namespace TestCallable
+
+#endif // TEST_CALLABLE_H
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 423932e2cd..24eb84127b 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -93,6 +93,7 @@
#include "tests/core/test_time.h"
#include "tests/core/threads/test_worker_thread_pool.h"
#include "tests/core/variant/test_array.h"
+#include "tests/core/variant/test_callable.h"
#include "tests/core/variant/test_dictionary.h"
#include "tests/core/variant/test_variant.h"
#include "tests/core/variant/test_variant_utility.h"
diff --git a/thirdparty/README.md b/thirdparty/README.md
index a36a8f209f..2c9bc36545 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -390,7 +390,7 @@ Files extracted from upstream source:
## icu4c
- Upstream: https://github.com/unicode-org/icu
-- Version: 74.1 (9edac7b78327a1cb58db29e2714b15f9fa14e4d7, 2023)
+- Version: 74.2 (2d029329c82c7792b985024b2bdab5fc7278fbc8, 2023)
- License: Unicode
Files extracted from upstream source:
@@ -690,7 +690,7 @@ Collection of single-file libraries used in Godot components.
## msdfgen
- Upstream: https://github.com/Chlumsky/msdfgen
-- Version: 1.10 (64a91eec3ca3787e6f78b4c99fcd3052ad3e37c0, 2021)
+- Version: 1.11 (f12d7ca00091a632a289865b85c3f2e0bfc6542d, 2023)
- License: MIT
Files extracted from the upstream source:
diff --git a/thirdparty/icu4c/common/unicode/uvernum.h b/thirdparty/icu4c/common/unicode/uvernum.h
index 9fc98e7380..1cdf8912f9 100644
--- a/thirdparty/icu4c/common/unicode/uvernum.h
+++ b/thirdparty/icu4c/common/unicode/uvernum.h
@@ -59,7 +59,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.6
*/
-#define U_ICU_VERSION_MINOR_NUM 1
+#define U_ICU_VERSION_MINOR_NUM 2
/** The current ICU patchlevel version as an integer.
* This value will change in the subsequent releases of ICU
@@ -132,7 +132,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.4
*/
-#define U_ICU_VERSION "74.1"
+#define U_ICU_VERSION "74.2"
/**
* The current ICU library major version number as a string, for library name suffixes.
@@ -151,7 +151,7 @@
/** Data version in ICU4C.
* @internal ICU 4.4 Internal Use Only
**/
-#define U_ICU_DATA_VERSION "74.1"
+#define U_ICU_DATA_VERSION "74.2"
#endif /* U_HIDE_INTERNAL_API */
/*===========================================================================
diff --git a/thirdparty/icu4c/icudt74l.dat b/thirdparty/icu4c/icudt74l.dat
index 8576067fd0..e4ce73e23c 100644
--- a/thirdparty/icu4c/icudt74l.dat
+++ b/thirdparty/icu4c/icudt74l.dat
Binary files differ
diff --git a/thirdparty/msdfgen/LICENSE.txt b/thirdparty/msdfgen/LICENSE.txt
index 9757001664..69054bd2e1 100644
--- a/thirdparty/msdfgen/LICENSE.txt
+++ b/thirdparty/msdfgen/LICENSE.txt
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2016 - 2022 Viktor Chlumsky
+Copyright (c) 2016 - 2023 Viktor Chlumsky
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/msdfgen/core/Bitmap.h b/thirdparty/msdfgen/core/Bitmap.h
index 14407d6c34..9a08749f47 100644
--- a/thirdparty/msdfgen/core/Bitmap.h
+++ b/thirdparty/msdfgen/core/Bitmap.h
@@ -18,17 +18,17 @@ public:
Bitmap(Bitmap<T, N> &&orig);
#endif
~Bitmap();
- Bitmap<T, N> & operator=(const BitmapConstRef<T, N> &orig);
- Bitmap<T, N> & operator=(const Bitmap<T, N> &orig);
+ Bitmap<T, N> &operator=(const BitmapConstRef<T, N> &orig);
+ Bitmap<T, N> &operator=(const Bitmap<T, N> &orig);
#ifdef MSDFGEN_USE_CPP11
- Bitmap<T, N> & operator=(Bitmap<T, N> &&orig);
+ Bitmap<T, N> &operator=(Bitmap<T, N> &&orig);
#endif
/// Bitmap width in pixels.
int width() const;
/// Bitmap height in pixels.
int height() const;
- T * operator()(int x, int y);
- const T * operator()(int x, int y) const;
+ T *operator()(int x, int y);
+ const T *operator()(int x, int y) const;
#ifdef MSDFGEN_USE_CPP11
explicit operator T *();
explicit operator const T *() const;
diff --git a/thirdparty/msdfgen/core/Bitmap.hpp b/thirdparty/msdfgen/core/Bitmap.hpp
index cb16cac8d4..9404357788 100644
--- a/thirdparty/msdfgen/core/Bitmap.hpp
+++ b/thirdparty/msdfgen/core/Bitmap.hpp
@@ -40,7 +40,7 @@ Bitmap<T, N>::~Bitmap() {
}
template <typename T, int N>
-Bitmap<T, N> & Bitmap<T, N>::operator=(const BitmapConstRef<T, N> &orig) {
+Bitmap<T, N> &Bitmap<T, N>::operator=(const BitmapConstRef<T, N> &orig) {
if (pixels != orig.pixels) {
delete [] pixels;
w = orig.width, h = orig.height;
@@ -51,7 +51,7 @@ Bitmap<T, N> & Bitmap<T, N>::operator=(const BitmapConstRef<T, N> &orig) {
}
template <typename T, int N>
-Bitmap<T, N> & Bitmap<T, N>::operator=(const Bitmap<T, N> &orig) {
+Bitmap<T, N> &Bitmap<T, N>::operator=(const Bitmap<T, N> &orig) {
if (this != &orig) {
delete [] pixels;
w = orig.w, h = orig.h;
@@ -63,7 +63,7 @@ Bitmap<T, N> & Bitmap<T, N>::operator=(const Bitmap<T, N> &orig) {
#ifdef MSDFGEN_USE_CPP11
template <typename T, int N>
-Bitmap<T, N> & Bitmap<T, N>::operator=(Bitmap<T, N> &&orig) {
+Bitmap<T, N> &Bitmap<T, N>::operator=(Bitmap<T, N> &&orig) {
if (this != &orig) {
delete [] pixels;
pixels = orig.pixels;
@@ -85,12 +85,12 @@ int Bitmap<T, N>::height() const {
}
template <typename T, int N>
-T * Bitmap<T, N>::operator()(int x, int y) {
+T *Bitmap<T, N>::operator()(int x, int y) {
return pixels+N*(w*y+x);
}
template <typename T, int N>
-const T * Bitmap<T, N>::operator()(int x, int y) const {
+const T *Bitmap<T, N>::operator()(int x, int y) const {
return pixels+N*(w*y+x);
}
diff --git a/thirdparty/msdfgen/core/BitmapRef.hpp b/thirdparty/msdfgen/core/BitmapRef.hpp
index 6f9620dcdf..cb17f95dcb 100644
--- a/thirdparty/msdfgen/core/BitmapRef.hpp
+++ b/thirdparty/msdfgen/core/BitmapRef.hpp
@@ -1,12 +1,10 @@
#pragma once
-#include <cstdlib>
+#include "base.h"
namespace msdfgen {
-typedef unsigned char byte;
-
/// Reference to a 2D image bitmap or a buffer acting as one. Pixel storage not owned or managed by the object.
template <typename T, int N = 1>
struct BitmapRef {
@@ -17,7 +15,7 @@ struct BitmapRef {
inline BitmapRef() : pixels(NULL), width(0), height(0) { }
inline BitmapRef(T *pixels, int width, int height) : pixels(pixels), width(width), height(height) { }
- inline T * operator()(int x, int y) const {
+ inline T *operator()(int x, int y) const {
return pixels+N*(width*y+x);
}
@@ -34,7 +32,7 @@ struct BitmapConstRef {
inline BitmapConstRef(const T *pixels, int width, int height) : pixels(pixels), width(width), height(height) { }
inline BitmapConstRef(const BitmapRef<T, N> &orig) : pixels(orig.pixels), width(orig.width), height(orig.height) { }
- inline const T * operator()(int x, int y) const {
+ inline const T *operator()(int x, int y) const {
return pixels+N*(width*y+x);
}
diff --git a/thirdparty/msdfgen/core/Contour.cpp b/thirdparty/msdfgen/core/Contour.cpp
index ca80d3c55a..57293dc58b 100644
--- a/thirdparty/msdfgen/core/Contour.cpp
+++ b/thirdparty/msdfgen/core/Contour.cpp
@@ -19,7 +19,7 @@ void Contour::addEdge(EdgeHolder &&edge) {
}
#endif
-EdgeHolder & Contour::addEdge() {
+EdgeHolder &Contour::addEdge() {
edges.resize(edges.size()+1);
return edges.back();
}
diff --git a/thirdparty/msdfgen/core/Contour.h b/thirdparty/msdfgen/core/Contour.h
index f79b269582..4cae48fad7 100644
--- a/thirdparty/msdfgen/core/Contour.h
+++ b/thirdparty/msdfgen/core/Contour.h
@@ -19,7 +19,7 @@ public:
void addEdge(EdgeHolder &&edge);
#endif
/// Creates a new edge in the contour and returns its reference.
- EdgeHolder & addEdge();
+ EdgeHolder &addEdge();
/// Adjusts the bounding box to fit the contour.
void bound(double &l, double &b, double &r, double &t) const;
/// Adjusts the bounding box to fit the contour border's mitered corners.
diff --git a/thirdparty/msdfgen/core/EdgeColor.h b/thirdparty/msdfgen/core/EdgeColor.h
index 9d49a5a89e..5d3730c9a6 100644
--- a/thirdparty/msdfgen/core/EdgeColor.h
+++ b/thirdparty/msdfgen/core/EdgeColor.h
@@ -1,6 +1,8 @@
#pragma once
+#include "base.h"
+
namespace msdfgen {
/// Edge color specifies which color channels an edge belongs to.
diff --git a/thirdparty/msdfgen/core/EdgeHolder.cpp b/thirdparty/msdfgen/core/EdgeHolder.cpp
index 1a8c5f66e9..cffcff46d3 100644
--- a/thirdparty/msdfgen/core/EdgeHolder.cpp
+++ b/thirdparty/msdfgen/core/EdgeHolder.cpp
@@ -31,7 +31,7 @@ EdgeHolder::~EdgeHolder() {
delete edgeSegment;
}
-EdgeHolder & EdgeHolder::operator=(const EdgeHolder &orig) {
+EdgeHolder &EdgeHolder::operator=(const EdgeHolder &orig) {
if (this != &orig) {
delete edgeSegment;
edgeSegment = orig.edgeSegment ? orig.edgeSegment->clone() : NULL;
@@ -40,7 +40,7 @@ EdgeHolder & EdgeHolder::operator=(const EdgeHolder &orig) {
}
#ifdef MSDFGEN_USE_CPP11
-EdgeHolder & EdgeHolder::operator=(EdgeHolder &&orig) {
+EdgeHolder &EdgeHolder::operator=(EdgeHolder &&orig) {
if (this != &orig) {
delete edgeSegment;
edgeSegment = orig.edgeSegment;
@@ -50,19 +50,19 @@ EdgeHolder & EdgeHolder::operator=(EdgeHolder &&orig) {
}
#endif
-EdgeSegment & EdgeHolder::operator*() {
+EdgeSegment &EdgeHolder::operator*() {
return *edgeSegment;
}
-const EdgeSegment & EdgeHolder::operator*() const {
+const EdgeSegment &EdgeHolder::operator*() const {
return *edgeSegment;
}
-EdgeSegment * EdgeHolder::operator->() {
+EdgeSegment *EdgeHolder::operator->() {
return edgeSegment;
}
-const EdgeSegment * EdgeHolder::operator->() const {
+const EdgeSegment *EdgeHolder::operator->() const {
return edgeSegment;
}
diff --git a/thirdparty/msdfgen/core/EdgeHolder.h b/thirdparty/msdfgen/core/EdgeHolder.h
index c4c5be7616..50a59b2189 100644
--- a/thirdparty/msdfgen/core/EdgeHolder.h
+++ b/thirdparty/msdfgen/core/EdgeHolder.h
@@ -22,14 +22,14 @@ public:
EdgeHolder(EdgeHolder &&orig);
#endif
~EdgeHolder();
- EdgeHolder & operator=(const EdgeHolder &orig);
+ EdgeHolder &operator=(const EdgeHolder &orig);
#ifdef MSDFGEN_USE_CPP11
- EdgeHolder & operator=(EdgeHolder &&orig);
+ EdgeHolder &operator=(EdgeHolder &&orig);
#endif
- EdgeSegment & operator*();
- const EdgeSegment & operator*() const;
- EdgeSegment * operator->();
- const EdgeSegment * operator->() const;
+ EdgeSegment &operator*();
+ const EdgeSegment &operator*() const;
+ EdgeSegment *operator->();
+ const EdgeSegment *operator->() const;
operator EdgeSegment *();
operator const EdgeSegment *() const;
diff --git a/thirdparty/msdfgen/core/MSDFErrorCorrection.cpp b/thirdparty/msdfgen/core/MSDFErrorCorrection.cpp
index 7918597fd2..9a5cefe128 100644
--- a/thirdparty/msdfgen/core/MSDFErrorCorrection.cpp
+++ b/thirdparty/msdfgen/core/MSDFErrorCorrection.cpp
@@ -19,8 +19,8 @@ namespace msdfgen {
#define CLASSIFIER_FLAG_CANDIDATE 0x01
#define CLASSIFIER_FLAG_ARTIFACT 0x02
-const double ErrorCorrectionConfig::defaultMinDeviationRatio = 1.11111111111111111;
-const double ErrorCorrectionConfig::defaultMinImproveRatio = 1.11111111111111111;
+MSDFGEN_PUBLIC const double ErrorCorrectionConfig::defaultMinDeviationRatio = 1.11111111111111111;
+MSDFGEN_PUBLIC const double ErrorCorrectionConfig::defaultMinImproveRatio = 1.11111111111111111;
/// The base artifact classifier recognizes artifacts based on the contents of the SDF alone.
class BaseArtifactClassifier {
@@ -317,7 +317,7 @@ static bool hasDiagonalArtifactInner(const ArtifactClassifier &artifactClassifie
em[0] = am, em[1] = dm;
tEnd[tEx0 > t[i]] = tEx0;
em[tEx0 > t[i]] = interpolatedMedian(a, l, q, tEx0);
- rangeFlags |= artifactClassifier.rangeTest(tEnd[0], tEnd[1], t[i], am, dm, xm);
+ rangeFlags |= artifactClassifier.rangeTest(tEnd[0], tEnd[1], t[i], em[0], em[1], xm);
}
// tEx1
if (tEx1 > 0 && tEx1 < 1) {
@@ -325,7 +325,7 @@ static bool hasDiagonalArtifactInner(const ArtifactClassifier &artifactClassifie
em[0] = am, em[1] = dm;
tEnd[tEx1 > t[i]] = tEx1;
em[tEx1 > t[i]] = interpolatedMedian(a, l, q, tEx1);
- rangeFlags |= artifactClassifier.rangeTest(tEnd[0], tEnd[1], t[i], am, dm, xm);
+ rangeFlags |= artifactClassifier.rangeTest(tEnd[0], tEnd[1], t[i], em[0], em[1], xm);
}
if (artifactClassifier.evaluate(t[i], xm, rangeFlags))
return true;
diff --git a/thirdparty/msdfgen/core/Projection.h b/thirdparty/msdfgen/core/Projection.h
index 7cdb1c307a..3c457776ac 100644
--- a/thirdparty/msdfgen/core/Projection.h
+++ b/thirdparty/msdfgen/core/Projection.h
@@ -1,7 +1,7 @@
#pragma once
-#include "Vector2.h"
+#include "Vector2.hpp"
namespace msdfgen {
diff --git a/thirdparty/msdfgen/core/Scanline.cpp b/thirdparty/msdfgen/core/Scanline.cpp
index 8e5352dbf6..7407be41b5 100644
--- a/thirdparty/msdfgen/core/Scanline.cpp
+++ b/thirdparty/msdfgen/core/Scanline.cpp
@@ -1,7 +1,7 @@
#include "Scanline.h"
-#include <algorithm>
+#include <cstdlib>
#include "arithmetics.hpp"
namespace msdfgen {
diff --git a/thirdparty/msdfgen/core/Scanline.h b/thirdparty/msdfgen/core/Scanline.h
index 9c8f34044b..c0abc68642 100644
--- a/thirdparty/msdfgen/core/Scanline.h
+++ b/thirdparty/msdfgen/core/Scanline.h
@@ -2,6 +2,7 @@
#pragma once
#include <vector>
+#include "base.h"
namespace msdfgen {
diff --git a/thirdparty/msdfgen/core/Shape.cpp b/thirdparty/msdfgen/core/Shape.cpp
index 8d6f47c807..cf99bd0f0c 100644
--- a/thirdparty/msdfgen/core/Shape.cpp
+++ b/thirdparty/msdfgen/core/Shape.cpp
@@ -1,7 +1,7 @@
#include "Shape.h"
-#include <algorithm>
+#include <cstdlib>
#include "arithmetics.hpp"
namespace msdfgen {
@@ -18,7 +18,7 @@ void Shape::addContour(Contour &&contour) {
}
#endif
-Contour & Shape::addContour() {
+Contour &Shape::addContour() {
contours.resize(contours.size()+1);
return contours.back();
}
@@ -40,15 +40,12 @@ bool Shape::validate() const {
}
static void deconvergeEdge(EdgeHolder &edgeHolder, int param) {
- {
- const QuadraticSegment *quadraticSegment = dynamic_cast<const QuadraticSegment *>(&*edgeHolder);
- if (quadraticSegment)
- edgeHolder = quadraticSegment->convertToCubic();
- }
- {
- CubicSegment *cubicSegment = dynamic_cast<CubicSegment *>(&*edgeHolder);
- if (cubicSegment)
- cubicSegment->deconverge(param, MSDFGEN_DECONVERGENCE_FACTOR);
+ switch (edgeHolder->type()) {
+ case (int) QuadraticSegment::EDGE_TYPE:
+ edgeHolder = static_cast<const QuadraticSegment *>(&*edgeHolder)->convertToCubic();
+ // fallthrough
+ case (int) CubicSegment::EDGE_TYPE:
+ static_cast<CubicSegment *>(&*edgeHolder)->deconverge(param, MSDFGEN_DECONVERGENCE_FACTOR);
}
}
@@ -162,16 +159,18 @@ void Shape::orientContours() {
}
}
}
- qsort(&intersections[0], intersections.size(), sizeof(Intersection), &Intersection::compare);
- // Disqualify multiple intersections
- for (int j = 1; j < (int) intersections.size(); ++j)
- if (intersections[j].x == intersections[j-1].x)
- intersections[j].direction = intersections[j-1].direction = 0;
- // Inspect scanline and deduce orientations of intersected contours
- for (int j = 0; j < (int) intersections.size(); ++j)
- if (intersections[j].direction)
- orientations[intersections[j].contourIndex] += 2*((j&1)^(intersections[j].direction > 0))-1;
- intersections.clear();
+ if (!intersections.empty()) {
+ qsort(&intersections[0], intersections.size(), sizeof(Intersection), &Intersection::compare);
+ // Disqualify multiple intersections
+ for (int j = 1; j < (int) intersections.size(); ++j)
+ if (intersections[j].x == intersections[j-1].x)
+ intersections[j].direction = intersections[j-1].direction = 0;
+ // Inspect scanline and deduce orientations of intersected contours
+ for (int j = 0; j < (int) intersections.size(); ++j)
+ if (intersections[j].direction)
+ orientations[intersections[j].contourIndex] += 2*((j&1)^(intersections[j].direction > 0))-1;
+ intersections.clear();
+ }
}
}
// Reverse contours that have the opposite orientation
diff --git a/thirdparty/msdfgen/core/Shape.h b/thirdparty/msdfgen/core/Shape.h
index 7539921ce7..fd9222dbc4 100644
--- a/thirdparty/msdfgen/core/Shape.h
+++ b/thirdparty/msdfgen/core/Shape.h
@@ -32,7 +32,7 @@ public:
void addContour(Contour &&contour);
#endif
/// Adds a blank contour and returns its reference.
- Contour & addContour();
+ Contour &addContour();
/// Normalizes the shape geometry for distance field generation.
void normalize();
/// Performs basic checks to determine if the object represents a valid shape.
diff --git a/thirdparty/msdfgen/core/ShapeDistanceFinder.h b/thirdparty/msdfgen/core/ShapeDistanceFinder.h
index 57df8d8e72..d8a584f645 100644
--- a/thirdparty/msdfgen/core/ShapeDistanceFinder.h
+++ b/thirdparty/msdfgen/core/ShapeDistanceFinder.h
@@ -2,7 +2,7 @@
#pragma once
#include <vector>
-#include "Vector2.h"
+#include "Vector2.hpp"
#include "edge-selectors.h"
#include "contour-combiners.h"
diff --git a/thirdparty/msdfgen/core/ShapeDistanceFinder.hpp b/thirdparty/msdfgen/core/ShapeDistanceFinder.hpp
index 028738e5c3..07fb5cdc0e 100644
--- a/thirdparty/msdfgen/core/ShapeDistanceFinder.hpp
+++ b/thirdparty/msdfgen/core/ShapeDistanceFinder.hpp
@@ -9,7 +9,11 @@ ShapeDistanceFinder<ContourCombiner>::ShapeDistanceFinder(const Shape &shape) :
template <class ContourCombiner>
typename ShapeDistanceFinder<ContourCombiner>::DistanceType ShapeDistanceFinder<ContourCombiner>::distance(const Point2 &origin) {
contourCombiner.reset(origin);
- typename ContourCombiner::EdgeSelectorType::EdgeCache *edgeCache = &shapeEdgeCache[0];
+#ifdef MSDFGEN_USE_CPP11
+ typename ContourCombiner::EdgeSelectorType::EdgeCache *edgeCache = shapeEdgeCache.data();
+#else
+ typename ContourCombiner::EdgeSelectorType::EdgeCache *edgeCache = shapeEdgeCache.empty() ? NULL : &shapeEdgeCache[0];
+#endif
for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
if (!contour->edges.empty()) {
diff --git a/thirdparty/msdfgen/core/SignedDistance.cpp b/thirdparty/msdfgen/core/SignedDistance.cpp
deleted file mode 100644
index be956d953e..0000000000
--- a/thirdparty/msdfgen/core/SignedDistance.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-
-#include "SignedDistance.h"
-
-#include <cmath>
-#include <cfloat>
-
-namespace msdfgen {
-
-SignedDistance::SignedDistance() : distance(-DBL_MAX), dot(1) { }
-
-SignedDistance::SignedDistance(double dist, double d) : distance(dist), dot(d) { }
-
-bool operator<(SignedDistance a, SignedDistance b) {
- return fabs(a.distance) < fabs(b.distance) || (fabs(a.distance) == fabs(b.distance) && a.dot < b.dot);
-}
-
-bool operator>(SignedDistance a, SignedDistance b) {
- return fabs(a.distance) > fabs(b.distance) || (fabs(a.distance) == fabs(b.distance) && a.dot > b.dot);
-}
-
-bool operator<=(SignedDistance a, SignedDistance b) {
- return fabs(a.distance) < fabs(b.distance) || (fabs(a.distance) == fabs(b.distance) && a.dot <= b.dot);
-}
-
-bool operator>=(SignedDistance a, SignedDistance b) {
- return fabs(a.distance) > fabs(b.distance) || (fabs(a.distance) == fabs(b.distance) && a.dot >= b.dot);
-}
-
-}
diff --git a/thirdparty/msdfgen/core/SignedDistance.h b/thirdparty/msdfgen/core/SignedDistance.h
deleted file mode 100644
index 91fee97600..0000000000
--- a/thirdparty/msdfgen/core/SignedDistance.h
+++ /dev/null
@@ -1,23 +0,0 @@
-
-#pragma once
-
-namespace msdfgen {
-
-/// Represents a signed distance and alignment, which together can be compared to uniquely determine the closest edge segment.
-class SignedDistance {
-
-public:
- double distance;
- double dot;
-
- SignedDistance();
- SignedDistance(double dist, double d);
-
- friend bool operator<(SignedDistance a, SignedDistance b);
- friend bool operator>(SignedDistance a, SignedDistance b);
- friend bool operator<=(SignedDistance a, SignedDistance b);
- friend bool operator>=(SignedDistance a, SignedDistance b);
-
-};
-
-}
diff --git a/thirdparty/msdfgen/core/SignedDistance.hpp b/thirdparty/msdfgen/core/SignedDistance.hpp
new file mode 100644
index 0000000000..62e73c03aa
--- /dev/null
+++ b/thirdparty/msdfgen/core/SignedDistance.hpp
@@ -0,0 +1,38 @@
+
+#pragma once
+
+#include <cmath>
+#include <cfloat>
+#include "base.h"
+
+namespace msdfgen {
+
+/// Represents a signed distance and alignment, which together can be compared to uniquely determine the closest edge segment.
+class SignedDistance {
+
+public:
+ double distance;
+ double dot;
+
+ inline SignedDistance() : distance(-DBL_MAX), dot(0) { }
+ inline SignedDistance(double dist, double d) : distance(dist), dot(d) { }
+
+};
+
+inline bool operator<(const SignedDistance a, const SignedDistance b) {
+ return fabs(a.distance) < fabs(b.distance) || (fabs(a.distance) == fabs(b.distance) && a.dot < b.dot);
+}
+
+inline bool operator>(const SignedDistance a, const SignedDistance b) {
+ return fabs(a.distance) > fabs(b.distance) || (fabs(a.distance) == fabs(b.distance) && a.dot > b.dot);
+}
+
+inline bool operator<=(const SignedDistance a, const SignedDistance b) {
+ return fabs(a.distance) < fabs(b.distance) || (fabs(a.distance) == fabs(b.distance) && a.dot <= b.dot);
+}
+
+inline bool operator>=(const SignedDistance a, const SignedDistance b) {
+ return fabs(a.distance) > fabs(b.distance) || (fabs(a.distance) == fabs(b.distance) && a.dot >= b.dot);
+}
+
+}
diff --git a/thirdparty/msdfgen/core/Vector2.cpp b/thirdparty/msdfgen/core/Vector2.cpp
deleted file mode 100644
index 896963ff2c..0000000000
--- a/thirdparty/msdfgen/core/Vector2.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-
-#include "Vector2.h"
-
-namespace msdfgen {
-
-Vector2::Vector2(double val) : x(val), y(val) { }
-
-Vector2::Vector2(double x, double y) : x(x), y(y) { }
-
-void Vector2::reset() {
- x = 0, y = 0;
-}
-
-void Vector2::set(double x, double y) {
- Vector2::x = x, Vector2::y = y;
-}
-
-double Vector2::length() const {
- return sqrt(x*x+y*y);
-}
-
-double Vector2::direction() const {
- return atan2(y, x);
-}
-
-Vector2 Vector2::normalize(bool allowZero) const {
- double len = length();
- if (len == 0)
- return Vector2(0, !allowZero);
- return Vector2(x/len, y/len);
-}
-
-Vector2 Vector2::getOrthogonal(bool polarity) const {
- return polarity ? Vector2(-y, x) : Vector2(y, -x);
-}
-
-Vector2 Vector2::getOrthonormal(bool polarity, bool allowZero) const {
- double len = length();
- if (len == 0)
- return polarity ? Vector2(0, !allowZero) : Vector2(0, -!allowZero);
- return polarity ? Vector2(-y/len, x/len) : Vector2(y/len, -x/len);
-}
-
-Vector2 Vector2::project(const Vector2 &vector, bool positive) const {
- Vector2 n = normalize(true);
- double t = dotProduct(vector, n);
- if (positive && t <= 0)
- return Vector2();
- return t*n;
-}
-
-Vector2::operator const void*() const {
- return x || y ? this : NULL;
-}
-
-bool Vector2::operator!() const {
- return !x && !y;
-}
-
-bool Vector2::operator==(const Vector2 &other) const {
- return x == other.x && y == other.y;
-}
-
-bool Vector2::operator!=(const Vector2 &other) const {
- return x != other.x || y != other.y;
-}
-
-Vector2 Vector2::operator+() const {
- return *this;
-}
-
-Vector2 Vector2::operator-() const {
- return Vector2(-x, -y);
-}
-
-Vector2 Vector2::operator+(const Vector2 &other) const {
- return Vector2(x+other.x, y+other.y);
-}
-
-Vector2 Vector2::operator-(const Vector2 &other) const {
- return Vector2(x-other.x, y-other.y);
-}
-
-Vector2 Vector2::operator*(const Vector2 &other) const {
- return Vector2(x*other.x, y*other.y);
-}
-
-Vector2 Vector2::operator/(const Vector2 &other) const {
- return Vector2(x/other.x, y/other.y);
-}
-
-Vector2 Vector2::operator*(double value) const {
- return Vector2(x*value, y*value);
-}
-
-Vector2 Vector2::operator/(double value) const {
- return Vector2(x/value, y/value);
-}
-
-Vector2 & Vector2::operator+=(const Vector2 &other) {
- x += other.x, y += other.y;
- return *this;
-}
-
-Vector2 & Vector2::operator-=(const Vector2 &other) {
- x -= other.x, y -= other.y;
- return *this;
-}
-
-Vector2 & Vector2::operator*=(const Vector2 &other) {
- x *= other.x, y *= other.y;
- return *this;
-}
-
-Vector2 & Vector2::operator/=(const Vector2 &other) {
- x /= other.x, y /= other.y;
- return *this;
-}
-
-Vector2 & Vector2::operator*=(double value) {
- x *= value, y *= value;
- return *this;
-}
-
-Vector2 & Vector2::operator/=(double value) {
- x /= value, y /= value;
- return *this;
-}
-
-double dotProduct(const Vector2 &a, const Vector2 &b) {
- return a.x*b.x+a.y*b.y;
-}
-
-double crossProduct(const Vector2 &a, const Vector2 &b) {
- return a.x*b.y-a.y*b.x;
-}
-
-Vector2 operator*(double value, const Vector2 &vector) {
- return Vector2(value*vector.x, value*vector.y);
-}
-
-Vector2 operator/(double value, const Vector2 &vector) {
- return Vector2(value/vector.x, value/vector.y);
-}
-
-}
diff --git a/thirdparty/msdfgen/core/Vector2.h b/thirdparty/msdfgen/core/Vector2.h
deleted file mode 100644
index 47ca637c3d..0000000000
--- a/thirdparty/msdfgen/core/Vector2.h
+++ /dev/null
@@ -1,66 +0,0 @@
-
-#pragma once
-
-#include <cstdlib>
-#include <cmath>
-
-namespace msdfgen {
-
-/**
-* A 2-dimensional euclidean vector with double precision.
-* Implementation based on the Vector2 template from Artery Engine.
-* @author Viktor Chlumsky
-*/
-struct Vector2 {
-
- double x, y;
-
- Vector2(double val = 0);
- Vector2(double x, double y);
- /// Sets the vector to zero.
- void reset();
- /// Sets individual elements of the vector.
- void set(double x, double y);
- /// Returns the vector's length.
- double length() const;
- /// Returns the angle of the vector in radians (atan2).
- double direction() const;
- /// Returns the normalized vector - one that has the same direction but unit length.
- Vector2 normalize(bool allowZero = false) const;
- /// Returns a vector with the same length that is orthogonal to this one.
- Vector2 getOrthogonal(bool polarity = true) const;
- /// Returns a vector with unit length that is orthogonal to this one.
- Vector2 getOrthonormal(bool polarity = true, bool allowZero = false) const;
- /// Returns a vector projected along this one.
- Vector2 project(const Vector2 &vector, bool positive = false) const;
- operator const void *() const;
- bool operator!() const;
- bool operator==(const Vector2 &other) const;
- bool operator!=(const Vector2 &other) const;
- Vector2 operator+() const;
- Vector2 operator-() const;
- Vector2 operator+(const Vector2 &other) const;
- Vector2 operator-(const Vector2 &other) const;
- Vector2 operator*(const Vector2 &other) const;
- Vector2 operator/(const Vector2 &other) const;
- Vector2 operator*(double value) const;
- Vector2 operator/(double value) const;
- Vector2 & operator+=(const Vector2 &other);
- Vector2 & operator-=(const Vector2 &other);
- Vector2 & operator*=(const Vector2 &other);
- Vector2 & operator/=(const Vector2 &other);
- Vector2 & operator*=(double value);
- Vector2 & operator/=(double value);
- /// Dot product of two vectors.
- friend double dotProduct(const Vector2 &a, const Vector2 &b);
- /// A special version of the cross product for 2D vectors (returns scalar value).
- friend double crossProduct(const Vector2 &a, const Vector2 &b);
- friend Vector2 operator*(double value, const Vector2 &vector);
- friend Vector2 operator/(double value, const Vector2 &vector);
-
-};
-
-/// A vector may also represent a point, which shall be differentiated semantically using the alias Point2.
-typedef Vector2 Point2;
-
-}
diff --git a/thirdparty/msdfgen/core/Vector2.hpp b/thirdparty/msdfgen/core/Vector2.hpp
new file mode 100644
index 0000000000..0208c61497
--- /dev/null
+++ b/thirdparty/msdfgen/core/Vector2.hpp
@@ -0,0 +1,167 @@
+
+#pragma once
+
+#include <cmath>
+#include "base.h"
+
+namespace msdfgen {
+
+/**
+ * A 2-dimensional euclidean floating-point vector.
+ * @author Viktor Chlumsky
+ */
+struct Vector2 {
+
+ double x, y;
+
+ inline Vector2(double val = 0) : x(val), y(val) { }
+
+ inline Vector2(double x, double y) : x(x), y(y) { }
+
+ /// Sets the vector to zero.
+ inline void reset() {
+ x = 0, y = 0;
+ }
+
+ /// Sets individual elements of the vector.
+ inline void set(double x, double y) {
+ this->x = x, this->y = y;
+ }
+
+ /// Returns the vector's squared length.
+ inline double squaredLength() const {
+ return x*x+y*y;
+ }
+
+ /// Returns the vector's length.
+ inline double length() const {
+ return sqrt(x*x+y*y);
+ }
+
+ /// Returns the normalized vector - one that has the same direction but unit length.
+ inline Vector2 normalize(bool allowZero = false) const {
+ if (double len = length())
+ return Vector2(x/len, y/len);
+ return Vector2(0, !allowZero);
+ }
+
+ /// Returns a vector with the same length that is orthogonal to this one.
+ inline Vector2 getOrthogonal(bool polarity = true) const {
+ return polarity ? Vector2(-y, x) : Vector2(y, -x);
+ }
+
+ /// Returns a vector with unit length that is orthogonal to this one.
+ inline Vector2 getOrthonormal(bool polarity = true, bool allowZero = false) const {
+ if (double len = length())
+ return polarity ? Vector2(-y/len, x/len) : Vector2(y/len, -x/len);
+ return polarity ? Vector2(0, !allowZero) : Vector2(0, -!allowZero);
+ }
+
+#ifdef MSDFGEN_USE_CPP11
+ inline explicit operator bool() const {
+ return x || y;
+ }
+#else
+ inline operator const void *() const {
+ return x || y ? this : NULL;
+ }
+#endif
+
+ inline Vector2 &operator+=(const Vector2 other) {
+ x += other.x, y += other.y;
+ return *this;
+ }
+
+ inline Vector2 &operator-=(const Vector2 other) {
+ x -= other.x, y -= other.y;
+ return *this;
+ }
+
+ inline Vector2 &operator*=(const Vector2 other) {
+ x *= other.x, y *= other.y;
+ return *this;
+ }
+
+ inline Vector2 &operator/=(const Vector2 other) {
+ x /= other.x, y /= other.y;
+ return *this;
+ }
+
+ inline Vector2 &operator*=(double value) {
+ x *= value, y *= value;
+ return *this;
+ }
+
+ inline Vector2 &operator/=(double value) {
+ x /= value, y /= value;
+ return *this;
+ }
+
+};
+
+/// A vector may also represent a point, which shall be differentiated semantically using the alias Point2.
+typedef Vector2 Point2;
+
+/// Dot product of two vectors.
+inline double dotProduct(const Vector2 a, const Vector2 b) {
+ return a.x*b.x+a.y*b.y;
+}
+
+/// A special version of the cross product for 2D vectors (returns scalar value).
+inline double crossProduct(const Vector2 a, const Vector2 b) {
+ return a.x*b.y-a.y*b.x;
+}
+
+inline bool operator==(const Vector2 a, const Vector2 b) {
+ return a.x == b.x && a.y == b.y;
+}
+
+inline bool operator!=(const Vector2 a, const Vector2 b) {
+ return a.x != b.x || a.y != b.y;
+}
+
+inline Vector2 operator+(const Vector2 v) {
+ return v;
+}
+
+inline Vector2 operator-(const Vector2 v) {
+ return Vector2(-v.x, -v.y);
+}
+
+inline bool operator!(const Vector2 v) {
+ return !v.x && !v.y;
+}
+
+inline Vector2 operator+(const Vector2 a, const Vector2 b) {
+ return Vector2(a.x+b.x, a.y+b.y);
+}
+
+inline Vector2 operator-(const Vector2 a, const Vector2 b) {
+ return Vector2(a.x-b.x, a.y-b.y);
+}
+
+inline Vector2 operator*(const Vector2 a, const Vector2 b) {
+ return Vector2(a.x*b.x, a.y*b.y);
+}
+
+inline Vector2 operator/(const Vector2 a, const Vector2 b) {
+ return Vector2(a.x/b.x, a.y/b.y);
+}
+
+inline Vector2 operator*(double a, const Vector2 b) {
+ return Vector2(a*b.x, a*b.y);
+}
+
+inline Vector2 operator/(double a, const Vector2 b) {
+ return Vector2(a/b.x, a/b.y);
+}
+
+inline Vector2 operator*(const Vector2 a, double b) {
+ return Vector2(a.x*b, a.y*b);
+}
+
+inline Vector2 operator/(const Vector2 a, double b) {
+ return Vector2(a.x/b, a.y/b);
+}
+
+}
diff --git a/thirdparty/msdfgen/core/arithmetics.hpp b/thirdparty/msdfgen/core/arithmetics.hpp
index 78c21d658e..d5158ad0d3 100644
--- a/thirdparty/msdfgen/core/arithmetics.hpp
+++ b/thirdparty/msdfgen/core/arithmetics.hpp
@@ -1,8 +1,8 @@
#pragma once
-#include <cstdlib>
#include <cmath>
+#include "base.h"
namespace msdfgen {
diff --git a/thirdparty/msdfgen/core/base.h b/thirdparty/msdfgen/core/base.h
new file mode 100644
index 0000000000..ab85c136e1
--- /dev/null
+++ b/thirdparty/msdfgen/core/base.h
@@ -0,0 +1,16 @@
+
+#pragma once
+
+// This file needs to be included first for all MSDFgen sources
+
+#ifndef MSDFGEN_PUBLIC
+#include <msdfgen/msdfgen-config.h>
+#endif
+
+#include <cstddef>
+
+namespace msdfgen {
+
+typedef unsigned char byte;
+
+}
diff --git a/thirdparty/msdfgen/core/bitmap-interpolation.hpp b/thirdparty/msdfgen/core/bitmap-interpolation.hpp
index a14b0fb534..ca2e48c080 100644
--- a/thirdparty/msdfgen/core/bitmap-interpolation.hpp
+++ b/thirdparty/msdfgen/core/bitmap-interpolation.hpp
@@ -2,7 +2,7 @@
#pragma once
#include "arithmetics.hpp"
-#include "Vector2.h"
+#include "Vector2.hpp"
#include "BitmapRef.hpp"
namespace msdfgen {
diff --git a/thirdparty/msdfgen/core/contour-combiners.cpp b/thirdparty/msdfgen/core/contour-combiners.cpp
index 31f4c5da71..bac5534810 100644
--- a/thirdparty/msdfgen/core/contour-combiners.cpp
+++ b/thirdparty/msdfgen/core/contour-combiners.cpp
@@ -33,7 +33,7 @@ void SimpleContourCombiner<EdgeSelector>::reset(const Point2 &p) {
}
template <class EdgeSelector>
-EdgeSelector & SimpleContourCombiner<EdgeSelector>::edgeSelector(int) {
+EdgeSelector &SimpleContourCombiner<EdgeSelector>::edgeSelector(int) {
return shapeEdgeSelector;
}
@@ -63,7 +63,7 @@ void OverlappingContourCombiner<EdgeSelector>::reset(const Point2 &p) {
}
template <class EdgeSelector>
-EdgeSelector & OverlappingContourCombiner<EdgeSelector>::edgeSelector(int i) {
+EdgeSelector &OverlappingContourCombiner<EdgeSelector>::edgeSelector(int i) {
return edgeSelectors[i];
}
diff --git a/thirdparty/msdfgen/core/contour-combiners.h b/thirdparty/msdfgen/core/contour-combiners.h
index 944b119aba..04dbc34230 100644
--- a/thirdparty/msdfgen/core/contour-combiners.h
+++ b/thirdparty/msdfgen/core/contour-combiners.h
@@ -16,7 +16,7 @@ public:
explicit SimpleContourCombiner(const Shape &shape);
void reset(const Point2 &p);
- EdgeSelector & edgeSelector(int i);
+ EdgeSelector &edgeSelector(int i);
DistanceType distance() const;
private:
@@ -34,7 +34,7 @@ public:
explicit OverlappingContourCombiner(const Shape &shape);
void reset(const Point2 &p);
- EdgeSelector & edgeSelector(int i);
+ EdgeSelector &edgeSelector(int i);
DistanceType distance() const;
private:
diff --git a/thirdparty/msdfgen/core/edge-coloring.cpp b/thirdparty/msdfgen/core/edge-coloring.cpp
index 6a87bba54d..da9b037735 100644
--- a/thirdparty/msdfgen/core/edge-coloring.cpp
+++ b/thirdparty/msdfgen/core/edge-coloring.cpp
@@ -5,6 +5,7 @@
#include <cmath>
#include <cstring>
#include <cfloat>
+#include <vector>
#include <queue>
#include "arithmetics.hpp"
@@ -244,7 +245,7 @@ static double edgeToEdgeDistance(const EdgeSegment &a, const EdgeSegment &b, int
return minDistance;
}
-static double splineToSplineDistance(EdgeSegment * const *edgeSegments, int aStart, int aEnd, int bStart, int bEnd, int precision) {
+static double splineToSplineDistance(EdgeSegment *const *edgeSegments, int aStart, int aEnd, int bStart, int bEnd, int precision) {
double minDistance = DBL_MAX;
for (int ai = aStart; ai < aEnd; ++ai)
for (int bi = bStart; bi < bEnd && minDistance; ++bi) {
@@ -254,7 +255,7 @@ static double splineToSplineDistance(EdgeSegment * const *edgeSegments, int aSta
return minDistance;
}
-static void colorSecondDegreeGraph(int *coloring, const int * const *edgeMatrix, int vertexCount, unsigned long long seed) {
+static void colorSecondDegreeGraph(int *coloring, const int *const *edgeMatrix, int vertexCount, unsigned long long seed) {
for (int i = 0; i < vertexCount; ++i) {
int possibleColors = 7;
for (int j = 0; j < i; ++j) {
@@ -301,7 +302,7 @@ static int vertexPossibleColors(const int *coloring, const int *edgeVector, int
return 7&~usedColors;
}
-static void uncolorSameNeighbors(std::queue<int> &uncolored, int *coloring, const int * const *edgeMatrix, int vertex, int vertexCount) {
+static void uncolorSameNeighbors(std::queue<int> &uncolored, int *coloring, const int *const *edgeMatrix, int vertex, int vertexCount) {
for (int i = vertex+1; i < vertexCount; ++i) {
if (edgeMatrix[vertex][i] && coloring[i] == coloring[vertex]) {
coloring[i] = -1;
@@ -316,7 +317,7 @@ static void uncolorSameNeighbors(std::queue<int> &uncolored, int *coloring, cons
}
}
-static bool tryAddEdge(int *coloring, int * const *edgeMatrix, int vertexCount, int vertexA, int vertexB, int *coloringBuffer) {
+static bool tryAddEdge(int *coloring, int *const *edgeMatrix, int vertexCount, int vertexA, int vertexB, int *coloringBuffer) {
static const int FIRST_POSSIBLE_COLOR[8] = { -1, 0, 1, 0, 2, 2, 1, 0 };
edgeMatrix[vertexA][vertexB] = 1;
edgeMatrix[vertexB][vertexA] = 1;
@@ -358,7 +359,7 @@ static bool tryAddEdge(int *coloring, int * const *edgeMatrix, int vertexCount,
}
static int cmpDoublePtr(const void *a, const void *b) {
- return sign(**reinterpret_cast<const double * const *>(a)-**reinterpret_cast<const double * const *>(b));
+ return sign(**reinterpret_cast<const double *const *>(a)-**reinterpret_cast<const double *const *>(b));
}
void edgeColoringByDistance(Shape &shape, double angleThreshold, unsigned long long seed) {
diff --git a/thirdparty/msdfgen/core/edge-segments.cpp b/thirdparty/msdfgen/core/edge-segments.cpp
index 5274a9a5a1..4fef89b95b 100644
--- a/thirdparty/msdfgen/core/edge-segments.cpp
+++ b/thirdparty/msdfgen/core/edge-segments.cpp
@@ -56,18 +56,42 @@ CubicSegment::CubicSegment(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor
p[3] = p3;
}
-LinearSegment * LinearSegment::clone() const {
+LinearSegment *LinearSegment::clone() const {
return new LinearSegment(p[0], p[1], color);
}
-QuadraticSegment * QuadraticSegment::clone() const {
+QuadraticSegment *QuadraticSegment::clone() const {
return new QuadraticSegment(p[0], p[1], p[2], color);
}
-CubicSegment * CubicSegment::clone() const {
+CubicSegment *CubicSegment::clone() const {
return new CubicSegment(p[0], p[1], p[2], p[3], color);
}
+int LinearSegment::type() const {
+ return (int) EDGE_TYPE;
+}
+
+int QuadraticSegment::type() const {
+ return (int) EDGE_TYPE;
+}
+
+int CubicSegment::type() const {
+ return (int) EDGE_TYPE;
+}
+
+const Point2 *LinearSegment::controlPoints() const {
+ return p;
+}
+
+const Point2 *QuadraticSegment::controlPoints() const {
+ return p;
+}
+
+const Point2 *CubicSegment::controlPoints() const {
+ return p;
+}
+
Point2 LinearSegment::point(double param) const {
return mix(p[0], p[1], param);
}
@@ -483,7 +507,7 @@ void CubicSegment::splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeS
part3 = new CubicSegment(point(2/3.), mix(mix(p[1], p[2], 2/3.), mix(p[2], p[3], 2/3.), 2/3.), p[2] == p[3] ? p[3] : mix(p[2], p[3], 2/3.), p[3], color);
}
-EdgeSegment * QuadraticSegment::convertToCubic() const {
+EdgeSegment *QuadraticSegment::convertToCubic() const {
return new CubicSegment(p[0], mix(p[0], p[1], 2/3.), mix(p[1], p[2], 1/3.), p[2], color);
}
diff --git a/thirdparty/msdfgen/core/edge-segments.h b/thirdparty/msdfgen/core/edge-segments.h
index 1c8fb599ff..71ce8fc4ab 100644
--- a/thirdparty/msdfgen/core/edge-segments.h
+++ b/thirdparty/msdfgen/core/edge-segments.h
@@ -1,8 +1,8 @@
#pragma once
-#include "Vector2.h"
-#include "SignedDistance.h"
+#include "Vector2.hpp"
+#include "SignedDistance.hpp"
#include "EdgeColor.h"
namespace msdfgen {
@@ -20,7 +20,11 @@ public:
EdgeSegment(EdgeColor edgeColor = WHITE) : color(edgeColor) { }
virtual ~EdgeSegment() { }
/// Creates a copy of the edge segment.
- virtual EdgeSegment * clone() const = 0;
+ virtual EdgeSegment *clone() const = 0;
+ /// Returns the numeric code of the edge segment's type.
+ virtual int type() const = 0;
+ /// Returns the array of control points.
+ virtual const Point2 *controlPoints() const = 0;
/// Returns the point on the edge specified by the parameter (between 0 and 1).
virtual Point2 point(double param) const = 0;
/// Returns the direction the edge has at the point specified by the parameter.
@@ -51,10 +55,16 @@ public:
class LinearSegment : public EdgeSegment {
public:
+ enum EdgeType {
+ EDGE_TYPE = 1
+ };
+
Point2 p[2];
LinearSegment(Point2 p0, Point2 p1, EdgeColor edgeColor = WHITE);
- LinearSegment * clone() const;
+ LinearSegment *clone() const;
+ int type() const;
+ const Point2 *controlPoints() const;
Point2 point(double param) const;
Vector2 direction(double param) const;
Vector2 directionChange(double param) const;
@@ -74,10 +84,16 @@ public:
class QuadraticSegment : public EdgeSegment {
public:
+ enum EdgeType {
+ EDGE_TYPE = 2
+ };
+
Point2 p[3];
QuadraticSegment(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor = WHITE);
- QuadraticSegment * clone() const;
+ QuadraticSegment *clone() const;
+ int type() const;
+ const Point2 *controlPoints() const;
Point2 point(double param) const;
Vector2 direction(double param) const;
Vector2 directionChange(double param) const;
@@ -91,7 +107,7 @@ public:
void moveEndPoint(Point2 to);
void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const;
- EdgeSegment * convertToCubic() const;
+ EdgeSegment *convertToCubic() const;
};
@@ -99,10 +115,16 @@ public:
class CubicSegment : public EdgeSegment {
public:
+ enum EdgeType {
+ EDGE_TYPE = 3
+ };
+
Point2 p[4];
CubicSegment(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor = WHITE);
- CubicSegment * clone() const;
+ CubicSegment *clone() const;
+ int type() const;
+ const Point2 *controlPoints() const;
Point2 point(double param) const;
Vector2 direction(double param) const;
Vector2 directionChange(double param) const;
diff --git a/thirdparty/msdfgen/core/edge-selectors.h b/thirdparty/msdfgen/core/edge-selectors.h
index 3620999f82..6b8e2d943f 100644
--- a/thirdparty/msdfgen/core/edge-selectors.h
+++ b/thirdparty/msdfgen/core/edge-selectors.h
@@ -1,8 +1,8 @@
#pragma once
-#include "Vector2.h"
-#include "SignedDistance.h"
+#include "Vector2.hpp"
+#include "SignedDistance.hpp"
#include "edge-segments.h"
namespace msdfgen {
diff --git a/thirdparty/msdfgen/core/equation-solver.cpp b/thirdparty/msdfgen/core/equation-solver.cpp
index 4144fa3340..7c1cbb39f8 100644
--- a/thirdparty/msdfgen/core/equation-solver.cpp
+++ b/thirdparty/msdfgen/core/equation-solver.cpp
@@ -49,7 +49,7 @@ static int solveCubicNormed(double x[3], double a, double b, double c) {
x[2] = q*cos(1/3.*(t-2*M_PI))-a;
return 3;
} else {
- double u = (r < 0 ? 1 : -1)*pow(fabs(r)+sqrt(r2-q3), 1/3.);
+ double u = (r < 0 ? 1 : -1)*pow(fabs(r)+sqrt(r2-q3), 1/3.);
double v = u == 0 ? 0 : q/u;
x[0] = (u+v)-a;
if (u == v || fabs(u-v) < 1e-12*fabs(u+v)) {
diff --git a/thirdparty/msdfgen/core/equation-solver.h b/thirdparty/msdfgen/core/equation-solver.h
index bae097b2b9..bfeeb15823 100644
--- a/thirdparty/msdfgen/core/equation-solver.h
+++ b/thirdparty/msdfgen/core/equation-solver.h
@@ -1,6 +1,8 @@
#pragma once
+#include "base.h"
+
namespace msdfgen {
// ax^2 + bx + c = 0
diff --git a/thirdparty/msdfgen/core/generator-config.h b/thirdparty/msdfgen/core/generator-config.h
index b430d37f3c..b7b153477f 100644
--- a/thirdparty/msdfgen/core/generator-config.h
+++ b/thirdparty/msdfgen/core/generator-config.h
@@ -1,7 +1,6 @@
#pragma once
-#include <cstdlib>
#include "BitmapRef.hpp"
#ifndef MSDFGEN_PUBLIC
diff --git a/thirdparty/msdfgen/core/msdf-error-correction.h b/thirdparty/msdfgen/core/msdf-error-correction.h
index d5384c9329..6318f184bb 100644
--- a/thirdparty/msdfgen/core/msdf-error-correction.h
+++ b/thirdparty/msdfgen/core/msdf-error-correction.h
@@ -1,7 +1,7 @@
#pragma once
-#include "Vector2.h"
+#include "Vector2.hpp"
#include "Projection.h"
#include "Shape.h"
#include "BitmapRef.hpp"
diff --git a/thirdparty/msdfgen/core/pixel-conversion.hpp b/thirdparty/msdfgen/core/pixel-conversion.hpp
index 7e9b6d08f0..3ef8a2d1da 100644
--- a/thirdparty/msdfgen/core/pixel-conversion.hpp
+++ b/thirdparty/msdfgen/core/pixel-conversion.hpp
@@ -5,8 +5,6 @@
namespace msdfgen {
-typedef unsigned char byte;
-
inline byte pixelFloatToByte(float x) {
return byte(clamp(256.f*x, 255.f));
}
diff --git a/thirdparty/msdfgen/core/rasterization.h b/thirdparty/msdfgen/core/rasterization.h
index 82d0c73d95..8ba41cd645 100644
--- a/thirdparty/msdfgen/core/rasterization.h
+++ b/thirdparty/msdfgen/core/rasterization.h
@@ -1,7 +1,7 @@
#pragma once
-#include "Vector2.h"
+#include "Vector2.hpp"
#include "Shape.h"
#include "Projection.h"
#include "Scanline.h"
diff --git a/thirdparty/msdfgen/core/render-sdf.h b/thirdparty/msdfgen/core/render-sdf.h
index 7f2d270b67..0fa695acf6 100644
--- a/thirdparty/msdfgen/core/render-sdf.h
+++ b/thirdparty/msdfgen/core/render-sdf.h
@@ -1,7 +1,7 @@
#pragma once
-#include "Vector2.h"
+#include "Vector2.hpp"
#include "BitmapRef.hpp"
namespace msdfgen {
diff --git a/thirdparty/msdfgen/core/sdf-error-estimation.h b/thirdparty/msdfgen/core/sdf-error-estimation.h
index d2fd40d2b8..f9008222ab 100644
--- a/thirdparty/msdfgen/core/sdf-error-estimation.h
+++ b/thirdparty/msdfgen/core/sdf-error-estimation.h
@@ -1,7 +1,7 @@
#pragma once
-#include "Vector2.h"
+#include "Vector2.hpp"
#include "Shape.h"
#include "Projection.h"
#include "Scanline.h"
diff --git a/thirdparty/msdfgen/core/shape-description.cpp b/thirdparty/msdfgen/core/shape-description.cpp
index a096fa2541..32c515d120 100644
--- a/thirdparty/msdfgen/core/shape-description.cpp
+++ b/thirdparty/msdfgen/core/shape-description.cpp
@@ -244,34 +244,37 @@ bool writeShapeDescription(FILE *output, const Shape &shape) {
default:;
}
}
- if (const LinearSegment *e = dynamic_cast<const LinearSegment *>(&**edge)) {
- fprintf(output, "\t");
- writeCoord(output, e->p[0]);
- fprintf(output, ";\n");
- if (colorCode)
- fprintf(output, "\t\t%c;\n", colorCode);
- }
- if (const QuadraticSegment *e = dynamic_cast<const QuadraticSegment *>(&**edge)) {
- fprintf(output, "\t");
- writeCoord(output, e->p[0]);
- fprintf(output, ";\n\t\t");
- if (colorCode)
- fprintf(output, "%c", colorCode);
- fprintf(output, "(");
- writeCoord(output, e->p[1]);
- fprintf(output, ");\n");
- }
- if (const CubicSegment *e = dynamic_cast<const CubicSegment *>(&**edge)) {
- fprintf(output, "\t");
- writeCoord(output, e->p[0]);
- fprintf(output, ";\n\t\t");
- if (colorCode)
- fprintf(output, "%c", colorCode);
- fprintf(output, "(");
- writeCoord(output, e->p[1]);
- fprintf(output, "; ");
- writeCoord(output, e->p[2]);
- fprintf(output, ");\n");
+ const Point2 *p = (*edge)->controlPoints();
+ switch ((*edge)->type()) {
+ case (int) LinearSegment::EDGE_TYPE:
+ fprintf(output, "\t");
+ writeCoord(output, p[0]);
+ fprintf(output, ";\n");
+ if (colorCode)
+ fprintf(output, "\t\t%c;\n", colorCode);
+ break;
+ case (int) QuadraticSegment::EDGE_TYPE:
+ fprintf(output, "\t");
+ writeCoord(output, p[0]);
+ fprintf(output, ";\n\t\t");
+ if (colorCode)
+ fprintf(output, "%c", colorCode);
+ fprintf(output, "(");
+ writeCoord(output, p[1]);
+ fprintf(output, ");\n");
+ break;
+ case (int) CubicSegment::EDGE_TYPE:
+ fprintf(output, "\t");
+ writeCoord(output, p[0]);
+ fprintf(output, ";\n\t\t");
+ if (colorCode)
+ fprintf(output, "%c", colorCode);
+ fprintf(output, "(");
+ writeCoord(output, p[1]);
+ fprintf(output, "; ");
+ writeCoord(output, p[2]);
+ fprintf(output, ");\n");
+ break;
}
}
fprintf(output, "\t#\n");
diff --git a/thirdparty/msdfgen/core/shape-description.h b/thirdparty/msdfgen/core/shape-description.h
index 5df7c50a03..6e2e223674 100644
--- a/thirdparty/msdfgen/core/shape-description.h
+++ b/thirdparty/msdfgen/core/shape-description.h
@@ -1,7 +1,6 @@
#pragma once
-#include <cstdlib>
#include <cstdio>
#include "Shape.h"
diff --git a/thirdparty/msdfgen/msdfgen.h b/thirdparty/msdfgen/msdfgen.h
index c9ae4f52dc..dff8beb634 100644
--- a/thirdparty/msdfgen/msdfgen.h
+++ b/thirdparty/msdfgen/msdfgen.h
@@ -4,7 +4,7 @@
/*
* MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR
* ---------------------------------------------
- * A utility by Viktor Chlumsky, (c) 2014 - 2022
+ * A utility by Viktor Chlumsky, (c) 2014 - 2023
*
* The technique used to generate multi-channel distance fields in this code
* has been developed by Viktor Chlumsky in 2014 for his master's thesis,
@@ -15,8 +15,9 @@
*
*/
+#include "core/base.h"
#include "core/arithmetics.hpp"
-#include "core/Vector2.h"
+#include "core/Vector2.hpp"
#include "core/Projection.h"
#include "core/Scanline.h"
#include "core/Shape.h"