summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/denoise/SCsub138
-rw-r--r--modules/denoise/config.py12
-rw-r--r--modules/denoise/denoise_wrapper.cpp66
-rw-r--r--modules/denoise/denoise_wrapper.h38
-rw-r--r--modules/denoise/lightmap_denoiser.cpp65
-rw-r--r--modules/denoise/lightmap_denoiser.h56
-rw-r--r--modules/denoise/register_types.cpp49
-rw-r--r--modules/denoise/register_types.h39
-rw-r--r--modules/denoise/resource_to_cpp.py68
-rw-r--r--modules/gdscript/gdscript.cpp20
-rw-r--r--modules/gdscript/gdscript.h12
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp149
-rw-r--r--modules/gdscript/gdscript_compiler.cpp29
-rw-r--r--modules/gdscript/gdscript_function.cpp2
-rw-r--r--modules/gdscript/gdscript_parser.cpp46
-rw-r--r--modules/gdscript/gdscript_parser.h4
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp4
-rw-r--r--modules/gdscript/gdscript_tokenizer.h1
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp9
-rw-r--r--modules/gdscript/gdscript_vm.cpp1
-rw-r--r--modules/gdscript/gdscript_warning.cpp2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/call_not_existing_static_method.gd7
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/call_not_existing_static_method.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_wrong_specified_type_with_literal_array.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_wrong_specified_type_with_literal_array.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_1.gd10
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_1.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_2.gd10
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_2.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_3.gd10
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_3.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_1.gd10
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_1.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_2.gd10
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_2.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_3.gd10
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_3.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_4.gd10
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_4.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/match_guard_invalid_expression.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/match_guard_invalid_expression.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/object_invalid_constructor.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/object_invalid_constructor.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/function_param_type_contravariance.gd20
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/function_param_type_contravariance.out1
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/function_return_type_covariance.gd32
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/function_return_type_covariance.out1
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/hard_variants.gd1
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/null_initializer.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/get_node_without_onready.gd1
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/unsafe_call_argument.gd37
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/unsafe_call_argument.out33
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/match_guard_with_assignment.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/match_guard_with_assignment.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/allowed_keywords_as_identifiers.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/features/allowed_keywords_as_identifiers.out1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/features/dollar_node_paths.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/lambda_ends_with_new_line.gd1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_function_calls.gd1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/super.gd1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/unicode_identifiers.gd1
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.gd6
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.out4
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/match_with_pattern_guards.gd71
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/match_with_pattern_guards.out10
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.gd45
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.out24
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/object_constructor.gd6
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/object_constructor.out2
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd1
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/static_variables.gd1
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/stringify.gd3
-rw-r--r--modules/gdscript/tests/scripts/utils.notest.gd84
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp10
-rw-r--r--modules/gltf/editor/editor_scene_importer_blend.cpp143
-rw-r--r--modules/gltf/editor/editor_scene_importer_blend.h3
-rw-r--r--modules/gltf/gltf_document.cpp14
-rw-r--r--modules/lightmapper_rd/config.py2
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp148
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.h13
-rw-r--r--modules/lightmapper_rd/lm_compute.glsl165
-rw-r--r--modules/lightmapper_rd/register_types.cpp1
-rw-r--r--modules/minimp3/SCsub3
-rw-r--r--modules/minimp3/audio_stream_mp3.cpp1
-rw-r--r--modules/minimp3/config.py8
-rw-r--r--modules/minimp3/resource_importer_mp3.cpp4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs72
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs2
-rw-r--r--modules/raycast/raycast_occlusion_cull.cpp72
-rw-r--r--modules/raycast/raycast_occlusion_cull.h4
-rw-r--r--modules/svg/SCsub71
-rw-r--r--modules/text_server_adv/SCsub6
-rw-r--r--modules/text_server_adv/gdextension_build/SConstruct73
-rw-r--r--modules/text_server_fb/SCsub2
-rw-r--r--modules/text_server_fb/gdextension_build/SConstruct73
97 files changed, 1248 insertions, 976 deletions
diff --git a/modules/denoise/SCsub b/modules/denoise/SCsub
deleted file mode 100644
index 967a511e1e..0000000000
--- a/modules/denoise/SCsub
+++ /dev/null
@@ -1,138 +0,0 @@
-#!/usr/bin/env python
-
-import resource_to_cpp
-
-Import("env")
-Import("env_modules")
-
-env_oidn = env_modules.Clone()
-
-# Thirdparty source files
-
-thirdparty_obj = []
-
-thirdparty_dir = "#thirdparty/oidn/"
-thirdparty_sources = [
- "core/api.cpp",
- "core/device.cpp",
- "core/filter.cpp",
- "core/network.cpp",
- "core/autoencoder.cpp",
- "core/transfer_function.cpp",
- "weights/rtlightmap_hdr.gen.cpp",
- "mkl-dnn/src/common/batch_normalization.cpp",
- "mkl-dnn/src/common/concat.cpp",
- "mkl-dnn/src/common/convolution.cpp",
- "mkl-dnn/src/common/convolution_pd.cpp",
- "mkl-dnn/src/common/deconvolution.cpp",
- "mkl-dnn/src/common/eltwise.cpp",
- "mkl-dnn/src/common/engine.cpp",
- "mkl-dnn/src/common/inner_product.cpp",
- "mkl-dnn/src/common/inner_product_pd.cpp",
- "mkl-dnn/src/common/lrn.cpp",
- "mkl-dnn/src/common/memory.cpp",
- "mkl-dnn/src/common/memory_desc_wrapper.cpp",
- "mkl-dnn/src/common/mkldnn_debug.cpp",
- "mkl-dnn/src/common/mkldnn_debug_autogenerated.cpp",
- "mkl-dnn/src/common/pooling.cpp",
- "mkl-dnn/src/common/primitive.cpp",
- "mkl-dnn/src/common/primitive_attr.cpp",
- "mkl-dnn/src/common/primitive_desc.cpp",
- "mkl-dnn/src/common/primitive_exec_types.cpp",
- "mkl-dnn/src/common/primitive_iterator.cpp",
- "mkl-dnn/src/common/query.cpp",
- "mkl-dnn/src/common/reorder.cpp",
- "mkl-dnn/src/common/rnn.cpp",
- "mkl-dnn/src/common/scratchpad.cpp",
- "mkl-dnn/src/common/shuffle.cpp",
- "mkl-dnn/src/common/softmax.cpp",
- "mkl-dnn/src/common/stream.cpp",
- "mkl-dnn/src/common/sum.cpp",
- "mkl-dnn/src/common/utils.cpp",
- "mkl-dnn/src/common/verbose.cpp",
- "mkl-dnn/src/cpu/cpu_barrier.cpp",
- "mkl-dnn/src/cpu/cpu_concat.cpp",
- "mkl-dnn/src/cpu/cpu_engine.cpp",
- "mkl-dnn/src/cpu/cpu_memory.cpp",
- "mkl-dnn/src/cpu/cpu_reducer.cpp",
- "mkl-dnn/src/cpu/cpu_reorder.cpp",
- "mkl-dnn/src/cpu/cpu_sum.cpp",
- "mkl-dnn/src/cpu/jit_avx2_conv_kernel_f32.cpp",
- "mkl-dnn/src/cpu/jit_avx2_convolution.cpp",
- "mkl-dnn/src/cpu/jit_avx512_common_conv_kernel.cpp",
- "mkl-dnn/src/cpu/jit_avx512_common_conv_winograd_kernel_f32.cpp",
- "mkl-dnn/src/cpu/jit_avx512_common_convolution.cpp",
- "mkl-dnn/src/cpu/jit_avx512_common_convolution_winograd.cpp",
- "mkl-dnn/src/cpu/jit_avx512_core_fp32_wino_conv_2x3.cpp",
- "mkl-dnn/src/cpu/jit_avx512_core_fp32_wino_conv_4x3.cpp",
- "mkl-dnn/src/cpu/jit_avx512_core_fp32_wino_conv_4x3_kernel.cpp",
- "mkl-dnn/src/cpu/jit_sse42_conv_kernel_f32.cpp",
- "mkl-dnn/src/cpu/jit_sse42_convolution.cpp",
- "mkl-dnn/src/cpu/jit_transpose_src_utils.cpp",
- "mkl-dnn/src/cpu/jit_uni_eltwise.cpp",
- "mkl-dnn/src/cpu/jit_uni_pool_kernel_f32.cpp",
- "mkl-dnn/src/cpu/jit_uni_pooling.cpp",
- "mkl-dnn/src/cpu/jit_uni_reorder.cpp",
- "mkl-dnn/src/cpu/jit_uni_reorder_utils.cpp",
- "mkl-dnn/src/cpu/jit_utils/jit_utils.cpp",
- "mkl-dnn/src/cpu/jit_utils/jitprofiling/jitprofiling.c",
- "common/platform.cpp",
- "common/thread.cpp",
- "common/tensor.cpp",
-]
-thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
-
-thirdparty_include_dirs = [
- "",
- "include",
- "mkl-dnn/include",
- "mkl-dnn/src",
- "mkl-dnn/src/common",
- "mkl-dnn/src/cpu/xbyak",
- "mkl-dnn/src/cpu",
-]
-thirdparty_include_dirs = [thirdparty_dir + file for file in thirdparty_include_dirs]
-
-
-env_oidn.Prepend(CPPPATH=thirdparty_include_dirs)
-env_oidn.Append(
- CPPDEFINES=[
- "MKLDNN_THR=MKLDNN_THR_SEQ",
- "OIDN_STATIC_LIB",
- "__STDC_CONSTANT_MACROS",
- "__STDC_LIMIT_MACROS",
- "DISABLE_VERBOSE",
- "MKLDNN_ENABLE_CONCURRENT_EXEC",
- ]
-)
-env_oidn.AppendUnique(CPPDEFINES=["NDEBUG"]) # No assert() even in debug builds.
-
-env_thirdparty = env_oidn.Clone()
-env_thirdparty.disable_warnings()
-
-if env["disable_exceptions"]:
- # OIDN hard-requires exceptions, so we re-enable them here.
- if env.msvc and ("_HAS_EXCEPTIONS", 0) in env_thirdparty["CPPDEFINES"]:
- env_thirdparty["CPPDEFINES"].remove(("_HAS_EXCEPTIONS", 0))
- env_thirdparty.AppendUnique(CCFLAGS=["/EHsc"])
- elif not env.msvc and "-fno-exceptions" in env_thirdparty["CCFLAGS"]:
- env_thirdparty["CCFLAGS"].remove("-fno-exceptions")
-
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
-env.modules_sources += thirdparty_obj
-
-weights_in_path = thirdparty_dir + "weights/rtlightmap_hdr.tza"
-weights_out_path = thirdparty_dir + "weights/rtlightmap_hdr.gen.cpp"
-
-env_thirdparty.Depends(weights_out_path, weights_in_path)
-env_thirdparty.CommandNoCache(weights_out_path, weights_in_path, resource_to_cpp.tza_to_cpp)
-
-# Godot source files
-
-module_obj = []
-
-env_oidn.add_source_files(module_obj, "*.cpp")
-env.modules_sources += module_obj
-
-# Needed to force rebuilding the module files when the thirdparty library is updated.
-env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/denoise/config.py b/modules/denoise/config.py
deleted file mode 100644
index 27d2ffbf86..0000000000
--- a/modules/denoise/config.py
+++ /dev/null
@@ -1,12 +0,0 @@
-def can_build(env, platform):
- # Thirdparty dependency OpenImage Denoise includes oneDNN library
- # and the version we use only supports x86_64.
- # It's also only relevant for tools build and desktop platforms,
- # as doing lightmap generation and denoising on Android or Web
- # would be a bit far-fetched.
- desktop_platforms = ["linuxbsd", "macos", "windows"]
- return env.editor_build and platform in desktop_platforms and env["arch"] == "x86_64"
-
-
-def configure(env):
- pass
diff --git a/modules/denoise/denoise_wrapper.cpp b/modules/denoise/denoise_wrapper.cpp
deleted file mode 100644
index 87f02cb4c6..0000000000
--- a/modules/denoise/denoise_wrapper.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/**************************************************************************/
-/* denoise_wrapper.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 "denoise_wrapper.h"
-
-#include <OpenImageDenoise/oidn.h>
-
-#include <stdio.h>
-
-void *oidn_denoiser_init() {
- OIDNDeviceImpl *device = oidnNewDevice(OIDN_DEVICE_TYPE_CPU);
- oidnCommitDevice(device);
- return device;
-}
-
-bool oidn_denoise(void *deviceptr, float *p_floats, int p_width, int p_height) {
- OIDNDeviceImpl *device = (OIDNDeviceImpl *)deviceptr;
- OIDNFilter filter = oidnNewFilter(device, "RTLightmap");
- oidnSetSharedFilterImage(filter, "color", (void *)p_floats, OIDN_FORMAT_FLOAT3, p_width, p_height, 0, 0, 0);
- oidnSetSharedFilterImage(filter, "output", (void *)p_floats, OIDN_FORMAT_FLOAT3, p_width, p_height, 0, 0, 0);
- oidnSetFilter1b(filter, "hdr", true);
- //oidnSetFilter1f(filter, "hdrScale", 1.0f);
- oidnCommitFilter(filter);
- oidnExecuteFilter(filter);
-
- const char *msg;
- bool success = true;
- if (oidnGetDeviceError(device, &msg) != OIDN_ERROR_NONE) {
- printf("LightmapDenoiser: %s\n", msg);
- success = false;
- }
-
- oidnReleaseFilter(filter);
- return success;
-}
-
-void oidn_denoiser_finish(void *device) {
- oidnReleaseDevice((OIDNDeviceImpl *)device);
-}
diff --git a/modules/denoise/denoise_wrapper.h b/modules/denoise/denoise_wrapper.h
deleted file mode 100644
index d4bf154a5d..0000000000
--- a/modules/denoise/denoise_wrapper.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/**************************************************************************/
-/* denoise_wrapper.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 DENOISE_WRAPPER_H
-#define DENOISE_WRAPPER_H
-
-void *oidn_denoiser_init();
-bool oidn_denoise(void *device, float *p_floats, int p_width, int p_height);
-void oidn_denoiser_finish(void *device);
-
-#endif // DENOISE_WRAPPER_H
diff --git a/modules/denoise/lightmap_denoiser.cpp b/modules/denoise/lightmap_denoiser.cpp
deleted file mode 100644
index 72764036e1..0000000000
--- a/modules/denoise/lightmap_denoiser.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/**************************************************************************/
-/* lightmap_denoiser.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 "lightmap_denoiser.h"
-
-#include "denoise_wrapper.h"
-
-#include "core/io/image.h"
-
-LightmapDenoiser *LightmapDenoiserOIDN::create_oidn_denoiser() {
- return memnew(LightmapDenoiserOIDN);
-}
-
-void LightmapDenoiserOIDN::make_default_denoiser() {
- create_function = create_oidn_denoiser;
-}
-
-Ref<Image> LightmapDenoiserOIDN::denoise_image(const Ref<Image> &p_image) {
- Ref<Image> img = p_image->duplicate();
-
- img->convert(Image::FORMAT_RGBF);
-
- Vector<uint8_t> data = img->get_data();
- if (!oidn_denoise(device, (float *)data.ptrw(), img->get_width(), img->get_height())) {
- return p_image;
- }
-
- img->set_data(img->get_width(), img->get_height(), false, img->get_format(), data);
- return img;
-}
-
-LightmapDenoiserOIDN::LightmapDenoiserOIDN() {
- device = oidn_denoiser_init();
-}
-
-LightmapDenoiserOIDN::~LightmapDenoiserOIDN() {
- oidn_denoiser_finish(device);
-}
diff --git a/modules/denoise/lightmap_denoiser.h b/modules/denoise/lightmap_denoiser.h
deleted file mode 100644
index 8f658ab096..0000000000
--- a/modules/denoise/lightmap_denoiser.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/**************************************************************************/
-/* lightmap_denoiser.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 LIGHTMAP_DENOISER_H
-#define LIGHTMAP_DENOISER_H
-
-#include "core/object/class_db.h"
-#include "scene/3d/lightmapper.h"
-
-struct OIDNDeviceImpl;
-
-class LightmapDenoiserOIDN : public LightmapDenoiser {
- GDCLASS(LightmapDenoiserOIDN, LightmapDenoiser);
-
-protected:
- void *device = nullptr;
-
-public:
- static LightmapDenoiser *create_oidn_denoiser();
-
- Ref<Image> denoise_image(const Ref<Image> &p_image) override;
-
- static void make_default_denoiser();
-
- LightmapDenoiserOIDN();
- ~LightmapDenoiserOIDN();
-};
-
-#endif // LIGHTMAP_DENOISER_H
diff --git a/modules/denoise/register_types.cpp b/modules/denoise/register_types.cpp
deleted file mode 100644
index a4264b07c5..0000000000
--- a/modules/denoise/register_types.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/**************************************************************************/
-/* 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 "lightmap_denoiser.h"
-
-#include "core/config/engine.h"
-
-void initialize_denoise_module(ModuleInitializationLevel p_level) {
- if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
- return;
- }
-
- LightmapDenoiserOIDN::make_default_denoiser();
-}
-
-void uninitialize_denoise_module(ModuleInitializationLevel p_level) {
- if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
- return;
- }
-}
diff --git a/modules/denoise/register_types.h b/modules/denoise/register_types.h
deleted file mode 100644
index 239877a5c7..0000000000
--- a/modules/denoise/register_types.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/**************************************************************************/
-/* 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 DENOISE_REGISTER_TYPES_H
-#define DENOISE_REGISTER_TYPES_H
-
-#include "modules/register_module_types.h"
-
-void initialize_denoise_module(ModuleInitializationLevel p_level);
-void uninitialize_denoise_module(ModuleInitializationLevel p_level);
-
-#endif // DENOISE_REGISTER_TYPES_H
diff --git a/modules/denoise/resource_to_cpp.py b/modules/denoise/resource_to_cpp.py
deleted file mode 100644
index a89eda9117..0000000000
--- a/modules/denoise/resource_to_cpp.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python
-
-## ======================================================================== ##
-## Copyright 2009-2019 Intel Corporation ##
-## ##
-## Licensed under the Apache License, Version 2.0 (the "License"); ##
-## you may not use this file except in compliance with the License. ##
-## You may obtain a copy of the License at ##
-## ##
-## http://www.apache.org/licenses/LICENSE-2.0 ##
-## ##
-## Unless required by applicable law or agreed to in writing, software ##
-## distributed under the License is distributed on an "AS IS" BASIS, ##
-## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ##
-## See the License for the specific language governing permissions and ##
-## limitations under the License. ##
-## ======================================================================== ##
-
-import os
-from array import array
-
-
-# Generates a C++ file from the specified binary resource file
-def generate(in_path, out_path):
- namespace = "oidn::weights"
- scopes = namespace.split("::")
-
- file_name = os.path.basename(in_path)
- var_name = os.path.splitext(file_name)[0]
-
- with open(in_path, "rb") as in_file, open(out_path, "w") as out_file:
- # Header
- out_file.write("// Generated from: %s\n" % file_name)
- out_file.write("#include <cstddef>\n\n")
-
- # Open the namespaces
- for s in scopes:
- out_file.write("namespace %s {\n" % s)
- if scopes:
- out_file.write("\n")
-
- # Read the file
- in_data = array("B", in_file.read())
-
- # Write the size
- out_file.write("//const size_t %s_size = %d;\n\n" % (var_name, len(in_data)))
-
- # Write the data
- out_file.write("unsigned char %s[] = {" % var_name)
- for i in range(len(in_data)):
- c = in_data[i]
- if i > 0:
- out_file.write(",")
- if (i + 1) % 20 == 1:
- out_file.write("\n")
- out_file.write("%d" % c)
- out_file.write("\n};\n")
-
- # Close the namespaces
- if scopes:
- out_file.write("\n")
- for scope in reversed(scopes):
- out_file.write("} // namespace %s\n" % scope)
-
-
-def tza_to_cpp(target, source, env):
- for x in zip(source, target):
- generate(str(x[0]), str(x[1]))
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 22be26fdc1..b5c80d9e2d 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -306,6 +306,9 @@ void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_incl
while (sptr) {
Vector<_GDScriptMemberSort> msort;
for (const KeyValue<StringName, MemberInfo> &E : sptr->member_indices) {
+ if (!sptr->members.has(E.key)) {
+ continue; // Skip base class members.
+ }
_GDScriptMemberSort ms;
ms.index = E.value.index;
ms.name = E.key;
@@ -1648,15 +1651,11 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
}
Variant::Type GDScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const {
- const GDScript *sptr = script.ptr();
- while (sptr) {
- if (sptr->member_indices.has(p_name)) {
- if (r_is_valid) {
- *r_is_valid = true;
- }
- return sptr->member_indices[p_name].property_info.type;
+ if (script->member_indices.has(p_name)) {
+ if (r_is_valid) {
+ *r_is_valid = true;
}
- sptr = sptr->_base;
+ return script->member_indices[p_name].property_info.type;
}
if (r_is_valid) {
@@ -1732,6 +1731,9 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
Vector<_GDScriptMemberSort> msort;
for (const KeyValue<StringName, GDScript::MemberInfo> &F : sptr->member_indices) {
+ if (!sptr->members.has(F.key)) {
+ continue; // Skip base class members.
+ }
_GDScriptMemberSort ms;
ms.index = F.value.index;
ms.name = F.key;
@@ -2415,6 +2417,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
"return",
"match",
"while",
+ "when",
// These keywords are not implemented currently, but reserved for (potential) future use.
// We highlight them as keywords to make errors easier to understand.
"trait",
@@ -2448,6 +2451,7 @@ bool GDScriptLanguage::is_control_flow_keyword(String p_keyword) const {
p_keyword == "match" ||
p_keyword == "pass" ||
p_keyword == "return" ||
+ p_keyword == "when" ||
p_keyword == "while";
}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 2b698d75d4..50ccfabcc1 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -94,12 +94,16 @@ class GDScript : public Script {
GDScript *_base = nullptr; //fast pointer access
GDScript *_owner = nullptr; //for subclasses
- HashSet<StringName> members; //members are just indices to the instantiated script.
- HashMap<StringName, Variant> constants;
+ // Members are just indices to the instantiated script.
+ HashMap<StringName, MemberInfo> member_indices; // Includes member info of all base GDScript classes.
+ HashSet<StringName> members; // Only members of the current class.
+
+ // Only static variables of the current class.
HashMap<StringName, MemberInfo> static_variables_indices;
- Vector<Variant> static_variables;
+ Vector<Variant> static_variables; // Static variable values.
+
+ HashMap<StringName, Variant> constants;
HashMap<StringName, GDScriptFunction *> member_functions;
- HashMap<StringName, MemberInfo> member_indices; //members are just indices to the instantiated script.
HashMap<StringName, Ref<GDScript>> subclasses;
HashMap<StringName, MethodInfo> _signals;
Dictionary rpc_config;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 55bb99133a..882c246706 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -248,7 +248,7 @@ Error GDScriptAnalyzer::check_native_member_name_conflict(const StringName &p_me
return ERR_PARSE_ERROR;
}
- if (GDScriptParser::get_builtin_type(p_member_name) != Variant::VARIANT_MAX) {
+ if (GDScriptParser::get_builtin_type(p_member_name) < Variant::VARIANT_MAX) {
push_error(vformat(R"(The member "%s" cannot have the same name as a builtin type.)", p_member_name), p_member_node);
return ERR_PARSE_ERROR;
}
@@ -673,11 +673,6 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
return bad_type;
}
result.kind = GDScriptParser::DataType::VARIANT;
- } else if (first == SNAME("Object")) {
- // Object is treated like a native type, not a built-in.
- result.kind = GDScriptParser::DataType::NATIVE;
- result.builtin_type = Variant::OBJECT;
- result.native_type = SNAME("Object");
} else if (GDScriptParser::get_builtin_type(first) < Variant::VARIANT_MAX) {
// Built-in types.
if (p_type->type_chain.size() > 1) {
@@ -1676,15 +1671,42 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
StringName native_base;
if (!p_is_lambda && get_function_signature(p_function, false, base_type, function_name, parent_return_type, parameters_types, default_par_count, method_flags, &native_base)) {
bool valid = p_function->is_static == method_flags.has_flag(METHOD_FLAG_STATIC);
- valid = valid && parent_return_type == p_function->get_datatype();
+
+ if (p_function->return_type != nullptr) {
+ // Check return type covariance.
+ GDScriptParser::DataType return_type = p_function->get_datatype();
+ if (return_type.is_variant()) {
+ // `is_type_compatible()` returns `true` if one of the types is `Variant`.
+ // Don't allow an explicitly specified `Variant` if the parent return type is narrower.
+ valid = valid && parent_return_type.is_variant();
+ } else if (return_type.kind == GDScriptParser::DataType::BUILTIN && return_type.builtin_type == Variant::NIL) {
+ // `is_type_compatible()` returns `true` if target is an `Object` and source is `null`.
+ // Don't allow `void` if the parent return type is a hard non-`void` type.
+ if (parent_return_type.is_hard_type() && !(parent_return_type.kind == GDScriptParser::DataType::BUILTIN && parent_return_type.builtin_type == Variant::NIL)) {
+ valid = false;
+ }
+ } else {
+ valid = valid && is_type_compatible(parent_return_type, return_type);
+ }
+ }
int par_count_diff = p_function->parameters.size() - parameters_types.size();
valid = valid && par_count_diff >= 0;
valid = valid && default_value_count >= default_par_count + par_count_diff;
- int i = 0;
- for (const GDScriptParser::DataType &par_type : parameters_types) {
- valid = valid && par_type == p_function->parameters[i++]->get_datatype();
+ if (valid) {
+ int i = 0;
+ for (const GDScriptParser::DataType &parent_par_type : parameters_types) {
+ // Check parameter type contravariance.
+ GDScriptParser::DataType current_par_type = p_function->parameters[i++]->get_datatype();
+ if (parent_par_type.is_variant() && parent_par_type.is_hard_type()) {
+ // `is_type_compatible()` returns `true` if one of the types is `Variant`.
+ // Don't allow narrowing a hard `Variant`.
+ valid = valid && current_par_type.is_variant();
+ } else {
+ valid = valid && is_type_compatible(current_par_type, parent_par_type);
+ }
+ }
}
if (!valid) {
@@ -1708,7 +1730,7 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
}
parent_signature += ") -> ";
- const String return_type = parent_return_type.is_hard_type() ? parent_return_type.to_string() : "Variant";
+ const String return_type = parent_return_type.to_string_strict();
if (return_type == "null") {
parent_signature += "void";
} else {
@@ -2152,6 +2174,9 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
} else if (!is_type_compatible(specified_type, variable_type)) {
p_for->use_conversion_assign = true;
}
+ if (p_for->list && p_for->list->type == GDScriptParser::Node::ARRAY) {
+ update_array_literal_element_type(static_cast<GDScriptParser::ArrayNode *>(p_for->list), specified_type);
+ }
}
p_for->variable->set_datatype(specified_type);
} else {
@@ -2219,6 +2244,10 @@ void GDScriptAnalyzer::resolve_match_branch(GDScriptParser::MatchBranchNode *p_m
resolve_match_pattern(p_match_branch->patterns[i], p_match_test);
}
+ if (p_match_branch->guard_body) {
+ resolve_suite(p_match_branch->guard_body);
+ }
+
resolve_suite(p_match_branch->block);
decide_suite_type(p_match_branch, p_match_branch->block);
@@ -2552,28 +2581,31 @@ void GDScriptAnalyzer::update_const_expression_builtin_type(GDScriptParser::Expr
// When an array literal is stored (or passed as function argument) to a typed context, we then assume the array is typed.
// This function determines which type is that (if any).
void GDScriptAnalyzer::update_array_literal_element_type(GDScriptParser::ArrayNode *p_array, const GDScriptParser::DataType &p_element_type) {
+ GDScriptParser::DataType expected_type = p_element_type;
+ expected_type.unset_container_element_type(); // Nested types (like `Array[Array[int]]`) are not currently supported.
+
for (int i = 0; i < p_array->elements.size(); i++) {
GDScriptParser::ExpressionNode *element_node = p_array->elements[i];
if (element_node->is_constant) {
- update_const_expression_builtin_type(element_node, p_element_type, "include");
+ update_const_expression_builtin_type(element_node, expected_type, "include");
}
- const GDScriptParser::DataType &element_type = element_node->get_datatype();
- if (element_type.has_no_type() || element_type.is_variant() || !element_type.is_hard_type()) {
+ const GDScriptParser::DataType &actual_type = element_node->get_datatype();
+ if (actual_type.has_no_type() || actual_type.is_variant() || !actual_type.is_hard_type()) {
mark_node_unsafe(element_node);
continue;
}
- if (!is_type_compatible(p_element_type, element_type, true, p_array)) {
- if (is_type_compatible(element_type, p_element_type)) {
+ if (!is_type_compatible(expected_type, actual_type, true, p_array)) {
+ if (is_type_compatible(actual_type, expected_type)) {
mark_node_unsafe(element_node);
continue;
}
- push_error(vformat(R"(Cannot have an element of type "%s" in an array of type "Array[%s]".)", element_type.to_string(), p_element_type.to_string()), element_node);
+ push_error(vformat(R"(Cannot have an element of type "%s" in an array of type "Array[%s]".)", actual_type.to_string(), expected_type.to_string()), element_node);
return;
}
}
GDScriptParser::DataType array_type = p_array->get_datatype();
- array_type.set_container_element_type(p_element_type);
+ array_type.set_container_element_type(expected_type);
p_array->set_datatype(array_type);
}
@@ -2899,19 +2931,20 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
if (!p_call->is_super && callee_type == GDScriptParser::Node::IDENTIFIER) {
// Call to name directly.
StringName function_name = p_call->function_name;
- Variant::Type builtin_type = GDScriptParser::get_builtin_type(function_name);
+ if (function_name == SNAME("Object")) {
+ push_error(R"*(Invalid constructor "Object()", use "Object.new()" instead.)*", p_call);
+ p_call->set_datatype(call_type);
+ return;
+ }
+
+ Variant::Type builtin_type = GDScriptParser::get_builtin_type(function_name);
if (builtin_type < Variant::VARIANT_MAX) {
// Is a builtin constructor.
call_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
call_type.kind = GDScriptParser::DataType::BUILTIN;
call_type.builtin_type = builtin_type;
- if (builtin_type == Variant::OBJECT) {
- call_type.kind = GDScriptParser::DataType::NATIVE;
- call_type.native_type = function_name; // "Object".
- }
-
bool safe_to_fold = true;
switch (builtin_type) {
// Those are stored by reference so not suited for compile-time construction.
@@ -2947,7 +2980,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
switch (err.error) {
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
- push_error(vformat(R"(Invalid argument for %s constructor: argument %d should be "%s" but is "%s".)", Variant::get_type_name(builtin_type), err.argument + 1,
+ push_error(vformat(R"*(Invalid argument for "%s()" constructor: argument %d should be "%s" but is "%s".)*", Variant::get_type_name(builtin_type), err.argument + 1,
Variant::get_type_name(Variant::Type(err.expected)), p_call->arguments[err.argument]->get_datatype().to_string()),
p_call->arguments[err.argument]);
break;
@@ -2963,10 +2996,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
push_error(vformat(R"(No constructor of "%s" matches the signature "%s".)", Variant::get_type_name(builtin_type), signature), p_call->callee);
} break;
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
- push_error(vformat(R"(Too many arguments for %s constructor. Received %d but expected %d.)", Variant::get_type_name(builtin_type), p_call->arguments.size(), err.expected), p_call);
+ push_error(vformat(R"*(Too many arguments for "%s()" constructor. Received %d but expected %d.)*", Variant::get_type_name(builtin_type), p_call->arguments.size(), err.expected), p_call);
break;
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
- push_error(vformat(R"(Too few arguments for %s constructor. Received %d but expected %d.)", Variant::get_type_name(builtin_type), p_call->arguments.size(), err.expected), p_call);
+ push_error(vformat(R"*(Too few arguments for "%s()" constructor. Received %d but expected %d.)*", Variant::get_type_name(builtin_type), p_call->arguments.size(), err.expected), p_call);
break;
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:
case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:
@@ -2977,21 +3010,27 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
break;
}
} else {
- // TODO: Check constructors without constants.
-
// If there's one argument, try to use copy constructor (those aren't explicitly defined).
if (p_call->arguments.size() == 1) {
GDScriptParser::DataType arg_type = p_call->arguments[0]->get_datatype();
- if (arg_type.is_variant()) {
- mark_node_unsafe(p_call->arguments[0]);
- } else {
+ if (arg_type.is_hard_type() && !arg_type.is_variant()) {
if (arg_type.kind == GDScriptParser::DataType::BUILTIN && arg_type.builtin_type == builtin_type) {
// Okay.
p_call->set_datatype(call_type);
return;
}
+ } else {
+#ifdef DEBUG_ENABLED
+ mark_node_unsafe(p_call);
+ // We don't know what type was expected since constructors support overloads.
+ // TODO: Improve this by checking for matching candidates?
+ parser->push_warning(p_call->arguments[0], GDScriptWarning::UNSAFE_CALL_ARGUMENT, "1", function_name, "<unknown type>", "Variant");
+#endif
+ p_call->set_datatype(call_type);
+ return;
}
}
+
List<MethodInfo> constructors;
Variant::get_constructor_list(builtin_type, &constructors);
bool match = false;
@@ -3008,14 +3047,14 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
for (int i = 0; i < p_call->arguments.size(); i++) {
GDScriptParser::DataType par_type = type_from_property(info.arguments[i], true);
-
- if (!is_type_compatible(par_type, p_call->arguments[i]->get_datatype(), true)) {
+ GDScriptParser::DataType arg_type = p_call->arguments[i]->get_datatype();
+ if (!is_type_compatible(par_type, arg_type, true)) {
types_match = false;
break;
#ifdef DEBUG_ENABLED
} else {
- if (par_type.builtin_type == Variant::INT && p_call->arguments[i]->get_datatype().builtin_type == Variant::FLOAT && builtin_type != Variant::INT) {
- parser->push_warning(p_call, GDScriptWarning::NARROWING_CONVERSION, p_call->function_name);
+ if (par_type.builtin_type == Variant::INT && arg_type.builtin_type == Variant::FLOAT && builtin_type != Variant::INT) {
+ parser->push_warning(p_call, GDScriptWarning::NARROWING_CONVERSION, function_name);
}
#endif
}
@@ -3023,9 +3062,19 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
if (types_match) {
for (int i = 0; i < p_call->arguments.size(); i++) {
+ GDScriptParser::DataType par_type = type_from_property(info.arguments[i], true);
if (p_call->arguments[i]->is_constant) {
- update_const_expression_builtin_type(p_call->arguments[i], type_from_property(info.arguments[i], true), "pass");
+ update_const_expression_builtin_type(p_call->arguments[i], par_type, "pass");
}
+#ifdef DEBUG_ENABLED
+ if (!(par_type.is_variant() && par_type.is_hard_type())) {
+ GDScriptParser::DataType arg_type = p_call->arguments[i]->get_datatype();
+ if (arg_type.is_variant() || !arg_type.is_hard_type() || !is_type_compatible(arg_type, par_type, true)) {
+ mark_node_unsafe(p_call);
+ parser->push_warning(p_call->arguments[i], GDScriptWarning::UNSAFE_CALL_ARGUMENT, itos(i + 1), function_name, par_type.to_string(), arg_type.to_string_strict());
+ }
+ }
+#endif
}
match = true;
call_type = type_from_property(info.return_val);
@@ -3331,8 +3380,8 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
#else
push_error(vformat(R"*(Function "%s()" not found in base %s.)*", p_call->function_name, base_name), p_call->is_super ? p_call : p_call->callee);
#endif // SUGGEST_GODOT4_RENAMES
- } else if (!found && (!p_call->is_super && base_type.is_hard_type() && base_type.kind == GDScriptParser::DataType::NATIVE && base_type.is_meta_type)) {
- push_error(vformat(R"*(Static function "%s()" not found in base "%s".)*", p_call->function_name, base_type.native_type), p_call);
+ } else if (!found && (!p_call->is_super && base_type.is_hard_type() && base_type.is_meta_type)) {
+ push_error(vformat(R"*(Static function "%s()" not found in base "%s".)*", p_call->function_name, base_type.to_string()), p_call);
}
}
@@ -3820,6 +3869,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
#endif
// Not a local, so check members.
+
if (!found_source) {
reduce_identifier_from_base(p_identifier);
if (p_identifier->source != GDScriptParser::IdentifierNode::UNDEFINED_SOURCE || p_identifier->get_datatype().is_set()) {
@@ -3872,10 +3922,10 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
StringName name = p_identifier->name;
p_identifier->source = GDScriptParser::IdentifierNode::UNDEFINED_SOURCE;
- // Check globals. We make an exception for Variant::OBJECT because it's the base class for
- // non-builtin types so we allow doing e.g. Object.new()
+ // Not a local or a member, so check globals.
+
Variant::Type builtin_type = GDScriptParser::get_builtin_type(name);
- if (builtin_type != Variant::OBJECT && builtin_type < Variant::VARIANT_MAX) {
+ if (builtin_type < Variant::VARIANT_MAX) {
if (can_be_builtin) {
p_identifier->set_datatype(make_builtin_meta_type(builtin_type));
return;
@@ -5003,21 +5053,28 @@ void GDScriptAnalyzer::validate_call_arg(const List<GDScriptParser::DataType> &p
GDScriptParser::DataType arg_type = p_call->arguments[i]->get_datatype();
if (arg_type.is_variant() || !arg_type.is_hard_type()) {
+#ifdef DEBUG_ENABLED
// Argument can be anything, so this is unsafe (unless the parameter is a hard variant).
if (!(par_type.is_hard_type() && par_type.is_variant())) {
mark_node_unsafe(p_call->arguments[i]);
+ parser->push_warning(p_call->arguments[i], GDScriptWarning::UNSAFE_CALL_ARGUMENT, itos(i + 1), p_call->function_name, par_type.to_string(), arg_type.to_string_strict());
}
+#endif
} else if (par_type.is_hard_type() && !is_type_compatible(par_type, arg_type, true)) {
- // Supertypes are acceptable for dynamic compliance, but it's unsafe.
- mark_node_unsafe(p_call);
if (!is_type_compatible(arg_type, par_type)) {
push_error(vformat(R"*(Invalid argument for "%s()" function: argument %d should be "%s" but is "%s".)*",
p_call->function_name, i + 1, par_type.to_string(), arg_type.to_string()),
p_call->arguments[i]);
+#ifdef DEBUG_ENABLED
+ } else {
+ // Supertypes are acceptable for dynamic compliance, but it's unsafe.
+ mark_node_unsafe(p_call);
+ parser->push_warning(p_call->arguments[i], GDScriptWarning::UNSAFE_CALL_ARGUMENT, itos(i + 1), p_call->function_name, par_type.to_string(), arg_type.to_string_strict());
+#endif
}
#ifdef DEBUG_ENABLED
} else if (par_type.kind == GDScriptParser::DataType::BUILTIN && par_type.builtin_type == Variant::INT && arg_type.kind == GDScriptParser::DataType::BUILTIN && arg_type.builtin_type == Variant::FLOAT) {
- parser->push_warning(p_call, GDScriptWarning::NARROWING_CONVERSION, p_call->function_name);
+ parser->push_warning(p_call->arguments[i], GDScriptWarning::NARROWING_CONVERSION, p_call->function_name);
#endif
}
}
@@ -5049,7 +5106,7 @@ void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_identifier
String class_path = ScriptServer::get_global_class_path(name).get_file();
parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, vformat(R"(global class defined in "%s")", class_path));
return;
- } else if (GDScriptParser::get_builtin_type(name) != Variant::VARIANT_MAX) {
+ } else if (GDScriptParser::get_builtin_type(name) < Variant::VARIANT_MAX) {
parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in type");
return;
}
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 97e02ac716..f417d323db 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -612,11 +612,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
arguments.push_back(arg);
}
- if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(call->function_name) != Variant::VARIANT_MAX) {
- // Construct a built-in type.
- Variant::Type vtype = GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name);
-
- gen->write_construct(result, vtype, arguments);
+ if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(call->function_name) < Variant::VARIANT_MAX) {
+ gen->write_construct(result, GDScriptParser::get_builtin_type(call->function_name), arguments);
} else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && Variant::has_utility_function(call->function_name)) {
// Variant utility function.
gen->write_call_utility(result, call->function_name, arguments);
@@ -1928,6 +1925,26 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
}
}
+ // If there's a guard, check its condition too.
+ if (branch->guard_body != nullptr) {
+ // Do this first so the guard does not run unless the pattern matched.
+ gen->write_and_left_operand(pattern_result);
+
+ // Don't actually use the block for the guard.
+ // The binds are already in the locals and we don't want to clear the result of the guard condition before we check the actual match.
+ GDScriptCodeGenerator::Address guard_result = _parse_expression(codegen, err, static_cast<GDScriptParser::ExpressionNode *>(branch->guard_body->statements[0]));
+ if (err) {
+ return err;
+ }
+
+ gen->write_and_right_operand(guard_result);
+ gen->write_end_and(pattern_result);
+
+ if (guard_result.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
+ }
+ }
+
// Check if pattern did match.
gen->write_if(pattern_result);
@@ -2794,7 +2811,7 @@ Error GDScriptCompiler::_prepare_compilation(GDScript *p_script, const GDScriptP
minfo.property_info = prop_info;
p_script->member_indices[name] = minfo;
- p_script->members.insert(Variant());
+ p_script->members.insert(name);
} break;
case GDScriptParser::ClassNode::Member::FUNCTION: {
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index 3e13d1525d..372c212d2b 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -140,7 +140,7 @@ Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_ar
if (p_argcount == 0) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
+ r_error.expected = 1;
return Variant();
} else if (p_argcount == 1) {
//noooneee
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 0801582dbd..9fb1030d12 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -52,11 +52,18 @@
#include "editor/editor_settings.h"
#endif
+// This function is used to determine that a type is "built-in" as opposed to native
+// and custom classes. So `Variant::NIL` and `Variant::OBJECT` are excluded:
+// `Variant::NIL` - `null` is literal, not a type.
+// `Variant::OBJECT` - `Object` should be treated as a class, not as a built-in type.
static HashMap<StringName, Variant::Type> builtin_types;
Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) {
- if (builtin_types.is_empty()) {
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- builtin_types[Variant::get_type_name((Variant::Type)i)] = (Variant::Type)i;
+ if (unlikely(builtin_types.is_empty())) {
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ Variant::Type type = (Variant::Type)i;
+ if (type != Variant::NIL && type != Variant::OBJECT) {
+ builtin_types[Variant::get_type_name(type)] = type;
+ }
}
}
@@ -2035,7 +2042,37 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() {
push_error(R"(No pattern found for "match" branch.)");
}
- if (!consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "match" patterns.)")) {
+ bool has_guard = false;
+ if (match(GDScriptTokenizer::Token::WHEN)) {
+ // Pattern guard.
+ // Create block for guard because it also needs to access the bound variables from patterns, and we don't want to add them to the outer scope.
+ branch->guard_body = alloc_node<SuiteNode>();
+ if (branch->patterns.size() > 0) {
+ for (const KeyValue<StringName, IdentifierNode *> &E : branch->patterns[0]->binds) {
+ SuiteNode::Local local(E.value, current_function);
+ local.type = SuiteNode::Local::PATTERN_BIND;
+ branch->guard_body->add_local(local);
+ }
+ }
+
+ SuiteNode *parent_block = current_suite;
+ branch->guard_body->parent_block = parent_block;
+ current_suite = branch->guard_body;
+
+ ExpressionNode *guard = parse_expression(false);
+ if (guard == nullptr) {
+ push_error(R"(Expected expression for pattern guard after "when".)");
+ } else {
+ branch->guard_body->statements.append(guard);
+ }
+ current_suite = parent_block;
+ complete_extents(branch->guard_body);
+
+ has_guard = true;
+ branch->has_wildcard = false; // If it has a guard, the wildcard might still not match.
+ }
+
+ if (!consume(GDScriptTokenizer::Token::COLON, vformat(R"(Expected ":"%s after "match" %s.)", has_guard ? "" : R"( or "when")", has_guard ? "pattern guard" : "patterns"))) {
complete_extents(branch);
return nullptr;
}
@@ -3674,6 +3711,7 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty
{ nullptr, nullptr, PREC_NONE }, // PASS,
{ nullptr, nullptr, PREC_NONE }, // RETURN,
{ nullptr, nullptr, PREC_NONE }, // MATCH,
+ { nullptr, nullptr, PREC_NONE }, // WHEN,
// Keywords
{ nullptr, &GDScriptParser::parse_cast, PREC_CAST }, // AS,
{ nullptr, nullptr, PREC_NONE }, // ASSERT,
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 3bd3696e99..2daadd7e6a 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -149,6 +149,7 @@ public:
_FORCE_INLINE_ bool is_hard_type() const { return type_source > INFERRED; }
String to_string() const;
+ _FORCE_INLINE_ String to_string_strict() const { return is_hard_type() ? to_string() : "Variant"; }
PropertyInfo to_property_info(const String &p_name) const;
_FORCE_INLINE_ void set_container_element_type(const DataType &p_type) {
@@ -948,6 +949,7 @@ public:
Vector<PatternNode *> patterns;
SuiteNode *block = nullptr;
bool has_wildcard = false;
+ SuiteNode *guard_body = nullptr;
MatchBranchNode() {
type = MATCH_BRANCH;
@@ -1530,7 +1532,7 @@ public:
bool is_tool() const { return _is_tool; }
ClassNode *find_class(const String &p_qualified_name) const;
bool has_class(const GDScriptParser::ClassNode *p_class) const;
- static Variant::Type get_builtin_type(const StringName &p_type);
+ static Variant::Type get_builtin_type(const StringName &p_type); // Excluding `Variant::NIL` and `Variant::OBJECT`.
CompletionContext get_completion_context() const { return completion_context; }
CompletionCall get_completion_call() const { return completion_call; }
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 07f2b8b406..98a3a1268f 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -99,6 +99,7 @@ static const char *token_names[] = {
"pass", // PASS,
"return", // RETURN,
"match", // MATCH,
+ "when", // WHEN,
// Keywords
"as", // AS,
"assert", // ASSERT,
@@ -187,6 +188,7 @@ bool GDScriptTokenizer::Token::is_identifier() const {
switch (type) {
case IDENTIFIER:
case MATCH: // Used in String.match().
+ case WHEN: // New keyword, avoid breaking existing code.
// Allow constants to be treated as regular identifiers.
case CONST_PI:
case CONST_INF:
@@ -241,6 +243,7 @@ bool GDScriptTokenizer::Token::is_node_name() const {
case VAR:
case VOID:
case WHILE:
+ case WHEN:
case YIELD:
return true;
default:
@@ -531,6 +534,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::annotation() {
KEYWORD("void", Token::VOID) \
KEYWORD_GROUP('w') \
KEYWORD("while", Token::WHILE) \
+ KEYWORD("when", Token::WHEN) \
KEYWORD_GROUP('y') \
KEYWORD("yield", Token::YIELD) \
KEYWORD_GROUP('I') \
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index f916407b18..6dd8a98652 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -105,6 +105,7 @@ public:
PASS,
RETURN,
MATCH,
+ WHEN,
// Keywords
AS,
ASSERT,
diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp
index d85b12b7fe..69a0b42d89 100644
--- a/modules/gdscript/gdscript_utility_functions.cpp
+++ b/modules/gdscript/gdscript_utility_functions.cpp
@@ -45,14 +45,12 @@
#define VALIDATE_ARG_COUNT(m_count) \
if (p_arg_count < m_count) { \
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; \
- r_error.argument = m_count; \
r_error.expected = m_count; \
*r_ret = Variant(); \
return; \
} \
if (p_arg_count > m_count) { \
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; \
- r_error.argument = m_count; \
r_error.expected = m_count; \
*r_ret = Variant(); \
return; \
@@ -119,7 +117,6 @@ struct GDScriptUtilityFunctionsDefinitions {
switch (p_arg_count) {
case 0: {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
r_error.expected = 1;
*r_ret = Variant();
} break;
@@ -223,7 +220,6 @@ struct GDScriptUtilityFunctionsDefinitions {
} break;
default: {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 3;
r_error.expected = 3;
*r_ret = Variant();
@@ -251,6 +247,7 @@ struct GDScriptUtilityFunctionsDefinitions {
} else if (p_args[0]->get_type() != Variant::OBJECT) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
*r_ret = Variant();
} else {
Object *obj = *p_args[0];
@@ -390,13 +387,13 @@ struct GDScriptUtilityFunctionsDefinitions {
static inline void Color8(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
if (p_arg_count < 3) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 3;
+ r_error.expected = 3;
*r_ret = Variant();
return;
}
if (p_arg_count > 4) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = 4;
+ r_error.expected = 4;
*r_ret = Variant();
return;
}
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index be18dee2cf..5ecae08f6c 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -519,7 +519,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
if (p_argcount > _argument_count) {
r_err.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
r_err.expected = _argument_count;
-
call_depth--;
return _get_default_variant_for_data_type(return_type);
} else if (p_argcount < _argument_count - _default_arg_count) {
diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp
index a0078f84d6..cabac07ef9 100644
--- a/modules/gdscript/gdscript_warning.cpp
+++ b/modules/gdscript/gdscript_warning.cpp
@@ -108,7 +108,7 @@ String GDScriptWarning::get_message() const {
return vformat(R"(The value is cast to "%s" but has an unknown type.)", symbols[0]);
case UNSAFE_CALL_ARGUMENT:
CHECK_SYMBOLS(4);
- return vformat(R"*(The argument %s of the function "%s()" requires a the subtype "%s" but the supertype "%s" was provided.)*", symbols[0], symbols[1], symbols[2], symbols[3]);
+ return vformat(R"*(The argument %s of the function "%s()" requires the subtype "%s" but the supertype "%s" was provided.)*", symbols[0], symbols[1], symbols[2], symbols[3]);
case UNSAFE_VOID_RETURN:
CHECK_SYMBOLS(2);
return vformat(R"*(The method "%s()" returns "void" but it's trying to return a call to "%s()" that can't be ensured to also be "void".)*", symbols[0], symbols[1]);
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/call_not_existing_static_method.gd b/modules/gdscript/tests/scripts/analyzer/errors/call_not_existing_static_method.gd
new file mode 100644
index 0000000000..87d1b9ea18
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/call_not_existing_static_method.gd
@@ -0,0 +1,7 @@
+# GH-73283
+
+class MyClass:
+ pass
+
+func test():
+ MyClass.not_existing_method()
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/call_not_existing_static_method.out b/modules/gdscript/tests/scripts/analyzer/errors/call_not_existing_static_method.out
new file mode 100644
index 0000000000..7340058dd4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/call_not_existing_static_method.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Static function "not_existing_method()" not found in base "MyClass".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_wrong_specified_type_with_literal_array.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_wrong_specified_type_with_literal_array.gd
new file mode 100644
index 0000000000..db3f3f4c72
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_wrong_specified_type_with_literal_array.gd
@@ -0,0 +1,5 @@
+# GH-82021
+
+func test():
+ for x: String in [1, 2, 3]:
+ print(x)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_wrong_specified_type_with_literal_array.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_wrong_specified_type_with_literal_array.out
new file mode 100644
index 0000000000..0bb654e7e2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_wrong_specified_type_with_literal_array.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot include a value of type "int" as "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_1.gd b/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_1.gd
new file mode 100644
index 0000000000..fdf22f6843
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_1.gd
@@ -0,0 +1,10 @@
+class A:
+ func f(_p: Object):
+ pass
+
+class B extends A:
+ func f(_p: Node):
+ pass
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_1.out b/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_1.out
new file mode 100644
index 0000000000..c6a7e40e8c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_1.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+The function signature doesn't match the parent. Parent signature is "f(Object) -> Variant".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_2.gd b/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_2.gd
new file mode 100644
index 0000000000..e4094f1d76
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_2.gd
@@ -0,0 +1,10 @@
+class A:
+ func f(_p: Variant):
+ pass
+
+class B extends A:
+ func f(_p: Node): # No `is_type_compatible()` misuse.
+ pass
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_2.out b/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_2.out
new file mode 100644
index 0000000000..52a6efc6fc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_2.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+The function signature doesn't match the parent. Parent signature is "f(Variant) -> Variant".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_3.gd b/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_3.gd
new file mode 100644
index 0000000000..17663da4f6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_3.gd
@@ -0,0 +1,10 @@
+class A:
+ func f(_p: int):
+ pass
+
+class B extends A:
+ func f(_p: float): # No implicit conversion.
+ pass
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_3.out b/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_3.out
new file mode 100644
index 0000000000..7a6207fd45
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/function_param_type_invalid_contravariance_3.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+The function signature doesn't match the parent. Parent signature is "f(int) -> Variant".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_1.gd b/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_1.gd
new file mode 100644
index 0000000000..6dfa75ecbc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_1.gd
@@ -0,0 +1,10 @@
+class A:
+ func f() -> Node:
+ return null
+
+class B extends A:
+ func f() -> Object:
+ return null
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_1.out b/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_1.out
new file mode 100644
index 0000000000..e680b2bd77
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_1.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+The function signature doesn't match the parent. Parent signature is "f() -> Node".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_2.gd b/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_2.gd
new file mode 100644
index 0000000000..366494b94f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_2.gd
@@ -0,0 +1,10 @@
+class A:
+ func f() -> Node:
+ return null
+
+class B extends A:
+ func f() -> Variant: # No `is_type_compatible()` misuse.
+ return null
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_2.out b/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_2.out
new file mode 100644
index 0000000000..e680b2bd77
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_2.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+The function signature doesn't match the parent. Parent signature is "f() -> Node".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_3.gd b/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_3.gd
new file mode 100644
index 0000000000..2cb4e7c616
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_3.gd
@@ -0,0 +1,10 @@
+class A:
+ func f() -> Node:
+ return null
+
+class B extends A:
+ func f() -> void: # No `is_type_compatible()` misuse.
+ return
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_3.out b/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_3.out
new file mode 100644
index 0000000000..e680b2bd77
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_3.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+The function signature doesn't match the parent. Parent signature is "f() -> Node".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_4.gd b/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_4.gd
new file mode 100644
index 0000000000..2cabce46f5
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_4.gd
@@ -0,0 +1,10 @@
+class A:
+ func f() -> float:
+ return 0.0
+
+class B extends A:
+ func f() -> int: # No implicit conversion.
+ return 0
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_4.out b/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_4.out
new file mode 100644
index 0000000000..72f2c493d4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/function_return_type_invalid_covariance_4.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+The function signature doesn't match the parent. Parent signature is "f() -> float".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/match_guard_invalid_expression.gd b/modules/gdscript/tests/scripts/analyzer/errors/match_guard_invalid_expression.gd
new file mode 100644
index 0000000000..1dcb9fc36a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/match_guard_invalid_expression.gd
@@ -0,0 +1,4 @@
+func test():
+ match 0:
+ _ when a == 0:
+ print("a does not exist")
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/match_guard_invalid_expression.out b/modules/gdscript/tests/scripts/analyzer/errors/match_guard_invalid_expression.out
new file mode 100644
index 0000000000..c5f0a90d6a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/match_guard_invalid_expression.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Identifier "a" not declared in the current scope.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/object_invalid_constructor.gd b/modules/gdscript/tests/scripts/analyzer/errors/object_invalid_constructor.gd
new file mode 100644
index 0000000000..1600c3001f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/object_invalid_constructor.gd
@@ -0,0 +1,4 @@
+# GH-73213
+
+func test():
+ print(Object())
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/object_invalid_constructor.out b/modules/gdscript/tests/scripts/analyzer/errors/object_invalid_constructor.out
new file mode 100644
index 0000000000..27668fcd48
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/object_invalid_constructor.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Invalid constructor "Object()", use "Object.new()" instead.
diff --git a/modules/gdscript/tests/scripts/analyzer/features/function_param_type_contravariance.gd b/modules/gdscript/tests/scripts/analyzer/features/function_param_type_contravariance.gd
new file mode 100644
index 0000000000..a43c233625
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/function_param_type_contravariance.gd
@@ -0,0 +1,20 @@
+class A:
+ func int_to_variant(_p: int): pass
+ func node_to_variant(_p: Node): pass
+ func node_2d_to_node(_p: Node2D): pass
+
+ func variant_to_untyped(_p: Variant): pass
+ func int_to_untyped(_p: int): pass
+ func node_to_untyped(_p: Node): pass
+
+class B extends A:
+ func int_to_variant(_p: Variant): pass
+ func node_to_variant(_p: Variant): pass
+ func node_2d_to_node(_p: Node): pass
+
+ func variant_to_untyped(_p): pass
+ func int_to_untyped(_p): pass
+ func node_to_untyped(_p): pass
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/features/function_param_type_contravariance.out b/modules/gdscript/tests/scripts/analyzer/features/function_param_type_contravariance.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/function_param_type_contravariance.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/analyzer/features/function_return_type_covariance.gd b/modules/gdscript/tests/scripts/analyzer/features/function_return_type_covariance.gd
new file mode 100644
index 0000000000..4de50b6731
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/function_return_type_covariance.gd
@@ -0,0 +1,32 @@
+class A:
+ func variant_to_int() -> Variant: return 0
+ func variant_to_node() -> Variant: return null
+ func node_to_node_2d() -> Node: return null
+
+ func untyped_to_void(): pass
+ func untyped_to_variant(): pass
+ func untyped_to_int(): pass
+ func untyped_to_node(): pass
+
+ func void_to_untyped() -> void: pass
+ func variant_to_untyped() -> Variant: return null
+ func int_to_untyped() -> int: return 0
+ func node_to_untyped() -> Node: return null
+
+class B extends A:
+ func variant_to_int() -> int: return 0
+ func variant_to_node() -> Node: return null
+ func node_to_node_2d() -> Node2D: return null
+
+ func untyped_to_void() -> void: pass
+ func untyped_to_variant() -> Variant: return null
+ func untyped_to_int() -> int: return 0
+ func untyped_to_node() -> Node: return null
+
+ func void_to_untyped(): pass
+ func variant_to_untyped(): pass
+ func int_to_untyped(): pass
+ func node_to_untyped(): pass
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/features/function_return_type_covariance.out b/modules/gdscript/tests/scripts/analyzer/features/function_return_type_covariance.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/function_return_type_covariance.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/analyzer/features/hard_variants.gd b/modules/gdscript/tests/scripts/analyzer/features/hard_variants.gd
index b447180ea8..d0f895d784 100644
--- a/modules/gdscript/tests/scripts/analyzer/features/hard_variants.gd
+++ b/modules/gdscript/tests/scripts/analyzer/features/hard_variants.gd
@@ -23,6 +23,7 @@ func test() -> void:
typed = variant()
inferred = variant()
+ @warning_ignore("unsafe_call_argument") # TODO: Hard vs Weak vs Unknown.
param_weak(typed)
param_typed(typed)
param_inferred(typed)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/null_initializer.gd b/modules/gdscript/tests/scripts/analyzer/features/null_initializer.gd
index 5a413e2015..08e7dc590e 100644
--- a/modules/gdscript/tests/scripts/analyzer/features/null_initializer.gd
+++ b/modules/gdscript/tests/scripts/analyzer/features/null_initializer.gd
@@ -6,10 +6,12 @@ var prop = null
func check_arg(arg = null) -> void:
if arg != null:
+ @warning_ignore("unsafe_call_argument")
print(check(arg))
func check_recur() -> void:
if recur != null:
+ @warning_ignore("unsafe_call_argument")
print(check(recur))
else:
recur = 1
@@ -22,11 +24,13 @@ func test() -> void:
if prop == null:
set('prop', 1)
+ @warning_ignore("unsafe_call_argument")
print(check(prop))
set('prop', null)
var loop = null
while loop != 2:
if loop != null:
+ @warning_ignore("unsafe_call_argument")
print(check(loop))
loop = 1 if loop == null else 2
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/get_node_without_onready.gd b/modules/gdscript/tests/scripts/analyzer/warnings/get_node_without_onready.gd
index 849df0921e..c1776fe1b4 100644
--- a/modules/gdscript/tests/scripts/analyzer/warnings/get_node_without_onready.gd
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/get_node_without_onready.gd
@@ -14,4 +14,5 @@ func test():
func do_add_node():
var node = Node.new()
node.name = "Node"
+ @warning_ignore("unsafe_call_argument")
add_child(node)
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/unsafe_call_argument.gd b/modules/gdscript/tests/scripts/analyzer/warnings/unsafe_call_argument.gd
new file mode 100644
index 0000000000..573060ae0f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/unsafe_call_argument.gd
@@ -0,0 +1,37 @@
+func variant_func(x: Variant) -> void:
+ print(x)
+
+func int_func(x: int) -> void:
+ print(x)
+
+func float_func(x: float) -> void:
+ print(x)
+
+# We don't want to execute it because of errors, just analyze.
+func no_exec_test():
+ var untyped_int = 42
+ var untyped_string = "abc"
+ var variant_int: Variant = 42
+ var variant_string: Variant = "abc"
+ var typed_int: int = 42
+
+ variant_func(untyped_int) # No warning.
+ variant_func(untyped_string) # No warning.
+ variant_func(variant_int) # No warning.
+ variant_func(variant_string) # No warning.
+ variant_func(typed_int) # No warning.
+
+ int_func(untyped_int)
+ int_func(untyped_string)
+ int_func(variant_int)
+ int_func(variant_string)
+ int_func(typed_int) # No warning.
+
+ float_func(untyped_int)
+ float_func(untyped_string)
+ float_func(variant_int)
+ float_func(variant_string)
+ float_func(typed_int) # No warning.
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/unsafe_call_argument.out b/modules/gdscript/tests/scripts/analyzer/warnings/unsafe_call_argument.out
new file mode 100644
index 0000000000..b8fcb67158
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/unsafe_call_argument.out
@@ -0,0 +1,33 @@
+GDTEST_OK
+>> WARNING
+>> Line: 24
+>> UNSAFE_CALL_ARGUMENT
+>> The argument 1 of the function "int_func()" requires the subtype "int" but the supertype "Variant" was provided.
+>> WARNING
+>> Line: 25
+>> UNSAFE_CALL_ARGUMENT
+>> The argument 1 of the function "int_func()" requires the subtype "int" but the supertype "Variant" was provided.
+>> WARNING
+>> Line: 26
+>> UNSAFE_CALL_ARGUMENT
+>> The argument 1 of the function "int_func()" requires the subtype "int" but the supertype "Variant" was provided.
+>> WARNING
+>> Line: 27
+>> UNSAFE_CALL_ARGUMENT
+>> The argument 1 of the function "int_func()" requires the subtype "int" but the supertype "Variant" was provided.
+>> WARNING
+>> Line: 30
+>> UNSAFE_CALL_ARGUMENT
+>> The argument 1 of the function "float_func()" requires the subtype "float" but the supertype "Variant" was provided.
+>> WARNING
+>> Line: 31
+>> UNSAFE_CALL_ARGUMENT
+>> The argument 1 of the function "float_func()" requires the subtype "float" but the supertype "Variant" was provided.
+>> WARNING
+>> Line: 32
+>> UNSAFE_CALL_ARGUMENT
+>> The argument 1 of the function "float_func()" requires the subtype "float" but the supertype "Variant" was provided.
+>> WARNING
+>> Line: 33
+>> UNSAFE_CALL_ARGUMENT
+>> The argument 1 of the function "float_func()" requires the subtype "float" but the supertype "Variant" was provided.
diff --git a/modules/gdscript/tests/scripts/parser/errors/match_guard_with_assignment.gd b/modules/gdscript/tests/scripts/parser/errors/match_guard_with_assignment.gd
new file mode 100644
index 0000000000..d88b4a37c4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/match_guard_with_assignment.gd
@@ -0,0 +1,5 @@
+func test():
+ var a = 0
+ match a:
+ 0 when a = 1:
+ print("assignment not allowed on pattern guard")
diff --git a/modules/gdscript/tests/scripts/parser/errors/match_guard_with_assignment.out b/modules/gdscript/tests/scripts/parser/errors/match_guard_with_assignment.out
new file mode 100644
index 0000000000..e8f9130706
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/match_guard_with_assignment.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Assignment is not allowed inside an expression.
diff --git a/modules/gdscript/tests/scripts/parser/features/allowed_keywords_as_identifiers.gd b/modules/gdscript/tests/scripts/parser/features/allowed_keywords_as_identifiers.gd
index 7e1982597c..0c8a5d1367 100644
--- a/modules/gdscript/tests/scripts/parser/features/allowed_keywords_as_identifiers.gd
+++ b/modules/gdscript/tests/scripts/parser/features/allowed_keywords_as_identifiers.gd
@@ -14,3 +14,7 @@ func test():
var TAU = "TAU"
print(TAU)
+
+ # New keyword for pattern guards.
+ var when = "when"
+ print(when)
diff --git a/modules/gdscript/tests/scripts/parser/features/allowed_keywords_as_identifiers.out b/modules/gdscript/tests/scripts/parser/features/allowed_keywords_as_identifiers.out
index aae2ae13d5..8ac8e92ef7 100644
--- a/modules/gdscript/tests/scripts/parser/features/allowed_keywords_as_identifiers.out
+++ b/modules/gdscript/tests/scripts/parser/features/allowed_keywords_as_identifiers.out
@@ -4,3 +4,4 @@ PI
INF
NAN
TAU
+when
diff --git a/modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.gd b/modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.gd
index f04f4de08d..19f6e08285 100644
--- a/modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.gd
+++ b/modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.gd
@@ -3,27 +3,32 @@ extends Node
func test():
var child = Node.new()
child.name = "Child"
+ @warning_ignore("unsafe_call_argument")
add_child(child)
child.owner = self
var hey = Node.new()
hey.name = "Hey"
+ @warning_ignore("unsafe_call_argument")
child.add_child(hey)
hey.owner = self
hey.unique_name_in_owner = true
var fake_hey = Node.new()
fake_hey.name = "Hey"
+ @warning_ignore("unsafe_call_argument")
add_child(fake_hey)
fake_hey.owner = self
var sub_child = Node.new()
sub_child.name = "SubChild"
+ @warning_ignore("unsafe_call_argument")
hey.add_child(sub_child)
sub_child.owner = self
var howdy = Node.new()
howdy.name = "Howdy"
+ @warning_ignore("unsafe_call_argument")
sub_child.add_child(howdy)
howdy.owner = self
howdy.unique_name_in_owner = true
diff --git a/modules/gdscript/tests/scripts/parser/features/dollar_node_paths.gd b/modules/gdscript/tests/scripts/parser/features/dollar_node_paths.gd
index 8ba558e91d..3d9404b20b 100644
--- a/modules/gdscript/tests/scripts/parser/features/dollar_node_paths.gd
+++ b/modules/gdscript/tests/scripts/parser/features/dollar_node_paths.gd
@@ -5,9 +5,11 @@ func test():
# Create the required node structure.
var hello = Node.new()
hello.name = "Hello"
+ @warning_ignore("unsafe_call_argument")
add_child(hello)
var world = Node.new()
world.name = "World"
+ @warning_ignore("unsafe_call_argument")
hello.add_child(world)
# All the ways of writing node paths below with the `$` operator are valid.
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 df6001c7e2..f16c768f7f 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
@@ -26,6 +26,7 @@ func test():
if true: (v as Callable).call()
print()
+ @warning_ignore("unsafe_call_argument")
other(v)
print()
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_function_calls.gd b/modules/gdscript/tests/scripts/parser/features/nested_function_calls.gd
index 59cdc7d6c2..31de73813f 100644
--- a/modules/gdscript/tests/scripts/parser/features/nested_function_calls.gd
+++ b/modules/gdscript/tests/scripts/parser/features/nested_function_calls.gd
@@ -2,4 +2,5 @@ func foo(x):
return x + 1
func test():
+ @warning_ignore("unsafe_call_argument")
print(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(0)))))))))))))))))))))))))
diff --git a/modules/gdscript/tests/scripts/parser/features/super.gd b/modules/gdscript/tests/scripts/parser/features/super.gd
index f5ae2a74a7..33accd92a9 100644
--- a/modules/gdscript/tests/scripts/parser/features/super.gd
+++ b/modules/gdscript/tests/scripts/parser/features/super.gd
@@ -36,6 +36,7 @@ class SayNothing extends Say:
print("howdy, see above")
func say(name):
+ @warning_ignore("unsafe_call_argument")
super(name + " super'd")
print(prefix, " say nothing... or not? ", name)
diff --git a/modules/gdscript/tests/scripts/parser/features/unicode_identifiers.gd b/modules/gdscript/tests/scripts/parser/features/unicode_identifiers.gd
index 523959a016..20cc0cee2e 100644
--- a/modules/gdscript/tests/scripts/parser/features/unicode_identifiers.gd
+++ b/modules/gdscript/tests/scripts/parser/features/unicode_identifiers.gd
@@ -29,6 +29,7 @@ func test():
const d = 1.1
_process(d)
+ @warning_ignore("unsafe_call_argument")
print(is_equal_approx(ㄥ, PI + (d * PI)))
func _process(Δ: float) -> void:
diff --git a/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.gd b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.gd
index 58b4df5a79..bc899a3a6f 100644
--- a/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.gd
@@ -21,6 +21,12 @@ func test():
var elem := e
prints(var_to_str(e), var_to_str(elem))
+ # GH-82021
+ print("Test implicitly typed array literal.")
+ for e: float in [100, 200, 300]:
+ var elem := e
+ prints(var_to_str(e), var_to_str(elem))
+
print("Test String-keys dictionary.")
var d1 := {a = 1, b = 2, c = 3}
for k: StringName in d1:
diff --git a/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.out b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.out
index f67f7d89d5..eeebdc4be5 100644
--- a/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.out
+++ b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_specified_types.out
@@ -15,6 +15,10 @@ Test typed int array.
10.0 10.0
20.0 20.0
30.0 30.0
+Test implicitly typed array literal.
+100.0 100.0
+200.0 200.0
+300.0 300.0
Test String-keys dictionary.
&"a" &"a"
&"b" &"b"
diff --git a/modules/gdscript/tests/scripts/runtime/features/match_with_pattern_guards.gd b/modules/gdscript/tests/scripts/runtime/features/match_with_pattern_guards.gd
new file mode 100644
index 0000000000..4cb51f8512
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/match_with_pattern_guards.gd
@@ -0,0 +1,71 @@
+var global := 0
+
+func test():
+ var a = 0
+ var b = 1
+
+ match a:
+ 0 when b == 0:
+ print("does not run" if true else "")
+ 0 when b == 1:
+ print("guards work")
+ _:
+ print("does not run")
+
+ match a:
+ var a_bind when b == 0:
+ prints("a is", a_bind, "and b is 0")
+ var a_bind when b == 1:
+ prints("a is", a_bind, "and b is 1")
+ _:
+ print("does not run")
+
+ match a:
+ var a_bind when a_bind < 0:
+ print("a is less than zero")
+ var a_bind when a_bind == 0:
+ print("a is equal to zero")
+ _:
+ print("a is more than zero")
+
+ match [1, 2, 3]:
+ [1, 2, var element] when element == 0:
+ print("does not run")
+ [1, 2, var element] when element == 3:
+ print("3rd element is 3")
+
+ match a:
+ _ when b == 0:
+ print("does not run")
+ _ when b == 1:
+ print("works with wildcard too.")
+ _:
+ print("does not run")
+
+ match a:
+ 0, 1 when b == 0:
+ print("does not run")
+ 0, 1 when b == 1:
+ print("guard with multiple patterns")
+ _:
+ print("does not run")
+
+ match a:
+ 0 when b == 0:
+ print("does not run")
+ 0:
+ print("regular pattern after guard mismatch")
+
+ match a:
+ 1 when side_effect():
+ print("should not run the side effect call")
+ 0 when side_effect():
+ print("will run the side effect call, but not this")
+ _:
+ assert(global == 1)
+ print("side effect only ran once")
+
+func side_effect():
+ print("side effect")
+ global += 1
+ return false
diff --git a/modules/gdscript/tests/scripts/runtime/features/match_with_pattern_guards.out b/modules/gdscript/tests/scripts/runtime/features/match_with_pattern_guards.out
new file mode 100644
index 0000000000..452d1ff4bf
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/match_with_pattern_guards.out
@@ -0,0 +1,10 @@
+GDTEST_OK
+guards work
+a is 0 and b is 1
+a is equal to zero
+3rd element is 3
+works with wildcard too.
+guard with multiple patterns
+regular pattern after guard mismatch
+side effect
+side effect only ran once
diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.gd b/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.gd
new file mode 100644
index 0000000000..d0cbeeab85
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.gd
@@ -0,0 +1,45 @@
+# GH-82169
+
+const Utils = preload("../../utils.notest.gd")
+
+class A:
+ static var test_static_var_a1
+ static var test_static_var_a2
+ var test_var_a1
+ var test_var_a2
+ static func test_static_func_a1(): pass
+ static func test_static_func_a2(): pass
+ func test_func_a1(): pass
+ func test_func_a2(): pass
+ signal test_signal_a1()
+ signal test_signal_a2()
+
+class B extends A:
+ static var test_static_var_b1
+ static var test_static_var_b2
+ var test_var_b1
+ var test_var_b2
+ static func test_static_func_b1(): pass
+ static func test_static_func_b2(): pass
+ func test_func_b1(): pass
+ func test_func_b2(): pass
+ signal test_signal_b1()
+ signal test_signal_b2()
+
+func test():
+ var b := B.new()
+ for property in (B as GDScript).get_property_list():
+ if str(property.name).begins_with("test_"):
+ print(Utils.get_property_signature(property, true))
+ print("---")
+ for property in b.get_property_list():
+ if str(property.name).begins_with("test_"):
+ print(Utils.get_property_signature(property))
+ print("---")
+ for method in b.get_method_list():
+ if str(method.name).begins_with("test_"):
+ print(Utils.get_method_signature(method))
+ print("---")
+ for method in b.get_signal_list():
+ if str(method.name).begins_with("test_"):
+ print(Utils.get_method_signature(method, true))
diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.out b/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.out
new file mode 100644
index 0000000000..f294b66ef9
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.out
@@ -0,0 +1,24 @@
+GDTEST_OK
+static var test_static_var_a1: Variant
+static var test_static_var_a2: Variant
+static var test_static_var_b1: Variant
+static var test_static_var_b2: Variant
+---
+var test_var_b1: Variant
+var test_var_b2: Variant
+var test_var_a1: Variant
+var test_var_a2: Variant
+---
+static func test_static_func_b1() -> void
+static func test_static_func_b2() -> void
+func test_func_b1() -> void
+func test_func_b2() -> void
+static func test_static_func_a1() -> void
+static func test_static_func_a2() -> void
+func test_func_a1() -> void
+func test_func_a2() -> void
+---
+signal test_signal_b1()
+signal test_signal_b2()
+signal test_signal_a1()
+signal test_signal_a2()
diff --git a/modules/gdscript/tests/scripts/runtime/features/object_constructor.gd b/modules/gdscript/tests/scripts/runtime/features/object_constructor.gd
new file mode 100644
index 0000000000..b875efef56
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/object_constructor.gd
@@ -0,0 +1,6 @@
+# GH-73213
+
+func test():
+ var object := Object.new() # Not `Object()`.
+ print(object.get_class())
+ object.free()
diff --git a/modules/gdscript/tests/scripts/runtime/features/object_constructor.out b/modules/gdscript/tests/scripts/runtime/features/object_constructor.out
new file mode 100644
index 0000000000..3673881576
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/object_constructor.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+Object
diff --git a/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd b/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd
index 2f55059334..fd1460a48f 100644
--- a/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd
@@ -12,6 +12,7 @@ func test():
print("end")
func test_construct(v, f):
+ @warning_ignore("unsafe_call_argument")
Vector2(v, v) # Built-in type construct.
assert(not f) # Test unary operator reading from `nil`.
diff --git a/modules/gdscript/tests/scripts/runtime/features/static_variables.gd b/modules/gdscript/tests/scripts/runtime/features/static_variables.gd
index 8da8bb7e53..7fa76ca4b0 100644
--- a/modules/gdscript/tests/scripts/runtime/features/static_variables.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/static_variables.gd
@@ -44,6 +44,7 @@ func test():
@warning_ignore("unsafe_method_access")
var path = get_script().get_path().get_base_dir()
+ @warning_ignore("unsafe_call_argument")
var other = load(path + "/static_variables_load.gd")
prints("load.perm:", other.perm)
diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.gd b/modules/gdscript/tests/scripts/runtime/features/stringify.gd
index fead2df854..1e66d8f34a 100644
--- a/modules/gdscript/tests/scripts/runtime/features/stringify.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/stringify.gd
@@ -24,7 +24,8 @@ func test():
print(StringName("hello"))
print(NodePath("hello/world"))
var node := Node.new()
- print(RID(node))
+ @warning_ignore("unsafe_call_argument")
+ print(RID(node)) # TODO: Why is the constructor (or implicit cast) not documented?
print(node.get_name)
print(node.property_list_changed)
node.free()
diff --git a/modules/gdscript/tests/scripts/utils.notest.gd b/modules/gdscript/tests/scripts/utils.notest.gd
index fb20817117..781843b8e2 100644
--- a/modules/gdscript/tests/scripts/utils.notest.gd
+++ b/modules/gdscript/tests/scripts/utils.notest.gd
@@ -17,7 +17,7 @@ static func get_type(property: Dictionary, is_return: bool = false) -> String:
TYPE_OBJECT:
if not str(property.class_name).is_empty():
return property.class_name
- return variant_get_type_name(property.type)
+ return type_string(property.type)
static func get_property_signature(property: Dictionary, is_static: bool = false) -> String:
@@ -66,88 +66,6 @@ static func get_method_signature(method: Dictionary, is_signal: bool = false) ->
return result
-static func variant_get_type_name(type: Variant.Type) -> String:
- match type:
- TYPE_NIL:
- return "Nil" # `Nil` in core, `null` in GDScript.
- TYPE_BOOL:
- return "bool"
- TYPE_INT:
- return "int"
- TYPE_FLOAT:
- return "float"
- TYPE_STRING:
- return "String"
- TYPE_VECTOR2:
- return "Vector2"
- TYPE_VECTOR2I:
- return "Vector2i"
- TYPE_RECT2:
- return "Rect2"
- TYPE_RECT2I:
- return "Rect2i"
- TYPE_VECTOR3:
- return "Vector3"
- TYPE_VECTOR3I:
- return "Vector3i"
- TYPE_TRANSFORM2D:
- return "Transform2D"
- TYPE_VECTOR4:
- return "Vector4"
- TYPE_VECTOR4I:
- return "Vector4i"
- TYPE_PLANE:
- return "Plane"
- TYPE_QUATERNION:
- return "Quaternion"
- TYPE_AABB:
- return "AABB"
- TYPE_BASIS:
- return "Basis"
- TYPE_TRANSFORM3D:
- return "Transform3D"
- TYPE_PROJECTION:
- return "Projection"
- TYPE_COLOR:
- return "Color"
- TYPE_STRING_NAME:
- return "StringName"
- TYPE_NODE_PATH:
- return "NodePath"
- TYPE_RID:
- return "RID"
- TYPE_OBJECT:
- return "Object"
- TYPE_CALLABLE:
- return "Callable"
- TYPE_SIGNAL:
- return "Signal"
- TYPE_DICTIONARY:
- return "Dictionary"
- TYPE_ARRAY:
- return "Array"
- TYPE_PACKED_BYTE_ARRAY:
- return "PackedByteArray"
- TYPE_PACKED_INT32_ARRAY:
- return "PackedInt32Array"
- TYPE_PACKED_INT64_ARRAY:
- return "PackedInt64Array"
- TYPE_PACKED_FLOAT32_ARRAY:
- return "PackedFloat32Array"
- TYPE_PACKED_FLOAT64_ARRAY:
- return "PackedFloat64Array"
- TYPE_PACKED_STRING_ARRAY:
- return "PackedStringArray"
- TYPE_PACKED_VECTOR2_ARRAY:
- return "PackedVector2Array"
- TYPE_PACKED_VECTOR3_ARRAY:
- return "PackedVector3Array"
- TYPE_PACKED_COLOR_ARRAY:
- return "PackedColorArray"
- push_error("Argument `type` is invalid. Use `TYPE_*` constants.")
- return "<invalid type>"
-
-
static func get_property_hint_name(hint: PropertyHint) -> String:
match hint:
PROPERTY_HINT_NONE:
diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp
index b86a8b3cb1..467bedc4b2 100644
--- a/modules/gdscript/tests/test_gdscript.cpp
+++ b/modules/gdscript/tests/test_gdscript.cpp
@@ -223,6 +223,16 @@ void test(TestType p_type) {
// Initialize the language for the test routine.
init_language(fa->get_path_absolute().get_base_dir());
+ // Load global classes.
+ TypedArray<Dictionary> script_classes = ProjectSettings::get_singleton()->get_global_class_list();
+ for (int i = 0; i < script_classes.size(); i++) {
+ Dictionary c = script_classes[i];
+ if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base")) {
+ continue;
+ }
+ ScriptServer::add_global_class(c["class"], c["base"], c["language"], c["path"]);
+ }
+
Vector<uint8_t> buf;
uint64_t flen = fa->get_length();
buf.resize(flen + 1);
diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp
index 3787d0fe5e..cb45a6589e 100644
--- a/modules/gltf/editor/editor_scene_importer_blend.cpp
+++ b/modules/gltf/editor/editor_scene_importer_blend.cpp
@@ -49,6 +49,67 @@
#include <shlwapi.h>
#endif
+static bool _get_blender_version(const String &p_path, int &r_major, int &r_minor, String *r_err = nullptr) {
+ String path = p_path;
+#ifdef WINDOWS_ENABLED
+ path = path.path_join("blender.exe");
+#else
+ path = path.path_join("blender");
+#endif
+
+#if defined(MACOS_ENABLED)
+ if (!FileAccess::exists(path)) {
+ path = p_path.path_join("Blender");
+ }
+#endif
+
+ if (!FileAccess::exists(path)) {
+ if (r_err) {
+ *r_err = TTR("Path does not contain a Blender installation.");
+ }
+ return false;
+ }
+ List<String> args;
+ args.push_back("--version");
+ String pipe;
+ Error err = OS::get_singleton()->execute(path, args, &pipe);
+ if (err != OK) {
+ if (r_err) {
+ *r_err = TTR("Can't execute Blender binary.");
+ }
+ return false;
+ }
+ int bl = pipe.find("Blender ");
+ if (bl == -1) {
+ if (r_err) {
+ *r_err = vformat(TTR("Unexpected --version output from Blender binary at: %s."), path);
+ }
+ return false;
+ }
+ pipe = pipe.substr(bl);
+ pipe = pipe.replace_first("Blender ", "");
+ int pp = pipe.find(".");
+ if (pp == -1) {
+ if (r_err) {
+ *r_err = TTR("Path supplied lacks a Blender binary.");
+ }
+ return false;
+ }
+ String v = pipe.substr(0, pp);
+ r_major = v.to_int();
+ if (r_major < 3) {
+ if (r_err) {
+ *r_err = TTR("This Blender installation is too old for this importer (not 3.0+).");
+ }
+ return false;
+ }
+
+ int pp2 = pipe.find(".", pp + 1);
+ r_minor = pp2 > pp ? pipe.substr(pp + 1, pp2 - pp - 1).to_int() : 0;
+
+ return true;
+}
+
uint32_t EditorSceneFormatImporterBlend::get_import_flags() const {
return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION;
}
@@ -60,8 +121,13 @@ void EditorSceneFormatImporterBlend::get_extensions(List<String> *r_extensions)
Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_t p_flags,
const HashMap<StringName, Variant> &p_options,
List<String> *r_missing_deps, Error *r_err) {
- // Get global paths for source and sink.
+ String blender_path = EDITOR_GET("filesystem/import/blender/blender3_path");
+ if (blender_major_version == -1 || blender_minor_version == -1) {
+ _get_blender_version(blender_path, blender_major_version, blender_minor_version, nullptr);
+ }
+
+ // Get global paths for source and sink.
// Escape paths to be valid Python strings to embed in the script.
const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape();
const String sink = ProjectSettings::get_singleton()->get_imported_files_path().path_join(
@@ -153,9 +219,17 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
parameters_map["export_tangents"] = false;
}
if (p_options.has(SNAME("blender/animation/group_tracks")) && p_options[SNAME("blender/animation/group_tracks")]) {
- parameters_map["export_nla_strips"] = true;
+ if (blender_major_version > 3 || (blender_major_version == 3 && blender_minor_version >= 6)) {
+ parameters_map["export_animation_mode"] = "ACTIONS";
+ } else {
+ parameters_map["export_nla_strips"] = true;
+ }
} else {
- parameters_map["export_nla_strips"] = false;
+ if (blender_major_version > 3 || (blender_major_version == 3 && blender_minor_version >= 6)) {
+ parameters_map["export_animation_mode"] = "ACTIVE_ACTIONS";
+ } else {
+ parameters_map["export_nla_strips"] = false;
+ }
}
if (p_options.has(SNAME("blender/animation/limit_playback")) && p_options[SNAME("blender/animation/limit_playback")]) {
parameters_map["export_frame_range"] = true;
@@ -269,67 +343,8 @@ void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, Li
///////////////////////////
static bool _test_blender_path(const String &p_path, String *r_err = nullptr) {
- String path = p_path;
-#ifdef WINDOWS_ENABLED
- path = path.path_join("blender.exe");
-#else
- path = path.path_join("blender");
-#endif
-
-#if defined(MACOS_ENABLED)
- if (!FileAccess::exists(path)) {
- path = path.path_join("Blender");
- }
-#endif
-
- if (!FileAccess::exists(path)) {
- if (r_err) {
- *r_err = TTR("Path does not contain a Blender installation.");
- }
- return false;
- }
- List<String> args;
- args.push_back("--version");
- String pipe;
- Error err = OS::get_singleton()->execute(path, args, &pipe);
- if (err != OK) {
- if (r_err) {
- *r_err = TTR("Can't execute Blender binary.");
- }
- return false;
- }
- int bl = pipe.find("Blender ");
- if (bl == -1) {
- if (r_err) {
- *r_err = vformat(TTR("Unexpected --version output from Blender binary at: %s"), path);
- }
- return false;
- }
- pipe = pipe.substr(bl);
- pipe = pipe.replace_first("Blender ", "");
- int pp = pipe.find(".");
- if (pp == -1) {
- if (r_err) {
- *r_err = TTR("Path supplied lacks a Blender binary.");
- }
- return false;
- }
- String v = pipe.substr(0, pp);
- int version = v.to_int();
- if (version < 3) {
- if (r_err) {
- *r_err = TTR("This Blender installation is too old for this importer (not 3.0+).");
- }
- return false;
- }
- if (version > 3) {
- if (r_err) {
- *r_err = TTR("This Blender installation is too new for this importer (not 3.x).");
- }
- return false;
- }
-
- return true;
+ int major, minor;
+ return _get_blender_version(p_path, major, minor, r_err);
}
bool EditorFileSystemImportFormatSupportQueryBlend::is_active() const {
diff --git a/modules/gltf/editor/editor_scene_importer_blend.h b/modules/gltf/editor/editor_scene_importer_blend.h
index c77a23f9f6..ec467db457 100644
--- a/modules/gltf/editor/editor_scene_importer_blend.h
+++ b/modules/gltf/editor/editor_scene_importer_blend.h
@@ -43,6 +43,9 @@ class ConfirmationDialog;
class EditorSceneFormatImporterBlend : public EditorSceneFormatImporter {
GDCLASS(EditorSceneFormatImporterBlend, EditorSceneFormatImporter);
+ int blender_major_version = -1;
+ int blender_minor_version = -1;
+
public:
enum {
BLEND_VISIBLE_ALL,
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index cee65d70c9..bac988630d 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -7347,6 +7347,12 @@ Error GLTFDocument::write_to_filesystem(Ref<GLTFState> p_state, const String &p_
}
Node *GLTFDocument::_generate_scene_node_tree(Ref<GLTFState> p_state) {
+ // Generate the skeletons and skins (if any).
+ Error err = _create_skeletons(p_state);
+ ERR_FAIL_COND_V_MSG(err != OK, nullptr, "GLTF: Failed to create skeletons.");
+ err = _create_skins(p_state);
+ ERR_FAIL_COND_V_MSG(err != OK, nullptr, "GLTF: Failed to create skins.");
+ // Generate the node tree.
Node *single_root;
if (p_state->extensions_used.has("GODOT_single_root")) {
_generate_scene_node(p_state, 0, nullptr, nullptr);
@@ -7539,14 +7545,6 @@ Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> p_state, const String &p_se
err = _determine_skeletons(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
- /* CREATE SKELETONS */
- err = _create_skeletons(p_state);
- ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
-
- /* CREATE SKINS */
- err = _create_skins(p_state);
- ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
-
/* PARSE MESHES (we have enough info now) */
err = _parse_meshes(p_state);
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
diff --git a/modules/lightmapper_rd/config.py b/modules/lightmapper_rd/config.py
index d22f9454ed..ecc61c2d7e 100644
--- a/modules/lightmapper_rd/config.py
+++ b/modules/lightmapper_rd/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return True
+ return env.editor_build and platform not in ["android", "ios"]
def configure(env):
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 4ed730b3af..556b0b4374 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -614,25 +614,29 @@ void LightmapperRD::_raster_geometry(RenderingDevice *rd, Size2i atlas_size, int
}
}
-LightmapperRD::BakeError LightmapperRD::_dilate(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices) {
+static Vector<RD::Uniform> dilate_or_denoise_common_uniforms(RID &p_source_light_tex, RID &p_dest_light_tex) {
Vector<RD::Uniform> uniforms;
{
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 0;
- u.append_id(dest_light_tex);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1;
- u.append_id(source_light_tex);
- uniforms.push_back(u);
- }
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 0;
+ u.append_id(p_dest_light_tex);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1;
+ u.append_id(p_source_light_tex);
+ uniforms.push_back(u);
}
+ return uniforms;
+}
+
+LightmapperRD::BakeError LightmapperRD::_dilate(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices) {
+ Vector<RD::Uniform> uniforms = dilate_or_denoise_common_uniforms(source_light_tex, dest_light_tex);
+
RID compute_shader_dilate = rd->shader_create_from_spirv(compute_shader->get_spirv_stages("dilate"));
ERR_FAIL_COND_V(compute_shader_dilate.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen
RID compute_shader_dilate_pipeline = rd->compute_pipeline_create(compute_shader_dilate);
@@ -667,7 +671,77 @@ LightmapperRD::BakeError LightmapperRD::_dilate(RenderingDevice *rd, Ref<RDShade
return BAKE_OK;
}
-LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function, void *p_bake_userdata, float p_exposure_normalization) {
+LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function) {
+ RID denoise_params_buffer = p_rd->uniform_buffer_create(sizeof(DenoiseParams));
+ DenoiseParams denoise_params;
+ denoise_params.spatial_bandwidth = 5.0f;
+ denoise_params.light_bandwidth = p_denoiser_strength;
+ denoise_params.albedo_bandwidth = 1.0f;
+ denoise_params.normal_bandwidth = 0.1f;
+ denoise_params.filter_strength = 10.0f;
+ p_rd->buffer_update(denoise_params_buffer, 0, sizeof(DenoiseParams), &denoise_params);
+
+ Vector<RD::Uniform> uniforms = dilate_or_denoise_common_uniforms(p_source_light_tex, p_dest_light_tex);
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 2;
+ u.append_id(p_source_normal_tex);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 3;
+ u.append_id(denoise_params_buffer);
+ uniforms.push_back(u);
+ }
+
+ RID compute_shader_denoise = p_rd->shader_create_from_spirv(p_compute_shader->get_spirv_stages("denoise"));
+ ERR_FAIL_COND_V(compute_shader_denoise.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES);
+
+ RID compute_shader_denoise_pipeline = p_rd->compute_pipeline_create(compute_shader_denoise);
+ RID denoise_uniform_set = p_rd->uniform_set_create(uniforms, compute_shader_denoise, 1);
+
+ // We denoise in fixed size regions and synchronize execution to avoid GPU timeouts.
+ // We use a region with 1/4 the amount of pixels if we're denoising SH lightmaps, as
+ // all four of them are denoised in the shader in one dispatch.
+ const int max_region_size = p_bake_sh ? 512 : 1024;
+ int x_regions = (p_atlas_size.width - 1) / max_region_size + 1;
+ int y_regions = (p_atlas_size.height - 1) / max_region_size + 1;
+ for (int s = 0; s < p_atlas_slices; s++) {
+ p_push_constant.atlas_slice = s;
+
+ for (int i = 0; i < x_regions; i++) {
+ for (int j = 0; j < y_regions; j++) {
+ int x = i * max_region_size;
+ int y = j * max_region_size;
+ int w = MIN((i + 1) * max_region_size, p_atlas_size.width) - x;
+ int h = MIN((j + 1) * max_region_size, p_atlas_size.height) - y;
+ p_push_constant.region_ofs[0] = x;
+ p_push_constant.region_ofs[1] = y;
+
+ RD::ComputeListID compute_list = p_rd->compute_list_begin();
+ p_rd->compute_list_bind_compute_pipeline(compute_list, compute_shader_denoise_pipeline);
+ p_rd->compute_list_bind_uniform_set(compute_list, p_compute_base_uniform_set, 0);
+ p_rd->compute_list_bind_uniform_set(compute_list, denoise_uniform_set, 1);
+ p_rd->compute_list_set_push_constant(compute_list, &p_push_constant, sizeof(PushConstant));
+ p_rd->compute_list_dispatch(compute_list, (w - 1) / 8 + 1, (h - 1) / 8 + 1, 1);
+ p_rd->compute_list_end();
+
+ p_rd->submit();
+ p_rd->sync();
+ }
+ }
+ }
+
+ p_rd->free(compute_shader_denoise);
+ p_rd->free(denoise_params_buffer);
+
+ return BAKE_OK;
+}
+
+LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_denoiser, float p_denoiser_strength, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function, void *p_bake_userdata, float p_exposure_normalization) {
if (p_step_function) {
p_step_function(0.0, RTR("Begin Bake"), p_bake_userdata, true);
}
@@ -1419,14 +1493,6 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
}
#endif
- {
- SWAP(light_accum_tex, light_accum_tex2);
- BakeError error = _dilate(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, light_accum_tex, atlas_size, atlas_slices * (p_bake_sh ? 4 : 1));
- if (unlikely(error != BAKE_OK)) {
- return error;
- }
- }
-
/* DENOISE */
if (p_use_denoiser) {
@@ -1434,39 +1500,23 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
p_step_function(0.8, RTR("Denoising"), p_bake_userdata, true);
}
- Ref<LightmapDenoiser> denoiser = LightmapDenoiser::create();
- if (denoiser.is_valid()) {
- for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) {
- Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i);
- Ref<Image> img = Image::create_from_data(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
-
- Ref<Image> denoised = denoiser->denoise_image(img);
- if (denoised != img) {
- denoised->convert(Image::FORMAT_RGBAH);
- Vector<uint8_t> ds = denoised->get_data();
- denoised.unref(); //avoid copy on write
- { //restore alpha
- uint32_t count = s.size() / 2; //uint16s
- const uint16_t *src = (const uint16_t *)s.ptr();
- uint16_t *dst = (uint16_t *)ds.ptrw();
- for (uint32_t j = 0; j < count; j += 4) {
- dst[j + 3] = src[j + 3];
- }
- }
- rd->texture_update(light_accum_tex, i, ds);
- }
- }
- }
-
{
SWAP(light_accum_tex, light_accum_tex2);
- BakeError error = _dilate(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, light_accum_tex, atlas_size, atlas_slices * (p_bake_sh ? 4 : 1));
+ BakeError error = _denoise(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, normal_tex, light_accum_tex, p_denoiser_strength, atlas_size, atlas_slices, p_bake_sh, p_step_function);
if (unlikely(error != BAKE_OK)) {
return error;
}
}
}
+ {
+ SWAP(light_accum_tex, light_accum_tex2);
+ BakeError error = _dilate(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, light_accum_tex, atlas_size, atlas_slices * (p_bake_sh ? 4 : 1));
+ if (unlikely(error != BAKE_OK)) {
+ return error;
+ }
+ }
+
#ifdef DEBUG_TEXTURES
for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) {
diff --git a/modules/lightmapper_rd/lightmapper_rd.h b/modules/lightmapper_rd/lightmapper_rd.h
index 061c9ba000..7120a21b84 100644
--- a/modules/lightmapper_rd/lightmapper_rd.h
+++ b/modules/lightmapper_rd/lightmapper_rd.h
@@ -229,11 +229,22 @@ class LightmapperRD : public Lightmapper {
Vector<Ref<Image>> bake_textures;
Vector<Color> probe_values;
+ struct DenoiseParams {
+ float spatial_bandwidth;
+ float light_bandwidth;
+ float albedo_bandwidth;
+ float normal_bandwidth;
+
+ float filter_strength;
+ float pad[3];
+ };
+
BakeError _blit_meshes_into_atlas(int p_max_texture_size, Vector<Ref<Image>> &albedo_images, Vector<Ref<Image>> &emission_images, AABB &bounds, Size2i &atlas_size, int &atlas_slices, BakeStepFunc p_step_function, void *p_bake_userdata);
void _create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata);
void _raster_geometry(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, int grid_size, AABB bounds, float p_bias, Vector<int> slice_triangle_count, RID position_tex, RID unocclude_tex, RID normal_tex, RID raster_depth_buffer, RID rasterize_shader, RID raster_base_uniform);
BakeError _dilate(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices);
+ BakeError _denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function);
public:
virtual void add_mesh(const MeshData &p_mesh) override;
@@ -241,7 +252,7 @@ public:
virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) override;
virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) override;
virtual void add_probe(const Vector3 &p_position) override;
- virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_bake_userdata = nullptr, float p_exposure_normalization = 1.0) override;
+ virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, float p_denoiser_strength, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_bake_userdata = nullptr, float p_exposure_normalization = 1.0) override;
int get_bake_texture_count() const override;
Ref<Image> get_bake_texture(int p_index) const override;
diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl
index 4d3f2d46a4..ce33f2ed1d 100644
--- a/modules/lightmapper_rd/lm_compute.glsl
+++ b/modules/lightmapper_rd/lm_compute.glsl
@@ -5,6 +5,7 @@ secondary = "#define MODE_BOUNCE_LIGHT";
dilate = "#define MODE_DILATE";
unocclude = "#define MODE_UNOCCLUDE";
light_probes = "#define MODE_LIGHT_PROBES";
+denoise = "#define MODE_DENOISE";
#[compute]
@@ -65,11 +66,24 @@ layout(set = 1, binding = 6) uniform texture2D environment;
layout(rgba32f, set = 1, binding = 5) uniform restrict writeonly image2DArray primary_dynamic;
#endif
-#ifdef MODE_DILATE
+#if defined(MODE_DILATE) || defined(MODE_DENOISE)
layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2DArray dest_light;
layout(set = 1, binding = 1) uniform texture2DArray source_light;
#endif
+#ifdef MODE_DENOISE
+layout(set = 1, binding = 2) uniform texture2DArray source_normal;
+layout(set = 1, binding = 3) uniform DenoiseParams {
+ float spatial_bandwidth;
+ float light_bandwidth;
+ float albedo_bandwidth;
+ float normal_bandwidth;
+
+ float filter_strength;
+}
+denoise_params;
+#endif
+
layout(push_constant, std430) uniform Params {
ivec2 atlas_size; // x used for light probe mode total probes
uint ray_count;
@@ -735,4 +749,153 @@ void main() {
imageStore(dest_light, ivec3(atlas_pos, params.atlas_slice), c);
#endif
+
+#ifdef MODE_DENOISE
+ // Joint Non-local means (JNLM) denoiser.
+ //
+ // Based on YoctoImageDenoiser's JNLM implementation with corrections from "Nonlinearly Weighted First-order Regression for Denoising Monte Carlo Renderings".
+ //
+ // <https://github.com/ManuelPrandini/YoctoImageDenoiser/blob/06e19489dd64e47792acffde536393802ba48607/libs/yocto_extension/yocto_extension.cpp#L207>
+ // <https://benedikt-bitterli.me/nfor/nfor.pdf>
+ //
+ // MIT License
+ //
+ // Copyright (c) 2020 ManuelPrandini
+ //
+ // 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.
+ //
+ // Most of the constants below have been hand-picked to fit the common scenarios lightmaps
+ // are generated with, but they can be altered freely to experiment and achieve better results.
+
+ // Half the size of the patch window around each pixel that is weighted to compute the denoised pixel.
+ // A value of 1 represents a 3x3 window, a value of 2 a 5x5 window, etc.
+ const int HALF_PATCH_WINDOW = 4;
+
+ // Half the size of the search window around each pixel that is denoised and weighted to compute the denoised pixel.
+ const int HALF_SEARCH_WINDOW = 10;
+
+ // For all of the following sigma values, smaller values will give less weight to pixels that have a bigger distance
+ // in the feature being evaluated. Therefore, smaller values are likely to cause more noise to appear, but will also
+ // cause less features to be erased in the process.
+
+ // Controls how much the spatial distance of the pixels influences the denoising weight.
+ const float SIGMA_SPATIAL = denoise_params.spatial_bandwidth;
+
+ // Controls how much the light color distance of the pixels influences the denoising weight.
+ const float SIGMA_LIGHT = denoise_params.light_bandwidth;
+
+ // Controls how much the albedo color distance of the pixels influences the denoising weight.
+ const float SIGMA_ALBEDO = denoise_params.albedo_bandwidth;
+
+ // Controls how much the normal vector distance of the pixels influences the denoising weight.
+ const float SIGMA_NORMAL = denoise_params.normal_bandwidth;
+
+ // Strength of the filter. The original paper recommends values around 10 to 15 times the Sigma parameter.
+ const float FILTER_VALUE = denoise_params.filter_strength * SIGMA_LIGHT;
+
+ // Formula constants.
+ const int PATCH_WINDOW_DIMENSION = (HALF_PATCH_WINDOW * 2 + 1);
+ const int PATCH_WINDOW_DIMENSION_SQUARE = (PATCH_WINDOW_DIMENSION * PATCH_WINDOW_DIMENSION);
+ const float TWO_SIGMA_SPATIAL_SQUARE = 2.0f * SIGMA_SPATIAL * SIGMA_SPATIAL;
+ const float TWO_SIGMA_LIGHT_SQUARE = 2.0f * SIGMA_LIGHT * SIGMA_LIGHT;
+ const float TWO_SIGMA_ALBEDO_SQUARE = 2.0f * SIGMA_ALBEDO * SIGMA_ALBEDO;
+ const float TWO_SIGMA_NORMAL_SQUARE = 2.0f * SIGMA_NORMAL * SIGMA_NORMAL;
+ const float FILTER_SQUARE_TWO_SIGMA_LIGHT_SQUARE = FILTER_VALUE * FILTER_VALUE * TWO_SIGMA_LIGHT_SQUARE;
+ const float EPSILON = 1e-6f;
+
+#ifdef USE_SH_LIGHTMAPS
+ const uint slice_count = 4;
+ const uint slice_base = params.atlas_slice * slice_count;
+#else
+ const uint slice_count = 1;
+ const uint slice_base = params.atlas_slice;
+#endif
+
+ for (uint i = 0; i < slice_count; i++) {
+ uint lightmap_slice = slice_base + i;
+ vec3 denoised_rgb = vec3(0.0f);
+ vec4 input_light = texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(atlas_pos, lightmap_slice), 0);
+ vec3 input_albedo = texelFetch(sampler2DArray(albedo_tex, linear_sampler), ivec3(atlas_pos, params.atlas_slice), 0).rgb;
+ vec3 input_normal = texelFetch(sampler2DArray(source_normal, linear_sampler), ivec3(atlas_pos, params.atlas_slice), 0).xyz;
+ if (length(input_normal) > EPSILON) {
+ // Compute the denoised pixel if the normal is valid.
+ float sum_weights = 0.0f;
+ vec3 input_rgb = input_light.rgb;
+ for (int search_y = -HALF_SEARCH_WINDOW; search_y <= HALF_SEARCH_WINDOW; search_y++) {
+ for (int search_x = -HALF_SEARCH_WINDOW; search_x <= HALF_SEARCH_WINDOW; search_x++) {
+ ivec2 search_pos = atlas_pos + ivec2(search_x, search_y);
+ vec3 search_rgb = texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(search_pos, lightmap_slice), 0).rgb;
+ vec3 search_albedo = texelFetch(sampler2DArray(albedo_tex, linear_sampler), ivec3(search_pos, params.atlas_slice), 0).rgb;
+ vec3 search_normal = texelFetch(sampler2DArray(source_normal, linear_sampler), ivec3(search_pos, params.atlas_slice), 0).xyz;
+ float patch_square_dist = 0.0f;
+ for (int offset_y = -HALF_PATCH_WINDOW; offset_y <= HALF_PATCH_WINDOW; offset_y++) {
+ for (int offset_x = -HALF_PATCH_WINDOW; offset_x <= HALF_PATCH_WINDOW; offset_x++) {
+ ivec2 offset_input_pos = atlas_pos + ivec2(offset_x, offset_y);
+ ivec2 offset_search_pos = search_pos + ivec2(offset_x, offset_y);
+ vec3 offset_input_rgb = texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(offset_input_pos, lightmap_slice), 0).rgb;
+ vec3 offset_search_rgb = texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(offset_search_pos, lightmap_slice), 0).rgb;
+ vec3 offset_delta_rgb = offset_input_rgb - offset_search_rgb;
+ patch_square_dist += dot(offset_delta_rgb, offset_delta_rgb) - TWO_SIGMA_LIGHT_SQUARE;
+ }
+ }
+
+ patch_square_dist = max(0.0f, patch_square_dist / (3.0f * PATCH_WINDOW_DIMENSION_SQUARE));
+
+ float weight = 1.0f;
+
+ // Ignore weight if search position is out of bounds.
+ weight *= step(0, search_pos.x) * step(search_pos.x, params.atlas_size.x - 1);
+ weight *= step(0, search_pos.y) * step(search_pos.y, params.atlas_size.y - 1);
+
+ // Ignore weight if normal is zero length.
+ weight *= step(EPSILON, length(search_normal));
+
+ // Weight with pixel distance.
+ vec2 pixel_delta = vec2(search_x, search_y);
+ float pixel_square_dist = dot(pixel_delta, pixel_delta);
+ weight *= exp(-pixel_square_dist / TWO_SIGMA_SPATIAL_SQUARE);
+
+ // Weight with patch.
+ weight *= exp(-patch_square_dist / FILTER_SQUARE_TWO_SIGMA_LIGHT_SQUARE);
+
+ // Weight with albedo.
+ vec3 albedo_delta = input_albedo - search_albedo;
+ float albedo_square_dist = dot(albedo_delta, albedo_delta);
+ weight *= exp(-albedo_square_dist / TWO_SIGMA_ALBEDO_SQUARE);
+
+ // Weight with normal.
+ vec3 normal_delta = input_normal - search_normal;
+ float normal_square_dist = dot(normal_delta, normal_delta);
+ weight *= exp(-normal_square_dist / TWO_SIGMA_NORMAL_SQUARE);
+
+ denoised_rgb += weight * search_rgb;
+ sum_weights += weight;
+ }
+ }
+
+ denoised_rgb /= sum_weights;
+ } else {
+ // Ignore pixels where the normal is empty, just copy the light color.
+ denoised_rgb = input_light.rgb;
+ }
+
+ imageStore(dest_light, ivec3(atlas_pos, lightmap_slice), vec4(denoised_rgb, input_light.a));
+ }
+#endif
}
diff --git a/modules/lightmapper_rd/register_types.cpp b/modules/lightmapper_rd/register_types.cpp
index 7ec4a40766..984ce88316 100644
--- a/modules/lightmapper_rd/register_types.cpp
+++ b/modules/lightmapper_rd/register_types.cpp
@@ -58,7 +58,6 @@ void initialize_lightmapper_rd_module(ModuleInitializationLevel p_level) {
GLOBAL_DEF("rendering/lightmapping/bake_quality/high_quality_probe_ray_count", 512);
GLOBAL_DEF("rendering/lightmapping/bake_quality/ultra_quality_probe_ray_count", 2048);
GLOBAL_DEF("rendering/lightmapping/bake_performance/max_rays_per_probe_pass", 64);
- GLOBAL_DEF("rendering/lightmapping/primitive_meshes/texel_size", 0.2);
#ifndef _3D_DISABLED
GDREGISTER_CLASS(LightmapperRD);
Lightmapper::create_gpu = create_lightmapper_rd;
diff --git a/modules/minimp3/SCsub b/modules/minimp3/SCsub
index 20e3165f38..09e84f71e9 100644
--- a/modules/minimp3/SCsub
+++ b/modules/minimp3/SCsub
@@ -13,5 +13,8 @@ if not env.msvc:
else:
env_minimp3.Prepend(CPPPATH=[thirdparty_dir])
+if not env["minimp3_extra_formats"]:
+ env_minimp3.Append(CPPDEFINES=["MINIMP3_ONLY_MP3"])
+
# Godot source files
env_minimp3.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp
index 6af86a96dc..4efa4d329e 100644
--- a/modules/minimp3/audio_stream_mp3.cpp
+++ b/modules/minimp3/audio_stream_mp3.cpp
@@ -28,7 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#define MINIMP3_ONLY_MP3
#define MINIMP3_FLOAT_OUTPUT
#define MINIMP3_IMPLEMENTATION
#define MINIMP3_NO_STDIO
diff --git a/modules/minimp3/config.py b/modules/minimp3/config.py
index e6bdcb2a83..115b376fc8 100644
--- a/modules/minimp3/config.py
+++ b/modules/minimp3/config.py
@@ -2,6 +2,14 @@ def can_build(env, platform):
return True
+def get_opts(platform):
+ from SCons.Variables import BoolVariable
+
+ return [
+ BoolVariable("minimp3_extra_formats", "Build minimp3 with MP1/MP2 decoding support", False),
+ ]
+
+
def configure(env):
pass
diff --git a/modules/minimp3/resource_importer_mp3.cpp b/modules/minimp3/resource_importer_mp3.cpp
index 4e56120ec6..d60b979c3f 100644
--- a/modules/minimp3/resource_importer_mp3.cpp
+++ b/modules/minimp3/resource_importer_mp3.cpp
@@ -47,6 +47,10 @@ String ResourceImporterMP3::get_visible_name() const {
}
void ResourceImporterMP3::get_recognized_extensions(List<String> *p_extensions) const {
+#ifndef MINIMP3_ONLY_MP3
+ p_extensions->push_back("mp1");
+ p_extensions->push_back("mp2");
+#endif
p_extensions->push_back("mp3");
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
index 81b2ffef34..09269508b7 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
@@ -134,6 +134,38 @@ namespace Godot
}
/// <summary>
+ /// Returns the difference between the two angles,
+ /// in range of -<see cref="Pi"/>, <see cref="Pi"/>.
+ /// When <paramref name="from"/> and <paramref name="to"/> are opposite,
+ /// returns -<see cref="Pi"/> if <paramref name="from"/> is smaller than <paramref name="to"/>,
+ /// or <see cref="Pi"/> otherwise.
+ /// </summary>
+ /// <param name="from">The start angle.</param>
+ /// <param name="to">The destination angle.</param>
+ /// <returns>The difference between the two angles.</returns>
+ public static float AngleDifference(float from, float to)
+ {
+ float difference = (to - from) % MathF.Tau;
+ return ((2.0f * difference) % MathF.Tau) - difference;
+ }
+
+ /// <summary>
+ /// Returns the difference between the two angles,
+ /// in range of -<see cref="Pi"/>, <see cref="Pi"/>.
+ /// When <paramref name="from"/> and <paramref name="to"/> are opposite,
+ /// returns -<see cref="Pi"/> if <paramref name="from"/> is smaller than <paramref name="to"/>,
+ /// or <see cref="Pi"/> otherwise.
+ /// </summary>
+ /// <param name="from">The start angle.</param>
+ /// <param name="to">The destination angle.</param>
+ /// <returns>The difference between the two angles.</returns>
+ public static double AngleDifference(double from, double to)
+ {
+ double difference = (to - from) % Math.Tau;
+ return ((2.0 * difference) % Math.Tau) - difference;
+ }
+
+ /// <summary>
/// Returns the arc sine of <paramref name="s"/> in radians.
/// Use to get the angle of sine <paramref name="s"/>.
/// </summary>
@@ -1093,9 +1125,7 @@ namespace Godot
/// <returns>The resulting angle of the interpolation.</returns>
public static float LerpAngle(float from, float to, float weight)
{
- float difference = (to - from) % MathF.Tau;
- float distance = ((2 * difference) % MathF.Tau) - difference;
- return from + (distance * weight);
+ return from + AngleDifference(from, to) * weight;
}
/// <summary>
@@ -1110,9 +1140,7 @@ namespace Godot
/// <returns>The resulting angle of the interpolation.</returns>
public static double LerpAngle(double from, double to, double weight)
{
- double difference = (to - from) % Math.Tau;
- double distance = ((2 * difference) % Math.Tau) - difference;
- return from + (distance * weight);
+ return from + AngleDifference(from, to) * weight;
}
/// <summary>
@@ -1429,6 +1457,38 @@ namespace Godot
}
/// <summary>
+ /// Rotates <paramref name="from"/> toward <paramref name="to"/> by the <paramref name="delta"/> amount. Will not go past <paramref name="to"/>.
+ /// Similar to <see cref="MoveToward(float, float, float)"/> but interpolates correctly when the angles wrap around <see cref="Tau"/>.
+ /// If <paramref name="delta"/> is negative, this function will rotate away from <paramref name="to"/>, toward the opposite angle, and will not go past the opposite angle.
+ /// </summary>
+ /// <param name="from">The start angle.</param>
+ /// <param name="to">The angle to move towards.</param>
+ /// <param name="delta">The amount to move by.</param>
+ /// <returns>The angle after moving.</returns>
+ public static float RotateToward(float from, float to, float delta)
+ {
+ float difference = AngleDifference(from, to);
+ float absDifference = Math.Abs(difference);
+ return from + Math.Clamp(delta, absDifference - MathF.PI, absDifference) * (difference >= 0.0f ? 1.0f : -1.0f);
+ }
+
+ /// <summary>
+ /// Rotates <paramref name="from"/> toward <paramref name="to"/> by the <paramref name="delta"/> amount. Will not go past <paramref name="to"/>.
+ /// Similar to <see cref="MoveToward(double, double, double)"/> but interpolates correctly when the angles wrap around <see cref="Tau"/>.
+ /// If <paramref name="delta"/> is negative, this function will rotate away from <paramref name="to"/>, toward the opposite angle, and will not go past the opposite angle.
+ /// </summary>
+ /// <param name="from">The start angle.</param>
+ /// <param name="to">The angle to move towards.</param>
+ /// <param name="delta">The amount to move by.</param>
+ /// <returns>The angle after moving.</returns>
+ public static double RotateToward(double from, double to, double delta)
+ {
+ double difference = AngleDifference(from, to);
+ double absDifference = Math.Abs(difference);
+ return from + Math.Clamp(delta, absDifference - Math.PI, absDifference) * (difference >= 0.0 ? 1.0 : -1.0);
+ }
+
+ /// <summary>
/// Rounds <paramref name="s"/> to the nearest whole number,
/// with halfway cases rounded towards the nearest multiple of two.
/// </summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs
index a656c5de90..dc53e48bd0 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs
@@ -206,7 +206,7 @@ namespace Godot.NativeInterop
}
case godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_TOO_MANY_ARGUMENTS:
case godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_TOO_FEW_ARGUMENTS:
- return $"Invalid call to {where}. Expected {error.Argument} arguments.";
+ return $"Invalid call to {where}. Expected {error.Expected} arguments.";
case godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD:
return $"Invalid call. Nonexistent {where}.";
case godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL:
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
index 0b203c5148..d26d4662a0 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -265,7 +265,7 @@ namespace Godot
return new Vector3(
Mathf.BezierDerivative(X, control1.X, control2.X, end.X, t),
Mathf.BezierDerivative(Y, control1.Y, control2.Y, end.Y, t),
- Mathf.BezierDerivative(Z, control1.Z, control2.Z, end.Y, t)
+ Mathf.BezierDerivative(Z, control1.Z, control2.Z, end.Z, t)
);
}
diff --git a/modules/raycast/raycast_occlusion_cull.cpp b/modules/raycast/raycast_occlusion_cull.cpp
index 234c2d161f..5005000eae 100644
--- a/modules/raycast/raycast_occlusion_cull.cpp
+++ b/modules/raycast/raycast_occlusion_cull.cpp
@@ -250,17 +250,15 @@ void RaycastOcclusionCull::free_occluder(RID p_occluder) {
////////////////////////////////////////////////////////
void RaycastOcclusionCull::add_scenario(RID p_scenario) {
- if (scenarios.has(p_scenario)) {
- scenarios[p_scenario].removed = false;
- } else {
- scenarios[p_scenario] = Scenario();
- }
+ ERR_FAIL_COND(scenarios.has(p_scenario));
+ scenarios[p_scenario] = Scenario();
}
void RaycastOcclusionCull::remove_scenario(RID p_scenario) {
- ERR_FAIL_COND(!scenarios.has(p_scenario));
- Scenario &scenario = scenarios[p_scenario];
- scenario.removed = true;
+ Scenario *scenario = scenarios.getptr(p_scenario);
+ ERR_FAIL_NULL(scenario);
+ scenario->free();
+ scenarios.erase(p_scenario);
}
void RaycastOcclusionCull::scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform3D &p_xform, bool p_enabled) {
@@ -390,6 +388,23 @@ void RaycastOcclusionCull::Scenario::_transform_vertices_range(const Vector3 *p_
}
}
+void RaycastOcclusionCull::Scenario::free() {
+ if (commit_thread) {
+ if (commit_thread->is_started()) {
+ commit_thread->wait_to_finish();
+ }
+ memdelete(commit_thread);
+ commit_thread = nullptr;
+ }
+
+ for (int i = 0; i < 2; i++) {
+ if (ebr_scene[i]) {
+ rtcReleaseScene(ebr_scene[i]);
+ ebr_scene[i] = nullptr;
+ }
+ }
+}
+
void RaycastOcclusionCull::Scenario::_commit_scene(void *p_ud) {
Scenario *scenario = (Scenario *)p_ud;
int commit_idx = 1 - (scenario->current_scene_idx);
@@ -397,8 +412,8 @@ void RaycastOcclusionCull::Scenario::_commit_scene(void *p_ud) {
scenario->commit_done = true;
}
-bool RaycastOcclusionCull::Scenario::update() {
- ERR_FAIL_NULL_V(singleton, false);
+void RaycastOcclusionCull::Scenario::update() {
+ ERR_FAIL_NULL(singleton);
if (commit_thread == nullptr) {
commit_thread = memnew(Thread);
@@ -409,22 +424,12 @@ bool RaycastOcclusionCull::Scenario::update() {
commit_thread->wait_to_finish();
current_scene_idx = 1 - current_scene_idx;
} else {
- return false;
+ return;
}
}
- if (removed) {
- if (ebr_scene[0]) {
- rtcReleaseScene(ebr_scene[0]);
- }
- if (ebr_scene[1]) {
- rtcReleaseScene(ebr_scene[1]);
- }
- return true;
- }
-
if (!dirty && removed_instances.is_empty() && dirty_instances_array.is_empty()) {
- return false;
+ return;
}
for (const RID &scenario : removed_instances) {
@@ -480,7 +485,6 @@ bool RaycastOcclusionCull::Scenario::update() {
dirty = false;
commit_done = false;
commit_thread->start(&Scenario::_commit_scene, this);
- return false;
}
void RaycastOcclusionCull::Scenario::_raycast(uint32_t p_idx, const RaycastThreadData *p_raycast_data) const {
@@ -544,13 +548,7 @@ void RaycastOcclusionCull::buffer_update(RID p_buffer, const Transform3D &p_cam_
}
Scenario &scenario = scenarios[buffer.scenario_rid];
-
- bool removed = scenario.update();
-
- if (removed) {
- scenarios.erase(buffer.scenario_rid);
- return;
- }
+ scenario.update();
buffer.update_camera_rays(p_cam_transform, p_cam_projection, p_cam_orthogonal);
@@ -603,19 +601,7 @@ RaycastOcclusionCull::RaycastOcclusionCull() {
RaycastOcclusionCull::~RaycastOcclusionCull() {
for (KeyValue<RID, Scenario> &K : scenarios) {
- Scenario &scenario = K.value;
- if (scenario.commit_thread) {
- if (scenario.commit_thread->is_started()) {
- scenario.commit_thread->wait_to_finish();
- }
- memdelete(scenario.commit_thread);
- }
-
- for (int i = 0; i < 2; i++) {
- if (scenario.ebr_scene[i]) {
- rtcReleaseScene(scenario.ebr_scene[i]);
- }
- }
+ K.value.free();
}
if (ebr_device != nullptr) {
diff --git a/modules/raycast/raycast_occlusion_cull.h b/modules/raycast/raycast_occlusion_cull.h
index c4e733b664..ab5eb4eaf0 100644
--- a/modules/raycast/raycast_occlusion_cull.h
+++ b/modules/raycast/raycast_occlusion_cull.h
@@ -132,7 +132,6 @@ private:
Thread *commit_thread = nullptr;
bool commit_done = true;
bool dirty = false;
- bool removed = false;
RTCScene ebr_scene[2] = { nullptr, nullptr };
int current_scene_idx = 0;
@@ -147,7 +146,8 @@ private:
void _transform_vertices_thread(uint32_t p_thread, TransformThreadData *p_data);
void _transform_vertices_range(const Vector3 *p_read, Vector3 *p_write, const Transform3D &p_xform, int p_from, int p_to);
static void _commit_scene(void *p_ud);
- bool update();
+ void free();
+ void update();
void _raycast(uint32_t p_thread, const RaycastThreadData *p_raycast_data) const;
void raycast(CameraRayTile *r_rays, const uint32_t *p_valid_masks, uint32_t p_tile_count) const;
diff --git a/modules/svg/SCsub b/modules/svg/SCsub
index 55b8c4f4a0..a99bc8df60 100644
--- a/modules/svg/SCsub
+++ b/modules/svg/SCsub
@@ -11,39 +11,45 @@ thirdparty_obj = []
thirdparty_dir = "#thirdparty/thorvg/"
thirdparty_sources = [
- "src/lib/sw_engine/tvgSwFill.cpp",
- "src/lib/sw_engine/tvgSwImage.cpp",
- "src/lib/sw_engine/tvgSwMath.cpp",
- "src/lib/sw_engine/tvgSwMemPool.cpp",
- "src/lib/sw_engine/tvgSwRaster.cpp",
- "src/lib/sw_engine/tvgSwRenderer.cpp",
- "src/lib/sw_engine/tvgSwRle.cpp",
- "src/lib/sw_engine/tvgSwShape.cpp",
- "src/lib/sw_engine/tvgSwStroke.cpp",
- "src/lib/tvgAccessor.cpp",
- "src/lib/tvgCanvas.cpp",
- "src/lib/tvgFill.cpp",
- "src/lib/tvgGlCanvas.cpp",
- "src/lib/tvgInitializer.cpp",
- "src/lib/tvgLoader.cpp",
- "src/lib/tvgPaint.cpp",
- "src/lib/tvgPicture.cpp",
- "src/lib/tvgRender.cpp",
- "src/lib/tvgSaver.cpp",
- "src/lib/tvgScene.cpp",
- "src/lib/tvgShape.cpp",
- "src/lib/tvgSwCanvas.cpp",
- "src/lib/tvgTaskScheduler.cpp",
- "src/utils/tvgBezier.cpp",
- "src/utils/tvgCompressor.cpp",
- "src/utils/tvgStr.cpp",
- "src/loaders/raw/tvgRawLoader.cpp",
+ # common
+ "src/common/tvgBezier.cpp",
+ "src/common/tvgCompressor.cpp",
+ "src/common/tvgMath.cpp",
+ "src/common/tvgStr.cpp",
+ # SVG parser
"src/loaders/svg/tvgSvgCssStyle.cpp",
"src/loaders/svg/tvgSvgLoader.cpp",
"src/loaders/svg/tvgSvgPath.cpp",
"src/loaders/svg/tvgSvgSceneBuilder.cpp",
"src/loaders/svg/tvgSvgUtil.cpp",
"src/loaders/svg/tvgXmlParser.cpp",
+ "src/loaders/raw/tvgRawLoader.cpp",
+ # renderer common
+ "src/renderer/tvgAccessor.cpp",
+ # "src/renderer/tvgAnimation.cpp",
+ "src/renderer/tvgCanvas.cpp",
+ "src/renderer/tvgFill.cpp",
+ # "src/renderer/tvgGlCanvas.cpp",
+ "src/renderer/tvgInitializer.cpp",
+ "src/renderer/tvgLoader.cpp",
+ "src/renderer/tvgPaint.cpp",
+ "src/renderer/tvgPicture.cpp",
+ "src/renderer/tvgRender.cpp",
+ # "src/renderer/tvgSaver.cpp",
+ "src/renderer/tvgScene.cpp",
+ "src/renderer/tvgShape.cpp",
+ "src/renderer/tvgSwCanvas.cpp",
+ "src/renderer/tvgTaskScheduler.cpp",
+ # renderer sw_engine
+ "src/renderer/sw_engine/tvgSwFill.cpp",
+ "src/renderer/sw_engine/tvgSwImage.cpp",
+ "src/renderer/sw_engine/tvgSwMath.cpp",
+ "src/renderer/sw_engine/tvgSwMemPool.cpp",
+ "src/renderer/sw_engine/tvgSwRaster.cpp",
+ "src/renderer/sw_engine/tvgSwRenderer.cpp",
+ "src/renderer/sw_engine/tvgSwRle.cpp",
+ "src/renderer/sw_engine/tvgSwShape.cpp",
+ "src/renderer/sw_engine/tvgSwStroke.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
@@ -57,16 +63,13 @@ env_thirdparty = env_svg.Clone()
env_thirdparty.disable_warnings()
env_thirdparty.Prepend(
CPPPATH=[
- thirdparty_dir + "src/lib",
- thirdparty_dir + "src/lib/sw_engine",
- thirdparty_dir + "src/loaders/raw",
+ thirdparty_dir + "src/common",
thirdparty_dir + "src/loaders/svg",
- thirdparty_dir + "src/utils",
+ thirdparty_dir + "src/renderer",
+ thirdparty_dir + "src/renderer/sw_engine",
+ thirdparty_dir + "src/loaders/raw",
]
)
-# Also requires libpng headers
-if env["builtin_libpng"]:
- env_thirdparty.Prepend(CPPPATH=["#thirdparty/libpng"])
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
env.modules_sources += thirdparty_obj
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index 1acff68135..3c468e61d7 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -40,7 +40,11 @@ msdfgen_enabled = "msdfgen" in env.module_list
if "svg" in env.module_list:
env_text_server_adv.Prepend(
- CPPPATH=["#thirdparty/thorvg/inc", "#thirdparty/thorvg/src/lib", "#thirdparty/thorvg/src/utils"]
+ CPPPATH=[
+ "#thirdparty/thorvg/inc",
+ "#thirdparty/thorvg/src/common",
+ "#thirdparty/thorvg/src/renderer",
+ ]
)
# Enable ThorVG static object linking.
env_text_server_adv.Append(CPPDEFINES=["TVG_STATIC"])
diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct
index bf29ad3016..b95c35f80d 100644
--- a/modules/text_server_adv/gdextension_build/SConstruct
+++ b/modules/text_server_adv/gdextension_build/SConstruct
@@ -42,51 +42,56 @@ if env["thorvg_enabled"] and env["freetype_enabled"]:
thirdparty_tvg_dir = "../../../thirdparty/thorvg/"
thirdparty_tvg_sources = [
- "src/lib/sw_engine/tvgSwFill.cpp",
- "src/lib/sw_engine/tvgSwImage.cpp",
- "src/lib/sw_engine/tvgSwMath.cpp",
- "src/lib/sw_engine/tvgSwMemPool.cpp",
- "src/lib/sw_engine/tvgSwRaster.cpp",
- "src/lib/sw_engine/tvgSwRenderer.cpp",
- "src/lib/sw_engine/tvgSwRle.cpp",
- "src/lib/sw_engine/tvgSwShape.cpp",
- "src/lib/sw_engine/tvgSwStroke.cpp",
- "src/lib/tvgAccessor.cpp",
- "src/lib/tvgCanvas.cpp",
- "src/lib/tvgFill.cpp",
- "src/lib/tvgGlCanvas.cpp",
- "src/lib/tvgInitializer.cpp",
- "src/lib/tvgLoader.cpp",
- "src/lib/tvgPaint.cpp",
- "src/lib/tvgPicture.cpp",
- "src/lib/tvgRender.cpp",
- "src/lib/tvgSaver.cpp",
- "src/lib/tvgScene.cpp",
- "src/lib/tvgShape.cpp",
- "src/lib/tvgSwCanvas.cpp",
- "src/lib/tvgTaskScheduler.cpp",
- "src/utils/tvgBezier.cpp",
- "src/utils/tvgCompressor.cpp",
- "src/utils/tvgStr.cpp",
- "src/loaders/raw/tvgRawLoader.cpp",
+ # common
+ "src/common/tvgBezier.cpp",
+ "src/common/tvgCompressor.cpp",
+ "src/common/tvgMath.cpp",
+ "src/common/tvgStr.cpp",
+ # SVG parser
"src/loaders/svg/tvgSvgCssStyle.cpp",
"src/loaders/svg/tvgSvgLoader.cpp",
"src/loaders/svg/tvgSvgPath.cpp",
"src/loaders/svg/tvgSvgSceneBuilder.cpp",
"src/loaders/svg/tvgSvgUtil.cpp",
"src/loaders/svg/tvgXmlParser.cpp",
+ "src/loaders/raw/tvgRawLoader.cpp",
+ # renderer common
+ "src/renderer/tvgAccessor.cpp",
+ # "src/renderer/tvgAnimation.cpp",
+ "src/renderer/tvgCanvas.cpp",
+ "src/renderer/tvgFill.cpp",
+ # "src/renderer/tvgGlCanvas.cpp",
+ "src/renderer/tvgInitializer.cpp",
+ "src/renderer/tvgLoader.cpp",
+ "src/renderer/tvgPaint.cpp",
+ "src/renderer/tvgPicture.cpp",
+ "src/renderer/tvgRender.cpp",
+ # "src/renderer/tvgSaver.cpp",
+ "src/renderer/tvgScene.cpp",
+ "src/renderer/tvgShape.cpp",
+ "src/renderer/tvgSwCanvas.cpp",
+ "src/renderer/tvgTaskScheduler.cpp",
+ # renderer sw_engine
+ "src/renderer/sw_engine/tvgSwFill.cpp",
+ "src/renderer/sw_engine/tvgSwImage.cpp",
+ "src/renderer/sw_engine/tvgSwMath.cpp",
+ "src/renderer/sw_engine/tvgSwMemPool.cpp",
+ "src/renderer/sw_engine/tvgSwRaster.cpp",
+ "src/renderer/sw_engine/tvgSwRenderer.cpp",
+ "src/renderer/sw_engine/tvgSwRle.cpp",
+ "src/renderer/sw_engine/tvgSwShape.cpp",
+ "src/renderer/sw_engine/tvgSwStroke.cpp",
]
thirdparty_tvg_sources = [thirdparty_tvg_dir + file for file in thirdparty_tvg_sources]
env_tvg.Append(
CPPPATH=[
"../../../thirdparty/thorvg/inc",
- "../../../thirdparty/thorvg/src/lib",
- "../../../thirdparty/thorvg/src/lib/sw_engine",
- "../../../thirdparty/thorvg/src/loaders/raw",
+ "../../../thirdparty/thorvg/src/common",
"../../../thirdparty/thorvg/src/loaders/svg",
- "../../../thirdparty/thorvg/src/utils",
- "../../../thirdparty/libpng",
+ "../../../thirdparty/thorvg/src/loaders/raw",
+ "../../../thirdparty/thorvg/src/renderer",
+ "../../../thirdparty/thorvg/src/renderer/sw_engine",
]
)
@@ -96,8 +101,8 @@ if env["thorvg_enabled"] and env["freetype_enabled"]:
env.Append(
CPPPATH=[
"../../../thirdparty/thorvg/inc",
- "../../../thirdparty/thorvg/src/lib",
- "../../../thirdparty/thorvg/src/utils",
+ "../../../thirdparty/thorvg/src/common",
+ "../../../thirdparty/thorvg/src/renderer",
]
)
env.Append(CPPDEFINES=["MODULE_SVG_ENABLED"])
diff --git a/modules/text_server_fb/SCsub b/modules/text_server_fb/SCsub
index 8705bc430d..e808864512 100644
--- a/modules/text_server_fb/SCsub
+++ b/modules/text_server_fb/SCsub
@@ -10,7 +10,7 @@ env_text_server_fb = env_modules.Clone()
if "svg" in env.module_list:
env_text_server_fb.Prepend(
- CPPPATH=["#thirdparty/thorvg/inc", "#thirdparty/thorvg/src/lib", "#thirdparty/thorvg/src/utils"]
+ CPPPATH=["#thirdparty/thorvg/inc", "#thirdparty/thorvg/src/common", "#thirdparty/thorvg/src/renderer"]
)
# Enable ThorVG static object linking.
env_text_server_fb.Append(CPPDEFINES=["TVG_STATIC"])
diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct
index 40bb2dc1b9..846ac02cf1 100644
--- a/modules/text_server_fb/gdextension_build/SConstruct
+++ b/modules/text_server_fb/gdextension_build/SConstruct
@@ -37,51 +37,56 @@ if env["thorvg_enabled"] and env["freetype_enabled"]:
thirdparty_tvg_dir = "../../../thirdparty/thorvg/"
thirdparty_tvg_sources = [
- "src/lib/sw_engine/tvgSwFill.cpp",
- "src/lib/sw_engine/tvgSwImage.cpp",
- "src/lib/sw_engine/tvgSwMath.cpp",
- "src/lib/sw_engine/tvgSwMemPool.cpp",
- "src/lib/sw_engine/tvgSwRaster.cpp",
- "src/lib/sw_engine/tvgSwRenderer.cpp",
- "src/lib/sw_engine/tvgSwRle.cpp",
- "src/lib/sw_engine/tvgSwShape.cpp",
- "src/lib/sw_engine/tvgSwStroke.cpp",
- "src/lib/tvgAccessor.cpp",
- "src/lib/tvgCanvas.cpp",
- "src/lib/tvgFill.cpp",
- "src/lib/tvgGlCanvas.cpp",
- "src/lib/tvgInitializer.cpp",
- "src/lib/tvgLoader.cpp",
- "src/lib/tvgPaint.cpp",
- "src/lib/tvgPicture.cpp",
- "src/lib/tvgRender.cpp",
- "src/lib/tvgSaver.cpp",
- "src/lib/tvgScene.cpp",
- "src/lib/tvgShape.cpp",
- "src/lib/tvgSwCanvas.cpp",
- "src/lib/tvgTaskScheduler.cpp",
- "src/utils/tvgBezier.cpp",
- "src/utils/tvgCompressor.cpp",
- "src/utils/tvgStr.cpp",
- "src/loaders/raw/tvgRawLoader.cpp",
+ # common
+ "src/common/tvgBezier.cpp",
+ "src/common/tvgCompressor.cpp",
+ "src/common/tvgMath.cpp",
+ "src/common/tvgStr.cpp",
+ # SVG parser
"src/loaders/svg/tvgSvgCssStyle.cpp",
"src/loaders/svg/tvgSvgLoader.cpp",
"src/loaders/svg/tvgSvgPath.cpp",
"src/loaders/svg/tvgSvgSceneBuilder.cpp",
"src/loaders/svg/tvgSvgUtil.cpp",
"src/loaders/svg/tvgXmlParser.cpp",
+ "src/loaders/raw/tvgRawLoader.cpp",
+ # renderer common
+ "src/renderer/tvgAccessor.cpp",
+ # "src/renderer/tvgAnimation.cpp",
+ "src/renderer/tvgCanvas.cpp",
+ "src/renderer/tvgFill.cpp",
+ # "src/renderer/tvgGlCanvas.cpp",
+ "src/renderer/tvgInitializer.cpp",
+ "src/renderer/tvgLoader.cpp",
+ "src/renderer/tvgPaint.cpp",
+ "src/renderer/tvgPicture.cpp",
+ "src/renderer/tvgRender.cpp",
+ # "src/renderer/tvgSaver.cpp",
+ "src/renderer/tvgScene.cpp",
+ "src/renderer/tvgShape.cpp",
+ "src/renderer/tvgSwCanvas.cpp",
+ "src/renderer/tvgTaskScheduler.cpp",
+ # renderer sw_engine
+ "src/renderer/sw_engine/tvgSwFill.cpp",
+ "src/renderer/sw_engine/tvgSwImage.cpp",
+ "src/renderer/sw_engine/tvgSwMath.cpp",
+ "src/renderer/sw_engine/tvgSwMemPool.cpp",
+ "src/renderer/sw_engine/tvgSwRaster.cpp",
+ "src/renderer/sw_engine/tvgSwRenderer.cpp",
+ "src/renderer/sw_engine/tvgSwRle.cpp",
+ "src/renderer/sw_engine/tvgSwShape.cpp",
+ "src/renderer/sw_engine/tvgSwStroke.cpp",
]
thirdparty_tvg_sources = [thirdparty_tvg_dir + file for file in thirdparty_tvg_sources]
env_tvg.Append(
CPPPATH=[
"../../../thirdparty/thorvg/inc",
- "../../../thirdparty/thorvg/src/lib",
- "../../../thirdparty/thorvg/src/lib/sw_engine",
- "../../../thirdparty/thorvg/src/loaders/raw",
+ "../../../thirdparty/thorvg/src/common",
"../../../thirdparty/thorvg/src/loaders/svg",
- "../../../thirdparty/thorvg/src/utils",
- "../../../thirdparty/libpng",
+ "../../../thirdparty/thorvg/src/loaders/raw",
+ "../../../thirdparty/thorvg/src/renderer",
+ "../../../thirdparty/thorvg/src/renderer/sw_engine",
]
)
@@ -91,8 +96,8 @@ if env["thorvg_enabled"] and env["freetype_enabled"]:
env.Append(
CPPPATH=[
"../../../thirdparty/thorvg/inc",
- "../../../thirdparty/thorvg/src/lib",
- "../../../thirdparty/thorvg/src/utils",
+ "../../../thirdparty/thorvg/src/common",
+ "../../../thirdparty/thorvg/src/renderer",
]
)
env.Append(CPPDEFINES=["MODULE_SVG_ENABLED"])