diff options
77 files changed, 1464 insertions, 1126 deletions
diff --git a/.github/workflows/first_interaction.yml b/.github/workflows/first_interaction.yml deleted file mode 100644 index ed0f5c860f..0000000000 --- a/.github/workflows/first_interaction.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: 🔗 GHA - -on: - issues: - types: [opened] - pull_request: - branches: [master] - types: [opened] - -jobs: - check_for_first_issue: - name: 🌱 Check for first interaction - runs-on: ubuntu-latest - steps: - - uses: actions/first-interaction@v1 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - issue-message: | - Hello from the maintainer team! - - First of all, thank you for taking the time to report an issue here. - - In case you haven't already, be sure to attach an MRP (minimal reproduction project) if **specific** steps or assets are needed in order to reproduce the issue. Contributors will use the MRP to validate that the fix is working as intended. - - The time it will take to assess and fix your issue may vary. Follow the blog about our [new releases](https://godotengine.org/blog/release/) and [pre-releases](https://godotengine.org/blog/pre-release/) to track new fixes or go to [our forum](https://forum.godotengine.org/) where users could help you in the meantime. - - Thank you for your patience. - pr-message: | - Hi there, fellow Godot contributor! - - Thank you for your first PR. - - Be sure to join us in the [developers chat](https://chat.godotengine.org) to talk about your PR, especially if you need help or guidance. Don't forget to consult the [contributing docs](https://docs.godotengine.org/en/stable/contributing/development/index.html) too! - - Thank you for your patience. diff --git a/.gitignore b/.gitignore index 46dcf84b43..3946cc96e5 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ platform/windows/godot_res.res # Ninja build files build.ninja .ninja +run_ninja_env.bat # Generated by Godot binary .import/ diff --git a/SConstruct b/SConstruct index 73ef420a0d..2cce05a20b 100644 --- a/SConstruct +++ b/SConstruct @@ -303,11 +303,6 @@ else: selected_platform = "macos" elif sys.platform == "win32": selected_platform = "windows" - else: - print("Could not detect platform automatically. Supported platforms:") - for x in platform_list: - print("\t" + x) - print("\nPlease run SCons again and select a valid platform: platform=<string>") if selected_platform != "": print("Automatically detected platform: " + selected_platform) @@ -334,6 +329,16 @@ if selected_platform == "javascript": print('Platform "javascript" has been renamed to "web" in Godot 4. Building for platform "web".') selected_platform = "web" +if selected_platform not in platform_list: + if selected_platform == "": + print("Could not detect platform automatically.") + elif selected_platform != "list": + print(f'Invalid target platform "{selected_platform}".') + + print("The following platforms are available:\n\t{}\n".format("\n\t".join(platform_list))) + print("Please run SCons again and select a valid platform: platform=<string>.") + Exit(0 if selected_platform == "list" else 255) + # Make sure to update this to the found, valid platform as it's used through the buildsystem as the reference. # It should always be re-set after calling `opts.Update()` otherwise it uses the original input value. env_base["platform"] = selected_platform @@ -480,571 +485,551 @@ if not env_base["deprecated"]: if env_base["precision"] == "double": env_base.Append(CPPDEFINES=["REAL_T_IS_DOUBLE"]) -if selected_platform in platform_list: - tmppath = "./platform/" + selected_platform - sys.path.insert(0, tmppath) - import detect - - env = env_base.Clone() - - # Default num_jobs to local cpu count if not user specified. - # SCons has a peculiarity where user-specified options won't be overridden - # by SetOption, so we can rely on this to know if we should use our default. - initial_num_jobs = env.GetOption("num_jobs") - altered_num_jobs = initial_num_jobs + 1 - env.SetOption("num_jobs", altered_num_jobs) - if env.GetOption("num_jobs") == altered_num_jobs: - cpu_count = os.cpu_count() - if cpu_count is None: - print("Couldn't auto-detect CPU count to configure build parallelism. Specify it with the -j argument.") - else: - safer_cpu_count = cpu_count if cpu_count <= 4 else cpu_count - 1 - print( - "Auto-detected %d CPU cores available for build parallelism. Using %d cores by default. You can override it with the -j argument." - % (cpu_count, safer_cpu_count) - ) - env.SetOption("num_jobs", safer_cpu_count) - - env.extra_suffix = "" - - if env["extra_suffix"] != "": - env.extra_suffix += "." + env["extra_suffix"] - - # Environment flags - env.Append(CPPDEFINES=env.get("cppdefines", "").split()) - env.Append(CCFLAGS=env.get("ccflags", "").split()) - env.Append(CXXFLAGS=env.get("cxxflags", "").split()) - env.Append(CFLAGS=env.get("cflags", "").split()) - env.Append(LINKFLAGS=env.get("linkflags", "").split()) - - # Feature build profile - disabled_classes = [] - if env["build_profile"] != "": - print("Using feature build profile: " + env["build_profile"]) - import json +tmppath = "./platform/" + selected_platform +sys.path.insert(0, tmppath) +import detect + +env = env_base.Clone() + +# Default num_jobs to local cpu count if not user specified. +# SCons has a peculiarity where user-specified options won't be overridden +# by SetOption, so we can rely on this to know if we should use our default. +initial_num_jobs = env.GetOption("num_jobs") +altered_num_jobs = initial_num_jobs + 1 +env.SetOption("num_jobs", altered_num_jobs) +if env.GetOption("num_jobs") == altered_num_jobs: + cpu_count = os.cpu_count() + if cpu_count is None: + print("Couldn't auto-detect CPU count to configure build parallelism. Specify it with the -j argument.") + else: + safer_cpu_count = cpu_count if cpu_count <= 4 else cpu_count - 1 + print( + "Auto-detected %d CPU cores available for build parallelism. Using %d cores by default. You can override it with the -j argument." + % (cpu_count, safer_cpu_count) + ) + env.SetOption("num_jobs", safer_cpu_count) + +env.extra_suffix = "" + +if env["extra_suffix"] != "": + env.extra_suffix += "." + env["extra_suffix"] + +# Environment flags +env.Append(CPPDEFINES=env.get("cppdefines", "").split()) +env.Append(CCFLAGS=env.get("ccflags", "").split()) +env.Append(CXXFLAGS=env.get("cxxflags", "").split()) +env.Append(CFLAGS=env.get("cflags", "").split()) +env.Append(LINKFLAGS=env.get("linkflags", "").split()) + +# Feature build profile +disabled_classes = [] +if env["build_profile"] != "": + print("Using feature build profile: " + env["build_profile"]) + import json - try: - ft = json.load(open(env["build_profile"])) - if "disabled_classes" in ft: - disabled_classes = ft["disabled_classes"] - if "disabled_build_options" in ft: - dbo = ft["disabled_build_options"] - for c in dbo: - env[c] = dbo[c] - except: - print("Error opening feature build profile: " + env["build_profile"]) - Exit(255) - methods.write_disabled_classes(disabled_classes) - - # Platform specific flags. - # These can sometimes override default options. - flag_list = platform_flags[selected_platform] - for f in flag_list: - if not (f[0] in ARGUMENTS) or ARGUMENTS[f[0]] == "auto": # Allow command line to override platform flags - env[f[0]] = f[1] - - # 'dev_mode' and 'production' are aliases to set default options if they haven't been - # set manually by the user. - # These need to be checked *after* platform specific flags so that different - # default values can be set (e.g. to keep LTO off for `production` on some platforms). - if env["dev_mode"]: - env["verbose"] = methods.get_cmdline_bool("verbose", True) - env["warnings"] = ARGUMENTS.get("warnings", "extra") - env["werror"] = methods.get_cmdline_bool("werror", True) - env["tests"] = methods.get_cmdline_bool("tests", True) - if env["production"]: - env["use_static_cpp"] = methods.get_cmdline_bool("use_static_cpp", True) - env["debug_symbols"] = methods.get_cmdline_bool("debug_symbols", False) - # LTO "auto" means we handle the preferred option in each platform detect.py. - env["lto"] = ARGUMENTS.get("lto", "auto") - - # Run SCU file generation script if in a SCU build. - if env["scu_build"]: - max_includes_per_scu = 8 - if env_base.dev_build == True: - max_includes_per_scu = 1024 - - read_scu_limit = int(env["scu_limit"]) - read_scu_limit = max(0, min(read_scu_limit, 1024)) - if read_scu_limit != 0: - max_includes_per_scu = read_scu_limit - - methods.set_scu_folders(scu_builders.generate_scu_files(max_includes_per_scu)) - - # Must happen after the flags' definition, as configure is when most flags - # are actually handled to change compile options, etc. - detect.configure(env) - - print(f'Building for platform "{selected_platform}", architecture "{env["arch"]}", target "{env["target"]}".') - if env.dev_build: - print("NOTE: Developer build, with debug optimization level and debug symbols (unless overridden).") - - # Set optimize and debug_symbols flags. - # "custom" means do nothing and let users set their own optimization flags. - # Needs to happen after configure to have `env.msvc` defined. - if env.msvc: - if env["debug_symbols"]: - env.Append(CCFLAGS=["/Zi", "/FS"]) - env.Append(LINKFLAGS=["/DEBUG:FULL"]) - else: - env.Append(LINKFLAGS=["/DEBUG:NONE"]) - - if env["optimize"] == "speed": - env.Append(CCFLAGS=["/O2"]) - env.Append(LINKFLAGS=["/OPT:REF"]) - elif env["optimize"] == "speed_trace": - env.Append(CCFLAGS=["/O2"]) - env.Append(LINKFLAGS=["/OPT:REF", "/OPT:NOICF"]) - elif env["optimize"] == "size": - env.Append(CCFLAGS=["/O1"]) - env.Append(LINKFLAGS=["/OPT:REF"]) - elif env["optimize"] == "debug" or env["optimize"] == "none": - env.Append(CCFLAGS=["/Od"]) + try: + ft = json.load(open(env["build_profile"])) + if "disabled_classes" in ft: + disabled_classes = ft["disabled_classes"] + if "disabled_build_options" in ft: + dbo = ft["disabled_build_options"] + for c in dbo: + env[c] = dbo[c] + except: + print("Error opening feature build profile: " + env["build_profile"]) + Exit(255) +methods.write_disabled_classes(disabled_classes) + +# Platform specific flags. +# These can sometimes override default options. +flag_list = platform_flags[selected_platform] +for f in flag_list: + if not (f[0] in ARGUMENTS) or ARGUMENTS[f[0]] == "auto": # Allow command line to override platform flags + env[f[0]] = f[1] + +# 'dev_mode' and 'production' are aliases to set default options if they haven't been +# set manually by the user. +# These need to be checked *after* platform specific flags so that different +# default values can be set (e.g. to keep LTO off for `production` on some platforms). +if env["dev_mode"]: + env["verbose"] = methods.get_cmdline_bool("verbose", True) + env["warnings"] = ARGUMENTS.get("warnings", "extra") + env["werror"] = methods.get_cmdline_bool("werror", True) + env["tests"] = methods.get_cmdline_bool("tests", True) +if env["production"]: + env["use_static_cpp"] = methods.get_cmdline_bool("use_static_cpp", True) + env["debug_symbols"] = methods.get_cmdline_bool("debug_symbols", False) + # LTO "auto" means we handle the preferred option in each platform detect.py. + env["lto"] = ARGUMENTS.get("lto", "auto") + +# Run SCU file generation script if in a SCU build. +if env["scu_build"]: + max_includes_per_scu = 8 + if env_base.dev_build == True: + max_includes_per_scu = 1024 + + read_scu_limit = int(env["scu_limit"]) + read_scu_limit = max(0, min(read_scu_limit, 1024)) + if read_scu_limit != 0: + max_includes_per_scu = read_scu_limit + + methods.set_scu_folders(scu_builders.generate_scu_files(max_includes_per_scu)) + +# Must happen after the flags' definition, as configure is when most flags +# are actually handled to change compile options, etc. +detect.configure(env) + +print(f'Building for platform "{selected_platform}", architecture "{env["arch"]}", target "{env["target"]}".') +if env.dev_build: + print("NOTE: Developer build, with debug optimization level and debug symbols (unless overridden).") + +# Set optimize and debug_symbols flags. +# "custom" means do nothing and let users set their own optimization flags. +# Needs to happen after configure to have `env.msvc` defined. +if env.msvc: + if env["debug_symbols"]: + env.Append(CCFLAGS=["/Zi", "/FS"]) + env.Append(LINKFLAGS=["/DEBUG:FULL"]) else: - if env["debug_symbols"]: - # Adding dwarf-4 explicitly makes stacktraces work with clang builds, - # otherwise addr2line doesn't understand them - env.Append(CCFLAGS=["-gdwarf-4"]) - if env.dev_build: - env.Append(CCFLAGS=["-g3"]) - else: - env.Append(CCFLAGS=["-g2"]) + env.Append(LINKFLAGS=["/DEBUG:NONE"]) + + if env["optimize"] == "speed": + env.Append(CCFLAGS=["/O2"]) + env.Append(LINKFLAGS=["/OPT:REF"]) + elif env["optimize"] == "speed_trace": + env.Append(CCFLAGS=["/O2"]) + env.Append(LINKFLAGS=["/OPT:REF", "/OPT:NOICF"]) + elif env["optimize"] == "size": + env.Append(CCFLAGS=["/O1"]) + env.Append(LINKFLAGS=["/OPT:REF"]) + elif env["optimize"] == "debug" or env["optimize"] == "none": + env.Append(CCFLAGS=["/Od"]) +else: + if env["debug_symbols"]: + # Adding dwarf-4 explicitly makes stacktraces work with clang builds, + # otherwise addr2line doesn't understand them + env.Append(CCFLAGS=["-gdwarf-4"]) + if env.dev_build: + env.Append(CCFLAGS=["-g3"]) else: - if methods.using_clang(env) and not methods.is_vanilla_clang(env): - # Apple Clang, its linker doesn't like -s. - env.Append(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"]) - else: - env.Append(LINKFLAGS=["-s"]) - - if env["optimize"] == "speed": - env.Append(CCFLAGS=["-O3"]) - # `-O2` is friendlier to debuggers than `-O3`, leading to better crash backtraces. - elif env["optimize"] == "speed_trace": - env.Append(CCFLAGS=["-O2"]) - elif env["optimize"] == "size": - env.Append(CCFLAGS=["-Os"]) - elif env["optimize"] == "debug": - env.Append(CCFLAGS=["-Og"]) - elif env["optimize"] == "none": - env.Append(CCFLAGS=["-O0"]) - - # Needs to happen after configure to handle "auto". - if env["lto"] != "none": - print("Using LTO: " + env["lto"]) - - # Set our C and C++ standard requirements. - # C++17 is required as we need guaranteed copy elision as per GH-36436. - # Prepending to make it possible to override. - # This needs to come after `configure`, otherwise we don't have env.msvc. - if not env.msvc: - # Specifying GNU extensions support explicitly, which are supported by - # both GCC and Clang. Both currently default to gnu11 and gnu++14. - env.Prepend(CFLAGS=["-std=gnu11"]) - env.Prepend(CXXFLAGS=["-std=gnu++17"]) + env.Append(CCFLAGS=["-g2"]) else: - # MSVC doesn't have clear C standard support, /std only covers C++. - # We apply it to CCFLAGS (both C and C++ code) in case it impacts C features. - env.Prepend(CCFLAGS=["/std:c++17"]) - - # Enforce our minimal compiler version requirements - cc_version = methods.get_compiler_version(env) or { - "major": None, - "minor": None, - "patch": None, - "metadata1": None, - "metadata2": None, - "date": None, - } - cc_version_major = int(cc_version["major"] or -1) - cc_version_minor = int(cc_version["minor"] or -1) - cc_version_metadata1 = cc_version["metadata1"] or "" - - if methods.using_gcc(env): - if cc_version_major == -1: - print( - "Couldn't detect compiler version, skipping version checks. " - "Build may fail if the compiler doesn't support C++17 fully." - ) - # GCC 8 before 8.4 has a regression in the support of guaranteed copy elision - # which causes a build failure: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86521 - elif cc_version_major == 8 and cc_version_minor < 4: - print( - "Detected GCC 8 version < 8.4, which is not supported due to a " - "regression in its C++17 guaranteed copy elision support. Use a " - 'newer GCC version, or Clang 6 or later by passing "use_llvm=yes" ' - "to the SCons command line." - ) - Exit(255) - elif cc_version_major < 7: - print( - "Detected GCC version older than 7, which does not fully support " - "C++17. Supported versions are GCC 7, 9 and later. Use a newer GCC " - 'version, or Clang 6 or later by passing "use_llvm=yes" to the ' - "SCons command line." - ) - Exit(255) - elif cc_version_metadata1 == "win32": + if methods.using_clang(env) and not methods.is_vanilla_clang(env): + # Apple Clang, its linker doesn't like -s. + env.Append(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"]) + else: + env.Append(LINKFLAGS=["-s"]) + + if env["optimize"] == "speed": + env.Append(CCFLAGS=["-O3"]) + # `-O2` is friendlier to debuggers than `-O3`, leading to better crash backtraces. + elif env["optimize"] == "speed_trace": + env.Append(CCFLAGS=["-O2"]) + elif env["optimize"] == "size": + env.Append(CCFLAGS=["-Os"]) + elif env["optimize"] == "debug": + env.Append(CCFLAGS=["-Og"]) + elif env["optimize"] == "none": + env.Append(CCFLAGS=["-O0"]) + +# Needs to happen after configure to handle "auto". +if env["lto"] != "none": + print("Using LTO: " + env["lto"]) + +# Set our C and C++ standard requirements. +# C++17 is required as we need guaranteed copy elision as per GH-36436. +# Prepending to make it possible to override. +# This needs to come after `configure`, otherwise we don't have env.msvc. +if not env.msvc: + # Specifying GNU extensions support explicitly, which are supported by + # both GCC and Clang. Both currently default to gnu11 and gnu++14. + env.Prepend(CFLAGS=["-std=gnu11"]) + env.Prepend(CXXFLAGS=["-std=gnu++17"]) +else: + # MSVC doesn't have clear C standard support, /std only covers C++. + # We apply it to CCFLAGS (both C and C++ code) in case it impacts C features. + env.Prepend(CCFLAGS=["/std:c++17"]) + +# Enforce our minimal compiler version requirements +cc_version = methods.get_compiler_version(env) or { + "major": None, + "minor": None, + "patch": None, + "metadata1": None, + "metadata2": None, + "date": None, +} +cc_version_major = int(cc_version["major"] or -1) +cc_version_minor = int(cc_version["minor"] or -1) +cc_version_metadata1 = cc_version["metadata1"] or "" + +if methods.using_gcc(env): + if cc_version_major == -1: + print( + "Couldn't detect compiler version, skipping version checks. " + "Build may fail if the compiler doesn't support C++17 fully." + ) + # GCC 8 before 8.4 has a regression in the support of guaranteed copy elision + # which causes a build failure: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86521 + elif cc_version_major == 8 and cc_version_minor < 4: + print( + "Detected GCC 8 version < 8.4, which is not supported due to a " + "regression in its C++17 guaranteed copy elision support. Use a " + 'newer GCC version, or Clang 6 or later by passing "use_llvm=yes" ' + "to the SCons command line." + ) + Exit(255) + elif cc_version_major < 7: + print( + "Detected GCC version older than 7, which does not fully support " + "C++17. Supported versions are GCC 7, 9 and later. Use a newer GCC " + 'version, or Clang 6 or later by passing "use_llvm=yes" to the ' + "SCons command line." + ) + Exit(255) + elif cc_version_metadata1 == "win32": + print( + "Detected mingw version is not using posix threads. Only posix " + "version of mingw is supported. " + 'Use "update-alternatives --config x86_64-w64-mingw32-g++" ' + "to switch to posix threads." + ) + Exit(255) +elif methods.using_clang(env): + if cc_version_major == -1: + print( + "Couldn't detect compiler version, skipping version checks. " + "Build may fail if the compiler doesn't support C++17 fully." + ) + # Apple LLVM versions differ from upstream LLVM version \o/, compare + # in https://en.wikipedia.org/wiki/Xcode#Toolchain_versions + elif env["platform"] == "macos" or env["platform"] == "ios": + vanilla = methods.is_vanilla_clang(env) + if vanilla and cc_version_major < 6: print( - "Detected mingw version is not using posix threads. Only posix " - "version of mingw is supported. " - 'Use "update-alternatives --config x86_64-w64-mingw32-g++" ' - "to switch to posix threads." + "Detected Clang version older than 6, which does not fully support " + "C++17. Supported versions are Clang 6 and later." ) Exit(255) - elif methods.using_clang(env): - if cc_version_major == -1: - print( - "Couldn't detect compiler version, skipping version checks. " - "Build may fail if the compiler doesn't support C++17 fully." - ) - # Apple LLVM versions differ from upstream LLVM version \o/, compare - # in https://en.wikipedia.org/wiki/Xcode#Toolchain_versions - elif env["platform"] == "macos" or env["platform"] == "ios": - vanilla = methods.is_vanilla_clang(env) - if vanilla and cc_version_major < 6: - print( - "Detected Clang version older than 6, which does not fully support " - "C++17. Supported versions are Clang 6 and later." - ) - Exit(255) - elif not vanilla and cc_version_major < 10: - print( - "Detected Apple Clang version older than 10, which does not fully " - "support C++17. Supported versions are Apple Clang 10 and later." - ) - Exit(255) - elif cc_version_major < 6: + elif not vanilla and cc_version_major < 10: print( - "Detected Clang version older than 6, which does not fully support " - "C++17. Supported versions are Clang 6 and later." + "Detected Apple Clang version older than 10, which does not fully " + "support C++17. Supported versions are Apple Clang 10 and later." ) Exit(255) + elif cc_version_major < 6: + print( + "Detected Clang version older than 6, which does not fully support " + "C++17. Supported versions are Clang 6 and later." + ) + Exit(255) - # Disable exception handling. Godot doesn't use exceptions anywhere, and this - # saves around 20% of binary size and very significant build time (GH-80513). - if env["disable_exceptions"]: - if env.msvc: - env.Append(CPPDEFINES=[("_HAS_EXCEPTIONS", 0)]) - else: - env.Append(CXXFLAGS=["-fno-exceptions"]) - elif env.msvc: - env.Append(CXXFLAGS=["/EHsc"]) - - # Configure compiler warnings - if env.msvc: # MSVC - if env["warnings"] == "no": - env.Append(CCFLAGS=["/w"]) - else: - if env["warnings"] == "extra": - env.Append(CCFLAGS=["/W4"]) - elif env["warnings"] == "all": - # C4458 is like -Wshadow. Part of /W4 but let's apply it for the default /W3 too. - env.Append(CCFLAGS=["/W3", "/w34458"]) - elif env["warnings"] == "moderate": - env.Append(CCFLAGS=["/W2"]) - # Disable warnings which we don't plan to fix. +# Disable exception handling. Godot doesn't use exceptions anywhere, and this +# saves around 20% of binary size and very significant build time (GH-80513). +if env["disable_exceptions"]: + if env.msvc: + env.Append(CPPDEFINES=[("_HAS_EXCEPTIONS", 0)]) + else: + env.Append(CXXFLAGS=["-fno-exceptions"]) +elif env.msvc: + env.Append(CXXFLAGS=["/EHsc"]) + +# Configure compiler warnings +if env.msvc: # MSVC + if env["warnings"] == "no": + env.Append(CCFLAGS=["/w"]) + else: + if env["warnings"] == "extra": + env.Append(CCFLAGS=["/W4"]) + elif env["warnings"] == "all": + # C4458 is like -Wshadow. Part of /W4 but let's apply it for the default /W3 too. + env.Append(CCFLAGS=["/W3", "/w34458"]) + elif env["warnings"] == "moderate": + env.Append(CCFLAGS=["/W2"]) + # Disable warnings which we don't plan to fix. + + env.Append( + CCFLAGS=[ + "/wd4100", # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism. + "/wd4127", # C4127 (conditional expression is constant) + "/wd4201", # C4201 (non-standard nameless struct/union): Only relevant for C89. + "/wd4244", # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale. + "/wd4245", + "/wd4267", + "/wd4305", # C4305 (truncation): double to float or real_t, too hard to avoid. + "/wd4514", # C4514 (unreferenced inline function has been removed) + "/wd4714", # C4714 (function marked as __forceinline not inlined) + "/wd4820", # C4820 (padding added after construct) + ] + ) + + if env["werror"]: + env.Append(CCFLAGS=["/WX"]) + env.Append(LINKFLAGS=["/WX"]) +else: # GCC, Clang + common_warnings = [] + if methods.using_gcc(env): + common_warnings += ["-Wshadow", "-Wno-misleading-indentation"] + if cc_version_major == 7: # Bogus warning fixed in 8+. + common_warnings += ["-Wno-strict-overflow"] + if cc_version_major < 11: + # Regression in GCC 9/10, spams so much in our variadic templates + # that we need to outright disable it. + common_warnings += ["-Wno-type-limits"] + if cc_version_major >= 12: # False positives in our error macros, see GH-58747. + common_warnings += ["-Wno-return-type"] + elif methods.using_clang(env) or methods.using_emcc(env): + common_warnings += ["-Wshadow-field-in-constructor", "-Wshadow-uncaptured-local"] + # We often implement `operator<` for structs of pointers as a requirement + # for putting them in `Set` or `Map`. We don't mind about unreliable ordering. + common_warnings += ["-Wno-ordered-compare-function-pointers"] + + if env["warnings"] == "extra": + env.Append(CCFLAGS=["-Wall", "-Wextra", "-Wwrite-strings", "-Wno-unused-parameter"] + common_warnings) + env.Append(CXXFLAGS=["-Wctor-dtor-privacy", "-Wnon-virtual-dtor"]) + if methods.using_gcc(env): env.Append( CCFLAGS=[ - "/wd4100", # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism. - "/wd4127", # C4127 (conditional expression is constant) - "/wd4201", # C4201 (non-standard nameless struct/union): Only relevant for C89. - "/wd4244", # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale. - "/wd4245", - "/wd4267", - "/wd4305", # C4305 (truncation): double to float or real_t, too hard to avoid. - "/wd4514", # C4514 (unreferenced inline function has been removed) - "/wd4714", # C4714 (function marked as __forceinline not inlined) - "/wd4820", # C4820 (padding added after construct) + "-Walloc-zero", + "-Wduplicated-branches", + "-Wduplicated-cond", + "-Wstringop-overflow=4", ] ) - - if env["werror"]: - env.Append(CCFLAGS=["/WX"]) - env.Append(LINKFLAGS=["/WX"]) - else: # GCC, Clang - common_warnings = [] - - if methods.using_gcc(env): - common_warnings += ["-Wshadow", "-Wno-misleading-indentation"] - if cc_version_major == 7: # Bogus warning fixed in 8+. - common_warnings += ["-Wno-strict-overflow"] - if cc_version_major < 11: - # Regression in GCC 9/10, spams so much in our variadic templates - # that we need to outright disable it. - common_warnings += ["-Wno-type-limits"] - if cc_version_major >= 12: # False positives in our error macros, see GH-58747. - common_warnings += ["-Wno-return-type"] + env.Append(CXXFLAGS=["-Wplacement-new=1"]) + # Need to fix a warning with AudioServer lambdas before enabling. + # if cc_version_major != 9: # GCC 9 had a regression (GH-36325). + # env.Append(CXXFLAGS=["-Wnoexcept"]) + if cc_version_major >= 9: + env.Append(CCFLAGS=["-Wattribute-alias=2"]) + if cc_version_major >= 11: # Broke on MethodBind templates before GCC 11. + env.Append(CCFLAGS=["-Wlogical-op"]) elif methods.using_clang(env) or methods.using_emcc(env): - common_warnings += ["-Wshadow-field-in-constructor", "-Wshadow-uncaptured-local"] - # We often implement `operator<` for structs of pointers as a requirement - # for putting them in `Set` or `Map`. We don't mind about unreliable ordering. - common_warnings += ["-Wno-ordered-compare-function-pointers"] - - if env["warnings"] == "extra": - env.Append(CCFLAGS=["-Wall", "-Wextra", "-Wwrite-strings", "-Wno-unused-parameter"] + common_warnings) - env.Append(CXXFLAGS=["-Wctor-dtor-privacy", "-Wnon-virtual-dtor"]) - if methods.using_gcc(env): - env.Append( - CCFLAGS=[ - "-Walloc-zero", - "-Wduplicated-branches", - "-Wduplicated-cond", - "-Wstringop-overflow=4", - ] - ) - env.Append(CXXFLAGS=["-Wplacement-new=1"]) - # Need to fix a warning with AudioServer lambdas before enabling. - # if cc_version_major != 9: # GCC 9 had a regression (GH-36325). - # env.Append(CXXFLAGS=["-Wnoexcept"]) - if cc_version_major >= 9: - env.Append(CCFLAGS=["-Wattribute-alias=2"]) - if cc_version_major >= 11: # Broke on MethodBind templates before GCC 11. - env.Append(CCFLAGS=["-Wlogical-op"]) - elif methods.using_clang(env) or methods.using_emcc(env): - env.Append(CCFLAGS=["-Wimplicit-fallthrough"]) - elif env["warnings"] == "all": - env.Append(CCFLAGS=["-Wall"] + common_warnings) - elif env["warnings"] == "moderate": - env.Append(CCFLAGS=["-Wall", "-Wno-unused"] + common_warnings) - else: # 'no' - env.Append(CCFLAGS=["-w"]) - - if env["werror"]: - env.Append(CCFLAGS=["-Werror"]) + env.Append(CCFLAGS=["-Wimplicit-fallthrough"]) + elif env["warnings"] == "all": + env.Append(CCFLAGS=["-Wall"] + common_warnings) + elif env["warnings"] == "moderate": + env.Append(CCFLAGS=["-Wall", "-Wno-unused"] + common_warnings) + else: # 'no' + env.Append(CCFLAGS=["-w"]) + + if env["werror"]: + env.Append(CCFLAGS=["-Werror"]) + +if hasattr(detect, "get_program_suffix"): + suffix = "." + detect.get_program_suffix() +else: + suffix = "." + selected_platform - if hasattr(detect, "get_program_suffix"): - suffix = "." + detect.get_program_suffix() - else: - suffix = "." + selected_platform +suffix += "." + env["target"] +if env.dev_build: + suffix += ".dev" - suffix += "." + env["target"] - if env.dev_build: - suffix += ".dev" +if env_base["precision"] == "double": + suffix += ".double" - if env_base["precision"] == "double": - suffix += ".double" +suffix += "." + env["arch"] - suffix += "." + env["arch"] +if not env["threads"]: + suffix += ".nothreads" - if not env["threads"]: - suffix += ".nothreads" +suffix += env.extra_suffix - suffix += env.extra_suffix +sys.path.remove(tmppath) +sys.modules.pop("detect") - sys.path.remove(tmppath) - sys.modules.pop("detect") +modules_enabled = OrderedDict() +env.module_dependencies = {} +env.module_icons_paths = [] +env.doc_class_path = platform_doc_class_path - modules_enabled = OrderedDict() - env.module_dependencies = {} - env.module_icons_paths = [] - env.doc_class_path = platform_doc_class_path +for name, path in modules_detected.items(): + if not env["module_" + name + "_enabled"]: + continue + sys.path.insert(0, path) + env.current_module = name + import config - for name, path in modules_detected.items(): - if not env["module_" + name + "_enabled"]: + if config.can_build(env, selected_platform): + # Disable it if a required dependency is missing. + if not env.module_check_dependencies(name): continue - sys.path.insert(0, path) - env.current_module = name - import config - - if config.can_build(env, selected_platform): - # Disable it if a required dependency is missing. - if not env.module_check_dependencies(name): - continue - - config.configure(env) - # Get doc classes paths (if present) - try: - doc_classes = config.get_doc_classes() - doc_path = config.get_doc_path() - for c in doc_classes: - env.doc_class_path[c] = path + "/" + doc_path - except Exception: - pass - # Get icon paths (if present) - try: - icons_path = config.get_icons_path() - env.module_icons_paths.append(path + "/" + icons_path) - except Exception: - # Default path for module icons - env.module_icons_paths.append(path + "/" + "icons") - modules_enabled[name] = path - - sys.path.remove(path) - sys.modules.pop("config") - - env.module_list = modules_enabled - methods.sort_module_list(env) - if env.editor_build: - # Add editor-specific dependencies to the dependency graph. - env.module_add_dependencies("editor", ["freetype", "svg"]) + config.configure(env) + # Get doc classes paths (if present) + try: + doc_classes = config.get_doc_classes() + doc_path = config.get_doc_path() + for c in doc_classes: + env.doc_class_path[c] = path + "/" + doc_path + except Exception: + pass + # Get icon paths (if present) + try: + icons_path = config.get_icons_path() + env.module_icons_paths.append(path + "/" + icons_path) + except Exception: + # Default path for module icons + env.module_icons_paths.append(path + "/" + "icons") + modules_enabled[name] = path - # And check if they are met. - if not env.module_check_dependencies("editor"): - print("Not all modules required by editor builds are enabled.") - Exit(255) + sys.path.remove(path) + sys.modules.pop("config") - methods.generate_version_header(env.module_version_string) - - env["PROGSUFFIX_WRAP"] = suffix + env.module_version_string + ".console" + env["PROGSUFFIX"] - env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"] - env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"] - # (SH)LIBSUFFIX will be used for our own built libraries - # LIBSUFFIXES contains LIBSUFFIX and SHLIBSUFFIX by default, - # so we need to append the default suffixes to keep the ability - # to link against thirdparty libraries (.a, .so, .lib, etc.). - if os.name == "nt": - # On Windows, only static libraries and import libraries can be - # statically linked - both using .lib extension - env["LIBSUFFIXES"] += [env["LIBSUFFIX"]] - else: - env["LIBSUFFIXES"] += [env["LIBSUFFIX"], env["SHLIBSUFFIX"]] - env["LIBSUFFIX"] = suffix + env["LIBSUFFIX"] - env["SHLIBSUFFIX"] = suffix + env["SHLIBSUFFIX"] +env.module_list = modules_enabled +methods.sort_module_list(env) - env["OBJPREFIX"] = env["object_prefix"] - env["SHOBJPREFIX"] = env["object_prefix"] +if env.editor_build: + # Add editor-specific dependencies to the dependency graph. + env.module_add_dependencies("editor", ["freetype", "svg"]) - if env["disable_3d"]: - if env.editor_build: - print("Build option 'disable_3d=yes' cannot be used for editor builds, only for export template builds.") - Exit(255) - else: - env.Append(CPPDEFINES=["_3D_DISABLED"]) - if env["disable_advanced_gui"]: - if env.editor_build: - print( - "Build option 'disable_advanced_gui=yes' cannot be used for editor builds, " - "only for export template builds." - ) - Exit(255) - else: - env.Append(CPPDEFINES=["ADVANCED_GUI_DISABLED"]) - if env["minizip"]: - env.Append(CPPDEFINES=["MINIZIP_ENABLED"]) - if env["brotli"]: - env.Append(CPPDEFINES=["BROTLI_ENABLED"]) - - if not env["verbose"]: - methods.no_verbose(sys, env) - - GLSL_BUILDERS = { - "RD_GLSL": env.Builder( - action=env.Run(glsl_builders.build_rd_headers), - suffix="glsl.gen.h", - src_suffix=".glsl", - ), - "GLSL_HEADER": env.Builder( - action=env.Run(glsl_builders.build_raw_headers), - suffix="glsl.gen.h", - src_suffix=".glsl", - ), - "GLES3_GLSL": env.Builder( - action=env.Run(gles3_builders.build_gles3_headers), - suffix="glsl.gen.h", - src_suffix=".glsl", - ), - } - env.Append(BUILDERS=GLSL_BUILDERS) - - scons_cache_path = os.environ.get("SCONS_CACHE") - if scons_cache_path != None: - CacheDir(scons_cache_path) - print("Scons cache enabled... (path: '" + scons_cache_path + "')") - - if env["vsproj"]: - env.vs_incs = [] - env.vs_srcs = [] - - # CompileDB and Ninja are only available with certain SCons versions which - # not everybody might have yet, so we have to check. - from SCons import __version__ as scons_raw_version - - scons_ver = env._get_major_minor_revision(scons_raw_version) - if env["compiledb"] and scons_ver < (4, 0, 0): - # Generating the compilation DB (`compile_commands.json`) requires SCons 4.0.0 or later. - print("The `compiledb=yes` option requires SCons 4.0 or later, but your version is %s." % scons_raw_version) + # And check if they are met. + if not env.module_check_dependencies("editor"): + print("Not all modules required by editor builds are enabled.") Exit(255) - if scons_ver >= (4, 0, 0): - env.Tool("compilation_db") - env.Alias("compiledb", env.CompilationDatabase()) - if env["ninja"]: - if scons_ver < (4, 2, 0): - print("The `ninja=yes` option requires SCons 4.2 or later, but your version is %s." % scons_raw_version) - Exit(255) - - SetOption("experimental", "ninja") - - # By setting this we allow the user to run ninja by themselves with all - # the flags they need, as apparently automatically running from scons - # is way slower. - SetOption("disable_execute_ninja", True) - - env.Tool("ninja") - - # Threads - if env["threads"]: - env.Append(CPPDEFINES=["THREADS_ENABLED"]) +methods.generate_version_header(env.module_version_string) + +env["PROGSUFFIX_WRAP"] = suffix + env.module_version_string + ".console" + env["PROGSUFFIX"] +env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"] +env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"] +# (SH)LIBSUFFIX will be used for our own built libraries +# LIBSUFFIXES contains LIBSUFFIX and SHLIBSUFFIX by default, +# so we need to append the default suffixes to keep the ability +# to link against thirdparty libraries (.a, .so, .lib, etc.). +if os.name == "nt": + # On Windows, only static libraries and import libraries can be + # statically linked - both using .lib extension + env["LIBSUFFIXES"] += [env["LIBSUFFIX"]] +else: + env["LIBSUFFIXES"] += [env["LIBSUFFIX"], env["SHLIBSUFFIX"]] +env["LIBSUFFIX"] = suffix + env["LIBSUFFIX"] +env["SHLIBSUFFIX"] = suffix + env["SHLIBSUFFIX"] - # Build subdirs, the build order is dependent on link order. - Export("env") +env["OBJPREFIX"] = env["object_prefix"] +env["SHOBJPREFIX"] = env["object_prefix"] - SConscript("core/SCsub") - SConscript("servers/SCsub") - SConscript("scene/SCsub") +if env["disable_3d"]: if env.editor_build: - SConscript("editor/SCsub") - SConscript("drivers/SCsub") - - SConscript("platform/SCsub") - SConscript("modules/SCsub") - if env["tests"]: - SConscript("tests/SCsub") - SConscript("main/SCsub") - - SConscript("platform/" + selected_platform + "/SCsub") # Build selected platform. - - # Microsoft Visual Studio Project Generation - if env["vsproj"]: - env["CPPPATH"] = [Dir(path) for path in env["CPPPATH"]] - methods.generate_vs_project(env, ARGUMENTS, env["vsproj_name"]) - methods.generate_cpp_hint_file("cpp.hint") - - # Check for the existence of headers - conf = Configure(env) - if "check_c_headers" in env: - headers = env["check_c_headers"] - for header in headers: - if conf.CheckCHeader(header): - env.AppendUnique(CPPDEFINES=[headers[header]]) - -elif selected_platform != "": - if selected_platform == "list": - print("The following platforms are available:\n") + print("Build option 'disable_3d=yes' cannot be used for editor builds, only for export template builds.") + Exit(255) else: - print('Invalid target platform "' + selected_platform + '".') - print("The following platforms were detected:\n") - - for x in platform_list: - print("\t" + x) - - print("\nPlease run SCons again and select a valid platform: platform=<string>") - - if selected_platform == "list": - # Exit early to suppress the rest of the built-in SCons messages - Exit() + env.Append(CPPDEFINES=["_3D_DISABLED"]) +if env["disable_advanced_gui"]: + if env.editor_build: + print( + "Build option 'disable_advanced_gui=yes' cannot be used for editor builds, " + "only for export template builds." + ) + Exit(255) else: + env.Append(CPPDEFINES=["ADVANCED_GUI_DISABLED"]) +if env["minizip"]: + env.Append(CPPDEFINES=["MINIZIP_ENABLED"]) +if env["brotli"]: + env.Append(CPPDEFINES=["BROTLI_ENABLED"]) + +if not env["verbose"]: + methods.no_verbose(sys, env) + +GLSL_BUILDERS = { + "RD_GLSL": env.Builder( + action=env.Run(glsl_builders.build_rd_headers), + suffix="glsl.gen.h", + src_suffix=".glsl", + ), + "GLSL_HEADER": env.Builder( + action=env.Run(glsl_builders.build_raw_headers), + suffix="glsl.gen.h", + src_suffix=".glsl", + ), + "GLES3_GLSL": env.Builder( + action=env.Run(gles3_builders.build_gles3_headers), + suffix="glsl.gen.h", + src_suffix=".glsl", + ), +} +env.Append(BUILDERS=GLSL_BUILDERS) + +scons_cache_path = os.environ.get("SCONS_CACHE") +if scons_cache_path != None: + CacheDir(scons_cache_path) + print("Scons cache enabled... (path: '" + scons_cache_path + "')") + +if env["vsproj"]: + env.vs_incs = [] + env.vs_srcs = [] + +# CompileDB and Ninja are only available with certain SCons versions which +# not everybody might have yet, so we have to check. +from SCons import __version__ as scons_raw_version + +scons_ver = env._get_major_minor_revision(scons_raw_version) +if env["compiledb"] and scons_ver < (4, 0, 0): + # Generating the compilation DB (`compile_commands.json`) requires SCons 4.0.0 or later. + print("The `compiledb=yes` option requires SCons 4.0 or later, but your version is %s." % scons_raw_version) + Exit(255) +if scons_ver >= (4, 0, 0): + env.Tool("compilation_db") + env.Alias("compiledb", env.CompilationDatabase()) + +if env["ninja"]: + if scons_ver < (4, 2, 0): + print("The `ninja=yes` option requires SCons 4.2 or later, but your version is %s." % scons_raw_version) Exit(255) -# The following only makes sense when the 'env' is defined, and assumes it is. -if "env" in locals(): - # FIXME: This method mixes both cosmetic progress stuff and cache handling... - methods.show_progress(env) - # TODO: replace this with `env.Dump(format="json")` - # once we start requiring SCons 4.0 as min version. - methods.dump(env) + SetOption("experimental", "ninja") + + # By setting this we allow the user to run ninja by themselves with all + # the flags they need, as apparently automatically running from scons + # is way slower. + SetOption("disable_execute_ninja", True) + + env.Tool("ninja") + +# Threads +if env["threads"]: + env.Append(CPPDEFINES=["THREADS_ENABLED"]) + +# Build subdirs, the build order is dependent on link order. +Export("env") + +SConscript("core/SCsub") +SConscript("servers/SCsub") +SConscript("scene/SCsub") +if env.editor_build: + SConscript("editor/SCsub") +SConscript("drivers/SCsub") + +SConscript("platform/SCsub") +SConscript("modules/SCsub") +if env["tests"]: + SConscript("tests/SCsub") +SConscript("main/SCsub") + +SConscript("platform/" + selected_platform + "/SCsub") # Build selected platform. + +# Microsoft Visual Studio Project Generation +if env["vsproj"]: + env["CPPPATH"] = [Dir(path) for path in env["CPPPATH"]] + methods.generate_vs_project(env, ARGUMENTS, env["vsproj_name"]) + methods.generate_cpp_hint_file("cpp.hint") + +# Check for the existence of headers +conf = Configure(env) +if "check_c_headers" in env: + headers = env["check_c_headers"] + for header in headers: + if conf.CheckCHeader(header): + env.AppendUnique(CPPDEFINES=[headers[header]]) + + +# FIXME: This method mixes both cosmetic progress stuff and cache handling... +methods.show_progress(env) +# TODO: replace this with `env.Dump(format="json")` +# once we start requiring SCons 4.0 as min version. +methods.dump(env) def print_elapsed_time(): diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 14023c5c75..1508469e27 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1538,6 +1538,7 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/block_size_kb", PROPERTY_HINT_RANGE, "4,2048,1,or_greater"), 256); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/max_size_mb", PROPERTY_HINT_RANGE, "1,1024,1,or_greater"), 128); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/texture_upload_region_size_px", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64); + GLOBAL_DEF_RST(PropertyInfo(Variant::BOOL, "rendering/rendering_device/pipeline_cache/enable"), true); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/rendering_device/pipeline_cache/save_chunk_size_mb", PROPERTY_HINT_RANGE, "0.000001,64.0,0.001,or_greater"), 3.0); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/vulkan/max_descriptors_per_pool", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64); diff --git a/core/crypto/SCsub b/core/crypto/SCsub index ac79e10d19..a6defdfdab 100644 --- a/core/crypto/SCsub +++ b/core/crypto/SCsub @@ -21,9 +21,9 @@ if is_builtin or not has_module: # to make a "light" build with only the necessary mbedtls files. if not has_module: # Minimal mbedTLS config file - env_crypto.Append( - CPPDEFINES=[("MBEDTLS_CONFIG_FILE", '\\"thirdparty/mbedtls/include/godot_core_mbedtls_config.h\\"')] - ) + config_path = "thirdparty/mbedtls/include/godot_core_mbedtls_config.h" + config_path = f"<{config_path}>" if env_crypto["ninja"] and env_crypto.msvc else f'\\"{config_path}\\"' + env_crypto.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)]) # Build minimal mbedTLS library (MD5/SHA/Base64/AES). env_thirdparty = env_crypto.Clone() env_thirdparty.disable_warnings() @@ -46,9 +46,9 @@ if not has_module: env.core_sources += thirdparty_obj elif is_builtin: # Module mbedTLS config file - env_crypto.Append( - CPPDEFINES=[("MBEDTLS_CONFIG_FILE", '\\"thirdparty/mbedtls/include/godot_module_mbedtls_config.h\\"')] - ) + config_path = "thirdparty/mbedtls/include/godot_module_mbedtls_config.h" + config_path = f"<{config_path}>" if env_crypto["ninja"] and env_crypto.msvc else f'\\"{config_path}\\"' + env_crypto.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)]) # Needed to force rebuilding the core files when the configuration file is updated. thirdparty_obj = ["#thirdparty/mbedtls/include/godot_module_mbedtls_config.h"] diff --git a/core/io/resource.cpp b/core/io/resource.cpp index dc974a545a..74f18ceee1 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -424,8 +424,7 @@ RID Resource::get_rid() const { } } if (_get_extension() && _get_extension()->get_rid) { - RID ret; - ret.from_uint64(_get_extension()->get_rid(_get_extension_instance())); + RID ret = RID::from_uint64(_get_extension()->get_rid(_get_extension_instance())); if (ret.is_valid()) { return ret; } diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp index 478fde3a64..80662c1b07 100644 --- a/core/math/convex_hull.cpp +++ b/core/math/convex_hull.cpp @@ -77,15 +77,17 @@ subject to the following restrictions: #ifdef DEBUG_ENABLED #define CHULL_ASSERT(m_cond) \ - do { \ + if constexpr (true) { \ if (unlikely(!(m_cond))) { \ ERR_PRINT("Assertion \"" _STR(m_cond) "\" failed."); \ } \ - } while (0) + } else \ + ((void)0) #else #define CHULL_ASSERT(m_cond) \ - do { \ - } while (0) + if constexpr (true) { \ + } else \ + ((void)0) #endif #if defined(DEBUG_CONVEX_HULL) || defined(SHOW_ITERATIONS) diff --git a/core/os/pool_allocator.cpp b/core/os/pool_allocator.cpp index acbaed4ce8..9a993cd14f 100644 --- a/core/os/pool_allocator.cpp +++ b/core/os/pool_allocator.cpp @@ -36,12 +36,13 @@ #include "core/string/print_string.h" #define COMPACT_CHUNK(m_entry, m_to_pos) \ - do { \ + if constexpr (true) { \ void *_dst = &((unsigned char *)pool)[m_to_pos]; \ void *_src = &((unsigned char *)pool)[(m_entry).pos]; \ memmove(_dst, _src, aligned((m_entry).len)); \ (m_entry).pos = m_to_pos; \ - } while (0); + } else \ + ((void)0) void PoolAllocator::mt_lock() const { } diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index bdef1b9bbe..2b62b72a51 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -2110,12 +2110,12 @@ CharString String::utf8() const { String String::utf16(const char16_t *p_utf16, int p_len) { String ret; - ret.parse_utf16(p_utf16, p_len); + ret.parse_utf16(p_utf16, p_len, true); return ret; } -Error String::parse_utf16(const char16_t *p_utf16, int p_len) { +Error String::parse_utf16(const char16_t *p_utf16, int p_len, bool p_default_little_endian) { if (!p_utf16) { return ERR_INVALID_DATA; } @@ -2125,8 +2125,12 @@ Error String::parse_utf16(const char16_t *p_utf16, int p_len) { int cstr_size = 0; int str_size = 0; +#ifdef BIG_ENDIAN_ENABLED + bool byteswap = p_default_little_endian; +#else + bool byteswap = !p_default_little_endian; +#endif /* HANDLE BOM (Byte Order Mark) */ - bool byteswap = false; // assume correct endianness if no BOM found if (p_len < 0 || p_len >= 1) { bool has_bom = false; if (uint16_t(p_utf16[0]) == 0xfeff) { // correct BOM, read as is diff --git a/core/string/ustring.h b/core/string/ustring.h index fa904c8200..693df6dcba 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -393,7 +393,7 @@ public: static String utf8(const char *p_utf8, int p_len = -1); Char16String utf16() const; - Error parse_utf16(const char16_t *p_utf16, int p_len = -1); + Error parse_utf16(const char16_t *p_utf16, int p_len = -1, bool p_default_little_endian = true); static String utf16(const char16_t *p_utf16, int p_len = -1); static uint32_t hash(const char32_t *p_cstr, int p_len); /* hash the string */ diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp index 60ae09c6f1..dcf4b287d1 100644 --- a/core/variant/variant_op.cpp +++ b/core/variant/variant_op.cpp @@ -230,18 +230,20 @@ public: }; #define register_string_op(m_op_type, m_op_code) \ - do { \ + if constexpr (true) { \ register_op<m_op_type<String, String>>(m_op_code, Variant::STRING, Variant::STRING); \ register_op<m_op_type<String, StringName>>(m_op_code, Variant::STRING, Variant::STRING_NAME); \ register_op<m_op_type<StringName, String>>(m_op_code, Variant::STRING_NAME, Variant::STRING); \ register_op<m_op_type<StringName, StringName>>(m_op_code, Variant::STRING_NAME, Variant::STRING_NAME); \ - } while (false) + } else \ + ((void)0) #define register_string_modulo_op(m_class, m_type) \ - do { \ + if constexpr (true) { \ register_op<OperatorEvaluatorStringFormat<String, m_class>>(Variant::OP_MODULE, Variant::STRING, m_type); \ register_op<OperatorEvaluatorStringFormat<StringName, m_class>>(Variant::OP_MODULE, Variant::STRING_NAME, m_type); \ - } while (false) + } else \ + ((void)0) void Variant::_register_variant_operators() { memset(operator_return_type_table, 0, sizeof(operator_return_type_table)); diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 4d3e838bb1..6a6f53ac60 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -2727,6 +2727,10 @@ <member name="rendering/rendering_device/driver.windows" type="String" setter="" getter=""> Windows override for [member rendering/rendering_device/driver]. </member> + <member name="rendering/rendering_device/pipeline_cache/enable" type="bool" setter="" getter="" default="true"> + Enable the pipeline cache that is saved to disk if the graphics API supports it. + [b]Note:[/b] This property is unable to control the pipeline caching the GPU driver itself does. Only turn this off along with deleting the contents of the driver's cache if you wish to simulate the experience a user will get when starting the game for the first time. + </member> <member name="rendering/rendering_device/pipeline_cache/save_chunk_size_mb" type="float" setter="" getter="" default="3.0"> Determines at which interval pipeline cache is saved to disk. The lower the value, the more often it is saved. </member> diff --git a/doc/classes/SkeletonProfile.xml b/doc/classes/SkeletonProfile.xml index 3ed29668e4..b5bb4e3639 100644 --- a/doc/classes/SkeletonProfile.xml +++ b/doc/classes/SkeletonProfile.xml @@ -83,6 +83,14 @@ Returns the texture of the group at [param group_idx] that will be the drawing group background image in the [BoneMap] editor. </description> </method> + <method name="is_required" qualifiers="const"> + <return type="bool" /> + <param index="0" name="bone_idx" type="int" /> + <description> + Returns whether the bone at [param bone_idx] is required for retargeting. + This value is used by the bone map editor. If this method returns [code]true[/code], and no bone is assigned, the handle color will be red on the bone map editor. + </description> + </method> <method name="set_bone_name"> <return type="void" /> <param index="0" name="bone_idx" type="int" /> @@ -141,6 +149,14 @@ Sets the reference pose transform for bone [param bone_idx]. </description> </method> + <method name="set_required"> + <return type="void" /> + <param index="0" name="bone_idx" type="int" /> + <param index="1" name="required" type="bool" /> + <description> + Sets the required status for bone [param bone_idx] to [param required]. + </description> + </method> <method name="set_tail_direction"> <return type="void" /> <param index="0" name="bone_idx" type="int" /> diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index cd70316aa9..c0cd7f79e7 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -1736,6 +1736,16 @@ [b]Note:[/b] The result may be longer or shorter than the original. </description> </method> + <method name="string_to_title" qualifiers="const"> + <return type="String" /> + <param index="0" name="string" type="String" /> + <param index="1" name="language" type="String" default="""" /> + <description> + Returns the string converted to title case. + [b]Note:[/b] Casing is locale dependent and context sensitive if server support [constant FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION] feature (supported by [TextServerAdvanced]). + [b]Note:[/b] The result may be longer or shorter than the original. + </description> + </method> <method name="string_to_upper" qualifiers="const"> <return type="String" /> <param index="0" name="string" type="String" /> diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml index 9b7fc42ddf..06a0daece6 100644 --- a/doc/classes/TextServerExtension.xml +++ b/doc/classes/TextServerExtension.xml @@ -1913,6 +1913,15 @@ Returns the string converted to lowercase. </description> </method> + <method name="_string_to_title" qualifiers="virtual const"> + <return type="String" /> + <param index="0" name="string" type="String" /> + <param index="1" name="language" type="String" /> + <description> + [b]Optional.[/b] + Returns the string converted to title case. + </description> + </method> <method name="_string_to_upper" qualifiers="virtual const"> <return type="String" /> <param index="0" name="string" type="String" /> diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml index 3d36eafb08..e197f7748c 100644 --- a/doc/classes/UndoRedo.xml +++ b/doc/classes/UndoRedo.xml @@ -112,7 +112,8 @@ <return type="void" /> <param index="0" name="object" type="Object" /> <description> - Register a reference for "do" that will be erased if the "do" history is lost. This is useful mostly for new nodes created for the "do" call. Do not use for resources. + Register a reference to an object that will be erased if the "do" history is deleted. This is useful for objects added by the "do" action and removed by the "undo" action. + When the "do" history is deleted, if the object is a [RefCounted], it will be unreferenced. Otherwise, it will be freed. Do not use for resources. [codeblock] var node = Node2D.new() undo_redo.create_action("Add node") @@ -143,7 +144,8 @@ <return type="void" /> <param index="0" name="object" type="Object" /> <description> - Register a reference for "undo" that will be erased if the "undo" history is lost. This is useful mostly for nodes removed with the "do" call (not the "undo" call!). + Register a reference to an object that will be erased if the "undo" history is deleted. This is useful for objects added by the "undo" action and removed by the "do" action. + When the "undo" history is deleted, if the object is a [RefCounted], it will be unreferenced. Otherwise, it will be freed. Do not use for resources. [codeblock] var node = $Node2D undo_redo.create_action("Remove node") @@ -272,10 +274,10 @@ Makes "do"/"undo" operations stay in separate actions. </constant> <constant name="MERGE_ENDS" value="1" enum="MergeMode"> - Makes so that the action's "undo" operations are from the first action created and the "do" operations are from the last subsequent action with the same name. + Merges this action with the previous one if they have the same name. Keeps only the first action's "undo" operations and the last action's "do" operations. Useful for sequential changes to a single value. </constant> <constant name="MERGE_ALL" value="2" enum="MergeMode"> - Makes subsequent actions with the same name be merged into one. + Merges this action with the previous one if they have the same name. </constant> </constants> </class> diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp index d7d77c6b8f..eebba6b00d 100644 --- a/drivers/gles3/storage/light_storage.cpp +++ b/drivers/gles3/storage/light_storage.cpp @@ -1064,7 +1064,11 @@ bool LightStorage::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_i for (int j = 0; j < sc; j++) { LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner); - ERR_CONTINUE(!sli); + if (!sli) { + // Found a released light instance. + found_used_idx = j; + break; + } if (sli->last_scene_pass != RasterizerSceneGLES3::get_singleton()->get_scene_pass()) { // Was just allocated, don't kill it so soon, wait a bit. diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 516b8f3d74..51e1c27070 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1367,6 +1367,10 @@ bool EditorFileSystem::_find_file(const String &p_file, EditorFileSystemDirector String f = ProjectSettings::get_singleton()->localize_path(p_file); + // Note: Only checks if base directory is case sensitive. + Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + bool fs_case_sensitive = dir->is_case_sensitive("res://"); + if (!f.begins_with("res://")) { return false; } @@ -1390,9 +1394,16 @@ bool EditorFileSystem::_find_file(const String &p_file, EditorFileSystemDirector int idx = -1; for (int j = 0; j < fs->get_subdir_count(); j++) { - if (fs->get_subdir(j)->get_name() == path[i]) { - idx = j; - break; + if (fs_case_sensitive) { + if (fs->get_subdir(j)->get_name() == path[i]) { + idx = j; + break; + } + } else { + if (fs->get_subdir(j)->get_name().to_lower() == path[i].to_lower()) { + idx = j; + break; + } } } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 022cf82426..bba1939f72 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -3471,7 +3471,9 @@ EditorHelpHighlighter::HighlightData EditorHelpHighlighter::_get_highlight_data( } text_edits[p_language]->set_text(p_source); - scripts[p_language]->set_source_code(p_source); + if (scripts[p_language].is_valid()) { // See GH-89610. + scripts[p_language]->set_source_code(p_source); + } highlighters[p_language]->_update_cache(); HighlightData result; @@ -3561,16 +3563,18 @@ EditorHelpHighlighter::EditorHelpHighlighter() { #ifdef MODULE_MONO_ENABLED TextEdit *csharp_text_edit = memnew(TextEdit); - Ref<CSharpScript> csharp; - csharp.instantiate(); + // See GH-89610. + //Ref<CSharpScript> csharp; + //csharp.instantiate(); Ref<EditorStandardSyntaxHighlighter> csharp_highlighter; csharp_highlighter.instantiate(); csharp_highlighter->set_text_edit(csharp_text_edit); - csharp_highlighter->_set_edited_resource(csharp); + //csharp_highlighter->_set_edited_resource(csharp); + csharp_highlighter->_set_script_language(CSharpLanguage::get_singleton()); text_edits[LANGUAGE_CSHARP] = csharp_text_edit; - scripts[LANGUAGE_CSHARP] = csharp; + //scripts[LANGUAGE_CSHARP] = csharp; highlighters[LANGUAGE_CSHARP] = csharp_highlighter; #endif } @@ -3578,14 +3582,10 @@ EditorHelpHighlighter::EditorHelpHighlighter() { EditorHelpHighlighter::~EditorHelpHighlighter() { #ifdef MODULE_GDSCRIPT_ENABLED memdelete(text_edits[LANGUAGE_GDSCRIPT]); - scripts[LANGUAGE_GDSCRIPT].unref(); - highlighters[LANGUAGE_GDSCRIPT].unref(); #endif #ifdef MODULE_MONO_ENABLED memdelete(text_edits[LANGUAGE_CSHARP]); - scripts[LANGUAGE_CSHARP].unref(); - highlighters[LANGUAGE_CSHARP].unref(); #endif } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 6f984f6fab..1c079bfca2 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -5324,7 +5324,7 @@ bool EditorNode::is_distraction_free_mode_enabled() const { return distraction_free->is_pressed(); } -Variant EditorNode::drag_resource(const Ref<Resource> &p_res, Control *p_from) { +Dictionary EditorNode::drag_resource(const Ref<Resource> &p_res, Control *p_from) { Control *drag_control = memnew(Control); TextureRect *drag_preview = memnew(TextureRect); Label *label = memnew(Label); @@ -5364,7 +5364,7 @@ Variant EditorNode::drag_resource(const Ref<Resource> &p_res, Control *p_from) { return drag_data; } -Variant EditorNode::drag_files_and_dirs(const Vector<String> &p_paths, Control *p_from) { +Dictionary EditorNode::drag_files_and_dirs(const Vector<String> &p_paths, Control *p_from) { bool has_folder = false; bool has_file = false; for (int i = 0; i < p_paths.size(); i++) { diff --git a/editor/editor_node.h b/editor/editor_node.h index 8bcf29811d..96acc8bf46 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -870,8 +870,8 @@ public: bool is_exiting() const { return exiting; } - Variant drag_resource(const Ref<Resource> &p_res, Control *p_from); - Variant drag_files_and_dirs(const Vector<String> &p_paths, Control *p_from); + Dictionary drag_resource(const Ref<Resource> &p_res, Control *p_from); + Dictionary drag_files_and_dirs(const Vector<String> &p_paths, Control *p_from); void add_tool_menu_item(const String &p_name, const Callable &p_callback); void add_tool_submenu_item(const String &p_name, PopupMenu *p_submenu); diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index a6c7d6b617..c59c221e02 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -328,6 +328,7 @@ void EditorPropertyArray::update_property() { memdelete(container); button_add_item = nullptr; container = nullptr; + slots.clear(); } return; } @@ -483,9 +484,10 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const { } Dictionary drag_data = p_drag_data; + const String drop_type = drag_data.get("type", ""); - if (drag_data.has("type") && String(drag_data["type"]) == "files") { - Vector<String> files = drag_data["files"]; + if (drop_type == "files") { + PackedStringArray files = drag_data["files"]; for (int i = 0; i < files.size(); i++) { const String &file = files[i]; @@ -504,6 +506,56 @@ bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const { return true; } + if (drop_type == "nodes") { + Array node_paths = drag_data["nodes"]; + + PackedStringArray allowed_subtype_array; + if (allowed_type == "NodePath") { + if (subtype_hint_string == "NodePath") { + return true; + } else { + for (int j = 0; j < subtype_hint_string.get_slice_count(","); j++) { + String ast = subtype_hint_string.get_slice(",", j).strip_edges(); + allowed_subtype_array.append(ast); + } + } + } + + bool is_drop_allowed = true; + + for (int i = 0; i < node_paths.size(); i++) { + const Node *dropped_node = get_node_or_null(node_paths[i]); + ERR_FAIL_NULL_V_MSG(dropped_node, false, "Could not get the dropped node by its path."); + + if (allowed_type != "NodePath") { + if (!ClassDB::is_parent_class(dropped_node->get_class_name(), allowed_type)) { + // Fail if one of the nodes is not of allowed type. + return false; + } + } + + // The array of NodePaths is restricted to specific types using @export_node_path(). + if (allowed_type == "NodePath" && subtype_hint_string != "NodePath") { + if (!allowed_subtype_array.has(dropped_node->get_class_name())) { + // The dropped node type was not found in the allowed subtype array, we must check if it inherits one of them. + for (const String &ast : allowed_subtype_array) { + if (ClassDB::is_parent_class(dropped_node->get_class_name(), ast)) { + is_drop_allowed = true; + break; + } else { + is_drop_allowed = false; + } + } + if (!is_drop_allowed) { + break; + } + } + } + } + + return is_drop_allowed; + } + return false; } @@ -515,18 +567,18 @@ void EditorPropertyArray::drop_data_fw(const Point2 &p_point, const Variant &p_d ERR_FAIL_COND(!_is_drop_valid(p_data)); Dictionary drag_data = p_data; + const String drop_type = drag_data.get("type", ""); + Variant array = object->get_array(); - if (drag_data.has("type") && String(drag_data["type"]) == "files") { - Vector<String> files = drag_data["files"]; - - Variant array = object->get_array(); + // Handle the case where array is not initialized yet. + if (!array.is_array()) { + initialize_array(array); + } else { + array = array.duplicate(); + } - // Handle the case where array is not initialized yet. - if (!array.is_array()) { - initialize_array(array); - } else { - array = array.duplicate(); - } + if (drop_type == "files") { + PackedStringArray files = drag_data["files"]; // Loop the file array and add to existing array. for (int i = 0; i < files.size(); i++) { @@ -540,6 +592,33 @@ void EditorPropertyArray::drop_data_fw(const Point2 &p_point, const Variant &p_d emit_changed(get_edited_property(), array); } + + if (drop_type == "nodes") { + Array node_paths = drag_data["nodes"]; + Node *base_node = get_base_node(); + + for (int i = 0; i < node_paths.size(); i++) { + const NodePath &path = node_paths[i]; + + if (subtype == Variant::OBJECT) { + array.call("push_back", get_node(path)); + } else if (subtype == Variant::NODE_PATH) { + array.call("push_back", base_node->get_path().rel_path_to(path)); + } + } + + emit_changed(get_edited_property(), array); + } +} + +Node *EditorPropertyArray::get_base_node() { + Node *base_node = Object::cast_to<Node>(InspectorDock::get_inspector_singleton()->get_edited_object()); + + if (!base_node) { + base_node = get_tree()->get_edited_scene_root(); + } + + return base_node; } void EditorPropertyArray::_notification(int p_what) { @@ -586,7 +665,7 @@ void EditorPropertyArray::_edit_pressed() { Variant array = get_edited_property_value(); if (!array.is_array() && edit->is_pressed()) { initialize_array(array); - get_edited_object()->set(get_edited_property(), array); + emit_changed(get_edited_property(), array); } get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed()); @@ -867,7 +946,7 @@ void EditorPropertyDictionary::setup(PropertyHint p_hint) { void EditorPropertyDictionary::update_property() { Variant updated_val = get_edited_property_value(); - if (updated_val.get_type() == Variant::NIL) { + if (updated_val.get_type() != Variant::DICTIONARY) { edit->set_text(TTR("Dictionary (Nil)")); // This provides symmetry with the array property. edit->set_pressed(false); if (container) { @@ -875,6 +954,7 @@ void EditorPropertyDictionary::update_property() { memdelete(container); button_add_item = nullptr; container = nullptr; + slots.clear(); } return; } @@ -1021,7 +1101,7 @@ void EditorPropertyDictionary::_edit_pressed() { Variant prop_val = get_edited_property_value(); if (prop_val.get_type() == Variant::NIL && edit->is_pressed()) { VariantInternal::initialize(&prop_val, Variant::DICTIONARY); - get_edited_object()->set(get_edited_property(), prop_val); + emit_changed(get_edited_property(), prop_val); } get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed()); diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h index b1bf45f1b7..dae0fc52a6 100644 --- a/editor/editor_properties_array_dict.h +++ b/editor/editor_properties_array_dict.h @@ -135,6 +135,8 @@ class EditorPropertyArray : public EditorProperty { void _reorder_button_up(); void _create_new_property_slot(); + Node *get_base_node(); + protected: Ref<EditorPropertyArrayObject> object; diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 1cb71aa933..eee589489d 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -615,6 +615,13 @@ void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<Strin } bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const { + { + const ObjectID source_picker = p_drag_data.get("source_picker", ObjectID()); + if (source_picker == get_instance_id()) { + return false; + } + } + if (base_type.is_empty()) { return true; } @@ -670,7 +677,9 @@ bool EditorResourcePicker::_is_type_valid(const String &p_type_name, const HashS Variant EditorResourcePicker::get_drag_data_fw(const Point2 &p_point, Control *p_from) { if (edited_resource.is_valid()) { - return EditorNode::get_singleton()->drag_resource(edited_resource, p_from); + Dictionary drag_data = EditorNode::get_singleton()->drag_resource(edited_resource, p_from); + drag_data["source_picker"] = get_instance_id(); + return drag_data; } return Variant(); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 4521f4d3ff..233f20a8b3 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -576,9 +576,9 @@ void FileSystemDock::_notification(int p_what) { if ((String(dd["favorite"]) == "all")) { tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN); } - } else if ((String(dd["type"]) == "files") || (String(dd["type"]) == "files_and_dirs") || (String(dd["type"]) == "resource")) { + } else if ((String(dd["type"]) == "files") || (String(dd["type"]) == "files_and_dirs")) { tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM | Tree::DROP_MODE_INBETWEEN); - } else if ((String(dd["type"]) == "nodes")) { + } else if ((String(dd["type"]) == "nodes") || (String(dd["type"]) == "resource")) { holding_branch = true; TreeItem *item = tree->get_next_selected(tree->get_root()); while (item) { @@ -1561,10 +1561,42 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin } void FileSystemDock::_update_resource_paths_after_move(const HashMap<String, String> &p_renames, const HashMap<String, ResourceUID::ID> &p_uids) const { - // Update the paths in ResourceUID, so that UIDs remain valid. - for (const KeyValue<String, ResourceUID::ID> &pair : p_uids) { - if (p_renames.has(pair.key)) { - ResourceUID::get_singleton()->set_id(pair.value, p_renames[pair.key]); + for (const KeyValue<String, String> &pair : p_renames) { + // Update UID path. + const String &old_path = pair.key; + const String &new_path = pair.value; + + const HashMap<String, ResourceUID::ID>::ConstIterator I = p_uids.find(old_path); + if (I) { + ResourceUID::get_singleton()->set_id(I->value, new_path); + } + + ScriptServer::remove_global_class_by_path(old_path); + + int index = -1; + EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->find_file(old_path, &index); + + if (!efd || index < 0) { + // The file was removed. + continue; + } + + // Update paths for global classes. + if (!efd->get_file_script_class_name(index).is_empty()) { + String lang; + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + if (ScriptServer::get_language(i)->handles_global_class_type(efd->get_file_type(index))) { + lang = ScriptServer::get_language(i)->get_name(); + break; + } + } + if (lang.is_empty()) { + continue; // No language found that can handle this global class. + } + + ScriptServer::add_global_class(efd->get_file_script_class_name(index), efd->get_file_script_class_extends(index), lang, new_path); + EditorNode::get_editor_data().script_class_set_icon_path(efd->get_file_script_class_name(index), efd->get_file_script_class_icon_path(index)); + EditorNode::get_editor_data().script_class_set_name(new_path, efd->get_file_script_class_name(index)); } } @@ -1583,10 +1615,13 @@ void FileSystemDock::_update_resource_paths_after_move(const HashMap<String, Str if (p_renames.has(base_path)) { base_path = p_renames[base_path]; + r->set_path(base_path + extra_path); } - - r->set_path(base_path + extra_path); } + + ScriptServer::save_global_classes(); + EditorNode::get_editor_data().script_class_save_icon_paths(); + EditorFileSystem::get_singleton()->emit_signal(SNAME("script_classes_updated")); } void FileSystemDock::_update_dependencies_after_move(const HashMap<String, String> &p_renames, const HashSet<String> &p_file_owners) const { @@ -1710,6 +1745,13 @@ void FileSystemDock::_make_scene_confirm() { } void FileSystemDock::_resource_removed(const Ref<Resource> &p_resource) { + const Ref<Script> &scr = p_resource; + if (scr.is_valid()) { + ScriptServer::remove_global_class_by_path(scr->get_path()); + ScriptServer::save_global_classes(); + EditorNode::get_editor_data().script_class_save_icon_paths(); + EditorFileSystem::get_singleton()->emit_signal(SNAME("script_classes_updated")); + } emit_signal(SNAME("resource_removed"), p_resource); } @@ -2757,7 +2799,7 @@ bool FileSystemDock::can_drop_data_fw(const Point2 &p_point, const Variant &p_da String to_dir; bool favorite; _get_drag_target_folder(to_dir, favorite, p_point, p_from); - return !to_dir.is_empty(); + return !favorite; } if (drag_data.has("type") && (String(drag_data["type"]) == "files" || String(drag_data["type"]) == "files_and_dirs")) { @@ -2872,7 +2914,12 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data, Ref<Resource> res = drag_data["resource"]; String to_dir; bool favorite; + tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM); _get_drag_target_folder(to_dir, favorite, p_point, p_from); + if (to_dir.is_empty()) { + to_dir = get_current_directory(); + } + if (res.is_valid() && !to_dir.is_empty()) { EditorNode::get_singleton()->push_item(res.ptr()); EditorNode::get_singleton()->save_resource_as(res, to_dir); @@ -2918,7 +2965,11 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data, if (drag_data.has("type") && String(drag_data["type"]) == "nodes") { String to_dir; bool favorite; + tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM); _get_drag_target_folder(to_dir, favorite, p_point, p_from); + if (to_dir.is_empty()) { + to_dir = get_current_directory(); + } SceneTreeDock::get_singleton()->save_branch_to_file(to_dir); } } @@ -2931,6 +2982,7 @@ void FileSystemDock::_get_drag_target_folder(String &target, bool &target_favori if (p_from == files) { int pos = files->get_item_at_position(p_point, true); if (pos == -1) { + target = get_current_directory(); return; } @@ -3454,37 +3506,41 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) { void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) { Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid() && holding_branch) { - const int item_idx = files->get_item_at_position(mm->get_position()); + const int item_idx = files->get_item_at_position(mm->get_position(), true); + files->deselect_all(); + String fpath; if (item_idx != -1) { - files->deselect_all(); - String fpath = files->get_item_metadata(item_idx); + fpath = files->get_item_metadata(item_idx); if (fpath.ends_with("/") || fpath == "res://") { files->select(item_idx); } + } else { + fpath = get_current_directory(); + } - TreeItem *deselect_item = tree->get_next_selected(tree->get_root()); - while (deselect_item) { - deselect_item->deselect(0); - deselect_item = tree->get_next_selected(deselect_item); + TreeItem *deselect_item = tree->get_next_selected(tree->get_root()); + while (deselect_item) { + deselect_item->deselect(0); + deselect_item = tree->get_next_selected(deselect_item); + } + + // Try to select the corresponding tree item. + TreeItem *tree_item = (item_idx != -1) ? tree->get_item_with_text(files->get_item_text(item_idx)) : nullptr; + + if (tree_item) { + tree_item->select(0); + } else { + // Find parent folder. + fpath = fpath.substr(0, fpath.rfind("/") + 1); + if (fpath.size() > String("res://").size()) { + fpath = fpath.left(fpath.size() - 2); // Remove last '/'. + const int slash_idx = fpath.rfind("/"); + fpath = fpath.substr(slash_idx + 1, fpath.size() - slash_idx - 1); } - // Try to select the corresponding tree item. - TreeItem *tree_item = tree->get_item_with_text(files->get_item_text(item_idx)); + tree_item = tree->get_item_with_text(fpath); if (tree_item) { tree_item->select(0); - } else { - // Find parent folder. - fpath = fpath.substr(0, fpath.rfind("/") + 1); - if (fpath.size() > String("res://").size()) { - fpath = fpath.left(fpath.size() - 2); // Remove last '/'. - const int slash_idx = fpath.rfind("/"); - fpath = fpath.substr(slash_idx + 1, fpath.size() - slash_idx - 1); - } - - tree_item = tree->get_item_with_text(fpath); - if (tree_item) { - tree_item->select(0); - } } } } diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp index 0dd75ea033..221061f9f7 100644 --- a/editor/gui/scene_tree_editor.cpp +++ b/editor/gui/scene_tree_editor.cpp @@ -897,6 +897,14 @@ void SceneTreeEditor::_cell_multi_selected(Object *p_object, int p_cell, bool p_ } } +void SceneTreeEditor::_tree_scroll_to_item(ObjectID p_item_id) { + ERR_FAIL_NULL(tree); + TreeItem *item = Object::cast_to<TreeItem>(ObjectDB::get_instance(p_item_id)); + if (item) { + tree->scroll_to_item(item, true); + } +} + void SceneTreeEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -942,7 +950,8 @@ void SceneTreeEditor::_notification(int p_what) { if (item) { // Must wait until tree is properly sized before scrolling. - callable_mp(tree, &Tree::scroll_to_item).call_deferred(item, true); + ObjectID item_id = item->get_instance_id(); + callable_mp(this, &SceneTreeEditor::_tree_scroll_to_item).call_deferred(item_id); } } } break; diff --git a/editor/gui/scene_tree_editor.h b/editor/gui/scene_tree_editor.h index c1abdcef8b..b4d9644f16 100644 --- a/editor/gui/scene_tree_editor.h +++ b/editor/gui/scene_tree_editor.h @@ -123,6 +123,7 @@ class SceneTreeEditor : public Control { void _set_item_custom_color(TreeItem *p_item, Color p_color); void _update_node_tooltip(Node *p_node, TreeItem *p_item); void _queue_update_node_tooltip(Node *p_node, TreeItem *p_item); + void _tree_scroll_to_item(ObjectID p_item_id); void _selection_changed(); Node *get_scene_node() const; diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp index 4c02d82caa..e67f3bd596 100644 --- a/editor/plugins/bone_map_editor_plugin.cpp +++ b/editor/plugins/bone_map_editor_plugin.cpp @@ -421,7 +421,7 @@ void BoneMapper::recreate_editor() { for (int i = 0; i < len; i++) { if (profile->get_group(i) == profile->get_group_name(current_group_idx)) { - BoneMapperButton *mb = memnew(BoneMapperButton(profile->get_bone_name(i), profile->is_require(i), current_bone_idx == i)); + BoneMapperButton *mb = memnew(BoneMapperButton(profile->get_bone_name(i), profile->is_required(i), current_bone_idx == i)); mb->connect("pressed", callable_mp(this, &BoneMapper::set_current_bone_idx).bind(i), CONNECT_DEFERRED); mb->set_h_grow_direction(GROW_DIRECTION_BOTH); mb->set_v_grow_direction(GROW_DIRECTION_BOTH); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index eeb84cb79e..6c63d9ff0d 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -137,12 +137,22 @@ void EditorStandardSyntaxHighlighter::_update_cache() { } } - const Ref<Script> scr = _get_edited_resource(); - if (scr.is_valid()) { + const ScriptLanguage *scr_lang = script_language; + StringName instance_base; + + if (scr_lang == nullptr) { + const Ref<Script> scr = _get_edited_resource(); + if (scr.is_valid()) { + scr_lang = scr->get_language(); + instance_base = scr->get_instance_base_type(); + } + } + + if (scr_lang != nullptr) { /* Core types. */ const Color basetype_color = EDITOR_GET("text_editor/theme/highlighting/base_type_color"); List<String> core_types; - scr->get_language()->get_core_type_words(&core_types); + scr_lang->get_core_type_words(&core_types); for (const String &E : core_types) { highlighter->add_keyword_color(E, basetype_color); } @@ -151,9 +161,9 @@ void EditorStandardSyntaxHighlighter::_update_cache() { const Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color"); const Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color"); List<String> keywords; - scr->get_language()->get_reserved_words(&keywords); + scr_lang->get_reserved_words(&keywords); for (const String &E : keywords) { - if (scr->get_language()->is_control_flow_keyword(E)) { + if (scr_lang->is_control_flow_keyword(E)) { highlighter->add_keyword_color(E, control_flow_keyword_color); } else { highlighter->add_keyword_color(E, keyword_color); @@ -162,7 +172,6 @@ void EditorStandardSyntaxHighlighter::_update_cache() { /* Member types. */ const Color member_variable_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color"); - StringName instance_base = scr->get_instance_base_type(); if (instance_base != StringName()) { List<PropertyInfo> plist; ClassDB::get_property_list(instance_base, &plist); @@ -187,7 +196,7 @@ void EditorStandardSyntaxHighlighter::_update_cache() { /* Comments */ const Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color"); List<String> comments; - scr->get_language()->get_comment_delimiters(&comments); + scr_lang->get_comment_delimiters(&comments); for (const String &comment : comments) { String beg = comment.get_slice(" ", 0); String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String(); @@ -197,7 +206,7 @@ void EditorStandardSyntaxHighlighter::_update_cache() { /* Doc comments */ const Color doc_comment_color = EDITOR_GET("text_editor/theme/highlighting/doc_comment_color"); List<String> doc_comments; - scr->get_language()->get_doc_comment_delimiters(&doc_comments); + scr_lang->get_doc_comment_delimiters(&doc_comments); for (const String &doc_comment : doc_comments) { String beg = doc_comment.get_slice(" ", 0); String end = doc_comment.get_slice_count(" ") > 1 ? doc_comment.get_slice(" ", 1) : String(); @@ -207,7 +216,7 @@ void EditorStandardSyntaxHighlighter::_update_cache() { /* Strings */ const Color string_color = EDITOR_GET("text_editor/theme/highlighting/string_color"); List<String> strings; - scr->get_language()->get_string_delimiters(&strings); + scr_lang->get_string_delimiters(&strings); for (const String &string : strings) { String beg = string.get_slice(" ", 0); String end = string.get_slice_count(" ") > 1 ? string.get_slice(" ", 1) : String(); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 4fff724866..0252e10b43 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -78,6 +78,7 @@ class EditorStandardSyntaxHighlighter : public EditorSyntaxHighlighter { private: Ref<CodeHighlighter> highlighter; + ScriptLanguage *script_language = nullptr; // See GH-89610. public: virtual void _update_cache() override; @@ -87,6 +88,8 @@ public: virtual Ref<EditorSyntaxHighlighter> _create() const override; + void _set_script_language(ScriptLanguage *p_script_language) { script_language = p_script_language; } + EditorStandardSyntaxHighlighter() { highlighter.instantiate(); } }; diff --git a/main/main.cpp b/main/main.cpp index cf40f764cf..6a132a37ae 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -347,7 +347,6 @@ void initialize_navigation_server() { // Fall back to dummy if no default server has been registered. if (!navigation_server_3d) { - WARN_PRINT_ONCE("No NavigationServer3D implementation has been registered! Falling back to a dummy implementation: navigation features will be unavailable."); navigation_server_3d = memnew(NavigationServer3DDummy); } @@ -358,7 +357,6 @@ void initialize_navigation_server() { // Init 2D Navigation Server navigation_server_2d = NavigationServer2DManager::new_default_server(); if (!navigation_server_2d) { - WARN_PRINT_ONCE("No NavigationServer2D implementation has been registered! Falling back to a dummy implementation: navigation features will be unavailable."); navigation_server_2d = memnew(NavigationServer2DDummy); } diff --git a/methods.py b/methods.py index 7af621befc..e65d2757bd 100644 --- a/methods.py +++ b/methods.py @@ -228,7 +228,32 @@ def get_version_info(module_version_string="", silent=False): return version_info +_cleanup_env = None +_cleanup_bool = False + + def write_file_if_needed(path, string): + """Generates a file only if it doesn't already exist or the content has changed. + + Utilizes a dedicated SCons environment to ensure the files are properly removed + during cleanup; will not attempt to create files during cleanup. + + - `path` - Path to the file in question; used to create cleanup logic. + - `string` - Content to compare against an existing file. + """ + global _cleanup_env + global _cleanup_bool + + if _cleanup_env is None: + from SCons.Environment import Environment + + _cleanup_env = Environment() + _cleanup_bool = _cleanup_env.GetOption("clean") + + _cleanup_env.Clean("#", path) + if _cleanup_bool: + return + try: with open(path, "r", encoding="utf-8", newline="\n") as f: if f.read() == string: diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 6af6460b31..f67f4913c3 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -3293,6 +3293,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a if (get_function_signature(p_call, is_constructor, base_type, p_call->function_name, return_type, par_types, default_arg_count, method_flags)) { // If the method is implemented in the class hierarchy, the virtual flag will not be set for that MethodInfo and the search stops there. // Virtual check only possible for super() calls because class hierarchy is known. Node/Objects may have scripts attached we don't know of at compile-time. + p_call->is_static = method_flags.has_flag(METHOD_FLAG_STATIC); if (p_call->is_super && method_flags.has_flag(METHOD_FLAG_VIRTUAL)) { push_error(vformat(R"*(Cannot call the parent class' virtual function "%s()" because it hasn't been defined.)*", p_call->function_name), p_call); } @@ -3311,7 +3312,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a base_type.is_meta_type = false; } - if (is_self && static_context && !method_flags.has_flag(METHOD_FLAG_STATIC)) { + if (is_self && static_context && !p_call->is_static) { // Get the parent function above any lambda. GDScriptParser::FunctionNode *parent_function = parser->current_function; while (parent_function && parent_function->source_lambda) { @@ -3323,10 +3324,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a } else { push_error(vformat(R"*(Cannot call non-static function "%s()" from a static variable initializer.)*", p_call->function_name), p_call); } - } else if (!is_self && base_type.is_meta_type && !method_flags.has_flag(METHOD_FLAG_STATIC)) { + } else if (!is_self && base_type.is_meta_type && !p_call->is_static) { base_type.is_meta_type = false; // For `to_string()`. push_error(vformat(R"*(Cannot call non-static function "%s()" on the class "%s" directly. Make an instance instead.)*", p_call->function_name, base_type.to_string()), p_call); - } else if (is_self && !method_flags.has_flag(METHOD_FLAG_STATIC)) { + } else if (is_self && !p_call->is_static) { mark_lambda_use_self(); } diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 13ed66710c..d706c1b101 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -648,7 +648,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code // Not exact arguments, but still can use method bind call. gen->write_call_method_bind(result, self, method, arguments); } - } else if (codegen.is_static || (codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") { + } else if (call->is_static || codegen.is_static || (codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") { GDScriptCodeGenerator::Address self; self.mode = GDScriptCodeGenerator::Address::CLASS; if (is_awaited) { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index ea67f1eaff..d047fa8e46 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -498,6 +498,7 @@ public: Vector<ExpressionNode *> arguments; StringName function_name; bool is_super = false; + bool is_static = false; CallNode() { type = CALL; diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp index b0283b0c55..d11300343a 100644 --- a/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp +++ b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp @@ -84,6 +84,11 @@ void EditorSceneExporterGLTFSettings::_get_property_list(List<PropertyInfo> *p_l } } +void EditorSceneExporterGLTFSettings::_on_extension_property_list_changed() { + generate_property_list(_document); + emit_signal("property_list_changed"); +} + bool EditorSceneExporterGLTFSettings::_set_extension_setting(const String &p_name_str, const Variant &p_value) { PackedStringArray split = String(p_name_str).split("/", true, 1); if (!_config_name_to_extension_map.has(split[0])) { @@ -130,6 +135,10 @@ void EditorSceneExporterGLTFSettings::generate_property_list(Ref<GLTFDocument> p String image_format_hint_string = "None,PNG,JPEG"; // Add properties from all document extensions. for (Ref<GLTFDocumentExtension> &extension : GLTFDocument::get_all_gltf_document_extensions()) { + const Callable on_prop_changed = callable_mp(this, &EditorSceneExporterGLTFSettings::_on_extension_property_list_changed); + if (!extension->is_connected("property_list_changed", on_prop_changed)) { + extension->connect("property_list_changed", on_prop_changed); + } const String config_prefix = get_friendly_config_prefix(extension); _config_name_to_extension_map[config_prefix] = extension; // If the extension allows saving in different image formats, add to the enum. diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_settings.h b/modules/gltf/editor/editor_scene_exporter_gltf_settings.h index 6032932367..e1ce674274 100644 --- a/modules/gltf/editor/editor_scene_exporter_gltf_settings.h +++ b/modules/gltf/editor/editor_scene_exporter_gltf_settings.h @@ -48,6 +48,7 @@ protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + void _on_extension_property_list_changed(); bool _set_extension_setting(const String &p_name_str, const Variant &p_value); bool _get_extension_setting(const String &p_name_str, Variant &r_ret) const; diff --git a/modules/mbedtls/SCsub b/modules/mbedtls/SCsub index 4b8f65d8ff..04d26f9942 100644 --- a/modules/mbedtls/SCsub +++ b/modules/mbedtls/SCsub @@ -100,9 +100,9 @@ if env["builtin_mbedtls"]: thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] env_mbed_tls.Prepend(CPPPATH=["#thirdparty/mbedtls/include/"]) - env_mbed_tls.Append( - CPPDEFINES=[("MBEDTLS_CONFIG_FILE", '\\"thirdparty/mbedtls/include/godot_module_mbedtls_config.h\\"')] - ) + config_path = "thirdparty/mbedtls/include/godot_module_mbedtls_config.h" + config_path = f"<{config_path}>" if env_mbed_tls["ninja"] and env_mbed_tls.msvc else f'\\"{config_path}\\"' + env_mbed_tls.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)]) env_thirdparty = env_mbed_tls.Clone() env_thirdparty.disable_warnings() diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index bf6cab11c7..d3899c809a 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -167,8 +167,8 @@ namespace GodotTools public void ShowConfirmCreateSlnDialog() { - _confirmCreateSlnDialog.Title = "C# solution already exists. This will override the existing C# project file, any manual changes will be lost.".TTR(); - _confirmCreateSlnDialog.DialogText = "Create C# solution".TTR(); + _confirmCreateSlnDialog.Title = "Create C# solution".TTR(); + _confirmCreateSlnDialog.DialogText = "C# solution already exists. This will override the existing C# project file, any manual changes will be lost.".TTR(); EditorInterface.Singleton.PopupDialogCentered(_confirmCreateSlnDialog); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs index ef3c9c79d4..7a88fea5f1 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs @@ -207,7 +207,7 @@ namespace Godot foreach (FieldInfo field in fields) { - Type fieldType = field.GetType(); + Type fieldType = field.FieldType; Variant.Type variantType = GD.TypeToVariantType(fieldType); @@ -216,7 +216,7 @@ namespace Godot static byte[] VarToBytes(in godot_variant var) { - NativeFuncs.godotsharp_var_to_bytes(var, false.ToGodotBool(), out var varBytes); + NativeFuncs.godotsharp_var_to_bytes(var, godot_bool.True, out var varBytes); using (varBytes) return Marshaling.ConvertNativePackedByteArrayToSystemArray(varBytes); } @@ -483,7 +483,7 @@ namespace Godot if (fieldInfo != null) { - var variantValue = GD.BytesToVar(valueBuffer); + var variantValue = GD.BytesToVarWithObjects(valueBuffer); object? managedValue = RuntimeTypeConversionHelper.ConvertToObjectOfType( (godot_variant)variantValue.NativeVar, fieldInfo.FieldType); fieldInfo.SetValue(recreatedTarget, managedValue); @@ -799,7 +799,7 @@ namespace Godot return func(variant); if (typeof(GodotObject).IsAssignableFrom(type)) - return Convert.ChangeType(VariantUtils.ConvertTo<GodotObject>(variant), type, CultureInfo.InvariantCulture); + return VariantUtils.ConvertTo<GodotObject>(variant); if (typeof(GodotObject[]).IsAssignableFrom(type)) { @@ -818,7 +818,7 @@ namespace Godot } using var godotArray = NativeFuncs.godotsharp_variant_as_array(variant); - return Convert.ChangeType(ConvertToSystemArrayOfGodotObject(godotArray, type), type, CultureInfo.InvariantCulture); + return ConvertToSystemArrayOfGodotObject(godotArray, type); } if (type.IsEnum) diff --git a/modules/navigation/2d/nav_mesh_generator_2d.cpp b/modules/navigation/2d/nav_mesh_generator_2d.cpp index 069cc0f4a8..0738a102eb 100644 --- a/modules/navigation/2d/nav_mesh_generator_2d.cpp +++ b/modules/navigation/2d/nav_mesh_generator_2d.cpp @@ -575,8 +575,6 @@ void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygo return; } - int tilemap_layer = 0; // only main tile map layer is supported - Ref<TileSet> tile_set = tilemap->get_tileset(); if (!tile_set.is_valid()) { return; @@ -589,77 +587,115 @@ void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygo return; } - const Transform2D tilemap_xform = p_source_geometry_data->root_node_transform * tilemap->get_global_transform(); - TypedArray<Vector2i> used_cells = tilemap->get_used_cells(tilemap_layer); + HashSet<Vector2i> cells_with_navigation_polygon; + HashSet<Vector2i> cells_with_collision_polygon; - for (int used_cell_index = 0; used_cell_index < used_cells.size(); used_cell_index++) { - const Vector2i &cell = used_cells[used_cell_index]; + const Transform2D tilemap_xform = p_source_geometry_data->root_node_transform * tilemap->get_global_transform(); - const TileData *tile_data = tilemap->get_cell_tile_data(tilemap_layer, cell, false); - if (tile_data == nullptr) { - continue; - } +#ifdef DEBUG_ENABLED + int error_print_counter = 0; + int error_print_max = 10; +#endif // DEBUG_ENABLED - // Transform flags. - const int alternative_id = tilemap->get_cell_alternative_tile(tilemap_layer, cell, false); - bool flip_h = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H); - bool flip_v = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V); - bool transpose = (alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE); + for (int tilemap_layer = 0; tilemap_layer < tilemap->get_layers_count(); tilemap_layer++) { + TypedArray<Vector2i> used_cells = tilemap->get_used_cells(tilemap_layer); - Transform2D tile_transform; - tile_transform.set_origin(tilemap->map_to_local(cell)); + for (int used_cell_index = 0; used_cell_index < used_cells.size(); used_cell_index++) { + const Vector2i &cell = used_cells[used_cell_index]; - const Transform2D tile_transform_offset = tilemap_xform * tile_transform; + const TileData *tile_data = tilemap->get_cell_tile_data(tilemap_layer, cell, false); + if (tile_data == nullptr) { + continue; + } - if (navigation_layers_count > 0) { - Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(tilemap_layer, flip_h, flip_v, transpose); - if (navigation_polygon.is_valid()) { - for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) { - const Vector<Vector2> &navigation_polygon_outline = navigation_polygon->get_outline(outline_index); - if (navigation_polygon_outline.size() == 0) { - continue; + // Transform flags. + const int alternative_id = tilemap->get_cell_alternative_tile(tilemap_layer, cell, false); + bool flip_h = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H); + bool flip_v = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V); + bool transpose = (alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE); + + Transform2D tile_transform; + tile_transform.set_origin(tilemap->map_to_local(cell)); + + const Transform2D tile_transform_offset = tilemap_xform * tile_transform; + + if (navigation_layers_count > 0) { + Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(tilemap_layer, flip_h, flip_v, transpose); + if (navigation_polygon.is_valid()) { + if (cells_with_navigation_polygon.has(cell)) { +#ifdef DEBUG_ENABLED + error_print_counter++; + if (error_print_counter <= error_print_max) { + WARN_PRINT(vformat("TileMap navigation mesh baking error. The TileMap cell key Vector2i(%s, %s) has navigation mesh from 2 or more different TileMap layers assigned. This can cause unexpected navigation mesh baking results. The duplicated cell data was ignored.", cell.x, cell.y)); + } +#endif // DEBUG_ENABLED + } else { + cells_with_navigation_polygon.insert(cell); + + for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) { + const Vector<Vector2> &navigation_polygon_outline = navigation_polygon->get_outline(outline_index); + if (navigation_polygon_outline.size() == 0) { + continue; + } + + Vector<Vector2> traversable_outline; + traversable_outline.resize(navigation_polygon_outline.size()); + + const Vector2 *navigation_polygon_outline_ptr = navigation_polygon_outline.ptr(); + Vector2 *traversable_outline_ptrw = traversable_outline.ptrw(); + + for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) { + traversable_outline_ptrw[traversable_outline_index] = tile_transform_offset.xform(navigation_polygon_outline_ptr[traversable_outline_index]); + } + + p_source_geometry_data->_add_traversable_outline(traversable_outline); + } } + } + } - Vector<Vector2> traversable_outline; - traversable_outline.resize(navigation_polygon_outline.size()); - - const Vector2 *navigation_polygon_outline_ptr = navigation_polygon_outline.ptr(); - Vector2 *traversable_outline_ptrw = traversable_outline.ptrw(); - - for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) { - traversable_outline_ptrw[traversable_outline_index] = tile_transform_offset.xform(navigation_polygon_outline_ptr[traversable_outline_index]); + if (physics_layers_count > 0 && (parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH) && (tile_set->get_physics_layer_collision_layer(tilemap_layer) & parsed_collision_mask)) { + if (cells_with_collision_polygon.has(cell)) { +#ifdef DEBUG_ENABLED + error_print_counter++; + if (error_print_counter <= error_print_max) { + WARN_PRINT(vformat("TileMap navigation mesh baking error. The cell key Vector2i(%s, %s) has collision polygons from 2 or more different TileMap layers assigned that all match the parsed collision mask. This can cause unexpected navigation mesh baking results. The duplicated cell data was ignored.", cell.x, cell.y)); } +#endif // DEBUG_ENABLED + } else { + cells_with_collision_polygon.insert(cell); - p_source_geometry_data->_add_traversable_outline(traversable_outline); - } - } - } + for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(tilemap_layer); collision_polygon_index++) { + PackedVector2Array collision_polygon_points = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index); + if (collision_polygon_points.size() == 0) { + continue; + } - if (physics_layers_count > 0 && (parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH) && (tile_set->get_physics_layer_collision_layer(tilemap_layer) & parsed_collision_mask)) { - for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(tilemap_layer); collision_polygon_index++) { - PackedVector2Array collision_polygon_points = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index); - if (collision_polygon_points.size() == 0) { - continue; - } + if (flip_h || flip_v || transpose) { + collision_polygon_points = TileData::get_transformed_vertices(collision_polygon_points, flip_h, flip_v, transpose); + } - if (flip_h || flip_v || transpose) { - collision_polygon_points = TileData::get_transformed_vertices(collision_polygon_points, flip_h, flip_v, transpose); - } + Vector<Vector2> obstruction_outline; + obstruction_outline.resize(collision_polygon_points.size()); - Vector<Vector2> obstruction_outline; - obstruction_outline.resize(collision_polygon_points.size()); + const Vector2 *collision_polygon_points_ptr = collision_polygon_points.ptr(); + Vector2 *obstruction_outline_ptrw = obstruction_outline.ptrw(); - const Vector2 *collision_polygon_points_ptr = collision_polygon_points.ptr(); - Vector2 *obstruction_outline_ptrw = obstruction_outline.ptrw(); + for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) { + obstruction_outline_ptrw[obstruction_outline_index] = tile_transform_offset.xform(collision_polygon_points_ptr[obstruction_outline_index]); + } - for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) { - obstruction_outline_ptrw[obstruction_outline_index] = tile_transform_offset.xform(collision_polygon_points_ptr[obstruction_outline_index]); + p_source_geometry_data->_add_obstruction_outline(obstruction_outline); + } } - - p_source_geometry_data->_add_obstruction_outline(obstruction_outline); } } } +#ifdef DEBUG_ENABLED + if (error_print_counter > error_print_max) { + ERR_PRINT(vformat("TileMap navigation mesh baking error. A total of %s cells with navigation or collision polygons from 2 or more different TileMap layers overlap. This can cause unexpected navigation mesh baking results. The duplicated cell data was ignored.", error_print_counter)); + } +#endif // DEBUG_ENABLED } void NavMeshGenerator2D::generator_parse_navigationobstacle_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node) { diff --git a/modules/openxr/util.h b/modules/openxr/util.h index 7488b5cf8e..4c611d6f4a 100644 --- a/modules/openxr/util.h +++ b/modules/openxr/util.h @@ -34,21 +34,23 @@ #define UNPACK(...) __VA_ARGS__ #define INIT_XR_FUNC_V(openxr_api, name) \ - do { \ + if constexpr (true) { \ XrResult get_instance_proc_addr_result; \ get_instance_proc_addr_result = openxr_api->get_instance_proc_addr(#name, (PFN_xrVoidFunction *)&name##_ptr); \ ERR_FAIL_COND_V(XR_FAILED(get_instance_proc_addr_result), false); \ - } while (0) + } else \ + ((void)0) #define EXT_INIT_XR_FUNC_V(name) INIT_XR_FUNC_V(OpenXRAPI::get_singleton(), name) #define OPENXR_API_INIT_XR_FUNC_V(name) INIT_XR_FUNC_V(this, name) #define INIT_XR_FUNC(openxr_api, name) \ - do { \ + if constexpr (true) { \ XrResult get_instance_proc_addr_result; \ get_instance_proc_addr_result = openxr_api->get_instance_proc_addr(#name, (PFN_xrVoidFunction *)&name##_ptr); \ ERR_FAIL_COND(XR_FAILED(get_instance_proc_addr_result)); \ - } while (0) + } else \ + ((void)0) #define EXT_INIT_XR_FUNC(name) INIT_XR_FUNC(OpenXRAPI::get_singleton(), name) #define OPENXR_API_INIT_XR_FUNC(name) INIT_XR_FUNC(this, name) @@ -59,16 +61,18 @@ #define EXT_TRY_INIT_XR_FUNC(name) TRY_INIT_XR_FUNC(OpenXRAPI::get_singleton(), name) #define OPENXR_TRY_API_INIT_XR_FUNC(name) TRY_INIT_XR_FUNC(this, name) #define GDEXTENSION_INIT_XR_FUNC(name) \ - do { \ + if constexpr (true) { \ name##_ptr = reinterpret_cast<PFN_##name>(get_openxr_api()->get_instance_proc_addr(#name)); \ ERR_FAIL_NULL(name##_ptr); \ - } while (0) + } else \ + ((void)0) #define GDEXTENSION_INIT_XR_FUNC_V(name) \ - do { \ + if constexpr (true) { \ name##_ptr = reinterpret_cast<PFN_##name>(get_openxr_api()->get_instance_proc_addr(#name)); \ ERR_FAIL_NULL_V(name##_ptr, false); \ - } while (0) + } else \ + ((void)0) #define EXT_PROTO_XRRESULT_FUNC1(func_name, arg1_type, arg1) \ PFN_##func_name func_name##_ptr = nullptr; \ diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index f5174d7d46..c092fd7511 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -1432,8 +1432,25 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f #endif if (!p_font_data->face_init) { - // Get style flags and name. - if (fd->face->family_name != nullptr) { + // When a font does not provide a `family_name`, FreeType tries to synthesize one based on other names. + // FreeType automatically converts non-ASCII characters to "?" in the synthesized name. + // To avoid that behavior, use the format-specific name directly if available. + hb_face_t *hb_face = hb_font_get_face(fd->hb_handle); + unsigned int num_entries = 0; + const hb_ot_name_entry_t *names = hb_ot_name_list_names(hb_face, &num_entries); + const hb_language_t english = hb_language_from_string("en", -1); + for (unsigned int i = 0; i < num_entries; i++) { + if (names[i].name_id != HB_OT_NAME_ID_FONT_FAMILY) { + continue; + } + if (!p_font_data->font_name.is_empty() && names[i].language != english) { + continue; + } + unsigned int text_size = hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, nullptr, nullptr) + 1; + p_font_data->font_name.resize(text_size); + hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, &text_size, (uint32_t *)p_font_data->font_name.ptrw()); + } + if (p_font_data->font_name.is_empty() && fd->face->family_name != nullptr) { p_font_data->font_name = String::utf8((const char *)fd->face->family_name); } if (fd->face->style_name != nullptr) { @@ -1452,7 +1469,6 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f p_font_data->style_flags.set_flag(FONT_FIXED_WIDTH); } - hb_face_t *hb_face = hb_font_get_face(fd->hb_handle); // Get supported scripts from OpenType font data. p_font_data->supported_scripts.clear(); unsigned int count = hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, nullptr, nullptr); @@ -6976,6 +6992,34 @@ String TextServerAdvanced::_string_to_lower(const String &p_string, const String return String::utf16(lower.ptr(), len); } +String TextServerAdvanced::_string_to_title(const String &p_string, const String &p_language) const { +#ifndef ICU_STATIC_DATA + if (!icu_data_loaded) { + return p_string.capitalize(); + } +#endif + + if (p_string.is_empty()) { + return p_string; + } + const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; + + // Convert to UTF-16. + Char16String utf16 = p_string.utf16(); + + Vector<char16_t> upper; + UErrorCode err = U_ZERO_ERROR; + int32_t len = u_strToTitle(nullptr, 0, utf16.get_data(), -1, nullptr, lang.ascii().get_data(), &err); + ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err)); + upper.resize(len); + err = U_ZERO_ERROR; + u_strToTitle(upper.ptrw(), len, utf16.get_data(), -1, nullptr, lang.ascii().get_data(), &err); + ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err)); + + // Convert back to UTF-32. + return String::utf16(upper.ptr(), len); +} + PackedInt32Array TextServerAdvanced::_string_get_word_breaks(const String &p_string, const String &p_language, int64_t p_chars_per_line) const { const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; // Convert to UTF-16. diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 154fe670eb..160eb27528 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -991,6 +991,7 @@ public: MODBIND2RC(String, string_to_upper, const String &, const String &); MODBIND2RC(String, string_to_lower, const String &, const String &); + MODBIND2RC(String, string_to_title, const String &, const String &); MODBIND0(cleanup); diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 302bd677fe..c3f62d7324 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -71,8 +71,10 @@ using namespace godot; #endif #endif -#ifdef MODULE_SVG_ENABLED #ifdef MODULE_FREETYPE_ENABLED +#include FT_SFNT_NAMES_H +#include FT_TRUETYPE_IDS_H +#ifdef MODULE_SVG_ENABLED #include "thorvg_svg_in_ot.h" #endif #endif @@ -857,8 +859,37 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale; if (!p_font_data->face_init) { - // Get style flags and name. - if (fd->face->family_name != nullptr) { + // When a font does not provide a `family_name`, FreeType tries to synthesize one based on other names. + // FreeType automatically converts non-ASCII characters to "?" in the synthesized name. + // To avoid that behavior, use the format-specific name directly if available. + if (FT_IS_SFNT(fd->face)) { + int name_count = FT_Get_Sfnt_Name_Count(fd->face); + for (int i = 0; i < name_count; i++) { + FT_SfntName sfnt_name; + if (FT_Get_Sfnt_Name(fd->face, i, &sfnt_name) != 0) { + continue; + } + if (sfnt_name.name_id != TT_NAME_ID_FONT_FAMILY && sfnt_name.name_id != TT_NAME_ID_TYPOGRAPHIC_FAMILY) { + continue; + } + if (!p_font_data->font_name.is_empty() && sfnt_name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES) { + continue; + } + + switch (sfnt_name.platform_id) { + case TT_PLATFORM_APPLE_UNICODE: { + p_font_data->font_name.parse_utf16((const char16_t *)sfnt_name.string, sfnt_name.string_len / 2, false); + } break; + + case TT_PLATFORM_MICROSOFT: { + if (sfnt_name.encoding_id == TT_MS_ID_UNICODE_CS || sfnt_name.encoding_id == TT_MS_ID_UCS_4) { + p_font_data->font_name.parse_utf16((const char16_t *)sfnt_name.string, sfnt_name.string_len / 2, false); + } + } break; + } + } + } + if (p_font_data->font_name.is_empty() && fd->face->family_name != nullptr) { p_font_data->font_name = String::utf8((const char *)fd->face->family_name); } if (fd->face->style_name != nullptr) { @@ -4439,6 +4470,10 @@ String TextServerFallback::_string_to_lower(const String &p_string, const String return p_string.to_lower(); } +String TextServerFallback::_string_to_title(const String &p_string, const String &p_language) const { + return p_string.capitalize(); +} + PackedInt32Array TextServerFallback::_string_get_word_breaks(const String &p_string, const String &p_language, int64_t p_chars_per_line) const { PackedInt32Array ret; diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index 0db1f7318f..9fd5af8b51 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -848,6 +848,7 @@ public: MODBIND2RC(String, string_to_upper, const String &, const String &); MODBIND2RC(String, string_to_lower, const String &, const String &); + MODBIND2RC(String, string_to_title, const String &, const String &); MODBIND0(cleanup); diff --git a/modules/upnp/doc_classes/UPNPDevice.xml b/modules/upnp/doc_classes/UPNPDevice.xml index a70ae1b9cc..82ac179611 100644 --- a/modules/upnp/doc_classes/UPNPDevice.xml +++ b/modules/upnp/doc_classes/UPNPDevice.xml @@ -71,7 +71,7 @@ <constant name="IGD_STATUS_HTTP_EMPTY" value="2" enum="IGDStatus"> Empty HTTP response. </constant> - <constant name="IGD_STATUS_NO_URLS" value="3" enum="IGDStatus"> + <constant name="IGD_STATUS_NO_URLS" value="3" enum="IGDStatus" deprecated="This value is no longer used."> Returned response contained no URLs. </constant> <constant name="IGD_STATUS_NO_IGD" value="4" enum="IGDStatus"> @@ -86,7 +86,7 @@ <constant name="IGD_STATUS_INVALID_CONTROL" value="7" enum="IGDStatus"> Invalid control. </constant> - <constant name="IGD_STATUS_MALLOC_ERROR" value="8" enum="IGDStatus"> + <constant name="IGD_STATUS_MALLOC_ERROR" value="8" enum="IGDStatus" deprecated="This value is no longer used."> Memory allocation error. </constant> <constant name="IGD_STATUS_UNKNOWN_ERROR" value="9" enum="IGDStatus"> diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp index 2812f37eb2..95453c1ecd 100644 --- a/modules/upnp/upnp.cpp +++ b/modules/upnp/upnp.cpp @@ -121,33 +121,20 @@ void UPNP::parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist) { return; } - struct UPNPUrls *urls = (UPNPUrls *)malloc(sizeof(struct UPNPUrls)); - - if (!urls) { - dev->set_igd_status(UPNPDevice::IGD_STATUS_MALLOC_ERROR); - return; - } - + struct UPNPUrls urls = {}; struct IGDdatas data; - memset(urls, 0, sizeof(struct UPNPUrls)); - parserootdesc(xml, size, &data); free(xml); xml = nullptr; - GetUPNPUrls(urls, &data, dev->get_description_url().utf8().get_data(), 0); - - if (!urls) { - dev->set_igd_status(UPNPDevice::IGD_STATUS_NO_URLS); - return; - } + GetUPNPUrls(&urls, &data, dev->get_description_url().utf8().get_data(), 0); char addr[16]; - int i = UPNP_GetValidIGD(devlist, urls, &data, (char *)&addr, 16); + int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16); if (i != 1) { - FreeUPNPUrls(urls); + FreeUPNPUrls(&urls); switch (i) { case 0: @@ -165,18 +152,18 @@ void UPNP::parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist) { } } - if (urls->controlURL[0] == '\0') { - FreeUPNPUrls(urls); + if (urls.controlURL[0] == '\0') { + FreeUPNPUrls(&urls); dev->set_igd_status(UPNPDevice::IGD_STATUS_INVALID_CONTROL); return; } - dev->set_igd_control_url(urls->controlURL); + dev->set_igd_control_url(urls.controlURL); dev->set_igd_service_type(data.first.servicetype); dev->set_igd_our_addr(addr); dev->set_igd_status(UPNPDevice::IGD_STATUS_OK); - FreeUPNPUrls(urls); + FreeUPNPUrls(&urls); } int UPNP::upnp_result(int in) { diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 64ef1397ba..19e215bfaf 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -1920,7 +1920,15 @@ bool EditorExportPlatformAndroid::get_export_option_visibility(const EditorExpor bool advanced_options_enabled = p_preset->are_advanced_options_enabled(); if (p_option == "graphics/opengl_debug" || p_option == "command_line/extra_args" || - p_option == "permissions/custom_permissions") { + p_option == "permissions/custom_permissions" || + p_option == "gradle_build/compress_native_libraries" || + p_option == "package/retain_data_on_uninstall" || + p_option == "package/exclude_from_recents" || + p_option == "package/show_in_app_library" || + p_option == "package/show_as_launcher_app" || + p_option == "apk_expansion/enable" || + p_option == "apk_expansion/SALT" || + p_option == "apk_expansion/public_key") { return advanced_options_enabled; } if (p_option == "gradle_build/gradle_build_directory" || p_option == "gradle_build/android_source_template") { diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index e540b7617f..2e007b5efc 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -3709,63 +3709,18 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA return MA_NOACTIVATE; // Do not activate, but process mouse messages. } } break; - case WM_SETFOCUS: { - windows[window_id].window_has_focus = true; - last_focused_window = window_id; - - // Restore mouse mode. - _set_mouse_mode_impl(mouse_mode); - - if (!app_focused) { - if (OS::get_singleton()->get_main_loop()) { - OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN); - } - app_focused = true; - } - } break; - case WM_KILLFOCUS: { - windows[window_id].window_has_focus = false; - last_focused_window = window_id; - - // Release capture unconditionally because it can be set due to dragging, in addition to captured mode. - ReleaseCapture(); - - // Release every touch to avoid sticky points. - for (const KeyValue<int, Vector2> &E : touch_state) { - _touch_event(window_id, false, E.value.x, E.value.y, E.key); - } - touch_state.clear(); - - bool self_steal = false; - HWND new_hwnd = (HWND)wParam; - if (IsWindow(new_hwnd)) { - self_steal = true; + case WM_ACTIVATEAPP: { + bool new_app_focused = (bool)wParam; + if (new_app_focused == app_focused) { + break; } - - if (!self_steal) { - if (OS::get_singleton()->get_main_loop()) { - OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT); - } - app_focused = false; + app_focused = new_app_focused; + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(app_focused ? MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN : MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT); } } break; - case WM_ACTIVATE: { // Watch for window activate message. - if (!windows[window_id].window_focused) { - _process_activate_event(window_id, wParam, lParam); - } else { - windows[window_id].saved_wparam = wParam; - windows[window_id].saved_lparam = lParam; - - // Run a timer to prevent event catching warning if the focused window is closing. - windows[window_id].focus_timer_id = SetTimer(windows[window_id].hWnd, 2, USER_TIMER_MINIMUM, (TIMERPROC) nullptr); - } - if (wParam != WA_INACTIVE) { - track_mouse_leave_event(hWnd); - - if (!IsIconic(hWnd)) { - SetFocus(hWnd); - } - } + case WM_ACTIVATE: { + _process_activate_event(window_id, wParam, lParam); return 0; // Return to the message loop. } break; case WM_GETMINMAXINFO: { @@ -3864,9 +3819,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } break; case WM_CLOSE: // Did we receive a close message? { - if (windows[window_id].focus_timer_id != 0U) { - KillTimer(windows[window_id].hWnd, windows[window_id].focus_timer_id); - } _send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST); return 0; // Jump back. @@ -4625,10 +4577,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (!Main::is_iterating()) { Main::iteration(); } - } else if (wParam == windows[window_id].focus_timer_id) { - _process_activate_event(window_id, windows[window_id].saved_wparam, windows[window_id].saved_lparam); - KillTimer(windows[window_id].hWnd, wParam); - windows[window_id].focus_timer_id = 0U; } } break; case WM_SYSKEYUP: @@ -4834,20 +4782,25 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { void DisplayServerWindows::_process_activate_event(WindowID p_window_id, WPARAM wParam, LPARAM lParam) { if (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) { - _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_IN); - windows[p_window_id].window_focused = true; + last_focused_window = p_window_id; alt_mem = false; control_mem = false; shift_mem = false; gr_mem = false; - - // Restore mouse mode. _set_mouse_mode_impl(mouse_mode); + if (!IsIconic(windows[p_window_id].hWnd)) { + SetFocus(windows[p_window_id].hWnd); + } + windows[p_window_id].window_focused = true; + _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_IN); } else { // WM_INACTIVE. Input::get_singleton()->release_pressed_events(); - _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_OUT); - windows[p_window_id].window_focused = false; + track_mouse_leave_event(windows[p_window_id].hWnd); + // Release capture unconditionally because it can be set due to dragging, in addition to captured mode. + ReleaseCapture(); alt_mem = false; + windows[p_window_id].window_focused = false; + _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_OUT); } if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[p_window_id].wtctx) { diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 1191f22968..cb209948b1 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -402,7 +402,6 @@ class DisplayServerWindows : public DisplayServer { // Timers. uint32_t move_timer_id = 0U; - uint32_t focus_timer_id = 0U; HANDLE wtctx; LOGCONTEXTW wtlc; diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index e9bab274c6..4b866fc6de 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -627,7 +627,7 @@ void Camera2D::align() { } void Camera2D::set_position_smoothing_speed(real_t p_speed) { - position_smoothing_speed = p_speed; + position_smoothing_speed = MAX(0, p_speed); _update_process_internal_for_smoothing(); } @@ -636,7 +636,7 @@ real_t Camera2D::get_position_smoothing_speed() const { } void Camera2D::set_rotation_smoothing_speed(real_t p_speed) { - rotation_smoothing_speed = p_speed; + rotation_smoothing_speed = MAX(0, p_speed); _update_process_internal_for_smoothing(); } diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp index caabb4225f..8415fb38cb 100644 --- a/scene/3d/decal.cpp +++ b/scene/3d/decal.cpp @@ -231,7 +231,7 @@ void Decal::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "texture_emission", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_EMISSION); ADD_GROUP("Parameters", ""); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_emission_energy", "get_emission_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_emission_energy", "get_emission_energy"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "albedo_mix", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_albedo_mix", "get_albedo_mix"); // A Normal Fade of 1.0 causes the decal to be invisible even if fully perpendicular to a surface. diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 17dfbb4516..566801c9f7 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -1055,7 +1055,6 @@ void Skeleton3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_rest_only"), "set_show_rest_only", "is_show_rest_only"); ADD_GROUP("Modifier", "modifier_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "modifier_reset_on_save", PROPERTY_HINT_NONE, ""), "set_modifier_reset_on_save_enabled", "is_modifier_reset_on_save_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "modifier_callback_mode_process", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_modifier_callback_mode_process", "get_modifier_callback_mode_process"); ADD_SIGNAL(MethodInfo("pose_updated")); diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp index 757ac68e46..01e1de8f23 100644 --- a/scene/animation/animation_mixer.cpp +++ b/scene/animation/animation_mixer.cpp @@ -689,14 +689,19 @@ bool AnimationMixer::_update_caches() { track_value->init_value = anim->track_get_key_value(i, 0); track_value->init_value.zero(); + track_value->init_use_continuous = callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS; + // Can't interpolate them, need to convert. track_value->is_variant_interpolatable = Animation::is_variant_interpolatable(track_value->init_value); // If there is a Reset Animation, it takes precedence by overwriting. if (has_reset_anim) { int rt = reset_anim->find_track(path, track_src_type); - if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) { - track_value->init_value = track_src_type == Animation::TYPE_VALUE ? reset_anim->track_get_key_value(rt, 0) : (reset_anim->track_get_key_value(rt, 0).operator Array())[0]; + if (rt >= 0) { + track_value->init_use_continuous = track_value->init_use_continuous || (reset_anim->value_track_get_update_mode(rt) != Animation::UPDATE_DISCRETE); // Take precedence Force Continuous. + if (reset_anim->track_get_key_count(rt) > 0) { + track_value->init_value = track_src_type == Animation::TYPE_VALUE ? reset_anim->track_get_key_value(rt, 0) : (reset_anim->track_get_key_value(rt, 0).operator Array())[0]; + } } } @@ -996,6 +1001,7 @@ void AnimationMixer::_blend_init() { TrackCacheValue *t = static_cast<TrackCacheValue *>(track); t->value = Animation::cast_to_blendwise(t->init_value); t->element_size = t->init_value.is_string() ? (real_t)(t->init_value.operator String()).length() : 0; + t->use_continuous = t->init_use_continuous; t->use_discrete = false; } break; case Animation::TYPE_AUDIO: { @@ -1415,6 +1421,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { bool is_discrete = is_value && a->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE; bool force_continuous = callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS; if (t->is_variant_interpolatable && (!is_discrete || force_continuous)) { + t->use_continuous = true; Variant value = is_value ? a->value_track_interpolate(i, time, is_discrete && force_continuous ? backward : false) : Variant(a->bezier_track_interpolate(i, time)); value = post_process_key_value(a, i, value, t->object_id); if (value == Variant()) { @@ -1727,7 +1734,7 @@ void AnimationMixer::_blend_apply() { case Animation::TYPE_VALUE: { TrackCacheValue *t = static_cast<TrackCacheValue *>(track); - if (!t->is_variant_interpolatable || (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT && t->use_discrete)) { + if (!t->is_variant_interpolatable || !t->use_continuous || (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT && t->use_discrete)) { break; // Don't overwrite the value set by UPDATE_DISCRETE. } @@ -1969,6 +1976,7 @@ void AnimationMixer::_build_backup_track_cache() { if (t_obj) { t->value = Animation::cast_to_blendwise(t_obj->get_indexed(t->subpath)); } + t->use_continuous = true; t->use_discrete = false; if (t->init_value.is_array()) { t->element_size = MAX(t->element_size.operator int(), (t->value.operator Array()).size()); diff --git a/scene/animation/animation_mixer.h b/scene/animation/animation_mixer.h index ed291bfe63..b7898cffc9 100644 --- a/scene/animation/animation_mixer.h +++ b/scene/animation/animation_mixer.h @@ -222,9 +222,14 @@ protected: Variant init_value; Variant value; Vector<StringName> subpath; + + // TODO: There are many boolean, can be packed into one integer. + bool init_use_continuous = false; + bool use_continuous = false; bool use_discrete = false; bool is_using_angle = false; bool is_variant_interpolatable = true; + Variant element_size; TrackCacheValue(const TrackCacheValue &p_other) : @@ -232,6 +237,8 @@ protected: init_value(p_other.init_value), value(p_other.value), subpath(p_other.subpath), + init_use_continuous(p_other.init_use_continuous), + use_continuous(p_other.use_continuous), use_discrete(p_other.use_discrete), is_using_angle(p_other.is_using_angle), is_variant_interpolatable(p_other.is_variant_interpolatable), diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 62bb14459d..f1a8c2f6ae 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -241,10 +241,6 @@ PackedStringArray Control::get_configuration_warnings() const { warnings.push_back(RTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\".")); } - if (get_z_index() != 0) { - warnings.push_back(RTR("Changing the Z index of a control only affects the drawing order, not the input event handling order.")); - } - return warnings; } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 11c200064e..beb2583b61 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -3780,7 +3780,7 @@ void Node::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "process_thread_messages", PROPERTY_HINT_FLAGS, "Process,Physics Process"), "set_process_thread_messages", "get_process_thread_messages"); ADD_GROUP("Physics Interpolation", "physics_interpolation_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_interpolation_mode", PROPERTY_HINT_ENUM, "Inherit,Off,On"), "set_physics_interpolation_mode", "get_physics_interpolation_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_interpolation_mode", PROPERTY_HINT_ENUM, "Inherit,On,Off"), "set_physics_interpolation_mode", "get_physics_interpolation_mode"); ADD_GROUP("Auto Translate", "auto_translate_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "auto_translate_mode", PROPERTY_HINT_ENUM, "Inherit,Always,Disabled"), "set_auto_translate_mode", "get_auto_translate_mode"); @@ -3833,7 +3833,7 @@ Node::Node() { data.unhandled_input = false; data.unhandled_key_input = false; - data.physics_interpolated = false; + data.physics_interpolated = true; data.parent_owned = false; data.in_constructor = true; diff --git a/scene/resources/skeleton_profile.cpp b/scene/resources/skeleton_profile.cpp index 24ed480289..2c1d3d4a4c 100644 --- a/scene/resources/skeleton_profile.cpp +++ b/scene/resources/skeleton_profile.cpp @@ -68,7 +68,7 @@ bool SkeletonProfile::_set(const StringName &p_path, const Variant &p_value) { } else if (what == "group") { set_group(which, p_value); } else if (what == "require") { - set_require(which, p_value); + set_required(which, p_value); } else { return false; } @@ -113,7 +113,7 @@ bool SkeletonProfile::_get(const StringName &p_path, Variant &r_ret) const { } else if (what == "group") { r_ret = get_group(which); } else if (what == "require") { - r_ret = is_require(which); + r_ret = is_required(which); } else { return false; } @@ -299,7 +299,7 @@ SkeletonProfile::TailDirection SkeletonProfile::get_tail_direction(int p_bone_id return bones[p_bone_idx].tail_direction; } -void SkeletonProfile::set_tail_direction(int p_bone_idx, const TailDirection p_tail_direction) { +void SkeletonProfile::set_tail_direction(int p_bone_idx, TailDirection p_tail_direction) { if (is_read_only) { return; } @@ -328,7 +328,7 @@ Transform3D SkeletonProfile::get_reference_pose(int p_bone_idx) const { return bones[p_bone_idx].reference_pose; } -void SkeletonProfile::set_reference_pose(int p_bone_idx, const Transform3D p_reference_pose) { +void SkeletonProfile::set_reference_pose(int p_bone_idx, const Transform3D &p_reference_pose) { if (is_read_only) { return; } @@ -342,7 +342,7 @@ Vector2 SkeletonProfile::get_handle_offset(int p_bone_idx) const { return bones[p_bone_idx].handle_offset; } -void SkeletonProfile::set_handle_offset(int p_bone_idx, const Vector2 p_handle_offset) { +void SkeletonProfile::set_handle_offset(int p_bone_idx, const Vector2 &p_handle_offset) { if (is_read_only) { return; } @@ -365,17 +365,17 @@ void SkeletonProfile::set_group(int p_bone_idx, const StringName &p_group) { emit_signal("profile_updated"); } -bool SkeletonProfile::is_require(int p_bone_idx) const { +bool SkeletonProfile::is_required(int p_bone_idx) const { ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), false); - return bones[p_bone_idx].require; + return bones[p_bone_idx].required; } -void SkeletonProfile::set_require(int p_bone_idx, const bool p_require) { +void SkeletonProfile::set_required(int p_bone_idx, bool p_required) { if (is_read_only) { return; } ERR_FAIL_INDEX(p_bone_idx, bones.size()); - bones.write[p_bone_idx].require = p_require; + bones.write[p_bone_idx].required = p_required; emit_signal("profile_updated"); } @@ -432,6 +432,9 @@ void SkeletonProfile::_bind_methods() { ClassDB::bind_method(D_METHOD("get_group", "bone_idx"), &SkeletonProfile::get_group); ClassDB::bind_method(D_METHOD("set_group", "bone_idx", "group"), &SkeletonProfile::set_group); + ClassDB::bind_method(D_METHOD("is_required", "bone_idx"), &SkeletonProfile::is_required); + ClassDB::bind_method(D_METHOD("set_required", "bone_idx", "required"), &SkeletonProfile::set_required); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "root_bone", PROPERTY_HINT_ENUM_SUGGESTION, ""), "set_root_bone", "get_root_bone"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "scale_base_bone", PROPERTY_HINT_ENUM_SUGGESTION, ""), "set_scale_base_bone", "get_scale_base_bone"); @@ -478,14 +481,14 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[1].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.75, 0); bones.write[1].handle_offset = Vector2(0.5, 0.5); bones.write[1].group = "Body"; - bones.write[1].require = true; + bones.write[1].required = true; bones.write[2].bone_name = "Spine"; bones.write[2].bone_parent = "Hips"; bones.write[2].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0); bones.write[2].handle_offset = Vector2(0.5, 0.43); bones.write[2].group = "Body"; - bones.write[2].require = true; + bones.write[2].required = true; bones.write[3].bone_name = "Chest"; bones.write[3].bone_parent = "Spine"; @@ -506,7 +509,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[5].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0); bones.write[5].handle_offset = Vector2(0.5, 0.23); bones.write[5].group = "Body"; - bones.write[5].require = false; + bones.write[5].required = false; bones.write[6].bone_name = "Head"; bones.write[6].bone_parent = "Neck"; @@ -514,7 +517,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[6].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0); bones.write[6].handle_offset = Vector2(0.5, 0.18); bones.write[6].group = "Body"; - bones.write[6].require = true; + bones.write[6].required = true; bones.write[7].bone_name = "LeftEye"; bones.write[7].bone_parent = "Head"; @@ -539,21 +542,21 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[10].reference_pose = Transform3D(0, 1, 0, 0, 0, 1, 1, 0, 0, 0.05, 0.1, 0); bones.write[10].handle_offset = Vector2(0.55, 0.235); bones.write[10].group = "Body"; - bones.write[10].require = true; + bones.write[10].required = true; bones.write[11].bone_name = "LeftUpperArm"; bones.write[11].bone_parent = "LeftShoulder"; bones.write[11].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.05, 0); bones.write[11].handle_offset = Vector2(0.6, 0.24); bones.write[11].group = "Body"; - bones.write[11].require = true; + bones.write[11].required = true; bones.write[12].bone_name = "LeftLowerArm"; bones.write[12].bone_parent = "LeftUpperArm"; bones.write[12].reference_pose = Transform3D(0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0.25, 0); bones.write[12].handle_offset = Vector2(0.7, 0.24); bones.write[12].group = "Body"; - bones.write[12].require = true; + bones.write[12].required = true; bones.write[13].bone_name = "LeftHand"; bones.write[13].bone_parent = "LeftLowerArm"; @@ -562,7 +565,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[13].reference_pose = Transform3D(0, 0, 1, 0, 1, 0, -1, 0, 0, 0, 0.25, 0); bones.write[13].handle_offset = Vector2(0.82, 0.235); bones.write[13].group = "Body"; - bones.write[13].require = true; + bones.write[13].required = true; bones.write[14].bone_name = "LeftThumbMetacarpal"; bones.write[14].bone_parent = "LeftHand"; @@ -659,21 +662,21 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[29].reference_pose = Transform3D(0, -1, 0, 0, 0, 1, -1, 0, 0, -0.05, 0.1, 0); bones.write[29].handle_offset = Vector2(0.45, 0.235); bones.write[29].group = "Body"; - bones.write[29].require = true; + bones.write[29].required = true; bones.write[30].bone_name = "RightUpperArm"; bones.write[30].bone_parent = "RightShoulder"; bones.write[30].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.05, 0); bones.write[30].handle_offset = Vector2(0.4, 0.24); bones.write[30].group = "Body"; - bones.write[30].require = true; + bones.write[30].required = true; bones.write[31].bone_name = "RightLowerArm"; bones.write[31].bone_parent = "RightUpperArm"; bones.write[31].reference_pose = Transform3D(0, 0, 1, 0, 1, 0, -1, 0, 0, 0, 0.25, 0); bones.write[31].handle_offset = Vector2(0.3, 0.24); bones.write[31].group = "Body"; - bones.write[31].require = true; + bones.write[31].required = true; bones.write[32].bone_name = "RightHand"; bones.write[32].bone_parent = "RightLowerArm"; @@ -682,7 +685,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[32].reference_pose = Transform3D(0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0.25, 0); bones.write[32].handle_offset = Vector2(0.18, 0.235); bones.write[32].group = "Body"; - bones.write[32].require = true; + bones.write[32].required = true; bones.write[33].bone_name = "RightThumbMetacarpal"; bones.write[33].bone_parent = "RightHand"; @@ -779,21 +782,21 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[48].reference_pose = Transform3D(-1, 0, 0, 0, -1, 0, 0, 0, 1, 0.1, 0, 0); bones.write[48].handle_offset = Vector2(0.549, 0.49); bones.write[48].group = "Body"; - bones.write[48].require = true; + bones.write[48].required = true; bones.write[49].bone_name = "LeftLowerLeg"; bones.write[49].bone_parent = "LeftUpperLeg"; bones.write[49].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.375, 0); bones.write[49].handle_offset = Vector2(0.548, 0.683); bones.write[49].group = "Body"; - bones.write[49].require = true; + bones.write[49].required = true; bones.write[50].bone_name = "LeftFoot"; bones.write[50].bone_parent = "LeftLowerLeg"; bones.write[50].reference_pose = Transform3D(-1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0.375, 0); bones.write[50].handle_offset = Vector2(0.545, 0.9); bones.write[50].group = "Body"; - bones.write[50].require = true; + bones.write[50].required = true; bones.write[51].bone_name = "LeftToes"; bones.write[51].bone_parent = "LeftFoot"; @@ -806,21 +809,21 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[52].reference_pose = Transform3D(-1, 0, 0, 0, -1, 0, 0, 0, 1, -0.1, 0, 0); bones.write[52].handle_offset = Vector2(0.451, 0.49); bones.write[52].group = "Body"; - bones.write[52].require = true; + bones.write[52].required = true; bones.write[53].bone_name = "RightLowerLeg"; bones.write[53].bone_parent = "RightUpperLeg"; bones.write[53].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.375, 0); bones.write[53].handle_offset = Vector2(0.452, 0.683); bones.write[53].group = "Body"; - bones.write[53].require = true; + bones.write[53].required = true; bones.write[54].bone_name = "RightFoot"; bones.write[54].bone_parent = "RightLowerLeg"; bones.write[54].reference_pose = Transform3D(-1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0.375, 0); bones.write[54].handle_offset = Vector2(0.455, 0.9); bones.write[54].group = "Body"; - bones.write[54].require = true; + bones.write[54].required = true; bones.write[55].bone_name = "RightToes"; bones.write[55].bone_parent = "RightFoot"; diff --git a/scene/resources/skeleton_profile.h b/scene/resources/skeleton_profile.h index 143f495c61..b5a3bce940 100644 --- a/scene/resources/skeleton_profile.h +++ b/scene/resources/skeleton_profile.h @@ -61,7 +61,7 @@ protected: Transform3D reference_pose; Vector2 handle_offset; StringName group; - bool require = false; + bool required = false; }; StringName root_bone; @@ -104,22 +104,22 @@ public: void set_bone_parent(int p_bone_idx, const StringName &p_bone_parent); TailDirection get_tail_direction(int p_bone_idx) const; - void set_tail_direction(int p_bone_idx, const TailDirection p_tail_direction); + void set_tail_direction(int p_bone_idx, TailDirection p_tail_direction); StringName get_bone_tail(int p_bone_idx) const; void set_bone_tail(int p_bone_idx, const StringName &p_bone_tail); Transform3D get_reference_pose(int p_bone_idx) const; - void set_reference_pose(int p_bone_idx, const Transform3D p_reference_pose); + void set_reference_pose(int p_bone_idx, const Transform3D &p_reference_pose); Vector2 get_handle_offset(int p_bone_idx) const; - void set_handle_offset(int p_bone_idx, const Vector2 p_handle_offset); + void set_handle_offset(int p_bone_idx, const Vector2 &p_handle_offset); StringName get_group(int p_bone_idx) const; void set_group(int p_bone_idx, const StringName &p_group); - bool is_require(int p_bone_idx) const; - void set_require(int p_bone_idx, const bool p_require); + bool is_required(int p_bone_idx) const; + void set_required(int p_bone_idx, bool p_required); bool has_bone(const StringName &p_bone_name); diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index b54f511d05..48c9cda253 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -777,7 +777,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color if (rb->get_scaling_3d_mode() != RS::VIEWPORT_SCALING_3D_MODE_OFF) { // can't do blit subpass because we're scaling using_subpass_post_process = false; - } else if (p_render_data->environment.is_valid() && (environment_get_glow_enabled(p_render_data->environment) || RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) || RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes))) { + } else if (p_render_data->environment.is_valid() && (environment_get_glow_enabled(p_render_data->environment) || RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) || RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes) || environment_get_background(p_render_data->environment) == RS::ENV_BG_CANVAS)) { // can't do blit subpass because we're using post processes using_subpass_post_process = false; } diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 7dfff0b76f..1fdccb929b 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -5089,7 +5089,8 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ draw_list = nullptr; compute_list = nullptr; - if (main_instance) { + bool project_pipeline_cache_enable = GLOBAL_GET("rendering/rendering_device/pipeline_cache/enable"); + if (main_instance && project_pipeline_cache_enable) { // Only the instance that is not a local device and is also the singleton is allowed to manage a pipeline cache. pipeline_cache_file_path = vformat("user://vulkan/pipelines.%s.%s", OS::get_singleton()->get_current_rendering_method(), diff --git a/servers/rendering/rendering_light_culler.cpp b/servers/rendering/rendering_light_culler.cpp index fdf0d73654..0889898f0b 100644 --- a/servers/rendering/rendering_light_culler.cpp +++ b/servers/rendering/rendering_light_culler.cpp @@ -427,15 +427,19 @@ bool RenderingLightCuller::_add_light_camera_planes(LightCullPlanes &r_cull_plan uint8_t *entry = &data.LUT_entries[lookup][0]; int n_edges = data.LUT_entry_sizes[lookup] - 1; + const Vector3 &pt2 = p_light_source.pos; + for (int e = 0; e < n_edges; e++) { int i0 = entry[e]; int i1 = entry[e + 1]; const Vector3 &pt0 = data.frustum_points[i0]; const Vector3 &pt1 = data.frustum_points[i1]; - // Create plane from 3 points. - Plane p(pt0, pt1, p_light_source.pos); - r_cull_planes.add_cull_plane(p); + if (!_is_colinear_tri(pt0, pt1, pt2)) { + // Create plane from 3 points. + Plane p(pt0, pt1, pt2); + r_cull_planes.add_cull_plane(p); + } } // Last to 0 edge. @@ -446,9 +450,11 @@ bool RenderingLightCuller::_add_light_camera_planes(LightCullPlanes &r_cull_plan const Vector3 &pt0 = data.frustum_points[i0]; const Vector3 &pt1 = data.frustum_points[i1]; - // Create plane from 3 points. - Plane p(pt0, pt1, p_light_source.pos); - r_cull_planes.add_cull_plane(p); + if (!_is_colinear_tri(pt0, pt1, pt2)) { + // Create plane from 3 points. + Plane p(pt0, pt1, pt2); + r_cull_planes.add_cull_plane(p); + } } #ifdef LIGHT_CULLER_DEBUG_LOGGING diff --git a/servers/rendering/rendering_light_culler.h b/servers/rendering/rendering_light_culler.h index 602543850a..0bf975430b 100644 --- a/servers/rendering/rendering_light_culler.h +++ b/servers/rendering/rendering_light_culler.h @@ -163,6 +163,39 @@ private: bool _prepare_light(const RendererSceneCull::Instance &p_instance, int32_t p_directional_light_id = -1); + // Avoid adding extra culling planes derived from near colinear triangles. + // The normals derived from these will be inaccurate, and can lead to false + // culling of objects that should be within the light volume. + bool _is_colinear_tri(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c) const { + // Lengths of sides a, b and c. + float la = (p_b - p_a).length(); + float lb = (p_c - p_b).length(); + float lc = (p_c - p_a).length(); + + // Get longest side into lc. + if (lb < la) { + SWAP(la, lb); + } + if (lc < lb) { + SWAP(lb, lc); + } + + // Prevent divide by zero. + if (lc > 0.00001f) { + // If the summed length of the smaller two + // sides is close to the length of the longest side, + // the points are colinear, and the triangle is near degenerate. + float ld = ((la + lb) - lc) / lc; + + // ld will be close to zero for colinear tris. + return ld < 0.00001f; + } + + // Don't create planes from tiny triangles, + // they won't be accurate. + return true; + } + // Internal version uses LightSource. bool _add_light_camera_planes(LightCullPlanes &r_cull_planes, const LightSource &p_light_source); diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index eb9f1c1484..53e1d119fd 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -341,6 +341,7 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_string_to_upper, "string", "language"); GDVIRTUAL_BIND(_string_to_lower, "string", "language"); + GDVIRTUAL_BIND(_string_to_title, "string", "language"); GDVIRTUAL_BIND(_parse_structured_text, "parser_type", "args", "text"); @@ -1507,6 +1508,14 @@ String TextServerExtension::string_to_upper(const String &p_string, const String return p_string; } +String TextServerExtension::string_to_title(const String &p_string, const String &p_language) const { + String ret; + if (GDVIRTUAL_CALL(_string_to_title, p_string, p_language, ret)) { + return ret; + } + return p_string; +} + String TextServerExtension::string_to_lower(const String &p_string, const String &p_language) const { String ret; if (GDVIRTUAL_CALL(_string_to_lower, p_string, p_language, ret)) { diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index 84d68de4fa..53d30abee4 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -566,8 +566,10 @@ public: virtual String string_to_upper(const String &p_string, const String &p_language = "") const override; virtual String string_to_lower(const String &p_string, const String &p_language = "") const override; + virtual String string_to_title(const String &p_string, const String &p_language = "") const override; GDVIRTUAL2RC(String, _string_to_upper, const String &, const String &); GDVIRTUAL2RC(String, _string_to_lower, const String &, const String &); + GDVIRTUAL2RC(String, _string_to_title, const String &, const String &); TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; GDVIRTUAL3RC(TypedArray<Vector3i>, _parse_structured_text, StructuredTextParser, const Array &, const String &); diff --git a/servers/text_server.cpp b/servers/text_server.cpp index 078ee27753..fac9e32d01 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -491,6 +491,7 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("string_to_upper", "string", "language"), &TextServer::string_to_upper, DEFVAL("")); ClassDB::bind_method(D_METHOD("string_to_lower", "string", "language"), &TextServer::string_to_lower, DEFVAL("")); + ClassDB::bind_method(D_METHOD("string_to_title", "string", "language"), &TextServer::string_to_title, DEFVAL("")); ClassDB::bind_method(D_METHOD("parse_structured_text", "parser_type", "args", "text"), &TextServer::parse_structured_text); diff --git a/servers/text_server.h b/servers/text_server.h index 4a16ae64e8..396d7ca8e5 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -546,6 +546,7 @@ public: // Other string operations. virtual String string_to_upper(const String &p_string, const String &p_language = "") const = 0; virtual String string_to_lower(const String &p_string, const String &p_language = "") const = 0; + virtual String string_to_title(const String &p_string, const String &p_language = "") const = 0; TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; diff --git a/tests/core/math/test_vector2.h b/tests/core/math/test_vector2.h index f23fffe5eb..fc3fd6a87d 100644 --- a/tests/core/math/test_vector2.h +++ b/tests/core/math/test_vector2.h @@ -354,6 +354,7 @@ TEST_CASE("[Vector2] Plane methods") { const Vector2 vector_y = Vector2(0, 1); const Vector2 vector_normal = Vector2(0.95879811270838721622267, 0.2840883296913739899919); const Vector2 vector_non_normal = Vector2(5.4, 1.6); + const real_t p_d = 99.1; CHECK_MESSAGE( vector.bounce(vector_y) == Vector2(1.2, -3.4), "Vector2 bounce on a plane with normal of the Y axis should."); @@ -373,6 +374,9 @@ TEST_CASE("[Vector2] Plane methods") { vector.project(vector_normal).is_equal_approx(Vector2(2.0292559899117276166, 0.60126103404791929382)), "Vector2 projected on a normal should return expected value."); CHECK_MESSAGE( + vector_normal.plane_project(p_d, vector).is_equal_approx(Vector2(94.187635516479631, 30.951892004882851)), + "Vector2 plane_project should return expected value."); + CHECK_MESSAGE( vector.slide(vector_y) == Vector2(1.2, 0), "Vector2 slide on a plane with normal of the Y axis should set the Y to zero."); CHECK_MESSAGE( diff --git a/thirdparty/README.md b/thirdparty/README.md index be386a3920..8fabe8a893 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -87,7 +87,7 @@ Files extracted from upstream source: ## certs - Upstream: Mozilla, via https://github.com/bagder/ca-bundle -- Version: git (bef37a977ccb45fb4c1b213b79dd6ba438077561, 2023) +- Version: git (c5a419971b1bec220368c619aaafd0b818aa119f, 2024) - License: MPL 2.0 @@ -194,7 +194,7 @@ commits. ## enet - Upstream: https://github.com/lsalzman/enet -- Version: git (ea4607a90dbfbcf4da2669ea998585253d8e70b1, 2023) +- Version: git (c44b7d0f7ff21edb702745e4c019d0537928c373, 2024) - License: MIT Files extracted from upstream source: @@ -838,11 +838,13 @@ folder. Files extracted from upstream source: +- `LICENSE.txt` - All `.cpp`, `.h` and `.inl` files -Important: Some files have Godot-made changes. -They are marked with `// -- GODOT start --` and `// -- GODOT end --` -comments and a patch is provided in the squish/ folder. +Some downstream changes have been made and are identified by +`// -- GODOT begin --` and `// -- GODOT end --` comments. +They can be reapplied using the patches included in the `patches` +folder. ## tinyexr diff --git a/thirdparty/certs/ca-certificates.crt b/thirdparty/certs/ca-certificates.crt index df7a026bed..f437587091 100644 --- a/thirdparty/certs/ca-certificates.crt +++ b/thirdparty/certs/ca-certificates.crt @@ -1,7 +1,7 @@ ## ## Bundle of CA Root Certificates ## -## Certificate data from Mozilla as of: Wed Dec 13 07:16:08 2023 GMT +## Certificate data from Mozilla as of: Mon Mar 11 15:15:21 2024 GMT ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates @@ -14,7 +14,7 @@ ## Just configure this file as the SSLCACertificateFile. ## ## Conversion done with mk-ca-bundle.pl version 1.29. -## SHA256: 1970dd65858925d68498d2356aea6d03f764422523c5887deca8ce3ba9e1f845 +## SHA256: 4d96bd539f4719e9ace493757afbe4a23ee8579de1c97fbebc50bba3c12e8c1e ## @@ -3532,3 +3532,50 @@ dVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670v64fG9PiO/yzcnMcmyiQ iRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17Org3bhzjlP1v9mxnhMUF6cKojawHhRUzN lM47ni3niAIi9G7oyOzWPPO5std3eqx7 -----END CERTIFICATE----- + +Telekom Security TLS ECC Root 2020 +================================== +-----BEGIN CERTIFICATE----- +MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQswCQYDVQQGEwJE +RTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJUZWxl +a29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIwMB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIz +NTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkg +R21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqG +SM49AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/OtdKPD/M1 +2kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDPf8iAC8GXs7s1J8nCG6NC +MEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6fMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMAoGCCqGSM49BAMDA2cAMGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZ +Mo7k+5Dck2TOrbRBR2Diz6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdU +ga/sf+Rn27iQ7t0l +-----END CERTIFICATE----- + +Telekom Security TLS RSA Root 2023 +================================== +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBjMQswCQYDVQQG +EwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJU +ZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAyMDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMy +NzIzNTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJp +dHkgR21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9cUD/h3VC +KSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHVcp6R+SPWcHu79ZvB7JPP +GeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMAU6DksquDOFczJZSfvkgdmOGjup5czQRx +UX11eKvzWarE4GC+j4NSuHUaQTXtvPM6Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWo +l8hHD/BeEIvnHRz+sTugBTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9 +FIS3R/qy8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73Jco4v +zLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg8qKrBC7m8kwOFjQg +rIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8rFEz0ciD0cmfHdRHNCk+y7AO+oML +KFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7S +WWO/gLCMk3PLNaaZlSJhZQNg+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUtqeXgj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2 +p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQpGv7qHBFfLp+ +sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm9S3ul0A8Yute1hTWjOKWi0Fp +kzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErwM807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy +/SKE8YXJN3nptT+/XOR0so8RYgDdGGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4 +mZqTuXNnQkYRIer+CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtz +aL1txKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+w6jv/naa +oqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aKL4x35bcF7DvB7L6Gs4a8 +wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+ljX273CXE2whJdV/LItM3z7gLfEdxquVeE +HVlNjM7IDiPCtyaaEBRx/pOyiriA8A4QntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0 +o82bNSQ3+pCTE4FCxpgmdTdmQRCsu/WU48IxK63nI1bMNSWSs1A= +-----END CERTIFICATE----- diff --git a/thirdparty/enet/patches/godot_socket.patch b/thirdparty/enet/patches/godot_socket.patch index 364b3536be..d0fb97fb92 100644 --- a/thirdparty/enet/patches/godot_socket.patch +++ b/thirdparty/enet/patches/godot_socket.patch @@ -1,5 +1,5 @@ diff --git a/thirdparty/enet/enet/enet.h b/thirdparty/enet/enet/enet.h -index fc45cbd0c9..77f8004b80 100644 +index 4a207041b3..5232f8a869 100644 --- a/thirdparty/enet/enet/enet.h +++ b/thirdparty/enet/enet/enet.h @@ -10,13 +10,19 @@ extern "C" @@ -22,7 +22,7 @@ index fc45cbd0c9..77f8004b80 100644 #include "enet/types.h" #include "enet/protocol.h" -@@ -86,11 +92,15 @@ typedef enum _ENetSocketShutdown +@@ -87,11 +93,15 @@ typedef enum _ENetSocketShutdown * but not for enet_host_create. Once a server responds to a broadcast, the * address is updated from ENET_HOST_BROADCAST to the server's actual IP address. */ @@ -38,7 +38,7 @@ index fc45cbd0c9..77f8004b80 100644 /** * Packet flag bit constants. -@@ -604,6 +614,10 @@ ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t, +@@ -608,6 +618,10 @@ ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t, extern size_t enet_protocol_command_size (enet_uint8); @@ -50,7 +50,7 @@ index fc45cbd0c9..77f8004b80 100644 } #endif diff --git a/thirdparty/enet/host.c b/thirdparty/enet/host.c -index 3b2180f7fd..21ab27e247 100644 +index fff946a392..adb3533cf1 100644 --- a/thirdparty/enet/host.c +++ b/thirdparty/enet/host.c @@ -87,7 +87,7 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL @@ -63,10 +63,10 @@ index 3b2180f7fd..21ab27e247 100644 host -> receivedData = NULL; host -> receivedDataLength = 0; diff --git a/thirdparty/enet/protocol.c b/thirdparty/enet/protocol.c -index 9d654f1d96..d7fe80f117 100644 +index 843a719af3..5f18700599 100644 --- a/thirdparty/enet/protocol.c +++ b/thirdparty/enet/protocol.c -@@ -309,7 +309,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet +@@ -318,7 +318,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet } else if (currentPeer -> state != ENET_PEER_STATE_CONNECTING && @@ -75,7 +75,7 @@ index 9d654f1d96..d7fe80f117 100644 { if (currentPeer -> address.port == host -> receivedAddress.port && currentPeer -> connectID == command -> connect.connectID) -@@ -1031,9 +1031,8 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event) +@@ -1043,9 +1043,8 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event) if (peer -> state == ENET_PEER_STATE_DISCONNECTED || peer -> state == ENET_PEER_STATE_ZOMBIE || @@ -87,7 +87,7 @@ index 9d654f1d96..d7fe80f117 100644 (peer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID && sessionID != peer -> incomingSessionID)) return 0; -@@ -1075,7 +1074,7 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event) +@@ -1090,7 +1089,7 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event) if (peer != NULL) { diff --git a/thirdparty/enet/protocol.c b/thirdparty/enet/protocol.c index af307af7e5..5f18700599 100644 --- a/thirdparty/enet/protocol.c +++ b/thirdparty/enet/protocol.c @@ -1071,11 +1071,14 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event) if (host -> checksum != NULL) { - enet_uint32 * checksum = (enet_uint32 *) & host -> receivedData [headerSize - sizeof (enet_uint32)], - desiredChecksum = * checksum; + enet_uint32 * checksum = (enet_uint32 *) & host -> receivedData [headerSize - sizeof (enet_uint32)]; + enet_uint32 desiredChecksum, newChecksum; ENetBuffer buffer; + /* Checksum may be an unaligned pointer, use memcpy to avoid undefined behaviour. */ + memcpy (& desiredChecksum, checksum, sizeof (enet_uint32)); - * checksum = peer != NULL ? peer -> connectID : 0; + newChecksum = peer != NULL ? peer -> connectID : 0; + memcpy (checksum, & newChecksum, sizeof (enet_uint32)); buffer.data = host -> receivedData; buffer.dataLength = host -> receivedDataLength; @@ -1703,9 +1706,12 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch if (host -> checksum != NULL) { enet_uint32 * checksum = (enet_uint32 *) & headerData [host -> buffers -> dataLength]; - * checksum = currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID ? currentPeer -> connectID : 0; + enet_uint32 newChecksum = currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID ? currentPeer -> connectID : 0; + /* Checksum may be unaligned, use memcpy to avoid undefined behaviour. */ + memcpy(checksum, & newChecksum, sizeof (enet_uint32)); host -> buffers -> dataLength += sizeof (enet_uint32); - * checksum = host -> checksum (host -> buffers, host -> bufferCount); + newChecksum = host -> checksum (host -> buffers, host -> bufferCount); + memcpy(checksum, & newChecksum, sizeof (enet_uint32)); } if (shouldCompress > 0) diff --git a/thirdparty/squish/LICENSE.txt b/thirdparty/squish/LICENSE.txt new file mode 100644 index 0000000000..e491e36226 --- /dev/null +++ b/thirdparty/squish/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2006 Simon Brown si@sjbrown.co.uk + +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. diff --git a/thirdparty/squish/godot-changes.patch b/thirdparty/squish/godot-changes.patch deleted file mode 100644 index 555fbc51d0..0000000000 --- a/thirdparty/squish/godot-changes.patch +++ /dev/null @@ -1,211 +0,0 @@ -diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp -index af8b98036..3d87adaa7 100644 ---- a/thirdparty/squish/colourblock.cpp -+++ b/thirdparty/squish/colourblock.cpp -@@ -24,6 +24,9 @@ - -------------------------------------------------------------------------- */ - - #include "colourblock.h" -+// -- Godot start -- -+#include "alpha.h" -+// -- Godot end -- - - namespace squish { - -@@ -211,4 +214,23 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 ) - } - } - -+// -- Godot start -- -+void DecompressColourBc5( u8* rgba, void const* block) -+{ -+ void const* rblock = block; -+ void const* gblock = reinterpret_cast< u8 const* >( block ) + 8; -+ DecompressAlphaDxt5(rgba,rblock); -+ for ( int i = 0; i < 16; ++i ) { -+ rgba[i*4] = rgba[i*4 + 3]; -+ } -+ DecompressAlphaDxt5(rgba,gblock); -+ for ( int i = 0; i < 16; ++i ) { -+ rgba[i*4+1] = rgba[i*4 + 3]; -+ rgba[i*4 + 2] = 0; -+ rgba[i*4 + 3] = 255; -+ } -+} -+// -- GODOT end -- -+ -+ - } // namespace squish -diff --git a/thirdparty/squish/colourblock.h b/thirdparty/squish/colourblock.h -index fee2cd7c5..3cb9b7e3b 100644 ---- a/thirdparty/squish/colourblock.h -+++ b/thirdparty/squish/colourblock.h -@@ -35,6 +35,9 @@ void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* - void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block ); - - void DecompressColour( u8* rgba, void const* block, bool isDxt1 ); -+// -- GODOT start -- -+void DecompressColourBc5( u8* rgba, void const* block ); -+// -- GODOT end -- - - } // namespace squish - -diff --git a/thirdparty/squish/config.h b/thirdparty/squish/config.h -index 92edefe96..05f8d7259 100644 ---- a/thirdparty/squish/config.h -+++ b/thirdparty/squish/config.h -@@ -32,6 +32,26 @@ - #endif - - // Set to 1 or 2 when building squish to use SSE or SSE2 instructions. -+// -- GODOT start -- -+#ifdef _MSC_VER -+ #if defined(_M_IX86_FP) -+ #if _M_IX86_FP >= 2 -+ #define SQUISH_USE_SSE 2 -+ #elif _M_IX86_FP >= 1 -+ #define SQUISH_USE_SSE 1 -+ #endif -+ #elif defined(_M_X64) -+ #define SQUISH_USE_SSE 2 -+ #endif -+#else -+ #if defined(__SSE2__) -+ #define SQUISH_USE_SSE 2 -+ #elif defined(__SSE__) -+ #define SQUISH_USE_SSE 1 -+ #endif -+#endif -+// -- GODOT end -- -+ - #ifndef SQUISH_USE_SSE - #define SQUISH_USE_SSE 0 - #endif -diff --git a/thirdparty/squish/squish.cpp b/thirdparty/squish/squish.cpp -index 1d22a64ad..fd11a147d 100644 ---- a/thirdparty/squish/squish.cpp -+++ b/thirdparty/squish/squish.cpp -@@ -135,7 +135,13 @@ void Decompress( u8* rgba, void const* block, int flags ) - colourBlock = reinterpret_cast< u8 const* >( block ) + 8; - - // decompress colour -- DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); -+ // -- GODOT start -- -+ //DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); -+ if(( flags & ( kBc5 ) ) != 0) -+ DecompressColourBc5( rgba, colourBlock); -+ else -+ DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); -+ // -- GODOT end -- - - // decompress alpha separately if necessary - if( ( flags & kDxt3 ) != 0 ) - -diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp -index 49401358bc..f14c9362bd 100644 ---- a/thirdparty/squish/colourblock.cpp -+++ b/thirdparty/squish/colourblock.cpp -@@ -24,9 +24,9 @@ - -------------------------------------------------------------------------- */ - - #include "colourblock.h" --// -- Godot start -- -+// -- GODOT start -- - #include "alpha.h" --// -- Godot end -- -+// -- GODOT end -- - - namespace squish { - -diff --git a/thirdparty/squish/godot-changes.patch b/thirdparty/squish/godot-changes.patch -index ef7bafb4b4..655a8cffc2 100644 ---- a/thirdparty/squish/godot-changes.patch -+++ b/thirdparty/squish/godot-changes.patch -@@ -1,22 +1,33 @@ - diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp --index af8b98036..3d87adaa7 100644 -+index af8b980365..f14c9362bd 100644 - --- a/thirdparty/squish/colourblock.cpp - +++ b/thirdparty/squish/colourblock.cpp - @@ -24,6 +24,9 @@ - -------------------------------------------------------------------------- */ - - #include "colourblock.h" --+// -- Godot start -- -++// -- GODOT start -- - +#include "alpha.h" --+// -- Godot end -- -++// -- GODOT end -- - - namespace squish { - --@@ -211,4 +214,23 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 ) -+@@ -211,4 +214,34 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 ) - } - } - --+// -- Godot start -- -++// -- GODOT start -- -++void DecompressColourBc4( u8* rgba, void const* block) -++{ -++ DecompressAlphaDxt5(rgba,block); -++ for ( int i = 0; i < 16; ++i ) { -++ rgba[i*4] = rgba[i*4 + 3]; -++ rgba[i*4 + 1] = 0; -++ rgba[i*4 + 2] = 0; -++ rgba[i*4 + 3] = 255; -++ } -++} -++ - +void DecompressColourBc5( u8* rgba, void const* block) - +{ - + void const* rblock = block; -@@ -37,21 +48,22 @@ index af8b98036..3d87adaa7 100644 - + - } // namespace squish - diff --git a/thirdparty/squish/colourblock.h b/thirdparty/squish/colourblock.h --index fee2cd7c5..3cb9b7e3b 100644 -+index fee2cd7c5d..e1eb9e4917 100644 - --- a/thirdparty/squish/colourblock.h - +++ b/thirdparty/squish/colourblock.h --@@ -35,6 +35,9 @@ void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* -+@@ -35,6 +35,10 @@ void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* - void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block ); - - void DecompressColour( u8* rgba, void const* block, bool isDxt1 ); - +// -- GODOT start -- -++void DecompressColourBc4( u8* rgba, void const* block ); - +void DecompressColourBc5( u8* rgba, void const* block ); - +// -- GODOT end -- - - } // namespace squish - - diff --git a/thirdparty/squish/config.h b/thirdparty/squish/config.h --index 92edefe96..05f8d7259 100644 -+index 92edefe966..05f8d72598 100644 - --- a/thirdparty/squish/config.h - +++ b/thirdparty/squish/config.h - @@ -32,6 +32,26 @@ -@@ -82,17 +94,19 @@ index 92edefe96..05f8d7259 100644 - #define SQUISH_USE_SSE 0 - #endif - diff --git a/thirdparty/squish/squish.cpp b/thirdparty/squish/squish.cpp --index 1d22a64ad..fd11a147d 100644 -+index 1d22a64ad6..086ba11cd0 100644 - --- a/thirdparty/squish/squish.cpp - +++ b/thirdparty/squish/squish.cpp --@@ -135,7 +135,13 @@ void Decompress( u8* rgba, void const* block, int flags ) -+@@ -135,7 +135,15 @@ void Decompress( u8* rgba, void const* block, int flags ) - colourBlock = reinterpret_cast< u8 const* >( block ) + 8; - - // decompress colour - - DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); - + // -- GODOT start -- - + //DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); --+ if(( flags & ( kBc5 ) ) != 0) -++ if(( flags & ( kBc4 ) ) != 0) -++ DecompressColourBc4( rgba, colourBlock); -++ else if(( flags & ( kBc5 ) ) != 0) - + DecompressColourBc5( rgba, colourBlock); - + else - + DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
\ No newline at end of file diff --git a/thirdparty/squish/patches/config_sse.patch b/thirdparty/squish/patches/config_sse.patch new file mode 100644 index 0000000000..047701ee32 --- /dev/null +++ b/thirdparty/squish/patches/config_sse.patch @@ -0,0 +1,31 @@ +diff --git a/thirdparty/squish/config.h b/thirdparty/squish/config.h +index 92edefe966..05f8d72598 100644 +--- a/thirdparty/squish/config.h ++++ b/thirdparty/squish/config.h +@@ -32,6 +32,26 @@ + #endif + + // Set to 1 or 2 when building squish to use SSE or SSE2 instructions. ++// -- GODOT start -- ++#ifdef _MSC_VER ++ #if defined(_M_IX86_FP) ++ #if _M_IX86_FP >= 2 ++ #define SQUISH_USE_SSE 2 ++ #elif _M_IX86_FP >= 1 ++ #define SQUISH_USE_SSE 1 ++ #endif ++ #elif defined(_M_X64) ++ #define SQUISH_USE_SSE 2 ++ #endif ++#else ++ #if defined(__SSE2__) ++ #define SQUISH_USE_SSE 2 ++ #elif defined(__SSE__) ++ #define SQUISH_USE_SSE 1 ++ #endif ++#endif ++// -- GODOT end -- ++ + #ifndef SQUISH_USE_SSE + #define SQUISH_USE_SSE 0 + #endif diff --git a/thirdparty/squish/patches/decompress_bc4_bc5.patch b/thirdparty/squish/patches/decompress_bc4_bc5.patch new file mode 100644 index 0000000000..949375560c --- /dev/null +++ b/thirdparty/squish/patches/decompress_bc4_bc5.patch @@ -0,0 +1,85 @@ +diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp +index af8b980365..f14c9362bd 100644 +--- a/thirdparty/squish/colourblock.cpp ++++ b/thirdparty/squish/colourblock.cpp +@@ -24,6 +24,9 @@ + -------------------------------------------------------------------------- */ + + #include "colourblock.h" ++// -- GODOT start -- ++#include "alpha.h" ++// -- GODOT end -- + + namespace squish { + +@@ -211,4 +214,34 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 ) + } + } + ++// -- GODOT start -- ++void DecompressColourBc4( u8* rgba, void const* block) ++{ ++ DecompressAlphaDxt5(rgba,block); ++ for ( int i = 0; i < 16; ++i ) { ++ rgba[i*4] = rgba[i*4 + 3]; ++ rgba[i*4 + 1] = 0; ++ rgba[i*4 + 2] = 0; ++ rgba[i*4 + 3] = 255; ++ } ++} ++ ++void DecompressColourBc5( u8* rgba, void const* block) ++{ ++ void const* rblock = block; ++ void const* gblock = reinterpret_cast< u8 const* >( block ) + 8; ++ DecompressAlphaDxt5(rgba,rblock); ++ for ( int i = 0; i < 16; ++i ) { ++ rgba[i*4] = rgba[i*4 + 3]; ++ } ++ DecompressAlphaDxt5(rgba,gblock); ++ for ( int i = 0; i < 16; ++i ) { ++ rgba[i*4+1] = rgba[i*4 + 3]; ++ rgba[i*4 + 2] = 0; ++ rgba[i*4 + 3] = 255; ++ } ++} ++// -- GODOT end -- ++ ++ + } // namespace squish +diff --git a/thirdparty/squish/colourblock.h b/thirdparty/squish/colourblock.h +index fee2cd7c5d..e1eb9e4917 100644 +--- a/thirdparty/squish/colourblock.h ++++ b/thirdparty/squish/colourblock.h +@@ -35,6 +35,10 @@ void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* + void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block ); + + void DecompressColour( u8* rgba, void const* block, bool isDxt1 ); ++// -- GODOT start -- ++void DecompressColourBc4( u8* rgba, void const* block ); ++void DecompressColourBc5( u8* rgba, void const* block ); ++// -- GODOT end -- + + } // namespace squish + +diff --git a/thirdparty/squish/squish.cpp b/thirdparty/squish/squish.cpp +index 1d22a64ad6..086ba11cd0 100644 +--- a/thirdparty/squish/squish.cpp ++++ b/thirdparty/squish/squish.cpp +@@ -135,7 +135,15 @@ void Decompress( u8* rgba, void const* block, int flags ) + colourBlock = reinterpret_cast< u8 const* >( block ) + 8; + + // decompress colour +- DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); ++ // -- GODOT start -- ++ //DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); ++ if(( flags & ( kBc4 ) ) != 0) ++ DecompressColourBc4( rgba, colourBlock); ++ else if(( flags & ( kBc5 ) ) != 0) ++ DecompressColourBc5( rgba, colourBlock); ++ else ++ DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); ++ // -- GODOT end -- + + // decompress alpha separately if necessary + if( ( flags & kDxt3 ) != 0 ) |