diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..1b15f551 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "engine"] + path = engine + url = https://github.com/godotengine/godot.git diff --git a/engine/.clangd b/engine/.clangd index 95a1e907..3c9792ea 100644 --- a/engine/.clangd +++ b/engine/.clangd @@ -5,7 +5,6 @@ Diagnostics: Includes: IgnoreHeader: - - core/typedefs\.h # Our "main" header, featuring transitive includes; allow everywhere. - \.compat\.inc --- # Header-specific conditions. diff --git a/engine/.editorconfig b/engine/.editorconfig index a2f93af3..c79c816e 100644 --- a/engine/.editorconfig +++ b/engine/.editorconfig @@ -16,5 +16,6 @@ indent_style = space indent_size = 2 indent_style = space -[*.svg] -insert_final_newline = false +[{*.props,*.vcxproj}] +indent_size = 2 +indent_style = space diff --git a/engine/.git-blame-ignore-revs b/engine/.git-blame-ignore-revs index d54ff309..3203caf8 100644 --- a/engine/.git-blame-ignore-revs +++ b/engine/.git-blame-ignore-revs @@ -66,3 +66,9 @@ bb5f390fb9b466be35a5df7651323d7e66afca31 # Style: Enforce `AllowShortFunctionsOnASingleLine` e06d83860d798b6766b23d6eae48557387a7db85 + +# Style: Enforce trailing newlines on svgs +7e5baa042639ffa835271703c720e2595e90afb8 + +# Style: Replace header guards with `#pragma once` +324512e11c1b7663c3cf47bec6ddbe65c6b8db2b diff --git a/engine/.gitignore b/engine/.gitignore index 2c3bf742..8adc7b78 100644 --- a/engine/.gitignore +++ b/engine/.gitignore @@ -263,6 +263,11 @@ bld/ !thirdparty/**/arm/ !thirdparty/**/arm64/ +thirdparty/swappy-frame-pacing/arm64-v8a/abi.json +thirdparty/swappy-frame-pacing/armeabi-v7a/abi.json +thirdparty/swappy-frame-pacing/x86/abi.json +thirdparty/swappy-frame-pacing/x86_64/abi.json + # Visual Studio 2015/2017 cache/options directory .vs/ diff --git a/engine/.pre-commit-config.yaml b/engine/.pre-commit-config.yaml index 5627d750..8c9f033a 100644 --- a/engine/.pre-commit-config.yaml +++ b/engine/.pre-commit-config.yaml @@ -4,24 +4,22 @@ default_language_version: exclude: | (?x)^( .*thirdparty/.*| - .*-so_wrap\.(h|c)| + .*-(dll|dylib|so)_wrap\.[ch]| platform/android/java/editor/src/main/java/com/android/.*| platform/android/java/lib/src/com/google/.* )$ repos: - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v19.1.3 + rev: v20.1.0 hooks: - id: clang-format files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java)$ types_or: [text] - exclude: ^tests/python_build/.* - id: clang-format name: clang-format-glsl files: \.glsl$ types_or: [text] - exclude: ^tests/python_build/.* args: [-style=file:misc/utility/clang_format_glsl.yml] - repo: https://github.com/pocc/pre-commit-hooks @@ -31,13 +29,12 @@ repos: files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java|glsl)$ args: [--fix, --quiet, --use-color] types_or: [text] - exclude: ^tests/python_build/.* - additional_dependencies: [clang-tidy==19.1.0] + additional_dependencies: [clang-tidy==20.1.0] require_serial: true stages: [manual] # Not automatically triggered, invoked via `pre-commit run --hook-stage manual clang-tidy` - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.4 + rev: v0.11.4 hooks: - id: ruff args: [--fix] @@ -48,14 +45,14 @@ repos: types_or: [text] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.14.1 + rev: v1.14.1 # Latest version that supports Python 3.8 hooks: - id: mypy files: \.py$ types_or: [text] - repo: https://github.com/codespell-project/codespell - rev: v2.3.0 + rev: v2.4.1 hooks: - id: codespell additional_dependencies: [tomli] @@ -88,6 +85,13 @@ repos: pass_filenames: false files: ^(doc/classes|.*/doc_classes)/.*\.xml$ + - id: validate-builders + name: validate-builders + language: python + entry: python tests/python_build/validate_builders.py + pass_filenames: false + files: ^(gles3|glsl)_builders\.py$ + - id: eslint name: eslint language: node @@ -154,7 +158,6 @@ repos: language: python entry: python misc/scripts/header_guards.py files: \.(h|hpp|hh|hxx)$ - exclude: ^.*/(dummy|thread|platform_config|platform_gl)\.h$ - id: file-format name: file-format diff --git a/engine/COPYRIGHT.txt b/engine/COPYRIGHT.txt index 34aa95ed..38009093 100644 --- a/engine/COPYRIGHT.txt +++ b/engine/COPYRIGHT.txt @@ -163,6 +163,11 @@ Comment: Temporal Anti-Aliasing resolve implementation Copyright: 2016, Panos Karabelas License: Expat +Files: thirdparty/accesskit/* +Comment: AccessKit +Copyright: 2023, The AccessKit Authors. +License: Expat + Files: thirdparty/amd-fsr/* Comment: AMD FidelityFX Super Resolution Copyright: 2021, Advanced Micro Devices, Inc. @@ -200,7 +205,7 @@ License: MPL-2.0 Files: thirdparty/clipper2/* Comment: Clipper2 -Copyright: 2010-2024, Angus Johnson +Copyright: 2010-2025, Angus Johnson License: BSL-1.0 Files: thirdparty/cvtt/* diff --git a/engine/SConstruct b/engine/SConstruct index f4500d75..03990864 100644 --- a/engine/SConstruct +++ b/engine/SConstruct @@ -14,6 +14,7 @@ from importlib.util import module_from_spec, spec_from_file_location from types import ModuleType from SCons import __version__ as scons_raw_version +from SCons.Builder import ListEmitter # Explicitly resolve the helper modules, this is done to avoid clash with # modules of the same name that might be randomly added (e.g. someone adding @@ -57,7 +58,7 @@ import gles3_builders import glsl_builders import methods import scu_builders -from misc.utility.color import STDERR_COLOR, print_error, print_info, print_warning +from misc.utility.color import is_stderr_color, print_error, print_info, print_warning from platform_methods import architecture_aliases, architectures, compatibility_platform_aliases if ARGUMENTS.get("target", "editor") == "editor": @@ -166,7 +167,7 @@ opts.Add( "optimize", "Optimization level (by default inferred from 'target' and 'dev_build')", "auto", - ("auto", "none", "custom", "debug", "speed", "speed_trace", "size"), + ("auto", "none", "custom", "debug", "speed", "speed_trace", "size", "size_extra"), ) ) opts.Add(BoolVariable("debug_symbols", "Build with debugging symbols", False)) @@ -186,11 +187,12 @@ opts.Add(BoolVariable("vulkan", "Enable the vulkan rendering driver", True)) opts.Add(BoolVariable("opengl3", "Enable the OpenGL/GLES3 rendering driver", True)) opts.Add(BoolVariable("d3d12", "Enable the Direct3D 12 rendering driver on supported platforms", False)) opts.Add(BoolVariable("metal", "Enable the Metal rendering driver on supported platforms (Apple arm64 only)", False)) -opts.Add(BoolVariable("openxr", "Enable the OpenXR driver", True)) opts.Add(BoolVariable("use_volk", "Use the volk library to load the Vulkan loader dynamically", True)) opts.Add(BoolVariable("disable_exceptions", "Force disabling exception handling code", True)) opts.Add("custom_modules", "A list of comma-separated directory paths containing custom modules to build.", "") opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True)) +opts.Add(BoolVariable("accesskit", "Use AccessKit C SDK", True)) +opts.Add(("accesskit_sdk_path", "Path to the AccessKit C SDK", "")) # Advanced options opts.Add( @@ -220,6 +222,11 @@ opts.Add("vsproj_name", "Name of the Visual Studio solution", "godot") opts.Add("import_env_vars", "A comma-separated list of environment variables to copy from the outer environment.", "") opts.Add(BoolVariable("disable_3d", "Disable 3D nodes for a smaller executable", False)) opts.Add(BoolVariable("disable_advanced_gui", "Disable advanced GUI nodes and behaviors", False)) +opts.Add(BoolVariable("disable_physics_2d", "Disable 2D physics nodes and server", False)) +opts.Add(BoolVariable("disable_physics_3d", "Disable 3D physics nodes and server", False)) +opts.Add(BoolVariable("disable_navigation_2d", "Disable 2D navigation features", False)) +opts.Add(BoolVariable("disable_navigation_3d", "Disable 3D navigation features", False)) +opts.Add(BoolVariable("disable_xr", "Disable XR nodes and server", False)) opts.Add("build_profile", "Path to a file containing a feature build profile", "") opts.Add(BoolVariable("modules_enabled_by_default", "If no, disable all modules except ones explicitly enabled", True)) opts.Add(BoolVariable("no_editor_splash", "Don't use the custom splash screen for the editor", True)) @@ -236,6 +243,13 @@ opts.Add(BoolVariable("engine_update_check", "Enable engine update checks in the opts.Add(BoolVariable("steamapi", "Enable minimal SteamAPI integration for usage time tracking (editor only)", False)) opts.Add("cache_path", "Path to a directory where SCons cache files will be stored. No value disables the cache.", "") opts.Add("cache_limit", "Max size (in GiB) for the SCons cache. 0 means no limit.", "0") +opts.Add( + BoolVariable( + "redirect_build_objects", + "Enable redirecting built objects/libraries to `bin/obj/` to declutter the repository.", + True, + ) +) # Thirdparty libraries opts.Add(BoolVariable("builtin_brotli", "Use the built-in Brotli library", True)) @@ -433,10 +447,19 @@ for tool in custom_tools: env.Tool(tool) -# add default include paths - +# Add default include paths. env.Prepend(CPPPATH=["#"]) +# Allow marking includes as external/system to avoid raising warnings. +env["_CCCOMCOM"] += " $_CPPEXTINCFLAGS" +env["CPPEXTPATH"] = [] +if env.scons_version < (4, 2): + env["_CPPEXTINCFLAGS"] = "${_concat(EXTINCPREFIX, CPPEXTPATH, EXTINCSUFFIX, __env__, RDirs, TARGET, SOURCE)}" +else: + env["_CPPEXTINCFLAGS"] = ( + "${_concat(EXTINCPREFIX, CPPEXTPATH, EXTINCSUFFIX, __env__, RDirs, TARGET, SOURCE, affect_signature=False)}" + ) + # configure ENV for platform env.platform_exporters = platform_exporters env.platform_apis = platform_apis @@ -696,83 +719,84 @@ if env["arch"] == "x86_32": # Explicitly specify colored output. if methods.using_gcc(env): - env.AppendUnique(CCFLAGS=["-fdiagnostics-color" if STDERR_COLOR else "-fno-diagnostics-color"]) + env.AppendUnique(CCFLAGS=["-fdiagnostics-color" if is_stderr_color() else "-fno-diagnostics-color"]) elif methods.using_clang(env) or methods.using_emcc(env): - env.AppendUnique(CCFLAGS=["-fcolor-diagnostics" if STDERR_COLOR else "-fno-color-diagnostics"]) + env.AppendUnique(CCFLAGS=["-fcolor-diagnostics" if is_stderr_color() else "-fno-color-diagnostics"]) if sys.platform == "win32": env.AppendUnique(CCFLAGS=["-fansi-escape-codes"]) # 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. +env.AppendUnique(CCFLAGS=["$OPTIMIZELEVEL"]) if env.msvc: if env["debug_symbols"]: - env.Append(CCFLAGS=["/Zi", "/FS"]) - env.Append(LINKFLAGS=["/DEBUG:FULL"]) + env.AppendUnique(CCFLAGS=["/Zi", "/FS"]) + env.AppendUnique(LINKFLAGS=["/DEBUG:FULL"]) else: - env.Append(LINKFLAGS=["/DEBUG:NONE"]) + env.AppendUnique(LINKFLAGS=["/DEBUG:NONE"]) if env["optimize"].startswith("speed"): - env.Append(CCFLAGS=["/O2"]) - env.Append(LINKFLAGS=["/OPT:REF"]) + env["OPTIMIZELEVEL"] = "/O2" + env.AppendUnique(LINKFLAGS=["/OPT:REF"]) if env["optimize"] == "speed_trace": - env.Append(LINKFLAGS=["/OPT:NOICF"]) - elif env["optimize"] == "size": - env.Append(CCFLAGS=["/O1"]) - env.Append(LINKFLAGS=["/OPT:REF"]) + env.AppendUnique(LINKFLAGS=["/OPT:NOICF"]) + elif env["optimize"].startswith("size"): + env["OPTIMIZELEVEL"] = "/O1" + env.AppendUnique(LINKFLAGS=["/OPT:REF"]) + if env["optimize"] == "size_extra": + env.AppendUnique(CPPDEFINES=["SIZE_EXTRA"]) elif env["optimize"] == "debug" or env["optimize"] == "none": - env.Append(CCFLAGS=["/Od"]) + env["OPTIMIZELEVEL"] = "/Od" else: if env["debug_symbols"]: if env["platform"] == "windows": if methods.using_clang(env): - env.Append(CCFLAGS=["-gdwarf-4"]) # clang dwarf-5 symbols are broken on Windows. + env.AppendUnique(CCFLAGS=["-gdwarf-4"]) # clang dwarf-5 symbols are broken on Windows. else: - env.Append(CCFLAGS=["-gdwarf-5"]) # For gcc, only dwarf-5 symbols seem usable by libbacktrace. + env.AppendUnique(CCFLAGS=["-gdwarf-5"]) # For gcc, only dwarf-5 symbols seem usable by libbacktrace. else: # Adding dwarf-4 explicitly makes stacktraces work with clang builds, # otherwise addr2line doesn't understand them - env.Append(CCFLAGS=["-gdwarf-4"]) + env.AppendUnique(CCFLAGS=["-gdwarf-4"]) if methods.using_emcc(env): # Emscripten only produces dwarf symbols when using "-g3". - env.Append(CCFLAGS=["-g3"]) + env.AppendUnique(CCFLAGS=["-g3"]) # Emscripten linker needs debug symbols options too. - env.Append(LINKFLAGS=["-gdwarf-4"]) - env.Append(LINKFLAGS=["-g3"]) + env.AppendUnique(LINKFLAGS=["-gdwarf-4"]) + env.AppendUnique(LINKFLAGS=["-g3"]) elif env.dev_build: - env.Append(CCFLAGS=["-g3"]) + env.AppendUnique(CCFLAGS=["-g3"]) else: - env.Append(CCFLAGS=["-g2"]) + env.AppendUnique(CCFLAGS=["-g2"]) if env["debug_paths_relative"]: # Remap absolute paths to relative paths for debug symbols. project_path = Dir("#").abspath - env.Append(CCFLAGS=[f"-ffile-prefix-map={project_path}=."]) + env.AppendUnique(CCFLAGS=[f"-ffile-prefix-map={project_path}=."]) else: if methods.is_apple_clang(env): # Apple Clang, its linker doesn't like -s. - env.Append(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"]) + env.AppendUnique(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"]) else: - env.Append(LINKFLAGS=["-s"]) + env.AppendUnique(LINKFLAGS=["-s"]) # Linker needs optimization flags too, at least for Emscripten. # For other toolchains, this _may_ be useful for LTO too to disambiguate. + env.AppendUnique(LINKFLAGS=["$OPTIMIZELEVEL"]) if env["optimize"] == "speed": - env.Append(CCFLAGS=["-O3"]) - env.Append(LINKFLAGS=["-O3"]) + env["OPTIMIZELEVEL"] = "-O3" # `-O2` is friendlier to debuggers than `-O3`, leading to better crash backtraces. elif env["optimize"] == "speed_trace": - env.Append(CCFLAGS=["-O2"]) - env.Append(LINKFLAGS=["-O2"]) - elif env["optimize"] == "size": - env.Append(CCFLAGS=["-Os"]) - env.Append(LINKFLAGS=["-Os"]) + env["OPTIMIZELEVEL"] = "-O2" + elif env["optimize"].startswith("size"): + env["OPTIMIZELEVEL"] = "-Os" + if env["optimize"] == "size_extra": + env.AppendUnique(CPPDEFINES=["SIZE_EXTRA"]) elif env["optimize"] == "debug": - env.Append(CCFLAGS=["-Og"]) - env.Append(LINKFLAGS=["-Og"]) + env["OPTIMIZELEVEL"] = "-Og" elif env["optimize"] == "none": - env.Append(CCFLAGS=["-O0"]) - env.Append(LINKFLAGS=["-O0"]) + env["OPTIMIZELEVEL"] = "-O0" # Needs to happen after configure to handle "auto". if env["lto"] != "none": @@ -813,6 +837,7 @@ elif env.msvc: env.Append(CXXFLAGS=["/EHsc"]) # Configure compiler warnings +env.AppendUnique(CCFLAGS=["$WARNLEVEL"]) if env.msvc and not methods.using_clang(env): # MSVC # Disable warnings which we don't plan to fix. disabled_warnings = [ @@ -830,19 +855,23 @@ if env.msvc and not methods.using_clang(env): # MSVC ] if env["warnings"] == "extra": - env.Append(CCFLAGS=["/W4"] + disabled_warnings) + env["WARNLEVEL"] = "/W4" + env.AppendUnique(CCFLAGS=disabled_warnings) elif env["warnings"] == "all": + env["WARNLEVEL"] = "/W3" # C4458 is like -Wshadow. Part of /W4 but let's apply it for the default /W3 too. - env.Append(CCFLAGS=["/W3", "/w34458"] + disabled_warnings) + env.AppendUnique(CCFLAGS=["/w34458"] + disabled_warnings) elif env["warnings"] == "moderate": - env.Append(CCFLAGS=["/W2"] + disabled_warnings) + env["WARNLEVEL"] = "/W2" + env.AppendUnique(CCFLAGS=disabled_warnings) else: # 'no' + env["WARNLEVEL"] = "/w" # C4267 is particularly finicky & needs to be explicitly disabled. - env.Append(CCFLAGS=["/w", "/wd4267"]) + env.AppendUnique(CCFLAGS=["/wd4267"]) if env["werror"]: - env.Append(CCFLAGS=["/WX"]) - env.Append(LINKFLAGS=["/WX"]) + env.AppendUnique(CCFLAGS=["/WX"]) + env.AppendUnique(LINKFLAGS=["/WX"]) else: # GCC, Clang common_warnings = [] @@ -861,14 +890,14 @@ else: # GCC, Clang # for putting them in `Set` or `Map`. We don't mind about unreliable ordering. common_warnings += ["-Wno-ordered-compare-function-pointers"] - # clang-cl will interpret `-Wall` as `-Weverything`, workaround with compatibility cast - W_ALL = "-Wall" if not env.msvc else "-W3" + # clang-cl will interpret `-Wall` as `-Weverything`, workaround with compatibility cast. + env["WARNLEVEL"] = "-Wall" if not env.msvc else "-W3" if env["warnings"] == "extra": - env.Append(CCFLAGS=[W_ALL, "-Wextra", "-Wwrite-strings", "-Wno-unused-parameter"] + common_warnings) - env.Append(CXXFLAGS=["-Wctor-dtor-privacy", "-Wnon-virtual-dtor"]) + env.AppendUnique(CCFLAGS=["-Wextra", "-Wwrite-strings", "-Wno-unused-parameter"] + common_warnings) + env.AppendUnique(CXXFLAGS=["-Wctor-dtor-privacy", "-Wnon-virtual-dtor"]) if methods.using_gcc(env): - env.Append( + env.AppendUnique( CCFLAGS=[ "-Walloc-zero", "-Wduplicated-branches", @@ -876,25 +905,38 @@ else: # GCC, Clang "-Wstringop-overflow=4", ] ) - env.Append(CXXFLAGS=["-Wplacement-new=1"]) + env.AppendUnique(CXXFLAGS=["-Wplacement-new=1", "-Wvirtual-inheritance"]) # 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"]) + env.AppendUnique(CCFLAGS=["-Wattribute-alias=2"]) if cc_version_major >= 11: # Broke on MethodBind templates before GCC 11. - env.Append(CCFLAGS=["-Wlogical-op"]) + env.AppendUnique(CCFLAGS=["-Wlogical-op"]) elif methods.using_clang(env) or methods.using_emcc(env): - env.Append(CCFLAGS=["-Wimplicit-fallthrough"]) + env.AppendUnique(CCFLAGS=["-Wimplicit-fallthrough"]) elif env["warnings"] == "all": - env.Append(CCFLAGS=[W_ALL] + common_warnings) + env.AppendUnique(CCFLAGS=common_warnings) elif env["warnings"] == "moderate": - env.Append(CCFLAGS=[W_ALL, "-Wno-unused"] + common_warnings) + env.AppendUnique(CCFLAGS=["-Wno-unused"] + common_warnings) else: # 'no' - env.Append(CCFLAGS=["-w"]) + env["WARNLEVEL"] = "-w" if env["werror"]: - env.Append(CCFLAGS=["-Werror"]) + env.AppendUnique(CCFLAGS=["-Werror"]) + +# Configure external includes. +if env.msvc: + if not methods.using_clang(env): + if cc_version_major < 16 or (cc_version_major == 16 and cc_version_minor < 10): + env.AppendUnique(CCFLAGS=["/experimental:external"]) + env.AppendUnique(CCFLAGS=["/external:anglebrackets"]) + env.AppendUnique(CCFLAGS=["/external:W0"]) + env["EXTINCPREFIX"] = "/external:I" + env["EXTINCSUFFIX"] = "" +else: + env["EXTINCPREFIX"] = "-isystem " + env["EXTINCSUFFIX"] = "" if hasattr(detect, "get_program_suffix"): suffix = "." + detect.get_program_suffix() @@ -918,6 +960,51 @@ suffix += env.extra_suffix sys.path.remove(tmppath) sys.modules.pop("detect") +if env.editor_build: + unsupported_opts = [] + for disable_opt in [ + "disable_3d", + "disable_advanced_gui", + "disable_physics_2d", + "disable_physics_3d", + "disable_navigation_2d", + "disable_navigation_3d", + ]: + if env[disable_opt]: + unsupported_opts.append(disable_opt) + if unsupported_opts != []: + print_error( + "The following build option(s) cannot be used for editor builds, but only for export template builds: {}.".format( + ", ".join(unsupported_opts) + ) + ) + Exit(255) + +if env["disable_3d"]: + env.Append(CPPDEFINES=["_3D_DISABLED"]) + env["disable_navigation_3d"] = True + env["disable_physics_3d"] = True + env["disable_xr"] = True +if env["disable_advanced_gui"]: + env.Append(CPPDEFINES=["ADVANCED_GUI_DISABLED"]) +if env["disable_physics_2d"]: + env.Append(CPPDEFINES=["PHYSICS_2D_DISABLED"]) +if env["disable_physics_3d"]: + env.Append(CPPDEFINES=["PHYSICS_3D_DISABLED"]) +if env["disable_navigation_2d"]: + env.Append(CPPDEFINES=["NAVIGATION_2D_DISABLED"]) +if env["disable_navigation_3d"]: + env.Append(CPPDEFINES=["NAVIGATION_3D_DISABLED"]) +if env["disable_xr"]: + env.Append(CPPDEFINES=["XR_DISABLED"]) +if env["minizip"]: + env.Append(CPPDEFINES=["MINIZIP_ENABLED"]) +if env["brotli"]: + env.Append(CPPDEFINES=["BROTLI_ENABLED"]) + +if not env["verbose"]: + methods.no_verbose(env) + modules_enabled = OrderedDict() env.module_dependencies = {} env.module_icons_paths = [] @@ -968,8 +1055,6 @@ if env.editor_build: print_error("Not all modules required by editor builds are enabled.") Exit(255) -env.version_info = methods.get_version_info(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"] @@ -989,28 +1074,6 @@ env["SHLIBSUFFIX"] = suffix + env["SHLIBSUFFIX"] env["OBJPREFIX"] = env["object_prefix"] env["SHOBJPREFIX"] = env["object_prefix"] -if env["disable_3d"]: - if env.editor_build: - print_error("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_error( - "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(env) - GLSL_BUILDERS = { "RD_GLSL": env.Builder( action=env.Run(glsl_builders.build_rd_headers), @@ -1051,6 +1114,14 @@ if env["ninja"]: if env["threads"]: env.Append(CPPDEFINES=["THREADS_ENABLED"]) +# Ensure build objects are put in their own folder if `redirect_build_objects` is enabled. +env.Prepend(LIBEMITTER=[methods.redirect_emitter]) +env.Prepend(SHLIBEMITTER=[methods.redirect_emitter]) +for key in (emitters := env.StaticObject.builder.emitter): + emitters[key] = ListEmitter([methods.redirect_emitter] + env.Flatten(emitters[key])) +for key in (emitters := env.SharedObject.builder.emitter): + emitters[key] = ListEmitter([methods.redirect_emitter] + env.Flatten(emitters[key])) + # Build subdirs, the build order is dependent on link order. Export("env") @@ -1082,11 +1153,11 @@ if "check_c_headers" in env: for header in headers: if conf.CheckCHeader(header): env.AppendUnique(CPPDEFINES=[headers[header]]) +conf.Finish() - -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) -methods.prepare_purge(env) -methods.prepare_timer() +# Miscellaneous & post-build methods. +if not env.GetOption("clean") and not env.GetOption("help"): + methods.dump(env) + methods.show_progress(env) + methods.prepare_purge(env) + methods.prepare_timer() diff --git a/engine/core/SCsub b/engine/core/SCsub index f055a75c..a252a074 100644 --- a/engine/core/SCsub +++ b/engine/core/SCsub @@ -51,8 +51,8 @@ if env["brotli"] and env["builtin_brotli"]: ] thirdparty_brotli_sources = [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources] - env_thirdparty.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"]) - env.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"]) + env_thirdparty.Prepend(CPPEXTPATH=[thirdparty_brotli_dir + "include"]) + env.Prepend(CPPEXTPATH=[thirdparty_brotli_dir + "include"]) if env.get("use_ubsan") or env.get("use_asan") or env.get("use_tsan") or env.get("use_lsan") or env.get("use_msan"): env_thirdparty.Append(CPPDEFINES=["BROTLI_BUILD_PORTABLE"]) @@ -69,8 +69,8 @@ if env["builtin_clipper2"]: ] thirdparty_clipper_sources = [thirdparty_clipper_dir + file for file in thirdparty_clipper_sources] - env_thirdparty.Prepend(CPPPATH=[thirdparty_clipper_dir + "include"]) - env.Prepend(CPPPATH=[thirdparty_clipper_dir + "include"]) + env_thirdparty.Prepend(CPPEXTPATH=[thirdparty_clipper_dir + "include"]) + env.Prepend(CPPEXTPATH=[thirdparty_clipper_dir + "include"]) env_thirdparty.Append(CPPDEFINES=["CLIPPER2_ENABLED"]) env.Append(CPPDEFINES=["CLIPPER2_ENABLED"]) @@ -94,9 +94,9 @@ if env["builtin_zlib"]: ] thirdparty_zlib_sources = [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources] - env_thirdparty.Prepend(CPPPATH=[thirdparty_zlib_dir]) + env_thirdparty.Prepend(CPPEXTPATH=[thirdparty_zlib_dir]) # Needs to be available in main env too - env.Prepend(CPPPATH=[thirdparty_zlib_dir]) + env.Prepend(CPPEXTPATH=[thirdparty_zlib_dir]) if env.dev_build: env_thirdparty.Append(CPPDEFINES=["ZLIB_DEBUG"]) # Affects headers so it should also be defined for Godot code @@ -148,9 +148,9 @@ if env["builtin_zstd"]: thirdparty_zstd_sources.append("decompress/huf_decompress_amd64.S") thirdparty_zstd_sources = [thirdparty_zstd_dir + file for file in thirdparty_zstd_sources] - env_thirdparty.Prepend(CPPPATH=[thirdparty_zstd_dir, thirdparty_zstd_dir + "common"]) + env_thirdparty.Prepend(CPPEXTPATH=[thirdparty_zstd_dir, thirdparty_zstd_dir + "common"]) env_thirdparty.Append(CPPDEFINES=["ZSTD_STATIC_LINKING_ONLY"]) - env.Prepend(CPPPATH=thirdparty_zstd_dir) + env.Prepend(CPPEXTPATH=thirdparty_zstd_dir) # Also needed in main env includes will trigger warnings env.Append(CPPDEFINES=["ZSTD_STATIC_LINKING_ONLY"]) @@ -167,10 +167,9 @@ env.add_source_files(env.core_sources, "*.cpp") # Generate disabled classes def disabled_class_builder(target, source, env): - with methods.generated_wrapper(target) as file: + with methods.generated_wrapper(str(target[0])) as file: for c in source[0].read(): - cs = c.strip() - if cs != "": + if cs := c.strip(): file.write(f"#define ClassDB_Disable_{cs} 1\n") @@ -179,49 +178,51 @@ env.CommandNoCache("disabled_classes.gen.h", env.Value(env.disabled_classes), en # Generate version info def version_info_builder(target, source, env): - with methods.generated_wrapper(target) as file: + with methods.generated_wrapper(str(target[0])) as file: file.write( """\ -#define VERSION_SHORT_NAME "{short_name}" -#define VERSION_NAME "{name}" -#define VERSION_MAJOR {major} -#define VERSION_MINOR {minor} -#define VERSION_PATCH {patch} -#define VERSION_STATUS "{status}" -#define VERSION_BUILD "{build}" -#define VERSION_MODULE_CONFIG "{module_config}" -#define VERSION_WEBSITE "{website}" -#define VERSION_DOCS_BRANCH "{docs_branch}" -#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH -""".format(**env.version_info) +#define GODOT_VERSION_SHORT_NAME "{short_name}" +#define GODOT_VERSION_NAME "{name}" +#define GODOT_VERSION_MAJOR {major} +#define GODOT_VERSION_MINOR {minor} +#define GODOT_VERSION_PATCH {patch} +#define GODOT_VERSION_STATUS "{status}" +#define GODOT_VERSION_BUILD "{build}" +#define GODOT_VERSION_MODULE_CONFIG "{module_config}" +#define GODOT_VERSION_WEBSITE "{website}" +#define GODOT_VERSION_DOCS_BRANCH "{docs_branch}" +#define GODOT_VERSION_DOCS_URL "https://docs.godotengine.org/en/" GODOT_VERSION_DOCS_BRANCH +""".format(**source[0].read()) ) -env.CommandNoCache("version_generated.gen.h", env.Value(env.version_info), env.Run(version_info_builder)) +env.CommandNoCache( + "version_generated.gen.h", + env.Value(methods.get_version_info(env.module_version_string)), + env.Run(version_info_builder), +) # Generate version hash def version_hash_builder(target, source, env): - with methods.generated_wrapper(target) as file: + with methods.generated_wrapper(str(target[0])) as file: file.write( """\ #include "core/version.h" -const char *const VERSION_HASH = "{git_hash}"; -const uint64_t VERSION_TIMESTAMP = {git_timestamp}; -""".format(**env.version_info) +const char *const GODOT_VERSION_HASH = "{git_hash}"; +const uint64_t GODOT_VERSION_TIMESTAMP = {git_timestamp}; +""".format(**source[0].read()) ) -gen_hash = env.CommandNoCache( - "version_hash.gen.cpp", env.Value(env.version_info["git_hash"]), env.Run(version_hash_builder) -) +gen_hash = env.CommandNoCache("version_hash.gen.cpp", env.Value(methods.get_git_info()), env.Run(version_hash_builder)) env.add_source_files(env.core_sources, gen_hash) # Generate AES256 script encryption key def encryption_key_builder(target, source, env): - with methods.generated_wrapper(target) as file: + with methods.generated_wrapper(str(target[0])) as file: file.write( f"""\ #include "core/config/project_settings.h" @@ -251,30 +252,21 @@ env.add_source_files(env.core_sources, gen_encrypt) # Certificates -env.Depends( - "#core/io/certs_compressed.gen.h", - ["#thirdparty/certs/ca-certificates.crt", env.Value(env["builtin_certs"]), env.Value(env["system_certs_path"])], -) env.CommandNoCache( "#core/io/certs_compressed.gen.h", - "#thirdparty/certs/ca-certificates.crt", + ["#thirdparty/certs/ca-certificates.crt", env.Value(env["builtin_certs"]), env.Value(env["system_certs_path"])], env.Run(core_builders.make_certs_header), ) # Authors -env.Depends("#core/authors.gen.h", "../AUTHORS.md") -env.CommandNoCache("#core/authors.gen.h", "../AUTHORS.md", env.Run(core_builders.make_authors_header)) +env.CommandNoCache("#core/authors.gen.h", "#AUTHORS.md", env.Run(core_builders.make_authors_header)) # Donors -env.Depends("#core/donors.gen.h", "../DONORS.md") -env.CommandNoCache("#core/donors.gen.h", "../DONORS.md", env.Run(core_builders.make_donors_header)) +env.CommandNoCache("#core/donors.gen.h", "#DONORS.md", env.Run(core_builders.make_donors_header)) # License -env.Depends("#core/license.gen.h", ["../COPYRIGHT.txt", "../LICENSE.txt"]) env.CommandNoCache( - "#core/license.gen.h", - ["../COPYRIGHT.txt", "../LICENSE.txt"], - env.Run(core_builders.make_license_header), + "#core/license.gen.h", ["#COPYRIGHT.txt", "#LICENSE.txt"], env.Run(core_builders.make_license_header) ) # Chain load SCsubs diff --git a/engine/core/config/engine.cpp b/engine/core/config/engine.cpp index 402e6281..0f7ead2f 100644 --- a/engine/core/config/engine.cpp +++ b/engine/core/config/engine.cpp @@ -125,17 +125,17 @@ double Engine::get_unfrozen_time_scale() const { Dictionary Engine::get_version_info() const { Dictionary dict; - dict["major"] = VERSION_MAJOR; - dict["minor"] = VERSION_MINOR; - dict["patch"] = VERSION_PATCH; - dict["hex"] = VERSION_HEX; - dict["status"] = VERSION_STATUS; - dict["build"] = VERSION_BUILD; + dict["major"] = GODOT_VERSION_MAJOR; + dict["minor"] = GODOT_VERSION_MINOR; + dict["patch"] = GODOT_VERSION_PATCH; + dict["hex"] = GODOT_VERSION_HEX; + dict["status"] = GODOT_VERSION_STATUS; + dict["build"] = GODOT_VERSION_BUILD; - String hash = String(VERSION_HASH); + String hash = String(GODOT_VERSION_HASH); dict["hash"] = hash.is_empty() ? String("unknown") : hash; - dict["timestamp"] = VERSION_TIMESTAMP; + dict["timestamp"] = GODOT_VERSION_TIMESTAMP; String stringver = String(dict["major"]) + "." + String(dict["minor"]); if ((int)dict["patch"] != 0) { diff --git a/engine/core/config/engine.h b/engine/core/config/engine.h index ec5fb955..701cfda5 100644 --- a/engine/core/config/engine.h +++ b/engine/core/config/engine.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef ENGINE_H -#define ENGINE_H +#pragma once #include "core/os/main_loop.h" #include "core/string/ustring.h" @@ -214,5 +213,3 @@ public: Engine(); virtual ~Engine(); }; - -#endif // ENGINE_H diff --git a/engine/core/config/project_settings.cpp b/engine/core/config/project_settings.cpp index e4cc0f9c..565a9734 100644 --- a/engine/core/config/project_settings.cpp +++ b/engine/core/config/project_settings.cpp @@ -77,7 +77,7 @@ String ProjectSettings::get_imported_files_path() const { // This is used by the project manager to provide the initial_settings for config/features. const PackedStringArray ProjectSettings::get_required_features() { PackedStringArray features; - features.append(VERSION_BRANCH); + features.append(GODOT_VERSION_BRANCH); #ifdef REAL_T_IS_DOUBLE features.append("Double Precision"); #endif @@ -92,9 +92,9 @@ const PackedStringArray ProjectSettings::_get_supported_features() { #endif // Allow pinning to a specific patch number or build type by marking // them as supported. They're only used if the user adds them manually. - features.append(VERSION_BRANCH "." _MKSTR(VERSION_PATCH)); - features.append(VERSION_FULL_CONFIG); - features.append(VERSION_FULL_BUILD); + features.append(GODOT_VERSION_BRANCH "." _MKSTR(GODOT_VERSION_PATCH)); + features.append(GODOT_VERSION_FULL_CONFIG); + features.append(GODOT_VERSION_FULL_BUILD); #ifdef RD_ENABLED features.append("Forward Plus"); @@ -173,7 +173,7 @@ String ProjectSettings::localize_path(const String &p_path) const { if (dir->change_dir(path) == OK) { String cwd = dir->get_current_dir(); - cwd = cwd.replace("\\", "/"); + cwd = cwd.replace_char('\\', '/'); // Ensure that we end with a '/'. // This is important to ensure that we do not wrongly localize the resource path @@ -208,7 +208,7 @@ String ProjectSettings::localize_path(const String &p_path) const { if (plocal[plocal.length() - 1] == '/') { sep += 1; } - return plocal + path.substr(sep, path.size() - sep); + return plocal + path.substr(sep); } } @@ -289,7 +289,7 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) { remove_autoload(node_name); } } else if (p_name.operator String().begins_with("global_group/")) { - String group_name = p_name.operator String().get_slice("/", 1); + String group_name = p_name.operator String().get_slicec('/', 1); if (global_groups.has(group_name)) { remove_global_group(group_name); } @@ -340,7 +340,7 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) { } add_autoload(autoload); } else if (p_name.operator String().begins_with("global_group/")) { - String group_name = p_name.operator String().get_slice("/", 1); + String group_name = p_name.operator String().get_slicec('/', 1); add_global_group(group_name, p_value); } } @@ -359,14 +359,14 @@ bool ProjectSettings::_get(const StringName &p_name, Variant &r_ret) const { return true; } -Variant ProjectSettings::get_setting_with_override(const StringName &p_name) const { +Variant ProjectSettings::get_setting_with_override_and_custom_features(const StringName &p_name, const Vector &p_features) const { _THREAD_SAFE_METHOD_ StringName name = p_name; if (feature_overrides.has(name)) { const LocalVector> &overrides = feature_overrides[name]; for (uint32_t i = 0; i < overrides.size(); i++) { - if (OS::get_singleton()->has_feature(overrides[i].first)) { // Custom features are checked in OS.has_feature() already. No need to check twice. + if (p_features.has(String(overrides[i].first).to_lower())) { if (props.has(overrides[i].second)) { name = overrides[i].second; break; @@ -376,12 +376,39 @@ Variant ProjectSettings::get_setting_with_override(const StringName &p_name) con } if (!props.has(name)) { - WARN_PRINT(vformat("Property not found: '%s'.", String(name))); + WARN_PRINT("Property not found: " + String(name)); return Variant(); } return props[name].variant; } +Variant ProjectSettings::get_setting_with_override(const StringName &p_name) const { + _THREAD_SAFE_METHOD_ + + const LocalVector> *overrides = feature_overrides.getptr(p_name); + if (overrides) { + for (uint32_t i = 0; i < overrides->size(); i++) { + if (!OS::get_singleton()->has_feature((*overrides)[i].first)) { + continue; + } + + // Custom features are checked in OS.has_feature() already. No need to check twice. + const RBMap::Element *override_prop = props.find((*overrides)[i].second); + if (override_prop) { + return override_prop->get().variant; + } + } + } + + const RBMap::Element *prop = props.find(p_name); + if (!prop) { + WARN_PRINT(vformat("Property not found: '%s'.", p_name)); + return Variant(); + } + + return prop->get().variant; +} + struct _VCSort { String name; Variant::Type type = Variant::VARIANT_MAX; @@ -564,7 +591,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b if (!OS::get_singleton()->get_resource_dir().is_empty()) { // OS will call ProjectSettings->get_resource_path which will be empty if not overridden! // If the OS would rather use a specific location, then it will not be empty. - resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/"); + resource_path = OS::get_singleton()->get_resource_dir().replace_char('\\', '/'); if (!resource_path.is_empty() && resource_path[resource_path.length() - 1] == '/') { resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end. } @@ -685,7 +712,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b while (true) { // Set the resource path early so things can be resolved when loading. resource_path = current_dir; - resource_path = resource_path.replace("\\", "/"); // Windows path to Unix path just in case. + resource_path = resource_path.replace_char('\\', '/'); // Windows path to Unix path just in case. err = _load_settings_text_or_binary(current_dir.path_join("project.godot"), current_dir.path_join("project.binary")); if (err == OK && !p_ignore_override) { // Optional, we don't mind if it fails. @@ -770,8 +797,7 @@ Error ProjectSettings::_load_settings_binary(const String &p_path) { cs.resize(slen + 1); cs[slen] = 0; f->get_buffer((uint8_t *)cs.ptr(), slen); - String key; - key.parse_utf8(cs.ptr(), slen); + String key = String::utf8(cs.ptr(), slen); uint32_t vlen = f->get_32(); Vector d; @@ -1129,7 +1155,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust category = ""; } else { category = category.substr(0, div); - name = name.substr(div + 1, name.size()); + name = name.substr(div + 1); } save_props[category].push_back(name); } @@ -1141,7 +1167,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust save_features += ","; } - String f = p_custom_features[i].strip_edges().replace("\"", ""); + String f = p_custom_features[i].strip_edges().remove_char('\"'); save_features += f; } @@ -1408,6 +1434,7 @@ void ProjectSettings::_bind_methods() { ClassDB::bind_method(D_METHOD("get_setting", "name", "default_value"), &ProjectSettings::get_setting, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("get_setting_with_override", "name"), &ProjectSettings::get_setting_with_override); ClassDB::bind_method(D_METHOD("get_global_class_list"), &ProjectSettings::get_global_class_list); + ClassDB::bind_method(D_METHOD("get_setting_with_override_and_custom_features", "name", "features"), &ProjectSettings::get_setting_with_override_and_custom_features); ClassDB::bind_method(D_METHOD("set_order", "name", "position"), &ProjectSettings::set_order); ClassDB::bind_method(D_METHOD("get_order", "name"), &ProjectSettings::get_order); ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &ProjectSettings::set_initial_value); @@ -1434,8 +1461,8 @@ void ProjectSettings::_add_builtin_input_map() { Array events; // Convert list of input events into array - for (List>::Element *I = E.value.front(); I; I = I->next()) { - events.push_back(I->get()); + for (const Ref &event : E.value) { + events.push_back(event); } Dictionary action; @@ -1488,6 +1515,9 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("application/config/auto_accept_quit", true); GLOBAL_DEF("application/config/quit_on_go_back", true); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "accessibility/general/accessibility_support", PROPERTY_HINT_ENUM, "Auto (When Screen Reader is Running),Always Active,Disabled"), 0); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "accessibility/general/updates_per_second", PROPERTY_HINT_RANGE, "1,100,1"), 60); + // The default window size is tuned to: // - Have a 16:9 aspect ratio, // - Have both dimensions divisible by 8 to better play along with video recording, @@ -1497,9 +1527,10 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen"), 0); - // Keep the enum values in sync with the `DisplayServer::SCREEN_` enum. - GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/initial_position_type", PROPERTY_HINT_ENUM, "Absolute,Center of Primary Screen,Center of Other Screen,Center of Screen With Mouse Pointer,Center of Screen With Keyboard Focus"), 1); + // Keep the enum values in sync with the `Window::WINDOW_INITIAL_POSITION_` enum. + GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/initial_position_type", PROPERTY_HINT_ENUM, "Absolute:0,Center of Primary Screen:1,Center of Other Screen:3,Center of Screen With Mouse Pointer:4,Center of Screen With Keyboard Focus:5"), 1); GLOBAL_DEF_BASIC(PropertyInfo(Variant::VECTOR2I, "display/window/size/initial_position"), Vector2i()); + // Keep the enum values in sync with the `DisplayServer::SCREEN_` enum. GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/initial_screen", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), 0); GLOBAL_DEF_BASIC("display/window/size/resizable", true); @@ -1509,6 +1540,8 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("display/window/size/extend_to_title", false); GLOBAL_DEF("display/window/size/no_focus", false); GLOBAL_DEF("display/window/size/sharp_corners", false); + GLOBAL_DEF("display/window/size/minimize_disabled", false); + GLOBAL_DEF("display/window/size/maximize_disabled", false); GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"), 0); // 8K resolution GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 0); // 8K resolution @@ -1543,8 +1576,13 @@ ProjectSettings::ProjectSettings() { #else custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Unsafe (deprecated),Safe,Separate"); #endif + +#ifndef PHYSICS_2D_DISABLED GLOBAL_DEF("physics/2d/run_on_separate_thread", false); +#endif // PHYSICS_2D_DISABLED +#ifndef PHYSICS_3D_DISABLED GLOBAL_DEF("physics/3d/run_on_separate_thread", false); +#endif // PHYSICS_3D_DISABLED GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "display/window/stretch/mode", PROPERTY_HINT_ENUM, "disabled,canvas_items,viewport"), "disabled"); GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "display/window/stretch/aspect", PROPERTY_HINT_ENUM, "ignore,keep,keep_width,keep_height,expand"), "keep"); @@ -1612,6 +1650,8 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_long_press_as_right_click", false); GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_pan_and_scale_gestures", false); GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "input_devices/pointing/android/rotary_input_scroll_axis", PROPERTY_HINT_ENUM, "Horizontal,Vertical"), 1); + GLOBAL_DEF("input_devices/pointing/android/override_volume_buttons", false); + GLOBAL_DEF_BASIC("input_devices/pointing/android/disable_scroll_deadzone", false); // These properties will not show up in the dialog. If you want to exclude whole groups, use add_hidden_prefix(). GLOBAL_DEF_INTERNAL("application/config/features", PackedStringArray()); @@ -1620,6 +1660,19 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF_INTERNAL("internationalization/locale/translations_pot_files", PackedStringArray()); GLOBAL_DEF_INTERNAL("internationalization/locale/translation_add_builtin_strings_to_pot", false); +#if !defined(NAVIGATION_2D_DISABLED) || !defined(NAVIGATION_3D_DISABLED) + GLOBAL_DEF("navigation/world/map_use_async_iterations", true); + + GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_multiple_threads", true); + GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_high_priority_threads", true); + + GLOBAL_DEF("navigation/pathfinding/max_threads", 4); + + GLOBAL_DEF("navigation/baking/use_crash_prevention_checks", true); + GLOBAL_DEF("navigation/baking/thread_model/baking_use_multiple_threads", true); + GLOBAL_DEF("navigation/baking/thread_model/baking_use_high_priority_threads", true); +#endif // !defined(NAVIGATION_2D_DISABLED) || !defined(NAVIGATION_3D_DISABLED) + ProjectSettings::get_singleton()->add_hidden_prefix("input/"); } diff --git a/engine/core/config/project_settings.h b/engine/core/config/project_settings.h index 02049290..65fa72ea 100644 --- a/engine/core/config/project_settings.h +++ b/engine/core/config/project_settings.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef PROJECT_SETTINGS_H -#define PROJECT_SETTINGS_H +#pragma once #include "core/object/class_db.h" @@ -194,6 +193,7 @@ public: List get_input_presets() const { return input_presets; } Variant get_setting_with_override(const StringName &p_name) const; + Variant get_setting_with_override_and_custom_features(const StringName &p_name, const Vector &p_features) const; bool is_using_datapack() const; bool is_project_loaded() const; @@ -243,5 +243,3 @@ Variant _GLOBAL_DEF(const PropertyInfo &p_info, const Variant &p_default, bool p #define GLOBAL_DEF_RST_NOVAL_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true, true) #define GLOBAL_DEF_INTERNAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, false, false, true) - -#endif // PROJECT_SETTINGS_H diff --git a/engine/core/core_bind.compat.inc b/engine/core/core_bind.compat.inc index 22c78623..8bfa66e4 100644 --- a/engine/core/core_bind.compat.inc +++ b/engine/core/core_bind.compat.inc @@ -30,7 +30,7 @@ #ifndef DISABLE_DEPRECATED -namespace core_bind { +namespace CoreBind { // Semaphore @@ -53,10 +53,12 @@ Dictionary OS::_execute_with_pipe_bind_compat_94434(const String &p_path, const } void OS::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("read_string_from_stdin", "buffer_size"), &OS::read_string_from_stdin); + ClassDB::bind_compatibility_method(D_METHOD("read_buffer_from_stdin", "buffer_size"), &OS::read_buffer_from_stdin); ClassDB::bind_compatibility_method(D_METHOD("read_string_from_stdin"), &OS::_read_string_from_stdin_bind_compat_91201); ClassDB::bind_compatibility_method(D_METHOD("execute_with_pipe", "path", "arguments"), &OS::_execute_with_pipe_bind_compat_94434); } -} // namespace core_bind +} // namespace CoreBind #endif // DISABLE_DEPRECATED diff --git a/engine/core/core_bind.cpp b/engine/core/core_bind.cpp index acd58978..d55305b2 100644 --- a/engine/core/core_bind.cpp +++ b/engine/core/core_bind.cpp @@ -42,7 +42,7 @@ #include "core/os/thread_safe.h" #include "core/variant/typed_array.h" -namespace core_bind { +namespace CoreBind { ////// ResourceLoader ////// @@ -466,8 +466,8 @@ bool OS::is_restart_on_exit_set() const { Vector OS::get_restart_on_exit_arguments() const { List args = ::OS::get_singleton()->get_restart_on_exit_arguments(); Vector args_vector; - for (List::Element *E = args.front(); E; E = E->next()) { - args_vector.push_back(E->get()); + for (const String &arg : args) { + args_vector.push_back(arg); } return args_vector; @@ -657,8 +657,8 @@ void OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_system_font_path_for_text", "font_name", "text", "locale", "script", "weight", "stretch", "italic"), &OS::get_system_font_path_for_text, DEFVAL(String()), DEFVAL(String()), DEFVAL(400), DEFVAL(100), DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path); - ClassDB::bind_method(D_METHOD("read_string_from_stdin", "buffer_size"), &OS::read_string_from_stdin); - ClassDB::bind_method(D_METHOD("read_buffer_from_stdin", "buffer_size"), &OS::read_buffer_from_stdin); + ClassDB::bind_method(D_METHOD("read_string_from_stdin", "buffer_size"), &OS::read_string_from_stdin, DEFVAL(1024)); + ClassDB::bind_method(D_METHOD("read_buffer_from_stdin", "buffer_size"), &OS::read_buffer_from_stdin, DEFVAL(1024)); ClassDB::bind_method(D_METHOD("get_stdin_type"), &OS::get_stdin_type); ClassDB::bind_method(D_METHOD("get_stdout_type"), &OS::get_stdout_type); ClassDB::bind_method(D_METHOD("get_stderr_type"), &OS::get_stderr_type); @@ -806,13 +806,11 @@ Vector Geometry2D::get_closest_points_between_segments(const Vector2 &p } Vector2 Geometry2D::get_closest_point_to_segment(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b) { - Vector2 s[2] = { p_a, p_b }; - return ::Geometry2D::get_closest_point_to_segment(p_point, s); + return ::Geometry2D::get_closest_point_to_segment(p_point, p_a, p_b); } Vector2 Geometry2D::get_closest_point_to_segment_uncapped(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b) { - Vector2 s[2] = { p_a, p_b }; - return ::Geometry2D::get_closest_point_to_segment_uncapped(p_point, s); + return ::Geometry2D::get_closest_point_to_segment_uncapped(p_point, p_a, p_b); } bool Geometry2D::point_is_inside_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) const { @@ -1069,13 +1067,11 @@ Vector Geometry3D::get_closest_points_between_segments(const Vector3 &p } Vector3 Geometry3D::get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b) { - Vector3 s[2] = { p_a, p_b }; - return ::Geometry3D::get_closest_point_to_segment(p_point, s); + return ::Geometry3D::get_closest_point_to_segment(p_point, p_a, p_b); } Vector3 Geometry3D::get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b) { - Vector3 s[2] = { p_a, p_b }; - return ::Geometry3D::get_closest_point_to_segment_uncapped(p_point, s); + return ::Geometry3D::get_closest_point_to_segment_uncapped(p_point, p_a, p_b); } Vector3 Geometry3D::get_triangle_barycentric_coords(const Vector3 &p_point, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2) { @@ -1241,6 +1237,9 @@ Vector Marshalls::base64_to_raw(const String &p_str) { } String Marshalls::utf8_to_base64(const String &p_str) { + if (p_str.is_empty()) { + return String(); + } CharString cstr = p_str.utf8(); String ret = CryptoCore::b64_encode_str((unsigned char *)cstr.get_data(), cstr.length()); ERR_FAIL_COND_V(ret.is_empty(), ret); @@ -1340,6 +1339,7 @@ void Thread::_start_func(void *ud) { // When the call returns, we will reference the thread again if possible. ObjectID th_instance_id = t->get_instance_id(); Callable target_callable = t->target_callable; + String id = t->get_id(); t = Ref(); Callable::CallError ce; @@ -1347,7 +1347,7 @@ void Thread::_start_func(void *ud) { target_callable.callp(nullptr, 0, ret, ce); // If script properly kept a reference to the thread, we should be able to re-reference it now // (well, or if the call failed, since we had to break chains anyway because the outcome isn't known upfront). - t = Ref(ObjectDB::get_instance(th_instance_id)); + t = ObjectDB::get_ref(th_instance_id); if (t.is_valid()) { t->ret = ret; t->running.clear(); @@ -1357,7 +1357,7 @@ void Thread::_start_func(void *ud) { } if (ce.error != Callable::CallError::CALL_OK) { - ERR_FAIL_MSG(vformat("Could not call function '%s' to start thread %d: %s.", func_name, t->get_id(), Variant::get_callable_error_text(t->target_callable, nullptr, 0, ce))); + ERR_FAIL_MSG(vformat("Could not call function '%s' to start thread %s: %s.", func_name, id, Variant::get_callable_error_text(target_callable, nullptr, 0, ce))); } } @@ -1419,7 +1419,7 @@ void Thread::_bind_methods() { BIND_ENUM_CONSTANT(PRIORITY_HIGH); } -namespace special { +namespace Special { ////// ClassDB ////// @@ -1438,8 +1438,8 @@ PackedStringArray ClassDB::get_class_list() const { } PackedStringArray ClassDB::get_inheriters_from_class(const StringName &p_class) const { - List classes; - ::ClassDB::get_inheriters_from_class(p_class, &classes); + LocalVector classes; + ::ClassDB::get_inheriters_from_class(p_class, classes); PackedStringArray ret; ret.resize(classes.size()); @@ -1746,7 +1746,7 @@ void ClassDB::_bind_methods() { BIND_ENUM_CONSTANT(API_NONE); } -} // namespace special +} // namespace Special ////// Engine ////// @@ -1876,8 +1876,8 @@ Vector Engine::get_singleton_list() const { List<::Engine::Singleton> singletons; ::Engine::get_singleton()->get_singletons(&singletons); Vector ret; - for (List<::Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) { - ret.push_back(E->get().name); + for (const ::Engine::Singleton &E : singletons) { + ret.push_back(E.name); } return ret; } @@ -2190,4 +2190,4 @@ void EngineDebugger::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_breakpoints"), &EngineDebugger::clear_breakpoints); } -} // namespace core_bind +} // namespace CoreBind diff --git a/engine/core/core_bind.h b/engine/core/core_bind.h index b96dc56b..ec74c53d 100644 --- a/engine/core/core_bind.h +++ b/engine/core/core_bind.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef CORE_BIND_H -#define CORE_BIND_H +#pragma once #include "core/debugger/engine_profiler.h" #include "core/io/resource_loader.h" @@ -42,7 +41,7 @@ class MainLoop; template class TypedArray; -namespace core_bind { +namespace CoreBind { class ResourceLoader : public Object { GDCLASS(ResourceLoader, Object); @@ -458,7 +457,7 @@ public: static void set_thread_safety_checks_enabled(bool p_enabled); }; -namespace special { +namespace Special { class ClassDB : public Object { GDCLASS(ClassDB, Object); @@ -524,7 +523,7 @@ public: ~ClassDB() {} }; -} // namespace special +} // namespace Special class Engine : public Object { GDCLASS(Engine, Object); @@ -652,23 +651,21 @@ public: ~EngineDebugger(); }; -} // namespace core_bind +} // namespace CoreBind -VARIANT_ENUM_CAST(core_bind::ResourceLoader::ThreadLoadStatus); -VARIANT_ENUM_CAST(core_bind::ResourceLoader::CacheMode); +VARIANT_ENUM_CAST(CoreBind::ResourceLoader::ThreadLoadStatus); +VARIANT_ENUM_CAST(CoreBind::ResourceLoader::CacheMode); -VARIANT_BITFIELD_CAST(core_bind::ResourceSaver::SaverFlags); +VARIANT_BITFIELD_CAST(CoreBind::ResourceSaver::SaverFlags); -VARIANT_ENUM_CAST(core_bind::OS::RenderingDriver); -VARIANT_ENUM_CAST(core_bind::OS::SystemDir); -VARIANT_ENUM_CAST(core_bind::OS::StdHandleType); +VARIANT_ENUM_CAST(CoreBind::OS::RenderingDriver); +VARIANT_ENUM_CAST(CoreBind::OS::SystemDir); +VARIANT_ENUM_CAST(CoreBind::OS::StdHandleType); -VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation); -VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType); -VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyEndType); +VARIANT_ENUM_CAST(CoreBind::Geometry2D::PolyBooleanOperation); +VARIANT_ENUM_CAST(CoreBind::Geometry2D::PolyJoinType); +VARIANT_ENUM_CAST(CoreBind::Geometry2D::PolyEndType); -VARIANT_ENUM_CAST(core_bind::Thread::Priority); +VARIANT_ENUM_CAST(CoreBind::Thread::Priority); -VARIANT_ENUM_CAST(core_bind::special::ClassDB::APIType); - -#endif // CORE_BIND_H +VARIANT_ENUM_CAST(CoreBind::Special::ClassDB::APIType); diff --git a/engine/core/core_builders.py b/engine/core/core_builders.py index d7c0603c..5eaac237 100644 --- a/engine/core/core_builders.py +++ b/engine/core/core_builders.py @@ -1,171 +1,104 @@ """Functions used to generate source files during build time""" -import zlib +from collections import OrderedDict +from io import TextIOWrapper - -def escape_string(s): - def charcode_to_c_escapes(c): - rev_result = [] - while c >= 256: - c, low = (c // 256, c % 256) - rev_result.append("\\%03o" % low) - rev_result.append("\\%03o" % c) - return "".join(reversed(rev_result)) - - result = "" - if isinstance(s, str): - s = s.encode("utf-8") - for c in s: - if not (32 <= c < 127) or c in (ord("\\"), ord('"')): - result += charcode_to_c_escapes(c) - else: - result += chr(c) - return result +import methods def make_certs_header(target, source, env): - src = str(source[0]) - dst = str(target[0]) - with open(src, "rb") as f, open(dst, "w", encoding="utf-8", newline="\n") as g: - buf = f.read() - decomp_size = len(buf) - - # Use maximum zlib compression level to further reduce file size - # (at the cost of initial build times). - buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION) - - g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - g.write("#ifndef CERTS_COMPRESSED_GEN_H\n") - g.write("#define CERTS_COMPRESSED_GEN_H\n") + buffer = methods.get_buffer(str(source[0])) + decomp_size = len(buffer) + buffer = methods.compress_buffer(buffer) + with methods.generated_wrapper(str(target[0])) as file: # System certs path. Editor will use them if defined. (for package maintainers) - path = env["system_certs_path"] - g.write('#define _SYSTEM_CERTS_PATH "%s"\n' % str(path)) + file.write('#define _SYSTEM_CERTS_PATH "{}"\n'.format(env["system_certs_path"])) if env["builtin_certs"]: # Defined here and not in env so changing it does not trigger a full rebuild. - g.write("#define BUILTIN_CERTS_ENABLED\n") - g.write("static const int _certs_compressed_size = " + str(len(buf)) + ";\n") - g.write("static const int _certs_uncompressed_size = " + str(decomp_size) + ";\n") - g.write("static const unsigned char _certs_compressed[] = {\n") - for i in range(len(buf)): - g.write("\t" + str(buf[i]) + ",\n") - g.write("};\n") - g.write("#endif // CERTS_COMPRESSED_GEN_H") + file.write(f"""\ +#define BUILTIN_CERTS_ENABLED + +inline constexpr int _certs_compressed_size = {len(buffer)}; +inline constexpr int _certs_uncompressed_size = {decomp_size}; +inline constexpr unsigned char _certs_compressed[] = {{ + {methods.format_buffer(buffer, 1)} +}}; +""") def make_authors_header(target, source, env): - sections = [ - "Project Founders", - "Lead Developer", - "Project Manager", - "Developers", - ] - sections_id = [ - "AUTHORS_FOUNDERS", - "AUTHORS_LEAD_DEVELOPERS", - "AUTHORS_PROJECT_MANAGERS", - "AUTHORS_DEVELOPERS", - ] + SECTIONS = { + "Project Founders": "AUTHORS_FOUNDERS", + "Lead Developer": "AUTHORS_LEAD_DEVELOPERS", + "Project Manager": "AUTHORS_PROJECT_MANAGERS", + "Developers": "AUTHORS_DEVELOPERS", + } + buffer = methods.get_buffer(str(source[0])) + reading = False - src = str(source[0]) - dst = str(target[0]) - with open(src, "r", encoding="utf-8") as f, open(dst, "w", encoding="utf-8", newline="\n") as g: - g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - g.write("#ifndef AUTHORS_GEN_H\n") - g.write("#define AUTHORS_GEN_H\n") - - reading = False + with methods.generated_wrapper(str(target[0])) as file: def close_section(): - g.write("\t0\n") - g.write("};\n") + file.write("\tnullptr,\n};\n\n") - for line in f: - if reading: - if line.startswith(" "): - g.write('\t"' + escape_string(line.strip()) + '",\n') - continue - if line.startswith("## "): + for line in buffer.decode().splitlines(): + if line.startswith(" ") and reading: + file.write(f'\t"{methods.to_escaped_cstring(line).strip()}",\n') + elif line.startswith("## "): if reading: close_section() reading = False - for section, section_id in zip(sections, sections_id): - if line.strip().endswith(section): - current_section = escape_string(section_id) - reading = True - g.write("const char *const " + current_section + "[] = {\n") - break + section = SECTIONS[line[3:].strip()] + if section: + file.write(f"inline constexpr const char *{section}[] = {{\n") + reading = True if reading: close_section() - g.write("#endif // AUTHORS_GEN_H\n") - def make_donors_header(target, source, env): - sections = [ - "Patrons", - "Platinum sponsors", - "Gold sponsors", - "Silver sponsors", - "Diamond members", - "Titanium members", - "Platinum members", - "Gold members", - ] - sections_id = [ - "DONORS_PATRONS", - "DONORS_SPONSORS_PLATINUM", - "DONORS_SPONSORS_GOLD", - "DONORS_SPONSORS_SILVER", - "DONORS_MEMBERS_DIAMOND", - "DONORS_MEMBERS_TITANIUM", - "DONORS_MEMBERS_PLATINUM", - "DONORS_MEMBERS_GOLD", - ] + SECTIONS = { + "Patrons": "DONORS_PATRONS", + "Platinum sponsors": "DONORS_SPONSORS_PLATINUM", + "Gold sponsors": "DONORS_SPONSORS_GOLD", + "Silver sponsors": "DONORS_SPONSORS_SILVER", + "Diamond members": "DONORS_MEMBERS_DIAMOND", + "Titanium members": "DONORS_MEMBERS_TITANIUM", + "Platinum members": "DONORS_MEMBERS_PLATINUM", + "Gold members": "DONORS_MEMBERS_GOLD", + } + buffer = methods.get_buffer(str(source[0])) + reading = False - src = str(source[0]) - dst = str(target[0]) - with open(src, "r", encoding="utf-8") as f, open(dst, "w", encoding="utf-8", newline="\n") as g: - g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - g.write("#ifndef DONORS_GEN_H\n") - g.write("#define DONORS_GEN_H\n") - - reading = False + with methods.generated_wrapper(str(target[0])) as file: def close_section(): - g.write("\t0\n") - g.write("};\n") + file.write("\tnullptr,\n};\n\n") - for line in f: - if reading >= 0: - if line.startswith(" "): - g.write('\t"' + escape_string(line.strip()) + '",\n') - continue - if line.startswith("## "): + for line in buffer.decode().splitlines(): + if line.startswith(" ") and reading: + file.write(f'\t"{methods.to_escaped_cstring(line).strip()}",\n') + elif line.startswith("## "): if reading: close_section() reading = False - for section, section_id in zip(sections, sections_id): - if line.strip().endswith(section): - current_section = escape_string(section_id) - reading = True - g.write("const char *const " + current_section + "[] = {\n") - break + section = SECTIONS.get(line[3:].strip()) + if section: + file.write(f"inline constexpr const char *{section}[] = {{\n") + reading = True if reading: close_section() - g.write("#endif // DONORS_GEN_H\n") - def make_license_header(target, source, env): src_copyright = str(source[0]) src_license = str(source[1]) - dst = str(target[0]) class LicenseReader: - def __init__(self, license_file): + def __init__(self, license_file: TextIOWrapper): self._license_file = license_file self.line_num = 0 self.current = self.next_line() @@ -188,9 +121,7 @@ def make_license_header(target, source, env): lines.append(self.current.strip()) return (tag, lines) - from collections import OrderedDict - - projects: dict = OrderedDict() + projects = OrderedDict() license_list = [] with open(src_copyright, "r", encoding="utf-8") as copyright_file: @@ -212,7 +143,7 @@ def make_license_header(target, source, env): part = {} reader.next_line() - data_list: list = [] + data_list = [] for project in iter(projects.values()): for part in project: part["file_index"] = len(data_list) @@ -220,96 +151,76 @@ def make_license_header(target, source, env): part["copyright_index"] = len(data_list) data_list += part["Copyright"] - with open(dst, "w", encoding="utf-8", newline="\n") as f: - f.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - f.write("#ifndef LICENSE_GEN_H\n") - f.write("#define LICENSE_GEN_H\n") - f.write("const char *const GODOT_LICENSE_TEXT =") + with open(src_license, "r", encoding="utf-8") as file: + license_text = file.read() - with open(src_license, "r", encoding="utf-8") as license_file: - for line in license_file: - escaped_string = escape_string(line.strip()) - f.write('\n\t\t"' + escaped_string + '\\n"') - f.write(";\n\n") + with methods.generated_wrapper(str(target[0])) as file: + file.write(f"""\ +inline constexpr const char *GODOT_LICENSE_TEXT = {{ +{methods.to_raw_cstring(license_text)} +}}; - f.write( - "struct ComponentCopyrightPart {\n" - "\tconst char *license;\n" - "\tconst char *const *files;\n" - "\tconst char *const *copyright_statements;\n" - "\tint file_count;\n" - "\tint copyright_count;\n" - "};\n\n" - ) +struct ComponentCopyrightPart {{ + const char *license; + const char *const *files; + const char *const *copyright_statements; + int file_count; + int copyright_count; +}}; - f.write( - "struct ComponentCopyright {\n" - "\tconst char *name;\n" - "\tconst ComponentCopyrightPart *parts;\n" - "\tint part_count;\n" - "};\n\n" - ) +struct ComponentCopyright {{ + const char *name; + const ComponentCopyrightPart *parts; + int part_count; +}}; - f.write("const char *const COPYRIGHT_INFO_DATA[] = {\n") +""") + + file.write("inline constexpr const char *COPYRIGHT_INFO_DATA[] = {\n") for line in data_list: - f.write('\t"' + escape_string(line) + '",\n') - f.write("};\n\n") + file.write(f'\t"{methods.to_escaped_cstring(line)}",\n') + file.write("};\n\n") - f.write("const ComponentCopyrightPart COPYRIGHT_PROJECT_PARTS[] = {\n") + file.write("inline constexpr ComponentCopyrightPart COPYRIGHT_PROJECT_PARTS[] = {\n") part_index = 0 part_indexes = {} for project_name, project in iter(projects.items()): part_indexes[project_name] = part_index for part in project: - f.write( - '\t{ "' - + escape_string(part["License"][0]) - + '", ' - + "©RIGHT_INFO_DATA[" - + str(part["file_index"]) - + "], " - + "©RIGHT_INFO_DATA[" - + str(part["copyright_index"]) - + "], " - + str(len(part["Files"])) - + ", " - + str(len(part["Copyright"])) - + " },\n" + file.write( + f'\t{{ "{methods.to_escaped_cstring(part["License"][0])}", ' + + f"©RIGHT_INFO_DATA[{part['file_index']}], " + + f"©RIGHT_INFO_DATA[{part['copyright_index']}], " + + f"{len(part['Files'])}, {len(part['Copyright'])} }},\n" ) part_index += 1 - f.write("};\n\n") + file.write("};\n\n") - f.write("const int COPYRIGHT_INFO_COUNT = " + str(len(projects)) + ";\n") + file.write(f"inline constexpr int COPYRIGHT_INFO_COUNT = {len(projects)};\n") - f.write("const ComponentCopyright COPYRIGHT_INFO[] = {\n") + file.write("inline constexpr ComponentCopyright COPYRIGHT_INFO[] = {\n") for project_name, project in iter(projects.items()): - f.write( - '\t{ "' - + escape_string(project_name) - + '", ' - + "©RIGHT_PROJECT_PARTS[" - + str(part_indexes[project_name]) - + "], " - + str(len(project)) - + " },\n" + file.write( + f'\t{{ "{methods.to_escaped_cstring(project_name)}", ' + + f"©RIGHT_PROJECT_PARTS[{part_indexes[project_name]}], " + + f"{len(project)} }},\n" ) - f.write("};\n\n") + file.write("};\n\n") - f.write("const int LICENSE_COUNT = " + str(len(license_list)) + ";\n") + file.write(f"inline constexpr int LICENSE_COUNT = {len(license_list)};\n") - f.write("const char *const LICENSE_NAMES[] = {\n") + file.write("inline constexpr const char *LICENSE_NAMES[] = {\n") for license in license_list: - f.write('\t"' + escape_string(license[0]) + '",\n') - f.write("};\n\n") + file.write(f'\t"{methods.to_escaped_cstring(license[0])}",\n') + file.write("};\n\n") - f.write("const char *const LICENSE_BODIES[] = {\n\n") + file.write("inline constexpr const char *LICENSE_BODIES[] = {\n\n") for license in license_list: + to_raw = [] for line in license[1:]: if line == ".": - f.write('\t"\\n"\n') + to_raw += [""] else: - f.write('\t"' + escape_string(line) + '\\n"\n') - f.write('\t"",\n\n') - f.write("};\n\n") - - f.write("#endif // LICENSE_GEN_H\n") + to_raw += [line] + file.write(f"{methods.to_raw_cstring(to_raw)},\n\n") + file.write("};\n\n") diff --git a/engine/core/core_constants.h b/engine/core/core_constants.h index 8ab4a78a..c432fdca 100644 --- a/engine/core/core_constants.h +++ b/engine/core/core_constants.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef CORE_CONSTANTS_H -#define CORE_CONSTANTS_H +#pragma once #include "core/string/string_name.h" #include "core/templates/hash_map.h" @@ -47,5 +46,3 @@ public: static bool is_global_enum(const StringName &p_enum); static void get_enum_values(const StringName &p_enum, HashMap *p_values); }; - -#endif // CORE_CONSTANTS_H diff --git a/engine/core/core_globals.h b/engine/core/core_globals.h index ebb1f41a..63a6a5b1 100644 --- a/engine/core/core_globals.h +++ b/engine/core/core_globals.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef CORE_GLOBALS_H -#define CORE_GLOBALS_H +#pragma once // Home for state needed from global functions // that cannot be stored in Engine or OS due to e.g. circular includes @@ -40,5 +39,3 @@ public: static bool print_line_enabled; static bool print_error_enabled; }; - -#endif // CORE_GLOBALS_H diff --git a/engine/core/core_string_names.h b/engine/core/core_string_names.h index be3bc38e..33203c5b 100644 --- a/engine/core/core_string_names.h +++ b/engine/core/core_string_names.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef CORE_STRING_NAMES_H -#define CORE_STRING_NAMES_H +#pragma once #include "core/string/string_name.h" @@ -87,5 +86,3 @@ public: }; #define CoreStringName(m_name) CoreStringNames::get_singleton()->m_name - -#endif // CORE_STRING_NAMES_H diff --git a/engine/core/crypto/SCsub b/engine/core/crypto/SCsub index 3cea6bfb..d33d119f 100644 --- a/engine/core/crypto/SCsub +++ b/engine/core/crypto/SCsub @@ -13,7 +13,7 @@ if is_builtin or not has_module: # Use our headers for builtin or if the module is not going to be compiled. # We decided not to depend on system mbedtls just for these few files that can # be easily extracted. - env_crypto.Prepend(CPPPATH=["#thirdparty/mbedtls/include"]) + env_crypto.Prepend(CPPEXTPATH=["#thirdparty/mbedtls/include"]) # MbedTLS core functions (for CryptoCore). # If the mbedtls module is compiled we don't need to add the .c files with our diff --git a/engine/core/crypto/aes_context.h b/engine/core/crypto/aes_context.h index ab0792ac..2ae62c84 100644 --- a/engine/core/crypto/aes_context.h +++ b/engine/core/crypto/aes_context.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef AES_CONTEXT_H -#define AES_CONTEXT_H +#pragma once #include "core/crypto/crypto_core.h" #include "core/object/ref_counted.h" @@ -64,5 +63,3 @@ public: }; VARIANT_ENUM_CAST(AESContext::Mode); - -#endif // AES_CONTEXT_H diff --git a/engine/core/crypto/crypto.h b/engine/core/crypto/crypto.h index dc4441c9..9c752e77 100644 --- a/engine/core/crypto/crypto.h +++ b/engine/core/crypto/crypto.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef CRYPTO_H -#define CRYPTO_H +#pragma once #include "core/crypto/hashing_context.h" #include "core/io/resource.h" @@ -167,5 +166,3 @@ public: virtual void get_recognized_extensions(const Ref &p_resource, List *p_extensions) const override; virtual bool recognize(const Ref &p_resource) const override; }; - -#endif // CRYPTO_H diff --git a/engine/core/crypto/crypto_core.cpp b/engine/core/crypto/crypto_core.cpp index 13852d51..9d2c346e 100644 --- a/engine/core/crypto/crypto_core.cpp +++ b/engine/core/crypto/crypto_core.cpp @@ -214,8 +214,8 @@ Error CryptoCore::AESContext::decrypt_cfb(size_t p_length, uint8_t p_iv[16], con } // CryptoCore -String CryptoCore::b64_encode_str(const uint8_t *p_src, int p_src_len) { - int b64len = p_src_len / 3 * 4 + 4 + 1; +String CryptoCore::b64_encode_str(const uint8_t *p_src, size_t p_src_len) { + size_t b64len = p_src_len / 3 * 4 + 4 + 1; Vector b64buff; b64buff.resize(b64len); uint8_t *w64 = b64buff.ptrw(); @@ -225,27 +225,27 @@ String CryptoCore::b64_encode_str(const uint8_t *p_src, int p_src_len) { return ret ? String() : (const char *)&w64[0]; } -Error CryptoCore::b64_encode(uint8_t *r_dst, int p_dst_len, size_t *r_len, const uint8_t *p_src, int p_src_len) { +Error CryptoCore::b64_encode(uint8_t *r_dst, size_t p_dst_len, size_t *r_len, const uint8_t *p_src, size_t p_src_len) { int ret = mbedtls_base64_encode(r_dst, p_dst_len, r_len, p_src, p_src_len); return ret ? FAILED : OK; } -Error CryptoCore::b64_decode(uint8_t *r_dst, int p_dst_len, size_t *r_len, const uint8_t *p_src, int p_src_len) { +Error CryptoCore::b64_decode(uint8_t *r_dst, size_t p_dst_len, size_t *r_len, const uint8_t *p_src, size_t p_src_len) { int ret = mbedtls_base64_decode(r_dst, p_dst_len, r_len, p_src, p_src_len); return ret ? FAILED : OK; } -Error CryptoCore::md5(const uint8_t *p_src, int p_src_len, unsigned char r_hash[16]) { +Error CryptoCore::md5(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[16]) { int ret = mbedtls_md5_ret(p_src, p_src_len, r_hash); return ret ? FAILED : OK; } -Error CryptoCore::sha1(const uint8_t *p_src, int p_src_len, unsigned char r_hash[20]) { +Error CryptoCore::sha1(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[20]) { int ret = mbedtls_sha1_ret(p_src, p_src_len, r_hash); return ret ? FAILED : OK; } -Error CryptoCore::sha256(const uint8_t *p_src, int p_src_len, unsigned char r_hash[32]) { +Error CryptoCore::sha256(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[32]) { int ret = mbedtls_sha256_ret(p_src, p_src_len, r_hash, 0); return ret ? FAILED : OK; } diff --git a/engine/core/crypto/crypto_core.h b/engine/core/crypto/crypto_core.h index 4a9ffda8..8ef50fbc 100644 --- a/engine/core/crypto/crypto_core.h +++ b/engine/core/crypto/crypto_core.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef CRYPTO_CORE_H -#define CRYPTO_CORE_H +#pragma once #include "core/object/ref_counted.h" @@ -107,13 +106,11 @@ public: Error decrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst); }; - static String b64_encode_str(const uint8_t *p_src, int p_src_len); - static Error b64_encode(uint8_t *r_dst, int p_dst_len, size_t *r_len, const uint8_t *p_src, int p_src_len); - static Error b64_decode(uint8_t *r_dst, int p_dst_len, size_t *r_len, const uint8_t *p_src, int p_src_len); + static String b64_encode_str(const uint8_t *p_src, size_t p_src_len); + static Error b64_encode(uint8_t *r_dst, size_t p_dst_len, size_t *r_len, const uint8_t *p_src, size_t p_src_len); + static Error b64_decode(uint8_t *r_dst, size_t p_dst_len, size_t *r_len, const uint8_t *p_src, size_t p_src_len); - static Error md5(const uint8_t *p_src, int p_src_len, unsigned char r_hash[16]); - static Error sha1(const uint8_t *p_src, int p_src_len, unsigned char r_hash[20]); - static Error sha256(const uint8_t *p_src, int p_src_len, unsigned char r_hash[32]); + static Error md5(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[16]); + static Error sha1(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[20]); + static Error sha256(const uint8_t *p_src, size_t p_src_len, unsigned char r_hash[32]); }; - -#endif // CRYPTO_CORE_H diff --git a/engine/core/crypto/hashing_context.h b/engine/core/crypto/hashing_context.h index 436afd83..6c9de6a8 100644 --- a/engine/core/crypto/hashing_context.h +++ b/engine/core/crypto/hashing_context.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef HASHING_CONTEXT_H -#define HASHING_CONTEXT_H +#pragma once #include "core/object/ref_counted.h" @@ -62,5 +61,3 @@ public: }; VARIANT_ENUM_CAST(HashingContext::HashType); - -#endif // HASHING_CONTEXT_H diff --git a/engine/core/debugger/debugger_marshalls.cpp b/engine/core/debugger/debugger_marshalls.cpp index cc36ca48..55b61f1c 100644 --- a/engine/core/debugger/debugger_marshalls.cpp +++ b/engine/core/debugger/debugger_marshalls.cpp @@ -36,8 +36,7 @@ #define CHECK_END(arr, expected, what) ERR_FAIL_COND_V_MSG((uint32_t)arr.size() > (uint32_t)expected, false, String("Malformed ") + what + " message from script debugger, message too long. Expected size: " + itos(expected) + ", actual size: " + itos(arr.size())) Array DebuggerMarshalls::ScriptStackDump::serialize() { - Array arr; - arr.push_back(frames.size() * 3); + Array arr = { frames.size() * 3 }; for (const ScriptLanguage::StackInfo &frame : frames) { arr.push_back(frame.file); arr.push_back(frame.line); @@ -64,10 +63,7 @@ bool DebuggerMarshalls::ScriptStackDump::deserialize(const Array &p_arr) { } Array DebuggerMarshalls::ScriptStackVariable::serialize(int max_size) { - Array arr; - arr.push_back(name); - arr.push_back(type); - arr.push_back(value.get_type()); + Array arr = { name, type, value.get_type() }; Variant var = value; if (value.get_type() == Variant::OBJECT && value.get_validated_object() == nullptr) { @@ -99,20 +95,20 @@ bool DebuggerMarshalls::ScriptStackVariable::deserialize(const Array &p_arr) { } Array DebuggerMarshalls::OutputError::serialize() { - Array arr; - arr.push_back(hr); - arr.push_back(min); - arr.push_back(sec); - arr.push_back(msec); - arr.push_back(source_file); - arr.push_back(source_func); - arr.push_back(source_line); - arr.push_back(error); - arr.push_back(error_descr); - arr.push_back(warning); unsigned int size = callstack.size(); + Array arr = { + hr, + min, + sec, msec, + source_file, + source_func, + source_line, + error, + error_descr, + warning, + size * 3 + }; const ScriptLanguage::StackInfo *r = callstack.ptr(); - arr.push_back(size * 3); for (int i = 0; i < callstack.size(); i++) { arr.push_back(r[i].file); arr.push_back(r[i].func); diff --git a/engine/core/debugger/debugger_marshalls.h b/engine/core/debugger/debugger_marshalls.h index 1072ddae..c661ef39 100644 --- a/engine/core/debugger/debugger_marshalls.h +++ b/engine/core/debugger/debugger_marshalls.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef DEBUGGER_MARSHALLS_H -#define DEBUGGER_MARSHALLS_H +#pragma once #include "core/input/shortcut.h" #include "core/object/script_language.h" @@ -73,5 +72,3 @@ struct DebuggerMarshalls { static Array serialize_key_shortcut(const Ref &p_shortcut); static Ref deserialize_key_shortcut(const Array &p_keys); }; - -#endif // DEBUGGER_MARSHALLS_H diff --git a/engine/core/debugger/engine_debugger.cpp b/engine/core/debugger/engine_debugger.cpp index a9f87ad8..8d0f5261 100644 --- a/engine/core/debugger/engine_debugger.cpp +++ b/engine/core/debugger/engine_debugger.cpp @@ -127,7 +127,7 @@ void EngineDebugger::iteration(uint64_t p_frame_ticks, uint64_t p_process_ticks, singleton->poll_events(true); } -void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, const Vector &p_breakpoints, void (*p_allow_focus_steal_fn)()) { +void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, bool p_ignore_error_breaks, const Vector &p_breakpoints, void (*p_allow_focus_steal_fn)()) { register_uri_handler("tcp://", RemoteDebuggerPeerTCP::create); // TCP is the default protocol. Platforms/modules can add more. if (p_uri.is_empty()) { return; @@ -149,8 +149,7 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, co singleton = memnew(RemoteDebugger(Ref(peer))); script_debugger = memnew(ScriptDebugger); // Notify editor of our pid (to allow focus stealing). - Array msg; - msg.push_back(OS::get_singleton()->get_process_id()); + Array msg = { OS::get_singleton()->get_process_id() }; singleton->send_message("set_pid", msg); } if (!singleton) { @@ -160,13 +159,14 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, co // There is a debugger, parse breakpoints. ScriptDebugger *singleton_script_debugger = singleton->get_script_debugger(); singleton_script_debugger->set_skip_breakpoints(p_skip_breakpoints); + singleton_script_debugger->set_ignore_error_breaks(p_ignore_error_breaks); for (int i = 0; i < p_breakpoints.size(); i++) { const String &bp = p_breakpoints[i]; int sp = bp.rfind_char(':'); ERR_CONTINUE_MSG(sp == -1, vformat("Invalid breakpoint: '%s', expected file:line format.", bp)); - singleton_script_debugger->insert_breakpoint(bp.substr(sp + 1, bp.length()).to_int(), bp.substr(0, sp)); + singleton_script_debugger->insert_breakpoint(bp.substr(sp + 1).to_int(), bp.substr(0, sp)); } allow_focus_steal_fn = p_allow_focus_steal_fn; diff --git a/engine/core/debugger/engine_debugger.h b/engine/core/debugger/engine_debugger.h index 1822915f..cfe1b6e3 100644 --- a/engine/core/debugger/engine_debugger.h +++ b/engine/core/debugger/engine_debugger.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef ENGINE_DEBUGGER_H -#define ENGINE_DEBUGGER_H +#pragma once #include "core/string/string_name.h" #include "core/string/ustring.h" @@ -107,7 +106,7 @@ public: _FORCE_INLINE_ static ScriptDebugger *get_script_debugger() { return script_debugger; } - static void initialize(const String &p_uri, bool p_skip_breakpoints, const Vector &p_breakpoints, void (*p_allow_focus_steal_fn)()); + static void initialize(const String &p_uri, bool p_skip_breakpoints, bool p_ignore_error_breaks, const Vector &p_breakpoints, void (*p_allow_focus_steal_fn)()); static void deinitialize(); static void register_profiler(const StringName &p_name, const Profiler &p_profiler); static void unregister_profiler(const StringName &p_name); @@ -140,5 +139,3 @@ public: virtual ~EngineDebugger(); }; - -#endif // ENGINE_DEBUGGER_H diff --git a/engine/core/debugger/engine_profiler.h b/engine/core/debugger/engine_profiler.h index d3d0021e..f74d20b8 100644 --- a/engine/core/debugger/engine_profiler.h +++ b/engine/core/debugger/engine_profiler.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef ENGINE_PROFILER_H -#define ENGINE_PROFILER_H +#pragma once #include "core/object/gdvirtual.gen.inc" #include "core/object/ref_counted.h" @@ -59,5 +58,3 @@ public: EngineProfiler() {} virtual ~EngineProfiler(); }; - -#endif // ENGINE_PROFILER_H diff --git a/engine/core/debugger/local_debugger.cpp b/engine/core/debugger/local_debugger.cpp index a5d807f6..47a6d15d 100644 --- a/engine/core/debugger/local_debugger.cpp +++ b/engine/core/debugger/local_debugger.cpp @@ -242,7 +242,7 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { } else if (line.begins_with("br") || line.begins_with("break")) { if (line.get_slice_count(" ") <= 1) { const HashMap> &breakpoints = script_debugger->get_breakpoints(); - if (breakpoints.size() == 0) { + if (breakpoints.is_empty()) { print_line("No Breakpoints."); continue; } diff --git a/engine/core/debugger/local_debugger.h b/engine/core/debugger/local_debugger.h index 13c975c4..5c603e5f 100644 --- a/engine/core/debugger/local_debugger.h +++ b/engine/core/debugger/local_debugger.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef LOCAL_DEBUGGER_H -#define LOCAL_DEBUGGER_H +#pragma once #include "core/debugger/engine_debugger.h" #include "core/object/script_language.h" @@ -55,5 +54,3 @@ public: LocalDebugger(); ~LocalDebugger(); }; - -#endif // LOCAL_DEBUGGER_H diff --git a/engine/core/debugger/remote_debugger.cpp b/engine/core/debugger/remote_debugger.cpp index f8e42e6d..d14ea59a 100644 --- a/engine/core/debugger/remote_debugger.cpp +++ b/engine/core/debugger/remote_debugger.cpp @@ -95,10 +95,7 @@ public: }; Error RemoteDebugger::_put_msg(const String &p_message, const Array &p_data) { - Array msg; - msg.push_back(p_message); - msg.push_back(Thread::get_caller_id()); - msg.push_back(p_data); + Array msg = { p_message, Thread::get_caller_id(), p_data }; Error err = peer->put_message(msg); if (err != OK) { n_messages_dropped++; @@ -235,9 +232,7 @@ void RemoteDebugger::flush_output() { types.push_back(MESSAGE_TYPE_LOG); } - Array arr; - arr.push_back(strings); - arr.push_back(types); + Array arr = { strings, types }; _put_msg("output", arr); output_strings.clear(); } @@ -413,17 +408,25 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { } ScriptLanguage *script_lang = script_debugger->get_break_language(); - const String error_str = script_lang ? script_lang->debug_get_error() : ""; - Array msg; - msg.push_back(p_can_continue); - msg.push_back(error_str); ERR_FAIL_NULL(script_lang); - msg.push_back(script_lang->debug_get_stack_level_count() > 0); - msg.push_back(Thread::get_caller_id() == Thread::get_main_id() ? String(RTR("Main Thread")) : itos(Thread::get_caller_id())); - if (allow_focus_steal_fn) { - allow_focus_steal_fn(); + const bool can_break = !(p_is_error_breakpoint && script_debugger->is_ignoring_error_breaks()); + const String error_str = script_lang ? script_lang->debug_get_error() : ""; + + if (can_break) { + Array msg = { + p_can_continue, + error_str, + script_lang->debug_get_stack_level_count() > 0, + Thread::get_caller_id() + }; + if (allow_focus_steal_fn) { + allow_focus_steal_fn(); + } + send_message("debug_enter", msg); + } else { + ERR_PRINT(error_str); + return; } - send_message("debug_enter", msg); Input::MouseMode mouse_mode = Input::MOUSE_MODE_VISIBLE; @@ -507,8 +510,7 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { script_lang->debug_get_globals(&globals, &globals_vals); ERR_FAIL_COND(globals.size() != globals_vals.size()); - Array var_size; - var_size.push_back(local_vals.size() + member_vals.size() + globals_vals.size()); + Array var_size = { local_vals.size() + member_vals.size() + globals_vals.size() }; send_message("stack_frame_vars", var_size); _send_stack_vars(locals, local_vals, 0); _send_stack_vars(members, member_vals, 1); @@ -530,6 +532,9 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { } else if (command == "set_skip_breakpoints") { ERR_FAIL_COND(data.is_empty()); script_debugger->set_skip_breakpoints(data[0]); + } else if (command == "set_ignore_error_breaks") { + ERR_FAIL_COND(data.is_empty()); + script_debugger->set_ignore_error_breaks(data[0]); } else if (command == "evaluate") { String expression_str = data[0]; int frame = data[1]; @@ -669,6 +674,9 @@ Error RemoteDebugger::_core_capture(const String &p_cmd, const Array &p_data, bo } else if (p_cmd == "set_skip_breakpoints") { ERR_FAIL_COND_V(p_data.is_empty(), ERR_INVALID_DATA); script_debugger->set_skip_breakpoints(p_data[0]); + } else if (p_cmd == "set_ignore_error_breaks") { + ERR_FAIL_COND_V(p_data.is_empty(), ERR_INVALID_DATA); + script_debugger->set_ignore_error_breaks(p_data[0]); } else if (p_cmd == "break") { script_debugger->debug(script_debugger->get_break_language()); } else { diff --git a/engine/core/debugger/remote_debugger.h b/engine/core/debugger/remote_debugger.h index e91d09be..cbac2257 100644 --- a/engine/core/debugger/remote_debugger.h +++ b/engine/core/debugger/remote_debugger.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef REMOTE_DEBUGGER_H -#define REMOTE_DEBUGGER_H +#pragma once #include "core/debugger/debugger_marshalls.h" #include "core/debugger/engine_debugger.h" @@ -122,5 +121,3 @@ public: explicit RemoteDebugger(Ref p_peer); ~RemoteDebugger(); }; - -#endif // REMOTE_DEBUGGER_H diff --git a/engine/core/debugger/remote_debugger_peer.cpp b/engine/core/debugger/remote_debugger_peer.cpp index 1afb7fe0..011e6722 100644 --- a/engine/core/debugger/remote_debugger_peer.cpp +++ b/engine/core/debugger/remote_debugger_peer.cpp @@ -96,7 +96,7 @@ void RemoteDebuggerPeerTCP::_write_out() { while (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED && tcp_client->wait(NetSocket::POLL_TYPE_OUT) == OK) { uint8_t *buf = out_buf.ptrw(); if (out_left <= 0) { - if (out_queue.size() == 0) { + if (out_queue.is_empty()) { break; // Nothing left to send } mutex.lock(); diff --git a/engine/core/debugger/remote_debugger_peer.h b/engine/core/debugger/remote_debugger_peer.h index 37da0a92..3b171e4b 100644 --- a/engine/core/debugger/remote_debugger_peer.h +++ b/engine/core/debugger/remote_debugger_peer.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef REMOTE_DEBUGGER_PEER_H -#define REMOTE_DEBUGGER_PEER_H +#pragma once #include "core/io/stream_peer_tcp.h" #include "core/object/ref_counted.h" @@ -92,5 +91,3 @@ public: RemoteDebuggerPeerTCP(Ref p_stream = Ref()); ~RemoteDebuggerPeerTCP(); }; - -#endif // REMOTE_DEBUGGER_PEER_H diff --git a/engine/core/debugger/script_debugger.cpp b/engine/core/debugger/script_debugger.cpp index e7d8654a..e522d9ba 100644 --- a/engine/core/debugger/script_debugger.cpp +++ b/engine/core/debugger/script_debugger.cpp @@ -58,7 +58,7 @@ void ScriptDebugger::remove_breakpoint(int p_line, const StringName &p_source) { } breakpoints[p_line].erase(p_source); - if (breakpoints[p_line].size() == 0) { + if (breakpoints[p_line].is_empty()) { breakpoints.erase(p_line); } } @@ -79,6 +79,14 @@ bool ScriptDebugger::is_skipping_breakpoints() { return skip_breakpoints; } +void ScriptDebugger::set_ignore_error_breaks(bool p_ignore) { + ignore_error_breaks = p_ignore; +} + +bool ScriptDebugger::is_ignoring_error_breaks() { + return ignore_error_breaks; +} + void ScriptDebugger::debug(ScriptLanguage *p_lang, bool p_can_continue, bool p_is_error_breakpoint) { ScriptLanguage *prev = break_lang; break_lang = p_lang; diff --git a/engine/core/debugger/script_debugger.h b/engine/core/debugger/script_debugger.h index fb786f1b..0a5ffe78 100644 --- a/engine/core/debugger/script_debugger.h +++ b/engine/core/debugger/script_debugger.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef SCRIPT_DEBUGGER_H -#define SCRIPT_DEBUGGER_H +#pragma once #include "core/object/script_language.h" #include "core/string/string_name.h" @@ -40,6 +39,7 @@ class ScriptDebugger { typedef ScriptLanguage::StackInfo StackInfo; bool skip_breakpoints = false; + bool ignore_error_breaks = false; HashMap> breakpoints; @@ -64,6 +64,8 @@ public: ScriptLanguage *get_break_language() { return break_lang; } void set_skip_breakpoints(bool p_skip_breakpoints); bool is_skipping_breakpoints(); + void set_ignore_error_breaks(bool p_ignore); + bool is_ignoring_error_breaks(); void insert_breakpoint(int p_line, const StringName &p_source); void remove_breakpoint(int p_line, const StringName &p_source); _ALWAYS_INLINE_ bool is_breakpoint(int p_line, const StringName &p_source) const { @@ -82,5 +84,3 @@ public: Vector get_error_stack_info() const; ScriptDebugger() {} }; - -#endif // SCRIPT_DEBUGGER_H diff --git a/engine/core/doc_data.cpp b/engine/core/doc_data.cpp index 28814435..d1904025 100644 --- a/engine/core/doc_data.cpp +++ b/engine/core/doc_data.cpp @@ -32,11 +32,11 @@ String DocData::get_default_value_string(const Variant &p_value) { if (p_value.get_type() == Variant::ARRAY) { - return Variant(Array(p_value, 0, StringName(), Variant())).get_construct_string().replace("\n", " "); + return Variant(Array(p_value, 0, StringName(), Variant())).get_construct_string().replace_char('\n', ' '); } else if (p_value.get_type() == Variant::DICTIONARY) { - return Variant(Dictionary(p_value, 0, StringName(), Variant(), 0, StringName(), Variant())).get_construct_string().replace("\n", " "); + return Variant(Dictionary(p_value, 0, StringName(), Variant(), 0, StringName(), Variant())).get_construct_string().replace_char('\n', ' '); } else { - return p_value.get_construct_string().replace("\n", " "); + return p_value.get_construct_string().replace_char('\n', ' '); } } @@ -51,7 +51,7 @@ void DocData::return_doc_from_retinfo(DocData::MethodDoc &p_method, const Proper } else if (p_retinfo.type == Variant::INT && p_retinfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { p_method.return_enum = p_retinfo.class_name; if (p_method.return_enum.begins_with("_")) { //proxy class - p_method.return_enum = p_method.return_enum.substr(1, p_method.return_enum.length()); + p_method.return_enum = p_method.return_enum.substr(1); } p_method.return_is_bitfield = p_retinfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD; p_method.return_type = "int"; @@ -85,7 +85,7 @@ void DocData::argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const } else if (p_arginfo.type == Variant::INT && p_arginfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { p_argument.enumeration = p_arginfo.class_name; if (p_argument.enumeration.begins_with("_")) { //proxy class - p_argument.enumeration = p_argument.enumeration.substr(1, p_argument.enumeration.length()); + p_argument.enumeration = p_argument.enumeration.substr(1); } p_argument.is_bitfield = p_arginfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD; p_argument.type = "int"; @@ -136,11 +136,10 @@ void DocData::method_doc_from_methodinfo(DocData::MethodDoc &p_method, const Met return_doc_from_retinfo(p_method, p_methodinfo.return_val); - int i = 0; - for (List::ConstIterator itr = p_methodinfo.arguments.begin(); itr != p_methodinfo.arguments.end(); ++itr, ++i) { + for (int64_t i = 0; i < p_methodinfo.arguments.size(); ++i) { DocData::ArgumentDoc argument; - argument_doc_from_arginfo(argument, *itr); - int default_arg_index = i - (p_methodinfo.arguments.size() - p_methodinfo.default_arguments.size()); + argument_doc_from_arginfo(argument, p_methodinfo.arguments[i]); + int64_t default_arg_index = i - (p_methodinfo.arguments.size() - p_methodinfo.default_arguments.size()); if (default_arg_index >= 0) { Variant default_arg = p_methodinfo.default_arguments[default_arg_index]; argument.default_value = get_default_value_string(default_arg); diff --git a/engine/core/doc_data.h b/engine/core/doc_data.h index 49f9c3aa..50e67ec7 100644 --- a/engine/core/doc_data.h +++ b/engine/core/doc_data.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef DOC_DATA_H -#define DOC_DATA_H +#pragma once #include "core/io/xml_parser.h" #include "core/variant/variant.h" @@ -115,7 +114,7 @@ public: // Must be an operator or a constructor since there is no other overloading if (name.left(8) == "operator") { if (arguments.size() == p_method.arguments.size()) { - if (arguments.size() == 0) { + if (arguments.is_empty()) { return false; } return arguments[0].type < p_method.arguments[0].type; @@ -127,7 +126,7 @@ public: // - 1. Default constructor: Foo() // - 2. Copy constructor: Foo(Foo) // - 3+. Other constructors Foo(Bar, ...) based on first argument's name - if (arguments.size() == 0 || p_method.arguments.size() == 0) { // 1. + if (arguments.is_empty() || p_method.arguments.is_empty()) { // 1. return arguments.size() < p_method.arguments.size(); } if (arguments[0].type == return_type || p_method.arguments[0].type == p_method.return_type) { // 2. @@ -795,8 +794,8 @@ public: if (p_dict.has("enums")) { enums = p_dict["enums"]; } - for (int i = 0; i < enums.size(); i++) { - doc.enums[enums.get_key_at_index(i)] = EnumDoc::from_dict(enums.get_value_at_index(i)); + for (const KeyValue &kv : enums) { + doc.enums[kv.key] = EnumDoc::from_dict(kv.value); } Array properties; @@ -980,5 +979,3 @@ public: static void argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const PropertyInfo &p_arginfo); static void method_doc_from_methodinfo(DocData::MethodDoc &p_method, const MethodInfo &p_methodinfo, const String &p_desc); }; - -#endif // DOC_DATA_H diff --git a/engine/core/error/error_list.cpp b/engine/core/error/error_list.cpp index f14cc84b..13e560c3 100644 --- a/engine/core/error/error_list.cpp +++ b/engine/core/error/error_list.cpp @@ -30,6 +30,8 @@ #include "error_list.h" +#include + const char *error_names[] = { "OK", // OK "Failed", // FAILED @@ -82,4 +84,4 @@ const char *error_names[] = { "Printer on fire", // ERR_PRINTER_ON_FIRE }; -static_assert(sizeof(error_names) / sizeof(*error_names) == ERR_MAX); +static_assert(std::size(error_names) == ERR_MAX); diff --git a/engine/core/error/error_list.h b/engine/core/error/error_list.h index cdf06eb0..cdc31ecd 100644 --- a/engine/core/error/error_list.h +++ b/engine/core/error/error_list.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef ERROR_LIST_H -#define ERROR_LIST_H +#pragma once /** Error List. Please never compare an error against FAILED * Either do result != OK , or !result. This way, Error fail @@ -98,5 +97,3 @@ enum Error { }; extern const char *error_names[]; - -#endif // ERROR_LIST_H diff --git a/engine/core/error/error_macros.cpp b/engine/core/error/error_macros.cpp index a2369992..74dc9336 100644 --- a/engine/core/error/error_macros.cpp +++ b/engine/core/error/error_macros.cpp @@ -31,6 +31,7 @@ #include "error_macros.h" #include "core/io/logger.h" +#include "core/object/object_id.h" #include "core/os/os.h" #include "core/string/ustring.h" @@ -187,7 +188,7 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file, } else { String node_name; if (p_id.is_valid()) { - Node *node = Object::cast_to(ObjectDB::get_instance(p_id)); + Node *node = ObjectDB::get_instance(p_id); if (node && node->is_inside_tree()) { node_name = "\"" + String(node->get_path()) + "\""; } else { diff --git a/engine/core/error/error_macros.h b/engine/core/error/error_macros.h index 752fd605..bedb84b4 100644 --- a/engine/core/error/error_macros.h +++ b/engine/core/error/error_macros.h @@ -28,15 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef ERROR_MACROS_H -#define ERROR_MACROS_H +#pragma once -#include "core/object/object_id.h" #include "core/typedefs.h" -#include // We'd normally use safe_refcount.h, but that would cause circular includes. +#include // IWYU pragma: keep // Used in macro. We'd normally use `safe_refcount.h`, but that would cause circular includes. class String; +class ObjectID; enum ErrorHandlerType { ERR_HANDLER_ERROR, @@ -62,16 +61,16 @@ void add_error_handler(ErrorHandlerList *p_handler); void remove_error_handler(const ErrorHandlerList *p_handler); // Functions used by the error macros. -void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); -void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); -void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); -void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); -void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); -void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); +_NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); +_NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); +_NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); +_NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); +_NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); +_NO_INLINE_ void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify = false, ErrorHandlerType p_type = ERR_HANDLER_ERROR); void _err_print_error_asap(const String &p_error, ErrorHandlerType p_type = ERR_HANDLER_ERROR); -void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message = "", bool p_editor_notify = false, bool fatal = false); -void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify = false, bool fatal = false); -void _err_flush_stdout(); +_NO_INLINE_ void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message = "", bool p_editor_notify = false, bool fatal = false); +_NO_INLINE_ void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify = false, bool fatal = false); +_NO_INLINE_ void _err_flush_stdout(); void _physics_interpolation_warning(const char *p_function, const char *p_file, int p_line, ObjectID p_id, const char *p_warn_string); @@ -845,5 +844,3 @@ void _physics_interpolation_warning(const char *p_function, const char *p_file, #define PHYSICS_INTERPOLATION_WARNING(m_string) \ _physics_interpolation_warning(FUNCTION_STR, __FILE__, __LINE__, ObjectID(UINT64_MAX), m_string) - -#endif // ERROR_MACROS_H diff --git a/engine/core/extension/extension_api_dump.cpp b/engine/core/extension/extension_api_dump.cpp index 52f1672a..93b1b272 100644 --- a/engine/core/extension/extension_api_dump.cpp +++ b/engine/core/extension/extension_api_dump.cpp @@ -96,8 +96,7 @@ static String fix_doc_description(const String &p_bbcode) { // Based on what EditorHelp does. return p_bbcode.dedent() - .replace("\t", "") - .replace("\r", "") + .remove_chars("\t\r") .strip_edges(); } @@ -107,16 +106,22 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) { { //header Dictionary header; - header["version_major"] = VERSION_MAJOR; - header["version_minor"] = VERSION_MINOR; -#if VERSION_PATCH - header["version_patch"] = VERSION_PATCH; + header["version_major"] = GODOT_VERSION_MAJOR; + header["version_minor"] = GODOT_VERSION_MINOR; +#if GODOT_VERSION_PATCH + header["version_patch"] = GODOT_VERSION_PATCH; #else header["version_patch"] = 0; #endif - header["version_status"] = VERSION_STATUS; - header["version_build"] = VERSION_BUILD; - header["version_full_name"] = VERSION_FULL_NAME; + header["version_status"] = GODOT_VERSION_STATUS; + header["version_build"] = GODOT_VERSION_BUILD; + header["version_full_name"] = GODOT_VERSION_FULL_NAME; + +#if REAL_T_IS_DOUBLE + header["precision"] = "double"; +#else + header["precision"] = "single"; +#endif api_dump["header"] = header; } @@ -278,43 +283,43 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) { #define REAL_MEMBER_OFFSET(type, member) \ { \ type, \ - member, \ - "float", \ - sizeof(float), \ - "float", \ - sizeof(float), \ - "double", \ - sizeof(double), \ - "double", \ - sizeof(double), \ + member, \ + "float", \ + sizeof(float), \ + "float", \ + sizeof(float), \ + "double", \ + sizeof(double), \ + "double", \ + sizeof(double), \ } #define INT32_MEMBER_OFFSET(type, member) \ { \ type, \ - member, \ - "int32", \ - sizeof(int32_t), \ - "int32", \ - sizeof(int32_t), \ - "int32", \ - sizeof(int32_t), \ - "int32", \ - sizeof(int32_t), \ + member, \ + "int32", \ + sizeof(int32_t), \ + "int32", \ + sizeof(int32_t), \ + "int32", \ + sizeof(int32_t), \ + "int32", \ + sizeof(int32_t), \ } #define INT32_BASED_BUILTIN_MEMBER_OFFSET(type, member, member_type, member_elems) \ { \ type, \ - member, \ - member_type, \ - sizeof(int32_t) * member_elems, \ - member_type, \ - sizeof(int32_t) * member_elems, \ - member_type, \ - sizeof(int32_t) * member_elems, \ - member_type, \ - sizeof(int32_t) * member_elems, \ + member, \ + member_type, \ + sizeof(int32_t) * member_elems, \ + member_type, \ + sizeof(int32_t) * member_elems, \ + member_type, \ + sizeof(int32_t) * member_elems, \ + member_type, \ + sizeof(int32_t) * member_elems, \ } #define REAL_BASED_BUILTIN_MEMBER_OFFSET(type, member, member_type, member_elems) \ @@ -970,14 +975,14 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) { Array values; List enum_constant_list; ClassDB::get_enum_constants(class_name, F, &enum_constant_list, true); - for (List::Element *G = enum_constant_list.front(); G; G = G->next()) { + for (const StringName &enum_constant : enum_constant_list) { Dictionary d3; - d3["name"] = String(G->get()); - d3["value"] = ClassDB::get_integer_constant(class_name, G->get()); + d3["name"] = String(enum_constant); + d3["value"] = ClassDB::get_integer_constant(class_name, enum_constant); if (p_include_docs) { for (const DocData::ConstantDoc &constant_doc : class_doc->constants) { - if (constant_doc.name == G->get()) { + if (constant_doc.name == enum_constant) { d3["description"] = fix_doc_description(constant_doc.description); break; } @@ -1048,9 +1053,8 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) { } Array arguments; - int i = 0; - for (List::ConstIterator itr = mi.arguments.begin(); itr != mi.arguments.end(); ++itr, ++i) { - const PropertyInfo &pinfo = *itr; + for (int64_t i = 0; i < mi.arguments.size(); ++i) { + const PropertyInfo &pinfo = mi.arguments[i]; Dictionary d3; d3["name"] = pinfo.name; @@ -1175,11 +1179,10 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) { Array arguments; - int i = 0; - for (List::ConstIterator itr = F.arguments.begin(); itr != F.arguments.end(); ++itr, ++i) { + for (int64_t i = 0; i < F.arguments.size(); ++i) { Dictionary d3; - d3["name"] = itr->name; - d3["type"] = get_property_info_type_name(*itr); + d3["name"] = F.arguments[i].name; + d3["type"] = get_property_info_type_name(F.arguments[i]); if (F.get_argument_meta(i) > 0) { d3["meta"] = get_type_meta_name((GodotTypeInfo::Metadata)F.get_argument_meta(i)); } @@ -1340,16 +1343,16 @@ static bool compare_value(const String &p_path, const String &p_field, const Var } else if (p_old_value.get_type() == Variant::DICTIONARY && p_new_value.get_type() == Variant::DICTIONARY) { Dictionary old_dict = p_old_value; Dictionary new_dict = p_new_value; - for (const Variant &key : old_dict.keys()) { - if (!new_dict.has(key)) { + for (const KeyValue &kv : old_dict) { + if (!new_dict.has(kv.key)) { failed = true; - print_error(vformat("Validate extension JSON: Error: Field '%s': %s was removed.", p_path, key)); + print_error(vformat("Validate extension JSON: Error: Field '%s': %s was removed.", p_path, kv.key)); continue; } - if (p_allow_name_change && key == "name") { + if (p_allow_name_change && kv.key == "name") { continue; } - if (!compare_value(path, key, old_dict[key], new_dict[key], p_allow_name_change)) { + if (!compare_value(path, kv.key, kv.value, new_dict[kv.key], p_allow_name_change)) { failed = true; } } @@ -1420,25 +1423,25 @@ static bool compare_dict_array(const Dictionary &p_old_api, const Dictionary &p_ bool optional = field.begins_with("*"); if (optional) { // This is an optional field, but if exists it has to exist in both. - field = field.substr(1, field.length()); + field = field.substr(1); } bool added = field.begins_with("+"); if (added) { // Meaning this field must either exist or contents may not exist. - field = field.substr(1, field.length()); + field = field.substr(1); } bool enum_values = field.begins_with("$"); if (enum_values) { // Meaning this field is a list of enum values. - field = field.substr(1, field.length()); + field = field.substr(1); } bool allow_name_change = field.begins_with("@"); if (allow_name_change) { // Meaning that when structurally comparing the old and new value, the dictionary entry 'name' may change. - field = field.substr(1, field.length()); + field = field.substr(1); } Variant old_value; @@ -1598,8 +1601,8 @@ Error GDExtensionAPIDump::validate_extension_json_file(const String &p_path) { int major = header["version_major"]; int minor = header["version_minor"]; - ERR_FAIL_COND_V_MSG(major != VERSION_MAJOR, ERR_INVALID_DATA, vformat("JSON API dump is for a different engine version (%d) than this one (%d)", major, VERSION_MAJOR)); - ERR_FAIL_COND_V_MSG(minor > VERSION_MINOR, ERR_INVALID_DATA, vformat("JSON API dump is for a newer version of the engine: %d.%d", major, minor)); + ERR_FAIL_COND_V_MSG(major != GODOT_VERSION_MAJOR, ERR_INVALID_DATA, vformat("JSON API dump is for a different engine version (%d) than this one (%d)", major, GODOT_VERSION_MAJOR)); + ERR_FAIL_COND_V_MSG(minor > GODOT_VERSION_MINOR, ERR_INVALID_DATA, vformat("JSON API dump is for a newer version of the engine: %d.%d", major, minor)); } bool failed = false; diff --git a/engine/core/extension/extension_api_dump.h b/engine/core/extension/extension_api_dump.h index 204a115f..027a8d91 100644 --- a/engine/core/extension/extension_api_dump.h +++ b/engine/core/extension/extension_api_dump.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef EXTENSION_API_DUMP_H -#define EXTENSION_API_DUMP_H +#pragma once #include "core/extension/gdextension.h" @@ -42,5 +41,3 @@ public: static Error validate_extension_json_file(const String &p_path); }; #endif - -#endif // EXTENSION_API_DUMP_H diff --git a/engine/core/extension/gdextension.cpp b/engine/core/extension/gdextension.cpp index f40612ec..ea314b71 100644 --- a/engine/core/extension/gdextension.cpp +++ b/engine/core/extension/gdextension.cpp @@ -679,6 +679,13 @@ void GDExtension::_get_library_path(GDExtensionClassLibraryPtr p_library, GDExte memnew_placement(r_path, String(library_path)); } +void GDExtension::_register_get_classes_used_callback(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback) { +#ifdef TOOLS_ENABLED + GDExtension *self = reinterpret_cast(p_library); + self->get_classes_used_callback = p_callback; +#endif +} + HashMap GDExtension::gdextension_interface_functions; void GDExtension::register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) { @@ -799,6 +806,7 @@ void GDExtension::initialize_gdextensions() { register_interface_function("classdb_register_extension_class_signal", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_signal); register_interface_function("classdb_unregister_extension_class", (GDExtensionInterfaceFunctionPtr)&GDExtension::_unregister_extension_class); register_interface_function("get_library_path", (GDExtensionInterfaceFunctionPtr)&GDExtension::_get_library_path); + register_interface_function("editor_register_get_classes_used_callback", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_get_classes_used_callback); } void GDExtension::finalize_gdextensions() { @@ -1034,6 +1042,14 @@ void GDExtension::_untrack_instance(void *p_user_data, void *p_instance) { extension->instances.erase(obj->get_instance_id()); } +PackedStringArray GDExtension::get_classes_used() const { + PackedStringArray ret; + if (get_classes_used_callback) { + get_classes_used_callback((GDExtensionTypePtr)&ret); + } + return ret; +} + Vector GDExtensionEditorPlugins::extension_classes; GDExtensionEditorPlugins::EditorPluginRegisterFunc GDExtensionEditorPlugins::editor_node_add_plugin = nullptr; GDExtensionEditorPlugins::EditorPluginRegisterFunc GDExtensionEditorPlugins::editor_node_remove_plugin = nullptr; diff --git a/engine/core/extension/gdextension.h b/engine/core/extension/gdextension.h index bfed8424..a40f7af4 100644 --- a/engine/core/extension/gdextension.h +++ b/engine/core/extension/gdextension.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GDEXTENSION_H -#define GDEXTENSION_H +#pragma once #include "core/extension/gdextension_interface.h" #include "core/extension/gdextension_loader.h" @@ -94,6 +93,7 @@ class GDExtension : public Resource { static void _register_extension_class_signal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_signal_name, const GDExtensionPropertyInfo *p_argument_info, GDExtensionInt p_argument_count); static void _unregister_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name); static void _get_library_path(GDExtensionClassLibraryPtr p_library, GDExtensionStringPtr r_path); + static void _register_get_classes_used_callback(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback); GDExtensionInitialization initialization; int32_t level_initialized = -1; @@ -102,6 +102,7 @@ class GDExtension : public Resource { bool is_reloading = false; Vector invalid_methods; Vector instance_bindings; + GDExtensionEditorGetClassesUsedCallback get_classes_used_callback = nullptr; static void _track_instance(void *p_user_data, void *p_instance); static void _untrack_instance(void *p_user_data, void *p_instance); @@ -156,6 +157,8 @@ public: void track_instance_binding(Object *p_object); void untrack_instance_binding(Object *p_object); + + PackedStringArray get_classes_used() const; #endif InitializationLevel get_minimum_library_initialization_level() const; @@ -226,5 +229,3 @@ public: }; #endif // TOOLS_ENABLED - -#endif // GDEXTENSION_H diff --git a/engine/core/extension/gdextension_interface.cpp b/engine/core/extension/gdextension_interface.cpp index 30f0ce98..725475d9 100644 --- a/engine/core/extension/gdextension_interface.cpp +++ b/engine/core/extension/gdextension_interface.cpp @@ -241,11 +241,25 @@ GDExtensionInterfaceFunctionPtr gdextension_get_proc_address(const char *p_name) return GDExtension::get_interface_function(p_name); } +#ifndef DISABLE_DEPRECATED static void gdextension_get_godot_version(GDExtensionGodotVersion *r_godot_version) { - r_godot_version->major = VERSION_MAJOR; - r_godot_version->minor = VERSION_MINOR; - r_godot_version->patch = VERSION_PATCH; - r_godot_version->string = VERSION_FULL_NAME; + r_godot_version->major = GODOT_VERSION_MAJOR; + r_godot_version->minor = GODOT_VERSION_MINOR; + r_godot_version->patch = GODOT_VERSION_PATCH; + r_godot_version->string = GODOT_VERSION_FULL_NAME; +} +#endif + +static void gdextension_get_godot_version2(GDExtensionGodotVersion2 *r_godot_version) { + r_godot_version->major = GODOT_VERSION_MAJOR; + r_godot_version->minor = GODOT_VERSION_MINOR; + r_godot_version->patch = GODOT_VERSION_PATCH; + r_godot_version->hex = GODOT_VERSION_HEX; + r_godot_version->status = GODOT_VERSION_STATUS; + r_godot_version->build = GODOT_VERSION_BUILD; + r_godot_version->hash = GODOT_VERSION_HASH; + r_godot_version->timestamp = GODOT_VERSION_TIMESTAMP; + r_godot_version->string = GODOT_VERSION_FULL_NAME; } // Memory Functions @@ -858,84 +872,82 @@ static GDExtensionPtrUtilityFunction gdextension_variant_get_ptr_utility_functio //string helpers static void gdextension_string_new_with_latin1_chars(GDExtensionUninitializedStringPtr r_dest, const char *p_contents) { - memnew_placement(r_dest, String(p_contents)); + String *dest = memnew_placement(r_dest, String); + dest->append_latin1(Span(p_contents, p_contents ? strlen(p_contents) : 0)); } static void gdextension_string_new_with_utf8_chars(GDExtensionUninitializedStringPtr r_dest, const char *p_contents) { - memnew_placement(r_dest, String); - String *dest = reinterpret_cast(r_dest); - dest->parse_utf8(p_contents); + String *dest = memnew_placement(r_dest, String); + dest->append_utf8(p_contents); } static void gdextension_string_new_with_utf16_chars(GDExtensionUninitializedStringPtr r_dest, const char16_t *p_contents) { - memnew_placement(r_dest, String); - String *dest = reinterpret_cast(r_dest); - dest->parse_utf16(p_contents); + String *dest = memnew_placement(r_dest, String); + dest->append_utf16(p_contents); } static void gdextension_string_new_with_utf32_chars(GDExtensionUninitializedStringPtr r_dest, const char32_t *p_contents) { - memnew_placement(r_dest, String((const char32_t *)p_contents)); + String *dest = memnew_placement(r_dest, String); + dest->append_utf32(Span(p_contents, p_contents ? strlen(p_contents) : 0)); } static void gdextension_string_new_with_wide_chars(GDExtensionUninitializedStringPtr r_dest, const wchar_t *p_contents) { if constexpr (sizeof(wchar_t) == 2) { - // wchar_t is 16 bit, parse. - memnew_placement(r_dest, String); - String *dest = reinterpret_cast(r_dest); - dest->parse_utf16((const char16_t *)p_contents); + // wchar_t is 16 bit (UTF-16). + String *dest = memnew_placement(r_dest, String); + dest->append_utf16((const char16_t *)p_contents); } else { - // wchar_t is 32 bit, copy. - memnew_placement(r_dest, String((const char32_t *)p_contents)); + // wchar_t is 32 bit (UTF-32). + String *string = memnew_placement(r_dest, String); + string->append_utf32(Span((const char32_t *)p_contents, p_contents ? strlen(p_contents) : 0)); } } static void gdextension_string_new_with_latin1_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const char *p_contents, GDExtensionInt p_size) { - memnew_placement(r_dest, String(p_contents, p_size)); + String *dest = memnew_placement(r_dest, String); + dest->append_latin1(Span(p_contents, p_contents ? _strlen_clipped(p_contents, p_size) : 0)); } static void gdextension_string_new_with_utf8_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const char *p_contents, GDExtensionInt p_size) { - memnew_placement(r_dest, String); - String *dest = reinterpret_cast(r_dest); - dest->parse_utf8(p_contents, p_size); + String *dest = memnew_placement(r_dest, String); + dest->append_utf8(p_contents, p_size); } static GDExtensionInt gdextension_string_new_with_utf8_chars_and_len2(GDExtensionUninitializedStringPtr r_dest, const char *p_contents, GDExtensionInt p_size) { - memnew_placement(r_dest, String); - String *dest = reinterpret_cast(r_dest); - return (GDExtensionInt)dest->parse_utf8(p_contents, p_size); + String *dest = memnew_placement(r_dest, String); + return (GDExtensionInt)dest->append_utf8(p_contents, p_size); } static void gdextension_string_new_with_utf16_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const char16_t *p_contents, GDExtensionInt p_char_count) { - memnew_placement(r_dest, String); - String *dest = reinterpret_cast(r_dest); - dest->parse_utf16(p_contents, p_char_count); + String *dest = memnew_placement(r_dest, String); + dest->append_utf16(p_contents, p_char_count); } static GDExtensionInt gdextension_string_new_with_utf16_chars_and_len2(GDExtensionUninitializedStringPtr r_dest, const char16_t *p_contents, GDExtensionInt p_char_count, GDExtensionBool p_default_little_endian) { - memnew_placement(r_dest, String); - String *dest = reinterpret_cast(r_dest); - return (GDExtensionInt)dest->parse_utf16(p_contents, p_char_count, p_default_little_endian); + String *dest = memnew_placement(r_dest, String); + return (GDExtensionInt)dest->append_utf16(p_contents, p_char_count, p_default_little_endian); } static void gdextension_string_new_with_utf32_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const char32_t *p_contents, GDExtensionInt p_char_count) { - memnew_placement(r_dest, String((const char32_t *)p_contents, p_char_count)); + String *string = memnew_placement(r_dest, String); + string->append_utf32(Span(p_contents, p_contents ? _strlen_clipped(p_contents, p_char_count) : 0)); } static void gdextension_string_new_with_wide_chars_and_len(GDExtensionUninitializedStringPtr r_dest, const wchar_t *p_contents, GDExtensionInt p_char_count) { if constexpr (sizeof(wchar_t) == 2) { - // wchar_t is 16 bit, parse. - memnew_placement(r_dest, String); - String *dest = reinterpret_cast(r_dest); - dest->parse_utf16((const char16_t *)p_contents, p_char_count); + // wchar_t is 16 bit (UTF-16). + String *dest = memnew_placement(r_dest, String); + dest->append_utf16((const char16_t *)p_contents, p_char_count); } else { - // wchar_t is 32 bit, copy. - memnew_placement(r_dest, String((const char32_t *)p_contents, p_char_count)); + // wchar_t is 32 bit (UTF-32). + String *string = memnew_placement(r_dest, String); + string->append_utf32(Span((const char32_t *)p_contents, p_contents ? _strlen_clipped((const char32_t *)p_contents, p_char_count) : 0)); } } static GDExtensionInt gdextension_string_to_latin1_chars(GDExtensionConstStringPtr p_self, char *r_text, GDExtensionInt p_max_write_length) { String *self = (String *)p_self; - CharString cs = self->ascii(true); + CharString cs = self->latin1(); GDExtensionInt len = cs.length(); if (r_text) { const char *s_text = cs.ptr(); @@ -1040,16 +1052,12 @@ static void gdextension_string_name_new_with_latin1_chars(GDExtensionUninitializ } static void gdextension_string_name_new_with_utf8_chars(GDExtensionUninitializedStringNamePtr r_dest, const char *p_contents) { - String tmp; - tmp.parse_utf8(p_contents); - + String tmp = String::utf8(p_contents); memnew_placement(r_dest, StringName(tmp)); } static void gdextension_string_name_new_with_utf8_chars_and_len(GDExtensionUninitializedStringNamePtr r_dest, const char *p_contents, GDExtensionInt p_size) { - String tmp; - tmp.parse_utf8(p_contents, p_size); - + String tmp = String::utf8(p_contents, p_size); memnew_placement(r_dest, StringName(tmp)); } @@ -1543,11 +1551,8 @@ static void gdextension_placeholder_script_instance_update(GDExtensionScriptInst properties_list.push_back(PropertyInfo::from_dict(d)); } - List keys; - values.get_key_list(&keys); - - for (const Variant &E : keys) { - values_map.insert(E, values[E]); + for (const KeyValue &kv : values) { + values_map.insert(kv.key, kv.value); } placeholder->update(properties_list, values_map); @@ -1572,6 +1577,15 @@ static GDExtensionScriptInstancePtr gdextension_object_get_script_instance(GDExt return script_instance_extension->instance; } +static void gdextension_object_set_script_instance(GDExtensionObjectPtr p_object, GDExtensionScriptInstancePtr p_script_instance) { + ERR_FAIL_NULL(p_object); + + Object *o = (Object *)p_object; + ScriptInstance *script_instance = (ScriptInstanceExtension *)p_script_instance; + + o->set_script_instance(script_instance); +} + #ifndef DISABLE_DEPRECATED static void gdextension_callable_custom_create(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo *p_custom_callable_info) { memnew_placement(r_callable, Callable(memnew(CallableCustomExtension(p_custom_callable_info)))); @@ -1666,7 +1680,10 @@ static void gdextension_editor_help_load_xml_from_utf8_chars(const char *p_data) #define REGISTER_INTERFACE_FUNC(m_name) GDExtension::register_interface_function(#m_name, (GDExtensionInterfaceFunctionPtr) & gdextension_##m_name) void gdextension_setup_interface() { +#ifndef DISABLE_DEPRECATED REGISTER_INTERFACE_FUNC(get_godot_version); +#endif // DISABLE_DEPRECATED + REGISTER_INTERFACE_FUNC(get_godot_version2); REGISTER_INTERFACE_FUNC(mem_alloc); REGISTER_INTERFACE_FUNC(mem_realloc); REGISTER_INTERFACE_FUNC(mem_free); @@ -1809,6 +1826,7 @@ void gdextension_setup_interface() { REGISTER_INTERFACE_FUNC(placeholder_script_instance_create); REGISTER_INTERFACE_FUNC(placeholder_script_instance_update); REGISTER_INTERFACE_FUNC(object_get_script_instance); + REGISTER_INTERFACE_FUNC(object_set_script_instance); #ifndef DISABLE_DEPRECATED REGISTER_INTERFACE_FUNC(callable_custom_create); #endif // DISABLE_DEPRECATED diff --git a/engine/core/extension/gdextension_interface.h b/engine/core/extension/gdextension_interface.h index ac0181e0..ecd40c86 100644 --- a/engine/core/extension/gdextension_interface.h +++ b/engine/core/extension/gdextension_interface.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GDEXTENSION_INTERFACE_H -#define GDEXTENSION_INTERFACE_H +#pragma once /* This is a C class header, you can copy it and use it directly in your own binders. * Together with the JSON file, you should be able to generate any binder. @@ -401,6 +400,9 @@ typedef struct { typedef void *GDExtensionClassLibraryPtr; +/* Passed a pointer to a PackedStringArray that should be filled with the classes that may be used by the GDExtension. */ +typedef void (*GDExtensionEditorGetClassesUsedCallback)(GDExtensionTypePtr p_packed_string_array); + /* Method */ typedef enum { @@ -790,9 +792,22 @@ typedef struct { const char *string; } GDExtensionGodotVersion; +typedef struct { + uint32_t major; + uint32_t minor; + uint32_t patch; + uint32_t hex; // Full version encoded as hexadecimal with one byte (2 hex digits) per number (e.g. for "3.1.12" it would be 0x03010C) + const char *status; // (e.g. "stable", "beta", "rc1", "rc2") + const char *build; // (e.g. "custom_build") + const char *hash; // Full Git commit hash. + uint64_t timestamp; // Git commit date UNIX timestamp in seconds, or 0 if unavailable. + const char *string; // (e.g. "Godot v3.1.4.stable.official.mono") +} GDExtensionGodotVersion2; + /** * @name get_godot_version * @since 4.1 + * @deprecated in Godot 4.5. Use `get_godot_version2` instead. * * Gets the Godot version that the GDExtension was loaded into. * @@ -800,6 +815,16 @@ typedef struct { */ typedef void (*GDExtensionInterfaceGetGodotVersion)(GDExtensionGodotVersion *r_godot_version); +/** + * @name get_godot_version2 + * @since 4.5 + * + * Gets the Godot version that the GDExtension was loaded into. + * + * @param r_godot_version A pointer to the structure to write the version information into. + */ +typedef void (*GDExtensionInterfaceGetGodotVersion2)(GDExtensionGodotVersion2 *r_godot_version); + /* INTERFACE: Memory */ /** @@ -2721,6 +2746,17 @@ typedef void (*GDExtensionInterfacePlaceHolderScriptInstanceUpdate)(GDExtensionS */ typedef GDExtensionScriptInstanceDataPtr (*GDExtensionInterfaceObjectGetScriptInstance)(GDExtensionConstObjectPtr p_object, GDExtensionObjectPtr p_language); +/** + * @name object_set_script_instance + * @since 4.5 + * + * Set the script instance data attached to this object. + * + * @param p_object A pointer to the Object. + * @param p_script_instance A pointer to the script instance data to attach to this object. + */ +typedef void (*GDExtensionInterfaceObjectSetScriptInstance)(GDExtensionObjectPtr p_object, GDExtensionScriptInstanceDataPtr p_script_instance); + /* INTERFACE: Callable */ /** @@ -3078,8 +3114,22 @@ typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars)(const char * */ typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen)(const char *p_data, GDExtensionInt p_size); +/** + * @name editor_register_get_classes_used_callback + * @since 4.5 + * + * Registers a callback that Godot can call to get the list of all classes (from ClassDB) that may be used by the calling GDExtension. + * + * This is used by the editor to generate a build profile (in "Tools" > "Engine Compilation Configuration Editor..." > "Detect from project"), + * in order to recompile Godot with only the classes used. + * In the provided callback, the GDExtension should provide the list of classes that _may_ be used statically, thus the time of invocation shouldn't matter. + * If a GDExtension doesn't register a callback, Godot will assume that it could be using any classes. + * + * @param p_library A pointer the library received by the GDExtension's entry point function. + * @param p_callback The callback to retrieve the list of classes used. + */ +typedef void (*GDExtensionInterfaceEditorRegisterGetClassesUsedCallback)(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback); + #ifdef __cplusplus } #endif - -#endif // GDEXTENSION_INTERFACE_H diff --git a/engine/core/extension/gdextension_library_loader.cpp b/engine/core/extension/gdextension_library_loader.cpp index 17200916..1d6be752 100644 --- a/engine/core/extension/gdextension_library_loader.cpp +++ b/engine/core/extension/gdextension_library_loader.cpp @@ -307,12 +307,12 @@ Error GDExtensionLibraryLoader::parse_gdextension_file(const String &p_path) { bool compatible = true; // Check version lexicographically. - if (VERSION_MAJOR != compatibility_minimum[0]) { - compatible = VERSION_MAJOR > compatibility_minimum[0]; - } else if (VERSION_MINOR != compatibility_minimum[1]) { - compatible = VERSION_MINOR > compatibility_minimum[1]; + if (GODOT_VERSION_MAJOR != compatibility_minimum[0]) { + compatible = GODOT_VERSION_MAJOR > compatibility_minimum[0]; + } else if (GODOT_VERSION_MINOR != compatibility_minimum[1]) { + compatible = GODOT_VERSION_MINOR > compatibility_minimum[1]; } else { - compatible = VERSION_PATCH >= compatibility_minimum[2]; + compatible = GODOT_VERSION_PATCH >= compatibility_minimum[2]; } if (!compatible) { ERR_PRINT(vformat("GDExtension only compatible with Godot version %d.%d.%d or later: %s", compatibility_minimum[0], compatibility_minimum[1], compatibility_minimum[2], p_path)); @@ -334,15 +334,15 @@ Error GDExtensionLibraryLoader::parse_gdextension_file(const String &p_path) { } compatible = true; - if (VERSION_MAJOR != compatibility_maximum[0]) { - compatible = VERSION_MAJOR < compatibility_maximum[0]; - } else if (VERSION_MINOR != compatibility_maximum[1]) { - compatible = VERSION_MINOR < compatibility_maximum[1]; + if (GODOT_VERSION_MAJOR != compatibility_maximum[0]) { + compatible = GODOT_VERSION_MAJOR < compatibility_maximum[0]; + } else if (GODOT_VERSION_MINOR != compatibility_maximum[1]) { + compatible = GODOT_VERSION_MINOR < compatibility_maximum[1]; } -#if VERSION_PATCH +#if GODOT_VERSION_PATCH // #if check to avoid -Wtype-limits warning when 0. else { - compatible = VERSION_PATCH <= compatibility_maximum[2]; + compatible = GODOT_VERSION_PATCH <= compatibility_maximum[2]; } #endif diff --git a/engine/core/extension/gdextension_library_loader.h b/engine/core/extension/gdextension_library_loader.h index f781611b..75ad0ebe 100644 --- a/engine/core/extension/gdextension_library_loader.h +++ b/engine/core/extension/gdextension_library_loader.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GDEXTENSION_LIBRARY_LOADER_H -#define GDEXTENSION_LIBRARY_LOADER_H +#pragma once #include @@ -38,6 +37,8 @@ #include "core/os/shared_object.h" class GDExtensionLibraryLoader : public GDExtensionLoader { + GDSOFTCLASS(GDExtensionLibraryLoader, GDExtensionLoader); + friend class GDExtensionManager; friend class GDExtension; @@ -81,5 +82,3 @@ public: Error parse_gdextension_file(const String &p_path); }; - -#endif // GDEXTENSION_LIBRARY_LOADER_H diff --git a/engine/core/extension/gdextension_loader.h b/engine/core/extension/gdextension_loader.h index 22895503..5d212779 100644 --- a/engine/core/extension/gdextension_loader.h +++ b/engine/core/extension/gdextension_loader.h @@ -28,14 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GDEXTENSION_LOADER_H -#define GDEXTENSION_LOADER_H +#pragma once #include "core/object/ref_counted.h" class GDExtension; class GDExtensionLoader : public RefCounted { + GDSOFTCLASS(GDExtensionLoader, GDExtensionLoader); + public: virtual Error open_library(const String &p_path) = 0; virtual Error initialize(GDExtensionInterfaceGetProcAddress p_get_proc_address, const Ref &p_extension, GDExtensionInitialization *r_initialization) = 0; @@ -44,5 +45,3 @@ public: virtual bool has_library_changed() const = 0; virtual bool library_exists() const = 0; }; - -#endif // GDEXTENSION_LOADER_H diff --git a/engine/core/extension/gdextension_manager.h b/engine/core/extension/gdextension_manager.h index 39a60047..1523c07c 100644 --- a/engine/core/extension/gdextension_manager.h +++ b/engine/core/extension/gdextension_manager.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GDEXTENSION_MANAGER_H -#define GDEXTENSION_MANAGER_H +#pragma once #include "core/extension/gdextension.h" @@ -92,5 +91,3 @@ public: }; VARIANT_ENUM_CAST(GDExtensionManager::LoadStatus) - -#endif // GDEXTENSION_MANAGER_H diff --git a/engine/core/extension/gdextension_special_compat_hashes.h b/engine/core/extension/gdextension_special_compat_hashes.h index 0d447897..9cfb9208 100644 --- a/engine/core/extension/gdextension_special_compat_hashes.h +++ b/engine/core/extension/gdextension_special_compat_hashes.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GDEXTENSION_SPECIAL_COMPAT_HASHES_H -#define GDEXTENSION_SPECIAL_COMPAT_HASHES_H +#pragma once #ifndef DISABLE_DEPRECATED @@ -58,5 +57,3 @@ public: }; #endif // DISABLE_DEPRECATED - -#endif // GDEXTENSION_SPECIAL_COMPAT_HASHES_H diff --git a/engine/core/extension/make_interface_dumper.py b/engine/core/extension/make_interface_dumper.py index af356882..45f257a3 100644 --- a/engine/core/extension/make_interface_dumper.py +++ b/engine/core/extension/make_interface_dumper.py @@ -1,55 +1,37 @@ -import zlib +import methods def run(target, source, env): - src = str(source[0]) - dst = str(target[0]) - with open(src, "rb") as f, open(dst, "w", encoding="utf-8", newline="\n") as g: - buf = f.read() - decomp_size = len(buf) - - # Use maximum zlib compression level to further reduce file size - # (at the cost of initial build times). - buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION) - - g.write( - """/* THIS FILE IS GENERATED DO NOT EDIT */ -#ifndef GDEXTENSION_INTERFACE_DUMP_H -#define GDEXTENSION_INTERFACE_DUMP_H + buffer = methods.get_buffer(str(source[0])) + decomp_size = len(buffer) + buffer = methods.compress_buffer(buffer) + with methods.generated_wrapper(str(target[0])) as file: + file.write(f"""\ #ifdef TOOLS_ENABLED #include "core/io/compression.h" #include "core/io/file_access.h" #include "core/string/ustring.h" -""" - ) +inline constexpr int _gdextension_interface_data_compressed_size = {len(buffer)}; +inline constexpr int _gdextension_interface_data_uncompressed_size = {decomp_size}; +inline constexpr unsigned char _gdextension_interface_data_compressed[] = {{ + {methods.format_buffer(buffer, 1)} +}}; - g.write("static const int _gdextension_interface_data_compressed_size = " + str(len(buf)) + ";\n") - g.write("static const int _gdextension_interface_data_uncompressed_size = " + str(decomp_size) + ";\n") - g.write("static const unsigned char _gdextension_interface_data_compressed[] = {\n") - for i in range(len(buf)): - g.write("\t" + str(buf[i]) + ",\n") - g.write("};\n") - - g.write( - """ -class GDExtensionInterfaceDump { - public: - static void generate_gdextension_interface_file(const String &p_path) { - Ref fa = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_MSG(fa.is_null(), vformat("Cannot open file '%s' for writing.", p_path)); - Vector data; - data.resize(_gdextension_interface_data_uncompressed_size); - int ret = Compression::decompress(data.ptrw(), _gdextension_interface_data_uncompressed_size, _gdextension_interface_data_compressed, _gdextension_interface_data_compressed_size, Compression::MODE_DEFLATE); - ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt."); - fa->store_buffer(data.ptr(), data.size()); - }; -}; +class GDExtensionInterfaceDump {{ + public: + static void generate_gdextension_interface_file(const String &p_path) {{ + Ref fa = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_MSG(fa.is_null(), vformat("Cannot open file '%s' for writing.", p_path)); + Vector data; + data.resize(_gdextension_interface_data_uncompressed_size); + int ret = Compression::decompress(data.ptrw(), _gdextension_interface_data_uncompressed_size, _gdextension_interface_data_compressed, _gdextension_interface_data_compressed_size, Compression::MODE_DEFLATE); + ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt."); + fa->store_buffer(data.ptr(), data.size()); + }}; +}}; #endif // TOOLS_ENABLED - -#endif // GDEXTENSION_INTERFACE_DUMP_H -""" - ) +""") diff --git a/engine/core/extension/make_wrappers.py b/engine/core/extension/make_wrappers.py index 665b6f0f..96936d8c 100644 --- a/engine/core/extension/make_wrappers.py +++ b/engine/core/extension/make_wrappers.py @@ -119,10 +119,7 @@ def generate_ex_version(argcount, const=False, returns=False): def run(target, source, env): max_versions = 12 - txt = """ -#ifndef GDEXTENSION_WRAPPERS_GEN_H -#define GDEXTENSION_WRAPPERS_GEN_H -""" + txt = "#pragma once" for i in range(max_versions + 1): txt += "\n/* Extension Wrapper " + str(i) + " Arguments */\n" @@ -138,7 +135,5 @@ def run(target, source, env): txt += generate_mod_version(i, True, False) txt += generate_mod_version(i, True, True) - txt += "\n#endif\n" - with open(str(target[0]), "w", encoding="utf-8", newline="\n") as f: f.write(txt) diff --git a/engine/core/input/default_controller_mappings.h b/engine/core/input/default_controller_mappings.h index 34e7d5d8..6d7c807a 100644 --- a/engine/core/input/default_controller_mappings.h +++ b/engine/core/input/default_controller_mappings.h @@ -28,12 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef DEFAULT_CONTROLLER_MAPPINGS_H -#define DEFAULT_CONTROLLER_MAPPINGS_H +#pragma once class DefaultControllerMappings { public: static const char *mappings[]; }; - -#endif // DEFAULT_CONTROLLER_MAPPINGS_H diff --git a/engine/core/input/input.cpp b/engine/core/input/input.cpp index f03b9c05..6b9fec6f 100644 --- a/engine/core/input/input.cpp +++ b/engine/core/input/input.cpp @@ -219,7 +219,7 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, Listpush_back(name.quote()); } } @@ -1594,8 +1594,8 @@ void Input::parse_mapping(const String &p_mapping) { continue; } - String output = entry[idx].get_slice(":", 0).replace(" ", ""); - String input = entry[idx].get_slice(":", 1).replace(" ", ""); + String output = entry[idx].get_slicec(':', 0).remove_char(' '); + String input = entry[idx].get_slicec(':', 1).remove_char(' '); if (output.length() < 1 || input.length() < 2) { continue; } diff --git a/engine/core/input/input.h b/engine/core/input/input.h index bbe185de..8d3b7ae3 100644 --- a/engine/core/input/input.h +++ b/engine/core/input/input.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef INPUT_H -#define INPUT_H +#pragma once #include "core/input/input_event.h" #include "core/object/object.h" @@ -86,7 +85,7 @@ public: typedef void (*EventDispatchFunc)(const Ref &p_event); private: - BitField mouse_button_mask; + BitField mouse_button_mask = MouseButtonMask::NONE; RBSet key_label_pressed; RBSet physical_keys_pressed; @@ -403,5 +402,3 @@ public: VARIANT_ENUM_CAST(Input::MouseMode); VARIANT_ENUM_CAST(Input::CursorShape); - -#endif // INPUT_H diff --git a/engine/core/input/input_builders.py b/engine/core/input/input_builders.py index 3685e726..c63f595f 100644 --- a/engine/core/input/input_builders.py +++ b/engine/core/input/input_builders.py @@ -2,18 +2,22 @@ from collections import OrderedDict +import methods + def make_default_controller_mappings(target, source, env): - dst = str(target[0]) - with open(dst, "w", encoding="utf-8", newline="\n") as g: - g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - g.write('#include "core/typedefs.h"\n') - g.write('#include "core/input/default_controller_mappings.h"\n') + with methods.generated_wrapper(str(target[0])) as file: + file.write("""\ +#include "core/input/default_controller_mappings.h" + +#include "core/typedefs.h" + +""") # ensure mappings have a consistent order - platform_mappings: dict = OrderedDict() - for src_path in source: - with open(str(src_path), "r", encoding="utf-8") as f: + platform_mappings = OrderedDict() + for src_path in map(str, source): + with open(src_path, "r", encoding="utf-8") as f: # read mapping file and skip header mapping_file_lines = f.readlines()[2:] @@ -32,28 +36,28 @@ def make_default_controller_mappings(target, source, env): line_parts = line.split(",") guid = line_parts[0] if guid in platform_mappings[current_platform]: - g.write( + file.write( "// WARNING: DATABASE {} OVERWROTE PRIOR MAPPING: {} {}\n".format( src_path, current_platform, platform_mappings[current_platform][guid] ) ) platform_mappings[current_platform][guid] = line - platform_variables = { - "Linux": "#ifdef LINUXBSD_ENABLED", - "Windows": "#ifdef WINDOWS_ENABLED", - "Mac OS X": "#ifdef MACOS_ENABLED", - "Android": "#ifdef ANDROID_ENABLED", - "iOS": "#ifdef IOS_ENABLED", - "Web": "#ifdef WEB_ENABLED", + PLATFORM_VARIABLES = { + "Linux": "LINUXBSD", + "Windows": "WINDOWS", + "Mac OS X": "MACOS", + "Android": "ANDROID", + "iOS": "IOS", + "Web": "WEB", } - g.write("const char* DefaultControllerMappings::mappings[] = {\n") + file.write("const char *DefaultControllerMappings::mappings[] = {\n") for platform, mappings in platform_mappings.items(): - variable = platform_variables[platform] - g.write("{}\n".format(variable)) + variable = PLATFORM_VARIABLES[platform] + file.write(f"#ifdef {variable}_ENABLED\n") for mapping in mappings.values(): - g.write('\t"{}",\n'.format(mapping)) - g.write("#endif\n") + file.write(f'\t"{mapping}",\n') + file.write(f"#endif // {variable}_ENABLED\n") - g.write("\tnullptr\n};\n") + file.write("\tnullptr\n};\n") diff --git a/engine/core/input/input_enums.h b/engine/core/input/input_enums.h index 182a5aab..d4efb3d8 100644 --- a/engine/core/input/input_enums.h +++ b/engine/core/input/input_enums.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef INPUT_ENUMS_H -#define INPUT_ENUMS_H +#pragma once #include "core/error/error_macros.h" @@ -138,4 +137,10 @@ inline MouseButtonMask mouse_button_to_mask(MouseButton button) { return MouseButtonMask(1 << ((int)button - 1)); } -#endif // INPUT_ENUMS_H +constexpr MouseButtonMask operator|(MouseButtonMask p_a, MouseButtonMask p_b) { + return static_cast(static_cast(p_a) | static_cast(p_b)); +} + +constexpr MouseButtonMask &operator|=(MouseButtonMask &p_a, MouseButtonMask p_b) { + return p_a = p_a | p_b; +} diff --git a/engine/core/input/input_event.cpp b/engine/core/input/input_event.cpp index 6e8cdc4b..85c35c05 100644 --- a/engine/core/input/input_event.cpp +++ b/engine/core/input/input_event.cpp @@ -230,7 +230,7 @@ void InputEventWithModifiers::set_modifiers_from_event(const InputEventWithModif } BitField InputEventWithModifiers::get_modifiers_mask() const { - BitField mask; + BitField mask = {}; if (is_ctrl_pressed()) { mask.set_flag(KeyModifierMask::CTRL); } @@ -385,11 +385,11 @@ bool InputEventKey::is_echo() const { } Key InputEventKey::get_keycode_with_modifiers() const { - return keycode | (int64_t)get_modifiers_mask(); + return keycode | get_modifiers_mask(); } Key InputEventKey::get_physical_keycode_with_modifiers() const { - return physical_keycode | (int64_t)get_modifiers_mask(); + return physical_keycode | get_modifiers_mask(); } Key InputEventKey::get_key_label_with_modifiers() const { diff --git a/engine/core/input/input_event.h b/engine/core/input/input_event.h index 19176f74..6e308f6c 100644 --- a/engine/core/input/input_event.h +++ b/engine/core/input/input_event.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef INPUT_EVENT_H -#define INPUT_EVENT_H +#pragma once #include "core/input/input_enums.h" #include "core/io/resource.h" @@ -209,7 +208,7 @@ public: class InputEventMouse : public InputEventWithModifiers { GDCLASS(InputEventMouse, InputEventWithModifiers); - BitField button_mask; + BitField button_mask = MouseButtonMask::NONE; Vector2 pos; Vector2 global_pos; @@ -595,5 +594,3 @@ public: InputEventShortcut(); }; - -#endif // INPUT_EVENT_H diff --git a/engine/core/input/input_map.cpp b/engine/core/input/input_map.cpp index bcd3b63a..ea03c25c 100644 --- a/engine/core/input/input_map.cpp +++ b/engine/core/input/input_map.cpp @@ -47,6 +47,8 @@ void InputMap::_bind_methods() { ClassDB::bind_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::add_action, DEFVAL(DEFAULT_DEADZONE)); ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action); + ClassDB::bind_method(D_METHOD("get_action_description", "action"), &InputMap::get_action_description); + ClassDB::bind_method(D_METHOD("action_set_deadzone", "action", "deadzone"), &InputMap::action_set_deadzone); ClassDB::bind_method(D_METHOD("action_get_deadzone", "action"), &InputMap::action_get_deadzone); ClassDB::bind_method(D_METHOD("action_add_event", "action", "event"), &InputMap::action_add_event); @@ -106,7 +108,7 @@ void InputMap::get_argument_options(const StringName &p_function, int p_idx, Lis continue; } - String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length()); + String name = pi.name.substr(pi.name.find_char('/') + 1); r_options->push_back(name.quote()); } } @@ -181,6 +183,25 @@ bool InputMap::has_action(const StringName &p_action) const { return input_map.has(p_action); } +String InputMap::get_action_description(const StringName &p_action) const { + ERR_FAIL_COND_V_MSG(!input_map.has(p_action), String(), suggest_actions(p_action)); + + String ret; + const List> &inputs = input_map[p_action].inputs; + for (Ref iek : inputs) { + if (iek.is_valid()) { + if (!ret.is_empty()) { + ret += RTR(" or "); + } + ret += iek->as_text(); + } + } + if (ret.is_empty()) { + ret = RTR("Action has no bound inputs"); + } + return ret; +} + float InputMap::action_get_deadzone(const StringName &p_action) { ERR_FAIL_COND_V_MSG(!input_map.has(p_action), 0.0f, suggest_actions(p_action)); @@ -304,7 +325,7 @@ void InputMap::load_from_project_settings() { continue; } - String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length()); + String name = pi.name.substr(pi.name.find_char('/') + 1); Dictionary action = GLOBAL_GET(pi.name); float deadzone = action.has("deadzone") ? (float)action["deadzone"] : DEFAULT_DEADZONE; @@ -344,6 +365,7 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = { { "ui_cut", TTRC("Cut") }, { "ui_copy", TTRC("Copy") }, { "ui_paste", TTRC("Paste") }, + { "ui_focus_mode", TTRC("Toggle Tab Focus Mode") }, { "ui_undo", TTRC("Undo") }, { "ui_redo", TTRC("Redo") }, { "ui_text_completion_query", TTRC("Completion Query") }, @@ -397,17 +419,21 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = { { "ui_text_submit", TTRC("Submit Text") }, { "ui_graph_duplicate", TTRC("Duplicate Nodes") }, { "ui_graph_delete", TTRC("Delete Nodes") }, + { "ui_graph_follow_left", TTRC("Follow Input Port Connection") }, + { "ui_graph_follow_right", TTRC("Follow Output Port Connection") }, { "ui_filedialog_up_one_level", TTRC("Go Up One Level") }, { "ui_filedialog_refresh", TTRC("Refresh") }, { "ui_filedialog_show_hidden", TTRC("Show Hidden") }, { "ui_swap_input_direction ", TTRC("Swap Input Direction") }, { "ui_unicode_start", TTRC("Start Unicode Character Input") }, + { "ui_colorpicker_delete_preset", TTRC("Toggle License Notices") }, + { "ui_accessibility_drag_and_drop", TTRC("Accessibility: Keyboard Drag and Drop") }, { "", ""} /* clang-format on */ }; String InputMap::get_builtin_display_name(const String &p_name) const { - int len = sizeof(_builtin_action_display_names) / sizeof(_BuiltinActionDisplayName); + constexpr int len = std::size(_builtin_action_display_names); for (int i = 0; i < len; i++) { if (_builtin_action_display_names[i].name == p_name) { @@ -487,6 +513,9 @@ const HashMap>> &InputMap::get_builtins() { inputs.push_back(InputEventKey::create_reference(Key::END)); default_builtin_cache.insert("ui_end", inputs); + inputs = List>(); + default_builtin_cache.insert("ui_accessibility_drag_and_drop", inputs); + // ///// UI basic Shortcuts ///// inputs = List>(); @@ -499,6 +528,10 @@ const HashMap>> &InputMap::get_builtins() { inputs.push_back(InputEventKey::create_reference(Key::INSERT | KeyModifierMask::CMD_OR_CTRL)); default_builtin_cache.insert("ui_copy", inputs); + inputs = List>(); + inputs.push_back(InputEventKey::create_reference(Key::M | KeyModifierMask::CTRL)); + default_builtin_cache.insert("ui_focus_mode", inputs); + inputs = List>(); inputs.push_back(InputEventKey::create_reference(Key::V | KeyModifierMask::CMD_OR_CTRL)); inputs.push_back(InputEventKey::create_reference(Key::INSERT | KeyModifierMask::SHIFT)); @@ -772,6 +805,22 @@ const HashMap>> &InputMap::get_builtins() { inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE)); default_builtin_cache.insert("ui_graph_delete", inputs); + inputs = List>(); + inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::CMD_OR_CTRL)); + default_builtin_cache.insert("ui_graph_follow_left", inputs); + + inputs = List>(); + inputs.push_back(InputEventKey::create_reference(Key::LEFT | KeyModifierMask::ALT)); + default_builtin_cache.insert("ui_graph_follow_left.macos", inputs); + + inputs = List>(); + inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::CMD_OR_CTRL)); + default_builtin_cache.insert("ui_graph_follow_right", inputs); + + inputs = List>(); + inputs.push_back(InputEventKey::create_reference(Key::RIGHT | KeyModifierMask::ALT)); + default_builtin_cache.insert("ui_graph_follow_right.macos", inputs); + // ///// UI File Dialog Shortcuts ///// inputs = List>(); inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE)); @@ -789,6 +838,12 @@ const HashMap>> &InputMap::get_builtins() { inputs.push_back(InputEventKey::create_reference(Key::QUOTELEFT | KeyModifierMask::CMD_OR_CTRL)); default_builtin_cache.insert("ui_swap_input_direction", inputs); + // ///// UI ColorPicker Shortcuts ///// + inputs = List>(); + inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::X)); + inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE)); + default_builtin_cache.insert("ui_colorpicker_delete_preset", inputs); + return default_builtin_cache; } diff --git a/engine/core/input/input_map.h b/engine/core/input/input_map.h index 520c10c4..00bc1550 100644 --- a/engine/core/input/input_map.h +++ b/engine/core/input/input_map.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef INPUT_MAP_H -#define INPUT_MAP_H +#pragma once #include "core/input/input_event.h" #include "core/object/class_db.h" @@ -86,6 +85,8 @@ public: void add_action(const StringName &p_action, float p_deadzone = DEFAULT_DEADZONE); void erase_action(const StringName &p_action); + String get_action_description(const StringName &p_action) const; + float action_get_deadzone(const StringName &p_action); void action_set_deadzone(const StringName &p_action, float p_deadzone); void action_add_event(const StringName &p_action, const Ref &p_event); @@ -116,5 +117,3 @@ public: InputMap(); ~InputMap(); }; - -#endif // INPUT_MAP_H diff --git a/engine/core/input/shortcut.h b/engine/core/input/shortcut.h index 4109e31f..5c054827 100644 --- a/engine/core/input/shortcut.h +++ b/engine/core/input/shortcut.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef SHORTCUT_H -#define SHORTCUT_H +#pragma once #include "core/input/input_event.h" #include "core/io/resource.h" @@ -55,5 +54,3 @@ public: static bool is_event_array_equal(const Array &p_event_array1, const Array &p_event_array2); }; - -#endif // SHORTCUT_H diff --git a/engine/core/io/compression.cpp b/engine/core/io/compression.cpp index 4e4627c4..79f37db1 100644 --- a/engine/core/io/compression.cpp +++ b/engine/core/io/compression.cpp @@ -42,6 +42,12 @@ #include #endif +// Caches for zstd. +static BinaryMutex mutex; +static ZSTD_DCtx *current_zstd_d_ctx = nullptr; +static bool current_zstd_long_distance_matching; +static int current_zstd_window_log_size; + int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size, Mode p_mode) { switch (p_mode) { case MODE_BROTLI: { @@ -187,12 +193,22 @@ int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p return total; } break; case MODE_ZSTD: { - ZSTD_DCtx *dctx = ZSTD_createDCtx(); - if (zstd_long_distance_matching) { - ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, zstd_window_log_size); + MutexLock lock(mutex); + + if (!current_zstd_d_ctx || current_zstd_long_distance_matching != zstd_long_distance_matching || current_zstd_window_log_size != zstd_window_log_size) { + if (current_zstd_d_ctx) { + ZSTD_freeDCtx(current_zstd_d_ctx); + } + + current_zstd_d_ctx = ZSTD_createDCtx(); + if (zstd_long_distance_matching) { + ZSTD_DCtx_setParameter(current_zstd_d_ctx, ZSTD_d_windowLogMax, zstd_window_log_size); + } + current_zstd_long_distance_matching = zstd_long_distance_matching; + current_zstd_window_log_size = zstd_window_log_size; } - int ret = ZSTD_decompressDCtx(dctx, p_dst, p_dst_max_size, p_src, p_src_size); - ZSTD_freeDCtx(dctx); + + int ret = ZSTD_decompressDCtx(current_zstd_d_ctx, p_dst, p_dst_max_size, p_src, p_src_size); return ret; } break; } diff --git a/engine/core/io/compression.h b/engine/core/io/compression.h index ea56ab8e..08468de9 100644 --- a/engine/core/io/compression.h +++ b/engine/core/io/compression.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef COMPRESSION_H -#define COMPRESSION_H +#pragma once #include "core/templates/vector.h" #include "core/typedefs.h" @@ -56,5 +55,3 @@ public: static int decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size, Mode p_mode = MODE_ZSTD); static int decompress_dynamic(Vector *p_dst_vect, int p_max_dst_size, const uint8_t *p_src, int p_src_size, Mode p_mode); }; - -#endif // COMPRESSION_H diff --git a/engine/core/io/config_file.h b/engine/core/io/config_file.h index 05b4ed89..01a860be 100644 --- a/engine/core/io/config_file.h +++ b/engine/core/io/config_file.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef CONFIG_FILE_H -#define CONFIG_FILE_H +#pragma once #include "core/io/file_access.h" #include "core/object/ref_counted.h" @@ -78,5 +77,3 @@ public: Error save_encrypted(const String &p_path, const Vector &p_key); Error save_encrypted_pass(const String &p_path, const String &p_pass); }; - -#endif // CONFIG_FILE_H diff --git a/engine/core/io/dir_access.cpp b/engine/core/io/dir_access.cpp index 4bdfc5a5..02f270da 100644 --- a/engine/core/io/dir_access.cpp +++ b/engine/core/io/dir_access.cpp @@ -146,7 +146,7 @@ Error DirAccess::make_dir_recursive(const String &p_dir) { full_dir = p_dir; } - full_dir = full_dir.replace("\\", "/"); + full_dir = full_dir.replace_char('\\', '/'); String base; @@ -336,7 +336,7 @@ Ref DirAccess::create_temp(const String &p_prefix, bool p_keep, Error uint32_t suffix_i = 0; String path; while (true) { - String datetime = Time::get_singleton()->get_datetime_string_from_system().replace("-", "").replace("T", "").replace(":", ""); + String datetime = Time::get_singleton()->get_datetime_string_from_system().remove_chars("-T:"); datetime += itos(Time::get_singleton()->get_ticks_usec()); String suffix = datetime + (suffix_i > 0 ? itos(suffix_i) : ""); path = (p_prefix.is_empty() ? "" : p_prefix + "-") + suffix; @@ -626,6 +626,10 @@ bool DirAccess::is_case_sensitive(const String &p_path) const { return true; } +bool DirAccess::is_equivalent(const String &p_path_a, const String &p_path_b) const { + return p_path_a == p_path_b; +} + void DirAccess::_bind_methods() { ClassDB::bind_static_method("DirAccess", D_METHOD("open", "path"), &DirAccess::_open); ClassDB::bind_static_method("DirAccess", D_METHOD("get_open_error"), &DirAccess::get_open_error); @@ -671,6 +675,7 @@ void DirAccess::_bind_methods() { ClassDB::bind_method(D_METHOD("get_include_hidden"), &DirAccess::get_include_hidden); ClassDB::bind_method(D_METHOD("is_case_sensitive", "path"), &DirAccess::is_case_sensitive); + ClassDB::bind_method(D_METHOD("is_equivalent", "path_a", "path_b"), &DirAccess::is_equivalent); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden"); diff --git a/engine/core/io/dir_access.h b/engine/core/io/dir_access.h index 588e0377..511a414f 100644 --- a/engine/core/io/dir_access.h +++ b/engine/core/io/dir_access.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef DIR_ACCESS_H -#define DIR_ACCESS_H +#pragma once #include "core/object/ref_counted.h" #include "core/string/ustring.h" @@ -169,10 +168,9 @@ public: virtual bool is_case_sensitive(const String &p_path) const; virtual bool is_bundle(const String &p_file) const { return false; } + virtual bool is_equivalent(const String &p_path_a, const String &p_path_b) const; public: DirAccess() {} virtual ~DirAccess(); }; - -#endif // DIR_ACCESS_H diff --git a/engine/core/io/dtls_server.h b/engine/core/io/dtls_server.h index 5ffed1ec..e22a0eff 100644 --- a/engine/core/io/dtls_server.h +++ b/engine/core/io/dtls_server.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef DTLS_SERVER_H -#define DTLS_SERVER_H +#pragma once #include "core/io/net_socket.h" #include "core/io/packet_peer_dtls.h" @@ -53,5 +52,3 @@ public: DTLSServer() {} }; - -#endif // DTLS_SERVER_H diff --git a/engine/core/io/file_access.cpp b/engine/core/io/file_access.cpp index 7d422bf0..68b85cd1 100644 --- a/engine/core/io/file_access.cpp +++ b/engine/core/io/file_access.cpp @@ -104,7 +104,7 @@ Ref FileAccess::create_temp(int p_mode_flags, const String &p_prefix uint32_t suffix_i = 0; String path; while (true) { - String datetime = Time::get_singleton()->get_datetime_string_from_system().replace("-", "").replace("T", "").replace(":", ""); + String datetime = Time::get_singleton()->get_datetime_string_from_system().remove_chars("-T:"); datetime += itos(Time::get_singleton()->get_ticks_usec()); String suffix = datetime + (suffix_i > 0 ? itos(suffix_i) : ""); path = TEMP_DIR.path_join((p_prefix.is_empty() ? "" : p_prefix + "-") + suffix + (extension.is_empty() ? "" : "." + extension)); @@ -259,7 +259,7 @@ FileAccess::AccessType FileAccess::get_access_type() const { String FileAccess::fix_path(const String &p_path) const { // Helper used by file accesses that use a single filesystem. - String r_path = p_path.replace("\\", "/"); + String r_path = p_path.replace_char('\\', '/'); switch (_access_type) { case ACCESS_RESOURCES: { @@ -313,9 +313,15 @@ uint16_t FileAccess::get_16() const { uint16_t data = 0; get_buffer(reinterpret_cast(&data), sizeof(uint16_t)); +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + data = BSWAP16(data); + } +#else if (big_endian) { data = BSWAP16(data); } +#endif return data; } @@ -324,9 +330,15 @@ uint32_t FileAccess::get_32() const { uint32_t data = 0; get_buffer(reinterpret_cast(&data), sizeof(uint32_t)); +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + data = BSWAP32(data); + } +#else if (big_endian) { data = BSWAP32(data); } +#endif return data; } @@ -335,9 +347,15 @@ uint64_t FileAccess::get_64() const { uint64_t data = 0; get_buffer(reinterpret_cast(&data), sizeof(uint64_t)); +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + data = BSWAP64(data); + } +#else if (big_endian) { data = BSWAP64(data); } +#endif return data; } @@ -429,7 +447,7 @@ class CharBuffer { public: _FORCE_INLINE_ CharBuffer() : buffer(stack_buffer), - capacity(sizeof(stack_buffer) / sizeof(char)) { + capacity(std::size(stack_buffer)) { } _FORCE_INLINE_ void push_back(char c) { @@ -565,7 +583,7 @@ String FileAccess::get_as_utf8_string(bool p_skip_cr) const { w[len] = 0; String s; - s.parse_utf8((const char *)w, len, p_skip_cr); + s.append_utf8((const char *)w, len, p_skip_cr); return s; } @@ -574,25 +592,43 @@ bool FileAccess::store_8(uint8_t p_dest) { } bool FileAccess::store_16(uint16_t p_dest) { +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + p_dest = BSWAP16(p_dest); + } +#else if (big_endian) { p_dest = BSWAP16(p_dest); } +#endif return store_buffer(reinterpret_cast(&p_dest), sizeof(uint16_t)); } bool FileAccess::store_32(uint32_t p_dest) { +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + p_dest = BSWAP32(p_dest); + } +#else if (big_endian) { p_dest = BSWAP32(p_dest); } +#endif return store_buffer(reinterpret_cast(&p_dest), sizeof(uint32_t)); } bool FileAccess::store_64(uint64_t p_dest) { +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + p_dest = BSWAP64(p_dest); + } +#else if (big_endian) { p_dest = BSWAP64(p_dest); } +#endif return store_buffer(reinterpret_cast(&p_dest), sizeof(uint64_t)); } @@ -629,8 +665,29 @@ uint64_t FileAccess::get_modified_time(const String &p_file) { Ref fa = create_for_path(p_file); ERR_FAIL_COND_V_MSG(fa.is_null(), 0, vformat("Cannot create FileAccess for path '%s'.", p_file)); - uint64_t mt = fa->_get_modified_time(p_file); - return mt; + return fa->_get_modified_time(p_file); +} + +uint64_t FileAccess::get_access_time(const String &p_file) { + if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && (PackedData::get_singleton()->has_path(p_file) || PackedData::get_singleton()->has_directory(p_file))) { + return 0; + } + + Ref fa = create_for_path(p_file); + ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "Cannot create FileAccess for path '" + p_file + "'."); + + return fa->_get_access_time(p_file); +} + +int64_t FileAccess::get_size(const String &p_file) { + if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && (PackedData::get_singleton()->has_path(p_file) || PackedData::get_singleton()->has_directory(p_file))) { + return PackedData::get_singleton()->get_size(p_file); + } + + Ref fa = create_for_path(p_file); + ERR_FAIL_COND_V_MSG(fa.is_null(), -1, "Cannot create FileAccess for path '" + p_file + "'."); + + return fa->_get_size(p_file); } BitField FileAccess::get_unix_permissions(const String &p_file) { @@ -723,9 +780,7 @@ String FileAccess::get_pascal_string() { get_buffer((uint8_t *)cs.ptr(), sl); cs[sl] = 0; - String ret; - ret.parse_utf8(cs.ptr(), sl); - return ret; + return String::utf8(cs.ptr(), sl); } bool FileAccess::store_line(const String &p_line) { @@ -817,7 +872,7 @@ String FileAccess::get_file_as_string(const String &p_path, Error *r_error) { } String ret; - ret.parse_utf8((const char *)array.ptr(), array.size()); + ret.append_utf8((const char *)array.ptr(), array.size()); return ret; } @@ -931,7 +986,7 @@ void FileAccess::_bind_methods() { ClassDB::bind_method(D_METHOD("get_float"), &FileAccess::get_float); ClassDB::bind_method(D_METHOD("get_double"), &FileAccess::get_double); ClassDB::bind_method(D_METHOD("get_real"), &FileAccess::get_real); - ClassDB::bind_method(D_METHOD("get_buffer", "length"), (Vector(FileAccess::*)(int64_t) const) & FileAccess::get_buffer); + ClassDB::bind_method(D_METHOD("get_buffer", "length"), (Vector (FileAccess::*)(int64_t) const) & FileAccess::get_buffer); ClassDB::bind_method(D_METHOD("get_line"), &FileAccess::get_line); ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &FileAccess::get_csv_line, DEFVAL(",")); ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &FileAccess::get_as_text, DEFVAL(false)); @@ -950,7 +1005,7 @@ void FileAccess::_bind_methods() { ClassDB::bind_method(D_METHOD("store_float", "value"), &FileAccess::store_float); ClassDB::bind_method(D_METHOD("store_double", "value"), &FileAccess::store_double); ClassDB::bind_method(D_METHOD("store_real", "value"), &FileAccess::store_real); - ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), (bool(FileAccess::*)(const Vector &)) & FileAccess::store_buffer); + ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), (bool (FileAccess::*)(const Vector &))&FileAccess::store_buffer); ClassDB::bind_method(D_METHOD("store_line", "line"), &FileAccess::store_line); ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &FileAccess::store_csv_line, DEFVAL(",")); ClassDB::bind_method(D_METHOD("store_string", "string"), &FileAccess::store_string); @@ -963,6 +1018,8 @@ void FileAccess::_bind_methods() { ClassDB::bind_static_method("FileAccess", D_METHOD("file_exists", "path"), &FileAccess::exists); ClassDB::bind_static_method("FileAccess", D_METHOD("get_modified_time", "file"), &FileAccess::get_modified_time); + ClassDB::bind_static_method("FileAccess", D_METHOD("get_access_time", "file"), &FileAccess::get_access_time); + ClassDB::bind_static_method("FileAccess", D_METHOD("get_size", "file"), &FileAccess::get_size); ClassDB::bind_static_method("FileAccess", D_METHOD("get_unix_permissions", "file"), &FileAccess::get_unix_permissions); ClassDB::bind_static_method("FileAccess", D_METHOD("set_unix_permissions", "file", "permissions"), &FileAccess::set_unix_permissions); diff --git a/engine/core/io/file_access.h b/engine/core/io/file_access.h index f53f1f18..1947da85 100644 --- a/engine/core/io/file_access.h +++ b/engine/core/io/file_access.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef FILE_ACCESS_H -#define FILE_ACCESS_H +#pragma once #include "core/io/compression.h" #include "core/math/math_defs.h" @@ -87,7 +86,11 @@ public: typedef void (*FileCloseFailNotify)(const String &); typedef Ref (*CreateFunc)(); +#ifdef BIG_ENDIAN_ENABLED + bool big_endian = true; +#else bool big_endian = false; +#endif bool real_is_double = false; virtual BitField _get_unix_permissions(const String &p_file) = 0; @@ -105,6 +108,8 @@ protected: virtual String fix_path(const String &p_path) const; virtual Error open_internal(const String &p_path, int p_mode_flags) = 0; ///< open a file virtual uint64_t _get_modified_time(const String &p_file) = 0; + virtual uint64_t _get_access_time(const String &p_file) = 0; + virtual int64_t _get_size(const String &p_file) = 0; virtual void _set_access_type(AccessType p_access); static FileCloseFailNotify close_fail_notify; @@ -239,6 +244,8 @@ public: static CreateFunc get_create_func(AccessType p_access); static bool exists(const String &p_name); ///< return true if a file exists static uint64_t get_modified_time(const String &p_file); + static uint64_t get_access_time(const String &p_file); + static int64_t get_size(const String &p_file); static BitField get_unix_permissions(const String &p_file); static Error set_unix_permissions(const String &p_file, BitField p_permissions); @@ -273,5 +280,3 @@ public: VARIANT_ENUM_CAST(FileAccess::CompressionMode); VARIANT_ENUM_CAST(FileAccess::ModeFlags); VARIANT_BITFIELD_CAST(FileAccess::UnixPermissionFlags); - -#endif // FILE_ACCESS_H diff --git a/engine/core/io/file_access_compressed.cpp b/engine/core/io/file_access_compressed.cpp index b7300ded..da313492 100644 --- a/engine/core/io/file_access_compressed.cpp +++ b/engine/core/io/file_access_compressed.cpp @@ -247,7 +247,11 @@ bool FileAccessCompressed::eof_reached() const { } uint64_t FileAccessCompressed::get_buffer(uint8_t *p_dst, uint64_t p_length) const { - ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); + if (p_length == 0) { + return 0; + } + + ERR_FAIL_NULL_V(p_dst, -1); ERR_FAIL_COND_V_MSG(f.is_null(), -1, "File must be opened before use."); ERR_FAIL_COND_V_MSG(writing, -1, "File has not been opened in read mode."); @@ -256,29 +260,38 @@ uint64_t FileAccessCompressed::get_buffer(uint8_t *p_dst, uint64_t p_length) con return 0; } - for (uint64_t i = 0; i < p_length; i++) { - p_dst[i] = read_ptr[read_pos]; - read_pos++; - if (read_pos >= read_block_size) { - read_block++; + uint64_t dst_idx = 0; + while (true) { + // Copy over as much of our current block as possible. + const uint32_t copied_bytes_count = MIN(p_length - dst_idx, read_block_size - read_pos); + memcpy(p_dst + dst_idx, read_ptr + read_pos, copied_bytes_count); + dst_idx += copied_bytes_count; + read_pos += copied_bytes_count; - if (read_block < read_block_count) { - //read another block of compressed data - f->get_buffer(comp_buffer.ptrw(), read_blocks[read_block].csize); - int ret = Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode); - ERR_FAIL_COND_V_MSG(ret == -1, -1, "Compressed file is corrupt."); - read_block_size = read_block == read_block_count - 1 ? read_total % block_size : block_size; - read_pos = 0; - - } else { - read_block--; - at_end = true; - if (i + 1 < p_length) { - read_eof = true; - } - return i + 1; - } + if (dst_idx == p_length) { + // We're done! We read back all that was requested. + return p_length; } + + // We're not done yet; try reading the next block. + read_block++; + + if (read_block >= read_block_count) { + // We're done! We read back the whole file. + read_block--; + at_end = true; + if (dst_idx + 1 < p_length) { + read_eof = true; + } + return dst_idx; + } + + // Read the next block of compressed data. + f->get_buffer(comp_buffer.ptrw(), read_blocks[read_block].csize); + int ret = Compression::decompress(buffer.ptrw(), read_blocks.size() == 1 ? read_total : block_size, comp_buffer.ptr(), read_blocks[read_block].csize, cmode); + ERR_FAIL_COND_V_MSG(ret == -1, -1, "Compressed file is corrupt."); + read_block_size = read_block == read_block_count - 1 ? read_total % block_size : block_size; + read_pos = 0; } return p_length; @@ -332,6 +345,22 @@ uint64_t FileAccessCompressed::_get_modified_time(const String &p_file) { } } +uint64_t FileAccessCompressed::_get_access_time(const String &p_file) { + if (f.is_valid()) { + return f->get_access_time(p_file); + } else { + return 0; + } +} + +int64_t FileAccessCompressed::_get_size(const String &p_file) { + if (f.is_valid()) { + return f->get_size(p_file); + } else { + return -1; + } +} + BitField FileAccessCompressed::_get_unix_permissions(const String &p_file) { if (f.is_valid()) { return f->_get_unix_permissions(p_file); diff --git a/engine/core/io/file_access_compressed.h b/engine/core/io/file_access_compressed.h index 607a45fc..7c5e6a5f 100644 --- a/engine/core/io/file_access_compressed.h +++ b/engine/core/io/file_access_compressed.h @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef FILE_ACCESS_COMPRESSED_H -#define FILE_ACCESS_COMPRESSED_H +#pragma once #include "core/io/compression.h" #include "core/io/file_access.h" class FileAccessCompressed : public FileAccess { + GDSOFTCLASS(FileAccessCompressed, FileAccess); Compression::Mode cmode = Compression::MODE_ZSTD; bool writing = false; uint64_t write_pos = 0; @@ -94,6 +94,8 @@ public: virtual bool file_exists(const String &p_name) override; ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file) override; + virtual uint64_t _get_access_time(const String &p_file) override; + virtual int64_t _get_size(const String &p_file) override; virtual BitField _get_unix_permissions(const String &p_file) override; virtual Error _set_unix_permissions(const String &p_file, BitField p_permissions) override; @@ -107,5 +109,3 @@ public: FileAccessCompressed() {} virtual ~FileAccessCompressed(); }; - -#endif // FILE_ACCESS_COMPRESSED_H diff --git a/engine/core/io/file_access_encrypted.cpp b/engine/core/io/file_access_encrypted.cpp index f2749157..7af7737c 100644 --- a/engine/core/io/file_access_encrypted.cpp +++ b/engine/core/io/file_access_encrypted.cpp @@ -30,9 +30,17 @@ #include "file_access_encrypted.h" -#include "core/crypto/crypto_core.h" #include "core/variant/variant.h" +CryptoCore::RandomGenerator *FileAccessEncrypted::_fae_static_rng = nullptr; + +void FileAccessEncrypted::deinitialize() { + if (_fae_static_rng) { + memdelete(_fae_static_rng); + _fae_static_rng = nullptr; + } +} + Error FileAccessEncrypted::open_and_parse(Ref p_base, const Vector &p_key, Mode p_mode, bool p_with_magic, const Vector &p_iv) { ERR_FAIL_COND_V_MSG(file.is_valid(), ERR_ALREADY_IN_USE, vformat("Can't open file while another file from path '%s' is open.", file->get_path_absolute())); ERR_FAIL_COND_V(p_key.size() != 32, ERR_INVALID_PARAMETER); @@ -48,9 +56,15 @@ Error FileAccessEncrypted::open_and_parse(Ref p_base, const Vectorinit() != OK) { + memdelete(_fae_static_rng); + _fae_static_rng = nullptr; + ERR_FAIL_V_MSG(FAILED, "Failed to initialize random number generator."); + } + } + Error err = _fae_static_rng->get_random_bytes(iv.ptrw(), 16); ERR_FAIL_COND_V(err != OK, err); } else { ERR_FAIL_COND_V(p_iv.size() != 16, ERR_INVALID_PARAMETER); @@ -265,7 +279,27 @@ bool FileAccessEncrypted::file_exists(const String &p_name) { } uint64_t FileAccessEncrypted::_get_modified_time(const String &p_file) { - return 0; + if (file.is_valid()) { + return file->get_modified_time(p_file); + } else { + return 0; + } +} + +uint64_t FileAccessEncrypted::_get_access_time(const String &p_file) { + if (file.is_valid()) { + return file->get_access_time(p_file); + } else { + return 0; + } +} + +int64_t FileAccessEncrypted::_get_size(const String &p_file) { + if (file.is_valid()) { + return file->get_size(p_file); + } else { + return -1; + } } BitField FileAccessEncrypted::_get_unix_permissions(const String &p_file) { diff --git a/engine/core/io/file_access_encrypted.h b/engine/core/io/file_access_encrypted.h index 570955b7..15cad3a1 100644 --- a/engine/core/io/file_access_encrypted.h +++ b/engine/core/io/file_access_encrypted.h @@ -28,14 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef FILE_ACCESS_ENCRYPTED_H -#define FILE_ACCESS_ENCRYPTED_H +#pragma once +#include "core/crypto/crypto_core.h" #include "core/io/file_access.h" #define ENCRYPTED_HEADER_MAGIC 0x43454447 class FileAccessEncrypted : public FileAccess { + GDSOFTCLASS(FileAccessEncrypted, FileAccess); + public: enum Mode : int32_t { MODE_READ, @@ -57,6 +59,8 @@ private: void _close(); + static CryptoCore::RandomGenerator *_fae_static_rng; + public: Error open_and_parse(Ref p_base, const Vector &p_key, Mode p_mode, bool p_with_magic = true, const Vector &p_iv = Vector()); Error open_and_parse_password(Ref p_base, const String &p_key, Mode p_mode); @@ -87,6 +91,8 @@ public: virtual bool file_exists(const String &p_name) override; ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file) override; + virtual uint64_t _get_access_time(const String &p_file) override; + virtual int64_t _get_size(const String &p_file) override; virtual BitField _get_unix_permissions(const String &p_file) override; virtual Error _set_unix_permissions(const String &p_file, BitField p_permissions) override; @@ -97,8 +103,8 @@ public: virtual void close() override; + static void deinitialize(); + FileAccessEncrypted() {} ~FileAccessEncrypted(); }; - -#endif // FILE_ACCESS_ENCRYPTED_H diff --git a/engine/core/io/file_access_memory.h b/engine/core/io/file_access_memory.h index 6845cf71..2ff638e9 100644 --- a/engine/core/io/file_access_memory.h +++ b/engine/core/io/file_access_memory.h @@ -28,12 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef FILE_ACCESS_MEMORY_H -#define FILE_ACCESS_MEMORY_H +#pragma once #include "core/io/file_access.h" class FileAccessMemory : public FileAccess { + GDSOFTCLASS(FileAccessMemory, FileAccess); uint8_t *data = nullptr; uint64_t length = 0; mutable uint64_t pos = 0; @@ -66,6 +66,9 @@ public: virtual bool file_exists(const String &p_name) override; ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file) override { return 0; } + virtual uint64_t _get_access_time(const String &p_file) override { return 0; } + virtual int64_t _get_size(const String &p_file) override { return -1; } + virtual BitField _get_unix_permissions(const String &p_file) override { return 0; } virtual Error _set_unix_permissions(const String &p_file, BitField p_permissions) override { return FAILED; } @@ -78,5 +81,3 @@ public: FileAccessMemory() {} }; - -#endif // FILE_ACCESS_MEMORY_H diff --git a/engine/core/io/file_access_pack.cpp b/engine/core/io/file_access_pack.cpp index 3fba2c70..788825f3 100644 --- a/engine/core/io/file_access_pack.cpp +++ b/engine/core/io/file_access_pack.cpp @@ -264,7 +264,7 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, f->get_32(); // patch number, not used for validation. ERR_FAIL_COND_V_MSG(version != PACK_FORMAT_VERSION, false, vformat("Pack version unsupported: %d.", version)); - ERR_FAIL_COND_V_MSG(ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), false, vformat("Pack created with a newer version of the engine: %d.%d.", ver_major, ver_minor)); + ERR_FAIL_COND_V_MSG(ver_major > GODOT_VERSION_MAJOR || (ver_major == GODOT_VERSION_MAJOR && ver_minor > GODOT_VERSION_MINOR), false, vformat("Pack created with a newer version of the engine: %d.%d.", ver_major, ver_minor)); uint32_t pack_flags = f->get_32(); uint64_t file_base = f->get_64(); @@ -306,9 +306,7 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, f->get_buffer((uint8_t *)cs.ptr(), sl); cs[sl] = 0; - String path; - path.parse_utf8(cs.ptr(), sl); - + String path = String::utf8(cs.ptr(), sl); uint64_t ofs = f->get_64(); uint64_t size = f->get_64(); uint8_t md5[16]; @@ -550,7 +548,7 @@ String DirAccessPack::get_drive(int p_drive) { } PackedData::PackedDir *DirAccessPack::_find_dir(const String &p_dir) { - String nd = p_dir.replace("\\", "/"); + String nd = p_dir.replace_char('\\', '/'); // Special handling since simplify_path() will forbid it if (p_dir == "..") { diff --git a/engine/core/io/file_access_pack.h b/engine/core/io/file_access_pack.h index 0e4e7cd2..9a482db7 100644 --- a/engine/core/io/file_access_pack.h +++ b/engine/core/io/file_access_pack.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef FILE_ACCESS_PACK_H -#define FILE_ACCESS_PACK_H +#pragma once #include "core/io/dir_access.h" #include "core/io/file_access.h" @@ -127,6 +126,8 @@ public: _FORCE_INLINE_ Ref try_open_path(const String &p_path); _FORCE_INLINE_ bool has_path(const String &p_path); + _FORCE_INLINE_ int64_t get_size(const String &p_path); + _FORCE_INLINE_ Ref try_open_directory(const String &p_path); _FORCE_INLINE_ bool has_directory(const String &p_path); @@ -156,6 +157,7 @@ public: }; class FileAccessPack : public FileAccess { + GDSOFTCLASS(FileAccessPack, FileAccess); PackedData::PackedFile pf; mutable uint64_t pos; @@ -165,6 +167,8 @@ class FileAccessPack : public FileAccess { Ref f; virtual Error open_internal(const String &p_path, int p_mode_flags) override; virtual uint64_t _get_modified_time(const String &p_file) override { return 0; } + virtual uint64_t _get_access_time(const String &p_file) override { return 0; } + virtual int64_t _get_size(const String &p_file) override { return -1; } virtual BitField _get_unix_permissions(const String &p_file) override { return 0; } virtual Error _set_unix_permissions(const String &p_file, BitField p_permissions) override { return FAILED; } @@ -200,6 +204,19 @@ public: FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file); }; +int64_t PackedData::get_size(const String &p_path) { + String simplified_path = p_path.simplify_path(); + PathMD5 pmd5(simplified_path.md5_buffer()); + HashMap::Iterator E = files.find(pmd5); + if (!E) { + return -1; // File not found. + } + if (E->value.offset == 0) { + return -1; // File was erased. + } + return E->value.size; +} + Ref PackedData::try_open_path(const String &p_path) { String simplified_path = p_path.simplify_path().trim_prefix("res://"); PathMD5 pmd5(simplified_path.md5_buffer()); @@ -225,6 +242,7 @@ bool PackedData::has_directory(const String &p_path) { } class DirAccessPack : public DirAccess { + GDSOFTCLASS(DirAccessPack, DirAccess); PackedData::PackedDir *current; List list_dirs; @@ -272,5 +290,3 @@ Ref PackedData::try_open_directory(const String &p_path) { } return da; } - -#endif // FILE_ACCESS_PACK_H diff --git a/engine/core/io/file_access_zip.h b/engine/core/io/file_access_zip.h index a1544fee..e1f4439d 100644 --- a/engine/core/io/file_access_zip.h +++ b/engine/core/io/file_access_zip.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef FILE_ACCESS_ZIP_H -#define FILE_ACCESS_ZIP_H +#pragma once #ifdef MINIZIP_ENABLED @@ -74,6 +73,7 @@ public: }; class FileAccessZip : public FileAccess { + GDSOFTCLASS(FileAccessZip, FileAccess); unzFile zfile = nullptr; unz_file_info64 file_info; @@ -102,7 +102,9 @@ public: virtual bool file_exists(const String &p_name) override; ///< return true if a file exists - virtual uint64_t _get_modified_time(const String &p_file) override { return 0; } // todo + virtual uint64_t _get_modified_time(const String &p_file) override { return 0; } + virtual uint64_t _get_access_time(const String &p_file) override { return 0; } + virtual int64_t _get_size(const String &p_file) override { return -1; } virtual BitField _get_unix_permissions(const String &p_file) override { return 0; } virtual Error _set_unix_permissions(const String &p_file, BitField p_permissions) override { return FAILED; } @@ -118,5 +120,3 @@ public: }; #endif // MINIZIP_ENABLED - -#endif // FILE_ACCESS_ZIP_H diff --git a/engine/core/io/http_client.cpp b/engine/core/io/http_client.cpp index b7a324e7..c452faf1 100644 --- a/engine/core/io/http_client.cpp +++ b/engine/core/io/http_client.cpp @@ -70,10 +70,9 @@ Error HTTPClient::_request(Method p_method, const String &p_url, const Vector &kv : p_dict) { + String encoded_key = String(kv.key).uri_encode(); + const Variant &value = kv.value; switch (value.get_type()) { case Variant::ARRAY: { // Repeat the key with every values @@ -118,7 +117,7 @@ Dictionary HTTPClient::_get_response_headers_as_dictionary() { continue; } String key = s.substr(0, sp).strip_edges(); - String value = s.substr(sp + 1, s.length()).strip_edges(); + String value = s.substr(sp + 1).strip_edges(); ret[key] = value; } diff --git a/engine/core/io/http_client.h b/engine/core/io/http_client.h index 59452911..fe2f2df2 100644 --- a/engine/core/io/http_client.h +++ b/engine/core/io/http_client.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef HTTP_CLIENT_H -#define HTTP_CLIENT_H +#pragma once #include "core/crypto/crypto.h" #include "core/io/ip.h" @@ -205,5 +204,3 @@ public: VARIANT_ENUM_CAST(HTTPClient::ResponseCode) VARIANT_ENUM_CAST(HTTPClient::Method); VARIANT_ENUM_CAST(HTTPClient::Status); - -#endif // HTTP_CLIENT_H diff --git a/engine/core/io/http_client_tcp.cpp b/engine/core/io/http_client_tcp.cpp index 3147b59c..f6495585 100644 --- a/engine/core/io/http_client_tcp.cpp +++ b/engine/core/io/http_client_tcp.cpp @@ -50,13 +50,13 @@ Error HTTPClientTCP::connect_to_host(const String &p_host, int p_port, Refis_server(), ERR_INVALID_PARAMETER); @@ -196,7 +196,7 @@ Error HTTPClientTCP::request(Method p_method, const String &p_url, const Vector< // Should it add utf8 encoding? } if (add_uagent) { - request += "User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")\r\n"; + request += "User-Agent: GodotEngine/" + String(GODOT_VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")\r\n"; } if (add_accept) { request += "Accept: */*\r\n"; @@ -483,8 +483,7 @@ Error HTTPClientTCP::poll() { (rs >= 4 && response_str[rs - 4] == '\r' && response_str[rs - 3] == '\n' && response_str[rs - 2] == '\r' && response_str[rs - 1] == '\n')) { // End of response, parse. response_str.push_back(0); - String response; - response.parse_utf8((const char *)response_str.ptr(), response_str.size()); + String response = String::utf8((const char *)response_str.ptr(), response_str.size()); Vector responses = response.split("\n"); body_size = -1; chunked = false; @@ -508,11 +507,11 @@ Error HTTPClientTCP::poll() { continue; } if (s.begins_with("content-length:")) { - body_size = s.substr(s.find_char(':') + 1, s.length()).strip_edges().to_int(); + body_size = s.substr(s.find_char(':') + 1).strip_edges().to_int(); body_left = body_size; } else if (s.begins_with("transfer-encoding:")) { - String encoding = header.substr(header.find_char(':') + 1, header.length()).strip_edges(); + String encoding = header.substr(header.find_char(':') + 1).strip_edges(); if (encoding == "chunked") { chunked = true; } diff --git a/engine/core/io/http_client_tcp.h b/engine/core/io/http_client_tcp.h index dd6cc6b8..4e4db3ac 100644 --- a/engine/core/io/http_client_tcp.h +++ b/engine/core/io/http_client_tcp.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef HTTP_CLIENT_TCP_H -#define HTTP_CLIENT_TCP_H +#pragma once #include "http_client.h" @@ -100,5 +99,3 @@ public: void set_https_proxy(const String &p_host, int p_port) override; HTTPClientTCP(); }; - -#endif // HTTP_CLIENT_TCP_H diff --git a/engine/core/io/image.cpp b/engine/core/io/image.cpp index 45f9599c..857a9ec6 100644 --- a/engine/core/io/image.cpp +++ b/engine/core/io/image.cpp @@ -31,7 +31,6 @@ #include "image.h" #include "core/config/project_settings.h" -#include "core/error/error_list.h" #include "core/error/error_macros.h" #include "core/io/image_loader.h" #include "core/io/resource_loader.h" @@ -89,11 +88,13 @@ SavePNGFunc Image::save_png_func = nullptr; SaveJPGFunc Image::save_jpg_func = nullptr; SaveEXRFunc Image::save_exr_func = nullptr; SaveWebPFunc Image::save_webp_func = nullptr; +SaveDDSFunc Image::save_dds_func = nullptr; SavePNGBufferFunc Image::save_png_buffer_func = nullptr; SaveJPGBufferFunc Image::save_jpg_buffer_func = nullptr; SaveEXRBufferFunc Image::save_exr_buffer_func = nullptr; SaveWebPBufferFunc Image::save_webp_buffer_func = nullptr; +SaveDDSBufferFunc Image::save_dds_buffer_func = nullptr; // External loader function pointers. @@ -105,6 +106,7 @@ ImageMemLoadFunc Image::_tga_mem_loader_func = nullptr; ImageMemLoadFunc Image::_bmp_mem_loader_func = nullptr; ScalableImageMemLoadFunc Image::_svg_scalable_mem_loader_func = nullptr; ImageMemLoadFunc Image::_ktx_mem_loader_func = nullptr; +ImageMemLoadFunc Image::_dds_mem_loader_func = nullptr; // External VRAM compression function pointers. @@ -571,7 +573,7 @@ static bool _are_formats_compatible(Image::Format p_format0, Image::Format p_for void Image::convert(Format p_new_format) { ERR_FAIL_INDEX_MSG(p_new_format, FORMAT_MAX, vformat("The Image format specified (%d) is out of range. See Image's Format enum.", p_new_format)); - if (data.size() == 0 || p_new_format == format) { + if (data.is_empty() || p_new_format == format) { return; } @@ -796,7 +798,7 @@ Image::Format Image::get_format() const { } static double _bicubic_interp_kernel(double x) { - x = ABS(x); + x = Math::abs(x); double bc = 0; @@ -1139,7 +1141,7 @@ bool Image::is_size_po2() const { } void Image::resize_to_po2(bool p_square, Interpolation p_interpolation) { - ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in compressed or custom image formats."); + ERR_FAIL_COND_MSG(is_compressed(), "Cannot resize in compressed image formats."); int w = next_power_of_2(width); int h = next_power_of_2(height); @@ -1158,7 +1160,7 @@ void Image::resize_to_po2(bool p_square, Interpolation p_interpolation) { void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { ERR_FAIL_COND_MSG(data.is_empty(), "Cannot resize image before creating it, use set_data() first."); - ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in compressed or custom image formats."); + ERR_FAIL_COND_MSG(is_compressed(), "Cannot resize in compressed image formats."); bool mipmap_aware = p_interpolation == INTERPOLATE_TRILINEAR /* || p_interpolation == INTERPOLATE_TRICUBIC */; @@ -1461,8 +1463,7 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { } void Image::crop_from_point(int p_x, int p_y, int p_width, int p_height) { - ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot crop in compressed or custom image formats."); - + ERR_FAIL_COND_MSG(is_compressed(), "Cannot crop in compressed image formats."); ERR_FAIL_COND_MSG(p_x < 0, "Start x position cannot be smaller than 0."); ERR_FAIL_COND_MSG(p_y < 0, "Start y position cannot be smaller than 0."); ERR_FAIL_COND_MSG(p_width <= 0, "Width of image must be greater than 0."); @@ -1515,7 +1516,7 @@ void Image::crop(int p_width, int p_height) { } void Image::rotate_90(ClockDirection p_direction) { - ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); + ERR_FAIL_COND_MSG(is_compressed(), "Cannot rotate in compressed image formats."); ERR_FAIL_COND_MSG(width <= 0, vformat("The Image width specified (%d pixels) must be greater than 0 pixels.", width)); ERR_FAIL_COND_MSG(height <= 0, vformat("The Image height specified (%d pixels) must be greater than 0 pixels.", height)); @@ -1633,7 +1634,7 @@ void Image::rotate_90(ClockDirection p_direction) { } void Image::rotate_180() { - ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); + ERR_FAIL_COND_MSG(is_compressed(), "Cannot rotate in compressed image formats."); ERR_FAIL_COND_MSG(width <= 0, vformat("The Image width specified (%d pixels) must be greater than 0 pixels.", width)); ERR_FAIL_COND_MSG(height <= 0, vformat("The Image height specified (%d pixels) must be greater than 0 pixels.", height)); @@ -1667,7 +1668,7 @@ void Image::rotate_180() { } void Image::flip_y() { - ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot flip_y in compressed or custom image formats."); + ERR_FAIL_COND_MSG(is_compressed(), "Cannot flip_y in compressed image formats."); bool used_mipmaps = has_mipmaps(); if (used_mipmaps) { @@ -1697,7 +1698,7 @@ void Image::flip_y() { } void Image::flip_x() { - ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot flip_x in compressed or custom image formats."); + ERR_FAIL_COND_MSG(is_compressed(), "Cannot flip_x in compressed image formats."); bool used_mipmaps = has_mipmaps(); if (used_mipmaps) { @@ -1789,10 +1790,6 @@ int64_t Image::_get_dst_image_size(int p_width, int p_height, Format p_format, i return size; } -bool Image::_can_modify(Format p_format) const { - return !Image::is_format_compressed(p_format); -} - template @@ -1926,7 +1923,7 @@ void Image::shrink_x2() { memcpy(new_data.ptrw(), data.ptr() + ofs, new_size); } else { // Generate a mipmap and replace the original. - ERR_FAIL_COND(!_can_modify(format)); + ERR_FAIL_COND(is_compressed()); new_data.resize((width / 2) * (height / 2) * get_format_pixel_size(format)); ERR_FAIL_COND(data.is_empty() || new_data.is_empty()); @@ -1963,7 +1960,7 @@ void Image::normalize() { } Error Image::generate_mipmaps(bool p_renormalize) { - ERR_FAIL_COND_V_MSG(!_can_modify(format), ERR_UNAVAILABLE, "Cannot generate mipmaps in compressed or custom image formats."); + ERR_FAIL_COND_V_MSG(is_compressed(), ERR_UNAVAILABLE, "Cannot generate mipmaps from compressed image formats."); ERR_FAIL_COND_V_MSG(format == FORMAT_RGBA4444, ERR_UNAVAILABLE, "Cannot generate mipmaps from RGBA4444 format."); ERR_FAIL_COND_V_MSG(width == 0 || height == 0, ERR_UNCONFIGURED, "Cannot generate mipmaps with width or height equal to 0."); @@ -2180,7 +2177,7 @@ void Image::clear_mipmaps() { } bool Image::is_empty() const { - return (data.size() == 0); + return (data.is_empty()); } Vector Image::get_data() const { @@ -2297,7 +2294,7 @@ void Image::initialize_data(const char **p_xpm) { switch (status) { case READING_HEADER: { String line_str = line_ptr; - line_str.replace("\t", " "); + line_str.replace_char('\t', ' '); size_width = line_str.get_slicec(' ', 0).to_int(); size_height = line_str.get_slicec(' ', 1).to_int(); @@ -2441,47 +2438,75 @@ void Image::initialize_data(const char **p_xpm) { } bool Image::is_invisible() const { - if (format == FORMAT_L8 || format == FORMAT_RGB8 || format == FORMAT_RG8) { - return false; - } - - int64_t len = data.size(); + int w, h; + int64_t len; + _get_mipmap_offset_and_size(1, len, w, h); if (len == 0) { return true; } - int w, h; - _get_mipmap_offset_and_size(1, len, w, h); - - const uint8_t *r = data.ptr(); - const unsigned char *data_ptr = r; - - bool detected = false; - switch (format) { case FORMAT_LA8: { - for (int i = 0; i < (len >> 1); i++) { - DETECT_NON_ALPHA(data_ptr[(i << 1) + 1]); - } + const int pixel_count = len / 2; + const uint16_t *pixeldata = reinterpret_cast(data.ptr()); + for (int i = 0; i < pixel_count; i++) { + if ((pixeldata[i] & 0xFF00) != 0) { + return false; + } + } } break; case FORMAT_RGBA8: { - for (int i = 0; i < (len >> 2); i++) { - DETECT_NON_ALPHA(data_ptr[(i << 2) + 3]) + const int pixel_count = len / 4; + const uint32_t *pixeldata = reinterpret_cast(data.ptr()); + + for (int i = 0; i < pixel_count; i++) { + if ((pixeldata[i] & 0xFF000000) != 0) { + return false; + } } - } break; + case FORMAT_RGBA4444: { + const int pixel_count = len / 2; + const uint16_t *pixeldata = reinterpret_cast(data.ptr()); - case FORMAT_DXT3: - case FORMAT_DXT5: { - detected = true; + for (int i = 0; i < pixel_count; i++) { + if ((pixeldata[i] & 0x000F) != 0) { + return false; + } + } + } break; + case FORMAT_RGBAH: { + // The alpha mask accounts for the sign bit. + const int pixel_count = len / 4; + const uint16_t *pixeldata = reinterpret_cast(data.ptr()); + + for (int i = 0; i < pixel_count; i += 4) { + if ((pixeldata[i + 3] & 0x7FFF) != 0) { + return false; + } + } + } break; + case FORMAT_RGBAF: { + // The alpha mask accounts for the sign bit. + const int pixel_count = len / 4; + const uint32_t *pixeldata = reinterpret_cast(data.ptr()); + + for (int i = 0; i < pixel_count; i += 4) { + if ((pixeldata[i + 3] & 0x7FFFFFFF) != 0) { + return false; + } + } } break; default: { + // Formats that are compressed or don't support alpha channels are presumed to be visible. + return false; } } - return !detected; + // Every pixel has been checked, the image is invisible. + return true; } Image::AlphaMode Image::detect_alpha() const { @@ -2603,6 +2628,21 @@ Vector Image::save_exr_to_buffer(bool p_grayscale) const { return save_exr_buffer_func(Ref((Image *)this), p_grayscale); } +Error Image::save_dds(const String &p_path) const { + if (save_dds_func == nullptr) { + return ERR_UNAVAILABLE; + } + + return save_dds_func(p_path, Ref((Image *)this)); +} + +Vector Image::save_dds_to_buffer() const { + if (save_dds_buffer_func == nullptr) { + return Vector(); + } + return save_dds_buffer_func(Ref((Image *)this)); +} + Error Image::save_webp(const String &p_path, const bool p_lossy, const float p_quality) const { if (save_webp_func == nullptr) { return ERR_UNAVAILABLE; @@ -2682,6 +2722,19 @@ Error Image::decompress() { return OK; } +bool Image::can_decompress(const String &p_format_tag) { + if (p_format_tag == "astc") { + return _image_decompress_astc != nullptr; + } else if (p_format_tag == "bptc") { + return _image_decompress_bptc != nullptr; + } else if (p_format_tag == "etc2") { + return _image_decompress_etc2 != nullptr; + } else if (p_format_tag == "s3tc") { + return _image_decompress_bc != nullptr; + } + return false; +} + Error Image::compress(CompressMode p_mode, CompressSource p_source, ASTCFormat p_astc_format) { ERR_FAIL_INDEX_V_MSG(p_mode, COMPRESS_MAX, ERR_INVALID_PARAMETER, "Invalid compress mode."); ERR_FAIL_INDEX_V_MSG(p_source, COMPRESS_SOURCE_MAX, ERR_INVALID_PARAMETER, "Invalid compress source."); @@ -2863,7 +2916,7 @@ void Image::blit_rect(const Ref &p_src, const Rect2i &p_src_rect, const P ERR_FAIL_COND(dsize == 0); ERR_FAIL_COND(srcdsize == 0); ERR_FAIL_COND(format != p_src->format); - ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot blit_rect in compressed or custom image formats."); + ERR_FAIL_COND_MSG(is_compressed(), "Cannot blit_rect in compressed image formats."); Rect2i src_rect; Rect2i dest_rect; @@ -3043,10 +3096,10 @@ void Image::_repeat_pixel_over_subsequent_memory(uint8_t *p_pixel, int p_pixel_s } void Image::fill(const Color &p_color) { - if (data.size() == 0) { + if (data.is_empty()) { return; } - ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill in compressed or custom image formats."); + ERR_FAIL_COND_MSG(is_compressed(), "Cannot fill in compressed image formats."); uint8_t *dst_data_ptr = data.ptrw(); @@ -3059,10 +3112,10 @@ void Image::fill(const Color &p_color) { } void Image::fill_rect(const Rect2i &p_rect, const Color &p_color) { - if (data.size() == 0) { + if (data.is_empty()) { return; } - ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill rect in compressed or custom image formats."); + ERR_FAIL_COND_MSG(is_compressed(), "Cannot fill rect in compressed image formats."); Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect.abs()); if (!r.has_area()) { @@ -3278,7 +3331,7 @@ void Image::_set_color_at_ofs(uint8_t *ptr, uint32_t ofs, const Color &p_color) uint16_t rgba = 0; rgba = uint16_t(CLAMP(p_color.r * 31.0, 0, 31)); - rgba |= uint16_t(CLAMP(p_color.g * 63.0, 0, 33)) << 5; + rgba |= uint16_t(CLAMP(p_color.g * 63.0, 0, 63)) << 5; rgba |= uint16_t(CLAMP(p_color.b * 31.0, 0, 31)) << 11; ((uint16_t *)ptr)[ofs] = rgba; @@ -3366,7 +3419,7 @@ int64_t Image::get_data_size() const { } void Image::adjust_bcs(float p_brightness, float p_contrast, float p_saturation) { - ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot adjust_bcs in compressed or custom image formats."); + ERR_FAIL_COND_MSG(is_compressed(), "Cannot adjust_bcs in compressed image formats."); uint8_t *w = data.ptrw(); uint32_t pixel_size = get_format_pixel_size(format); @@ -3524,6 +3577,9 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("save_jpg_to_buffer", "quality"), &Image::save_jpg_to_buffer, DEFVAL(0.75)); ClassDB::bind_method(D_METHOD("save_exr", "path", "grayscale"), &Image::save_exr, DEFVAL(false)); ClassDB::bind_method(D_METHOD("save_exr_to_buffer", "grayscale"), &Image::save_exr_to_buffer, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("save_dds", "path"), &Image::save_dds); + ClassDB::bind_method(D_METHOD("save_dds_to_buffer"), &Image::save_dds_to_buffer); + ClassDB::bind_method(D_METHOD("save_webp", "path", "lossy", "quality"), &Image::save_webp, DEFVAL(false), DEFVAL(0.75f)); ClassDB::bind_method(D_METHOD("save_webp_to_buffer", "lossy", "quality"), &Image::save_webp_to_buffer, DEFVAL(false), DEFVAL(0.75f)); @@ -3577,6 +3633,7 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("load_tga_from_buffer", "buffer"), &Image::load_tga_from_buffer); ClassDB::bind_method(D_METHOD("load_bmp_from_buffer", "buffer"), &Image::load_bmp_from_buffer); ClassDB::bind_method(D_METHOD("load_ktx_from_buffer", "buffer"), &Image::load_ktx_from_buffer); + ClassDB::bind_method(D_METHOD("load_dds_from_buffer", "buffer"), &Image::load_dds_from_buffer); ClassDB::bind_method(D_METHOD("load_svg_from_buffer", "buffer", "scale"), &Image::load_svg_from_buffer, DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("load_svg_from_string", "svg_str", "scale"), &Image::load_svg_from_string, DEFVAL(1.0)); @@ -3677,7 +3734,7 @@ void Image::normal_map_to_xy() { } Ref Image::rgbe_to_srgb() { - if (data.size() == 0) { + if (data.is_empty()) { return Ref(); } @@ -3724,7 +3781,7 @@ Ref Image::get_image_from_mipmap(int p_mipmap) const { } void Image::bump_map_to_normal_map(float bump_scale) { - ERR_FAIL_COND(!_can_modify(format)); + ERR_FAIL_COND(is_compressed()); clear_mipmaps(); convert(Image::FORMAT_RF); @@ -3799,7 +3856,7 @@ bool Image::detect_signed(bool p_include_mips) const { } void Image::srgb_to_linear() { - if (data.size() == 0) { + if (data.is_empty()) { return; } @@ -3830,7 +3887,7 @@ void Image::srgb_to_linear() { } void Image::linear_to_srgb() { - if (data.size() == 0) { + if (data.is_empty()) { return; } @@ -3861,7 +3918,7 @@ void Image::linear_to_srgb() { } void Image::premultiply_alpha() { - if (data.size() == 0) { + if (data.is_empty()) { return; } @@ -3883,7 +3940,7 @@ void Image::premultiply_alpha() { } void Image::fix_alpha_edges() { - if (data.size() == 0) { + if (data.is_empty()) { return; } @@ -4072,6 +4129,14 @@ Error Image::load_bmp_from_buffer(const Vector &p_array) { return _load_from_buffer(p_array, _bmp_mem_loader_func); } +Error Image::load_dds_from_buffer(const Vector &p_array) { + ERR_FAIL_NULL_V_MSG( + _dds_mem_loader_func, + ERR_UNAVAILABLE, + "The DDS module isn't enabled. Recompile the Godot editor or export template binary with the `module_dds_enabled=yes` SCons option."); + return _load_from_buffer(p_array, _dds_mem_loader_func); +} + Error Image::load_svg_from_buffer(const Vector &p_array, float scale) { ERR_FAIL_NULL_V_MSG( _svg_scalable_mem_loader_func, @@ -4266,10 +4331,10 @@ Dictionary Image::compute_image_metrics(const Ref p_compared_image, bool // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Dictionary result; - result["max"] = INFINITY; - result["mean"] = INFINITY; - result["mean_squared"] = INFINITY; - result["root_mean_squared"] = INFINITY; + result["max"] = Math::INF; + result["mean"] = Math::INF; + result["mean_squared"] = Math::INF; + result["root_mean_squared"] = Math::INF; result["peak_snr"] = 0.0f; ERR_FAIL_COND_V(p_compared_image.is_null(), result); diff --git a/engine/core/io/image.h b/engine/core/io/image.h index 992c4359..3cb57a3a 100644 --- a/engine/core/io/image.h +++ b/engine/core/io/image.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef IMAGE_H -#define IMAGE_H +#pragma once #include "core/io/resource.h" #include "core/math/color.h" @@ -59,6 +58,9 @@ typedef Vector (*SaveWebPBufferFunc)(const Ref &p_img, const boo typedef Error (*SaveEXRFunc)(const String &p_path, const Ref &p_img, bool p_grayscale); typedef Vector (*SaveEXRBufferFunc)(const Ref &p_img, bool p_grayscale); +typedef Error (*SaveDDSFunc)(const String &p_path, const Ref &p_img); +typedef Vector (*SaveDDSBufferFunc)(const Ref &p_img); + class Image : public Resource { GDCLASS(Image, Resource); @@ -186,10 +188,12 @@ public: static SaveJPGFunc save_jpg_func; static SaveEXRFunc save_exr_func; static SaveWebPFunc save_webp_func; + static SaveDDSFunc save_dds_func; static SavePNGBufferFunc save_png_buffer_func; static SaveEXRBufferFunc save_exr_buffer_func; static SaveJPGBufferFunc save_jpg_buffer_func; static SaveWebPBufferFunc save_webp_buffer_func; + static SaveDDSBufferFunc save_dds_buffer_func; // External loader function pointers. @@ -201,6 +205,7 @@ public: static ImageMemLoadFunc _bmp_mem_loader_func; static ScalableImageMemLoadFunc _svg_scalable_mem_loader_func; static ImageMemLoadFunc _ktx_mem_loader_func; + static ImageMemLoadFunc _dds_mem_loader_func; // External VRAM compression function pointers. @@ -251,7 +256,6 @@ private: _FORCE_INLINE_ void _get_mipmap_offset_and_size(int p_mipmap, int64_t &r_offset, int &r_width, int &r_height) const; // Get where the mipmap begins in data. static int64_t _get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps = -1, int *r_mm_width = nullptr, int *r_mm_height = nullptr); - bool _can_modify(Format p_format) const; _FORCE_INLINE_ void _get_clipped_src_and_dest_rects(const Ref &p_src, const Rect2i &p_src_rect, const Point2i &p_dest, Rect2i &r_clipped_src_rect, Rect2i &r_clipped_dest_rect) const; @@ -334,9 +338,11 @@ public: static Ref load_from_file(const String &p_path); Error save_png(const String &p_path) const; Error save_jpg(const String &p_path, float p_quality = 0.75) const; + Error save_dds(const String &p_path) const; Vector save_png_to_buffer() const; Vector save_jpg_to_buffer(float p_quality = 0.75) const; Vector save_exr_to_buffer(bool p_grayscale = false) const; + Vector save_dds_to_buffer() const; Error save_exr(const String &p_path, bool p_grayscale = false) const; Error save_webp(const String &p_path, const bool p_lossy = false, const float p_quality = 0.75f) const; Vector save_webp_to_buffer(const bool p_lossy = false, const float p_quality = 0.75f) const; @@ -373,6 +379,8 @@ public: bool is_compressed() const; static bool is_format_compressed(Format p_format); + static bool can_decompress(const String &p_format_tag); + void fix_alpha_edges(); void premultiply_alpha(); void srgb_to_linear(); @@ -403,6 +411,7 @@ public: Error load_tga_from_buffer(const Vector &p_array); Error load_bmp_from_buffer(const Vector &p_array); Error load_ktx_from_buffer(const Vector &p_array); + Error load_dds_from_buffer(const Vector &p_array); Error load_svg_from_buffer(const Vector &p_array, float scale = 1.0); Error load_svg_from_string(const String &p_svg_str, float scale = 1.0); @@ -442,5 +451,3 @@ VARIANT_ENUM_CAST(Image::UsedChannels) VARIANT_ENUM_CAST(Image::AlphaMode) VARIANT_ENUM_CAST(Image::RoughnessChannel) VARIANT_ENUM_CAST(Image::ASTCFormat) - -#endif // IMAGE_H diff --git a/engine/core/io/image_loader.h b/engine/core/io/image_loader.h index 26af6503..00642da0 100644 --- a/engine/core/io/image_loader.h +++ b/engine/core/io/image_loader.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef IMAGE_LOADER_H -#define IMAGE_LOADER_H +#pragma once #include "core/core_bind.h" #include "core/io/file_access.h" @@ -108,5 +107,3 @@ public: virtual bool handles_type(const String &p_type) const override; virtual String get_resource_type(const String &p_path) const override; }; - -#endif // IMAGE_LOADER_H diff --git a/engine/core/io/ip.h b/engine/core/io/ip.h index 4816d59a..9d23a465 100644 --- a/engine/core/io/ip.h +++ b/engine/core/io/ip.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef IP_H -#define IP_H +#pragma once #include "core/io/ip_address.h" #include "core/os/os.h" @@ -110,5 +109,3 @@ public: VARIANT_ENUM_CAST(IP::Type); VARIANT_ENUM_CAST(IP::ResolverStatus); - -#endif // IP_H diff --git a/engine/core/io/ip_address.cpp b/engine/core/io/ip_address.cpp index f12c896d..78b8a19f 100644 --- a/engine/core/io/ip_address.cpp +++ b/engine/core/io/ip_address.cpp @@ -148,7 +148,7 @@ void IPAddress::_parse_ipv6(const String &p_string) { void IPAddress::_parse_ipv4(const String &p_string, int p_start, uint8_t *p_ret) { String ip; if (p_start != 0) { - ip = p_string.substr(p_start, p_string.length() - p_start); + ip = p_string.substr(p_start); } else { ip = p_string; } diff --git a/engine/core/io/ip_address.h b/engine/core/io/ip_address.h index da7b0f77..114038d9 100644 --- a/engine/core/io/ip_address.h +++ b/engine/core/io/ip_address.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef IP_ADDRESS_H -#define IP_ADDRESS_H +#pragma once #include "core/string/ustring.h" @@ -96,4 +95,6 @@ public: IPAddress() { clear(); } }; -#endif // IP_ADDRESS_H +// Zero-constructing IPAddress initializes field, valid, and wildcard to 0 (and thus empty). +template <> +struct is_zero_constructible : std::true_type {}; diff --git a/engine/core/io/json.cpp b/engine/core/io/json.cpp index 131a7e80..fcb6182f 100644 --- a/engine/core/io/json.cpp +++ b/engine/core/io/json.cpp @@ -122,8 +122,7 @@ String JSON::_stringify(const Variant &p_var, const String &p_indent, int p_cur_ ERR_FAIL_COND_V_MSG(p_markers.has(d.id()), "\"{...}\"", "Converting circular structure to JSON."); p_markers.insert(d.id()); - List keys; - d.get_key_list(&keys); + LocalVector keys = d.get_key_list(); if (p_sort_keys) { keys.sort_custom(); @@ -664,201 +663,96 @@ Variant JSON::_from_native(const Variant &p_variant, bool p_full_objects, int p_ case Variant::VECTOR2: { const Vector2 v = p_variant; - - Array args; - args.push_back(v.x); - args.push_back(v.y); - + Array args = { v.x, v.y }; RETURN_ARGS; } break; case Variant::VECTOR2I: { const Vector2i v = p_variant; - - Array args; - args.push_back(v.x); - args.push_back(v.y); - + Array args = { v.x, v.y }; RETURN_ARGS; } break; case Variant::RECT2: { const Rect2 r = p_variant; - - Array args; - args.push_back(r.position.x); - args.push_back(r.position.y); - args.push_back(r.size.width); - args.push_back(r.size.height); - + Array args = { r.position.x, r.position.y, r.size.width, r.size.height }; RETURN_ARGS; } break; case Variant::RECT2I: { const Rect2i r = p_variant; - - Array args; - args.push_back(r.position.x); - args.push_back(r.position.y); - args.push_back(r.size.width); - args.push_back(r.size.height); - + Array args = { r.position.x, r.position.y, r.size.width, r.size.height }; RETURN_ARGS; } break; case Variant::VECTOR3: { const Vector3 v = p_variant; - - Array args; - args.push_back(v.x); - args.push_back(v.y); - args.push_back(v.z); - + Array args = { v.x, v.y, v.z }; RETURN_ARGS; } break; case Variant::VECTOR3I: { const Vector3i v = p_variant; - - Array args; - args.push_back(v.x); - args.push_back(v.y); - args.push_back(v.z); - + Array args = { v.x, v.y, v.z }; RETURN_ARGS; } break; case Variant::TRANSFORM2D: { const Transform2D t = p_variant; - - Array args; - args.push_back(t[0].x); - args.push_back(t[0].y); - args.push_back(t[1].x); - args.push_back(t[1].y); - args.push_back(t[2].x); - args.push_back(t[2].y); - + Array args = { t[0].x, t[0].y, t[1].x, t[1].y, t[2].x, t[2].y }; RETURN_ARGS; } break; case Variant::VECTOR4: { const Vector4 v = p_variant; - - Array args; - args.push_back(v.x); - args.push_back(v.y); - args.push_back(v.z); - args.push_back(v.w); - + Array args = { v.x, v.y, v.z, v.w }; RETURN_ARGS; } break; case Variant::VECTOR4I: { const Vector4i v = p_variant; - - Array args; - args.push_back(v.x); - args.push_back(v.y); - args.push_back(v.z); - args.push_back(v.w); - + Array args = { v.x, v.y, v.z, v.w }; RETURN_ARGS; } break; case Variant::PLANE: { const Plane p = p_variant; - - Array args; - args.push_back(p.normal.x); - args.push_back(p.normal.y); - args.push_back(p.normal.z); - args.push_back(p.d); - + Array args = { p.normal.x, p.normal.y, p.normal.z, p.d }; RETURN_ARGS; } break; case Variant::QUATERNION: { const Quaternion q = p_variant; - - Array args; - args.push_back(q.x); - args.push_back(q.y); - args.push_back(q.z); - args.push_back(q.w); - + Array args = { q.x, q.y, q.z, q.w }; RETURN_ARGS; } break; case Variant::AABB: { const AABB aabb = p_variant; - - Array args; - args.push_back(aabb.position.x); - args.push_back(aabb.position.y); - args.push_back(aabb.position.z); - args.push_back(aabb.size.x); - args.push_back(aabb.size.y); - args.push_back(aabb.size.z); - + Array args = { aabb.position.x, aabb.position.y, aabb.position.z, aabb.size.x, aabb.size.y, aabb.size.z }; RETURN_ARGS; } break; case Variant::BASIS: { const Basis b = p_variant; - Array args; - args.push_back(b.get_column(0).x); - args.push_back(b.get_column(0).y); - args.push_back(b.get_column(0).z); - args.push_back(b.get_column(1).x); - args.push_back(b.get_column(1).y); - args.push_back(b.get_column(1).z); - args.push_back(b.get_column(2).x); - args.push_back(b.get_column(2).y); - args.push_back(b.get_column(2).z); + Array args = { b.get_column(0).x, b.get_column(0).y, b.get_column(0).z, + b.get_column(1).x, b.get_column(1).y, b.get_column(1).z, + b.get_column(2).x, b.get_column(2).y, b.get_column(2).z }; RETURN_ARGS; } break; case Variant::TRANSFORM3D: { const Transform3D t = p_variant; - Array args; - args.push_back(t.basis.get_column(0).x); - args.push_back(t.basis.get_column(0).y); - args.push_back(t.basis.get_column(0).z); - args.push_back(t.basis.get_column(1).x); - args.push_back(t.basis.get_column(1).y); - args.push_back(t.basis.get_column(1).z); - args.push_back(t.basis.get_column(2).x); - args.push_back(t.basis.get_column(2).y); - args.push_back(t.basis.get_column(2).z); - args.push_back(t.origin.x); - args.push_back(t.origin.y); - args.push_back(t.origin.z); + Array args = { t.basis.get_column(0).x, t.basis.get_column(0).y, t.basis.get_column(0).z, + t.basis.get_column(1).x, t.basis.get_column(1).y, t.basis.get_column(1).z, + t.basis.get_column(2).x, t.basis.get_column(2).y, t.basis.get_column(2).z, + t.origin.x, t.origin.y, t.origin.z }; RETURN_ARGS; } break; case Variant::PROJECTION: { const Projection p = p_variant; - Array args; - args.push_back(p[0].x); - args.push_back(p[0].y); - args.push_back(p[0].z); - args.push_back(p[0].w); - args.push_back(p[1].x); - args.push_back(p[1].y); - args.push_back(p[1].z); - args.push_back(p[1].w); - args.push_back(p[2].x); - args.push_back(p[2].y); - args.push_back(p[2].z); - args.push_back(p[2].w); - args.push_back(p[3].x); - args.push_back(p[3].y); - args.push_back(p[3].z); - args.push_back(p[3].w); + Array args = { p[0].x, p[0].y, p[0].z, p[0].w, + p[1].x, p[1].y, p[1].z, p[1].w, + p[2].x, p[2].y, p[2].z, p[2].w, + p[3].x, p[3].y, p[3].z, p[3].w }; RETURN_ARGS; } break; case Variant::COLOR: { const Color c = p_variant; - - Array args; - args.push_back(c.r); - args.push_back(c.g); - args.push_back(c.b); - args.push_back(c.a); - + Array args = { c.r, c.g, c.b, c.a }; RETURN_ARGS; } break; @@ -922,12 +816,9 @@ Variant JSON::_from_native(const Variant &p_variant, bool p_full_objects, int p_ ERR_FAIL_COND_V_MSG(p_depth > Variant::MAX_RECURSION_DEPTH, ret, "Variant is too deep. Bailing."); - List keys; - dict.get_key_list(&keys); - - for (const Variant &key : keys) { - args.push_back(_from_native(key, p_full_objects, p_depth + 1)); - args.push_back(_from_native(dict[key], p_full_objects, p_depth + 1)); + for (const KeyValue &kv : dict) { + args.push_back(_from_native(kv.key, p_full_objects, p_depth + 1)); + args.push_back(_from_native(kv.value, p_full_objects, p_depth + 1)); } return ret; diff --git a/engine/core/io/json.h b/engine/core/io/json.h index 70baf289..9169e578 100644 --- a/engine/core/io/json.h +++ b/engine/core/io/json.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef JSON_H -#define JSON_H +#pragma once #include "core/io/resource.h" #include "core/io/resource_loader.h" @@ -125,5 +124,3 @@ public: virtual void get_recognized_extensions(const Ref &p_resource, List *p_extensions) const override; virtual bool recognize(const Ref &p_resource) const override; }; - -#endif // JSON_H diff --git a/engine/core/io/logger.cpp b/engine/core/io/logger.cpp index 2965a1ea..26fb06eb 100644 --- a/engine/core/io/logger.cpp +++ b/engine/core/io/logger.cpp @@ -36,10 +36,9 @@ #include "core/templates/rb_set.h" #include "modules/modules_enabled.gen.h" // For regex. + #ifdef MODULE_REGEX_ENABLED #include "modules/regex/regex.h" -#else -class RegEx : public RefCounted {}; #endif // MODULE_REGEX_ENABLED #if defined(MINGW_ENABLED) || defined(_MSC_VER) @@ -156,7 +155,7 @@ void RotatedFileLogger::rotate_file() { if (FileAccess::exists(base_path)) { if (max_files > 1) { - String timestamp = Time::get_singleton()->get_datetime_string_from_system().replace(":", "."); + String timestamp = Time::get_singleton()->get_datetime_string_from_system().replace_char(':', '.'); String backup_name = base_path.get_basename() + timestamp; if (!base_path.get_extension().is_empty()) { backup_name += "." + base_path.get_extension(); diff --git a/engine/core/io/logger.h b/engine/core/io/logger.h index e55f73f6..f3d8acad 100644 --- a/engine/core/io/logger.h +++ b/engine/core/io/logger.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef LOGGER_H -#define LOGGER_H +#pragma once #include "core/io/file_access.h" #include "core/string/ustring.h" @@ -109,5 +108,3 @@ public: virtual ~CompositeLogger(); }; - -#endif // LOGGER_H diff --git a/engine/core/io/marshalls.cpp b/engine/core/io/marshalls.cpp index 19efe289..c81aaecc 100644 --- a/engine/core/io/marshalls.cpp +++ b/engine/core/io/marshalls.cpp @@ -107,7 +107,7 @@ static Error _decode_string(const uint8_t *&buf, int &len, int *r_len, String &r ERR_FAIL_COND_V(strlen < 0 || strlen + pad > len, ERR_FILE_EOF); String str; - ERR_FAIL_COND_V(str.parse_utf8((const char *)buf, strlen) != OK, ERR_INVALID_DATA); + ERR_FAIL_COND_V(str.append_utf8((const char *)buf, strlen) != OK, ERR_INVALID_DATA); r_string = str; // Add padding. @@ -1345,7 +1345,7 @@ static Error _encode_container_type(const ContainerType &p_type, uint8_t *&buf, _encode_string(EncodedObjectAsID::get_class_static(), buf, r_len); } } else if (p_type.class_name != StringName()) { - _encode_string(p_full_objects ? p_type.class_name.operator String() : EncodedObjectAsID::get_class_static(), buf, r_len); + _encode_string(p_full_objects ? p_type.class_name : EncodedObjectAsID::get_class_static(), buf, r_len); } else { // No need to check `p_full_objects` since `class_name` should be non-empty for `builtin_type == Variant::OBJECT`. if (buf) { @@ -1849,19 +1849,16 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } r_len += 4; - List keys; - dict.get_key_list(&keys); - - for (const Variant &key : keys) { + for (const KeyValue &kv : dict) { int len; - Error err = encode_variant(key, buf, len, p_full_objects, p_depth + 1); + Error err = encode_variant(kv.key, buf, len, p_full_objects, p_depth + 1); ERR_FAIL_COND_V(err, err); ERR_FAIL_COND_V(len % 4, ERR_BUG); r_len += len; if (buf) { buf += len; } - const Variant *value = dict.getptr(key); + const Variant *value = dict.getptr(kv.key); ERR_FAIL_NULL_V(value, ERR_BUG); err = encode_variant(*value, buf, len, p_full_objects, p_depth + 1); ERR_FAIL_COND_V(err, err); diff --git a/engine/core/io/marshalls.h b/engine/core/io/marshalls.h index 82c760c2..1d057d4d 100644 --- a/engine/core/io/marshalls.h +++ b/engine/core/io/marshalls.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef MARSHALLS_H -#define MARSHALLS_H +#pragma once #include "core/math/math_defs.h" #include "core/object/ref_counted.h" @@ -226,5 +225,3 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects = false, int p_depth = 0); Vector vector3_to_float32_array(const Vector3 *vecs, size_t count); - -#endif // MARSHALLS_H diff --git a/engine/core/io/missing_resource.h b/engine/core/io/missing_resource.h index 4cded5ca..702cd3b3 100644 --- a/engine/core/io/missing_resource.h +++ b/engine/core/io/missing_resource.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef MISSING_RESOURCE_H -#define MISSING_RESOURCE_H +#pragma once #include "core/io/resource.h" @@ -61,5 +60,3 @@ public: MissingResource(); }; - -#endif // MISSING_RESOURCE_H diff --git a/engine/core/io/net_socket.h b/engine/core/io/net_socket.h index 49b23575..49671ece 100644 --- a/engine/core/io/net_socket.h +++ b/engine/core/io/net_socket.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef NET_SOCKET_H -#define NET_SOCKET_H +#pragma once #include "core/io/ip.h" #include "core/object/ref_counted.h" @@ -79,5 +78,3 @@ public: virtual ~NetSocket() {} }; - -#endif // NET_SOCKET_H diff --git a/engine/core/io/packed_data_container.cpp b/engine/core/io/packed_data_container.cpp index ca236ce0..222e1679 100644 --- a/engine/core/io/packed_data_container.cpp +++ b/engine/core/io/packed_data_container.cpp @@ -268,14 +268,12 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector &tmpd encode_uint32(TYPE_DICT, &tmpdata.write[pos + 0]); encode_uint32(len, &tmpdata.write[pos + 4]); - List keys; - d.get_key_list(&keys); List sortk; - for (const Variant &key : keys) { + for (const KeyValue &kv : d) { DictKey dk; - dk.hash = key.hash(); - dk.key = key; + dk.hash = kv.key.hash(); + dk.key = kv.key; sortk.push_back(dk); } diff --git a/engine/core/io/packed_data_container.h b/engine/core/io/packed_data_container.h index f4ffa090..8d25d5c9 100644 --- a/engine/core/io/packed_data_container.h +++ b/engine/core/io/packed_data_container.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef PACKED_DATA_CONTAINER_H -#define PACKED_DATA_CONTAINER_H +#pragma once #include "core/io/resource.h" @@ -100,5 +99,3 @@ public: PackedDataContainerRef() {} }; - -#endif // PACKED_DATA_CONTAINER_H diff --git a/engine/core/io/packet_peer.h b/engine/core/io/packet_peer.h index 86ebe32c..91d3bc44 100644 --- a/engine/core/io/packet_peer.h +++ b/engine/core/io/packet_peer.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef PACKET_PEER_H -#define PACKET_PEER_H +#pragma once #include "core/io/stream_peer.h" #include "core/object/class_db.h" @@ -124,5 +123,3 @@ public: int get_output_buffer_max_size() const; PacketPeerStream(); }; - -#endif // PACKET_PEER_H diff --git a/engine/core/io/packet_peer_dtls.h b/engine/core/io/packet_peer_dtls.h index 03d97a59..5de9640d 100644 --- a/engine/core/io/packet_peer_dtls.h +++ b/engine/core/io/packet_peer_dtls.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef PACKET_PEER_DTLS_H -#define PACKET_PEER_DTLS_H +#pragma once #include "core/crypto/crypto.h" #include "core/io/packet_peer_udp.h" @@ -64,5 +63,3 @@ public: }; VARIANT_ENUM_CAST(PacketPeerDTLS::Status); - -#endif // PACKET_PEER_DTLS_H diff --git a/engine/core/io/packet_peer_udp.cpp b/engine/core/io/packet_peer_udp.cpp index 3463c41a..91e9934f 100644 --- a/engine/core/io/packet_peer_udp.cpp +++ b/engine/core/io/packet_peer_udp.cpp @@ -105,18 +105,16 @@ Error PacketPeerUDP::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { return ERR_UNAVAILABLE; } -/* Bogus GCC warning here: - * In member function 'int RingBuffer::read(T*, int, bool) [with T = unsigned char]', - * inlined from 'virtual Error PacketPeerUDP::get_packet(const uint8_t**, int&)' at core/io/packet_peer_udp.cpp:112:9, - * inlined from 'virtual Error PacketPeerUDP::get_packet(const uint8_t**, int&)' at core/io/packet_peer_udp.cpp:99:7: - * Error: ./core/ring_buffer.h:68:46: error: writing 1 byte into a region of size 0 [-Werror=stringop-overflow=] - * 68 | p_buf[dst++] = read[pos + i]; - * | ~~~~~~~~~~~~~^~~~~~~ - */ -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic warning "-Wstringop-overflow=0" -#endif + /* Bogus GCC warning here: + * In member function 'int RingBuffer::read(T*, int, bool) [with T = unsigned char]', + * inlined from 'virtual Error PacketPeerUDP::get_packet(const uint8_t**, int&)' at core/io/packet_peer_udp.cpp:112:9, + * inlined from 'virtual Error PacketPeerUDP::get_packet(const uint8_t**, int&)' at core/io/packet_peer_udp.cpp:99:7: + * Error: ./core/ring_buffer.h:68:46: error: writing 1 byte into a region of size 0 [-Werror=stringop-overflow=] + * 68 | p_buf[dst++] = read[pos + i]; + * | ~~~~~~~~~~~~~^~~~~~~ + */ + GODOT_GCC_WARNING_PUSH + GODOT_GCC_PRAGMA(GCC diagnostic warning "-Wstringop-overflow=0") // Can't "ignore" this for some reason. uint32_t size = 0; uint8_t ipv6[16] = {}; @@ -129,9 +127,7 @@ Error PacketPeerUDP::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { *r_buffer = packet_buffer; r_buffer_size = size; -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif + GODOT_GCC_WARNING_POP return OK; } diff --git a/engine/core/io/packet_peer_udp.h b/engine/core/io/packet_peer_udp.h index c69a138c..1c909860 100644 --- a/engine/core/io/packet_peer_udp.h +++ b/engine/core/io/packet_peer_udp.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef PACKET_PEER_UDP_H -#define PACKET_PEER_UDP_H +#pragma once #include "core/io/ip.h" #include "core/io/net_socket.h" @@ -97,5 +96,3 @@ public: PacketPeerUDP(); ~PacketPeerUDP(); }; - -#endif // PACKET_PEER_UDP_H diff --git a/engine/core/io/pck_packer.cpp b/engine/core/io/pck_packer.cpp index c7cfca19..75870f09 100644 --- a/engine/core/io/pck_packer.cpp +++ b/engine/core/io/pck_packer.cpp @@ -91,9 +91,9 @@ Error PCKPacker::pck_start(const String &p_pck_path, int p_alignment, const Stri file->store_32(PACK_HEADER_MAGIC); file->store_32(PACK_FORMAT_VERSION); - file->store_32(VERSION_MAJOR); - file->store_32(VERSION_MINOR); - file->store_32(VERSION_PATCH); + file->store_32(GODOT_VERSION_MAJOR); + file->store_32(GODOT_VERSION_MINOR); + file->store_32(GODOT_VERSION_PATCH); uint32_t pack_flags = 0; if (enc_dir) { @@ -118,8 +118,7 @@ Error PCKPacker::add_file_removal(const String &p_target_path) { pf.size = 0; pf.removal = true; - pf.md5.resize(16); - pf.md5.fill(0); + pf.md5.resize_zeroed(16); files.push_back(pf); diff --git a/engine/core/io/pck_packer.h b/engine/core/io/pck_packer.h index 043a1dbd..4c386b36 100644 --- a/engine/core/io/pck_packer.h +++ b/engine/core/io/pck_packer.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef PCK_PACKER_H -#define PCK_PACKER_H +#pragma once #include "core/object/ref_counted.h" @@ -66,5 +65,3 @@ public: PCKPacker() {} }; - -#endif // PCK_PACKER_H diff --git a/engine/core/io/plist.cpp b/engine/core/io/plist.cpp index 30c786ae..b02ca8a7 100644 --- a/engine/core/io/plist.cpp +++ b/engine/core/io/plist.cpp @@ -383,14 +383,16 @@ void PListNode::store_text(String &p_stream, uint8_t p_indent) const { p_stream += String("\t").repeat(p_indent); p_stream += "\n"; p_stream += String("\t").repeat(p_indent); - p_stream += data_string + "\n"; + // Data should be Base64 (i.e. ASCII only). + p_stream += String::ascii(data_string) + "\n"; p_stream += String("\t").repeat(p_indent); p_stream += "\n"; } break; case PList::PLNodeType::PL_NODE_TYPE_DATE: { p_stream += String("\t").repeat(p_indent); p_stream += ""; - p_stream += data_string; + // Data should be ISO 8601 (i.e. ASCII only). + p_stream += String::ascii(data_string); p_stream += "\n"; } break; case PList::PLNodeType::PL_NODE_TYPE_STRING: { @@ -629,7 +631,7 @@ bool PList::load_file(const String &p_filename) { unsigned char magic[8]; fb->get_buffer(magic, 8); - if (String((const char *)magic, 8) == "bplist00") { + if (String::ascii(Span((const char *)magic, 8)) == "bplist00") { fb->seek_end(-26); trailer.offset_size = fb->get_8(); trailer.ref_size = fb->get_8(); @@ -645,10 +647,8 @@ bool PList::load_file(const String &p_filename) { Vector array = FileAccess::get_file_as_bytes(p_filename, &err); ERR_FAIL_COND_V(err != OK, false); - String ret; - ret.parse_utf8((const char *)array.ptr(), array.size()); String err_str; - bool ok = load_string(ret, err_str); + bool ok = load_string(String::utf8((const char *)array.ptr(), array.size()), err_str); ERR_FAIL_COND_V_MSG(!ok, false, "PList: " + err_str); return true; diff --git a/engine/core/io/plist.h b/engine/core/io/plist.h index 7b319906..6d2dcef3 100644 --- a/engine/core/io/plist.h +++ b/engine/core/io/plist.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef PLIST_H -#define PLIST_H +#pragma once // Property list file format (application/x-plist) parser, property list ASN-1 serialization. @@ -84,6 +83,8 @@ public: /*************************************************************************/ class PListNode : public RefCounted { + GDSOFTCLASS(PListNode, RefCounted); + static int _asn1_size_len(uint8_t p_len_octets); public: @@ -122,5 +123,3 @@ public: PListNode() {} ~PListNode() {} }; - -#endif // PLIST_H diff --git a/engine/core/io/remote_filesystem_client.h b/engine/core/io/remote_filesystem_client.h index f96c263c..6b4db9b5 100644 --- a/engine/core/io/remote_filesystem_client.h +++ b/engine/core/io/remote_filesystem_client.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef REMOTE_FILESYSTEM_CLIENT_H -#define REMOTE_FILESYSTEM_CLIENT_H +#pragma once #include "core/string/ustring.h" #include "core/templates/hash_set.h" @@ -60,5 +59,3 @@ public: Error synchronize_with_server(const String &p_host, int p_port, const String &p_password, String &r_cache_path); virtual ~RemoteFilesystemClient() {} }; - -#endif // REMOTE_FILESYSTEM_CLIENT_H diff --git a/engine/core/io/resource.cpp b/engine/core/io/resource.cpp index 886ec6f5..fac829d9 100644 --- a/engine/core/io/resource.cpp +++ b/engine/core/io/resource.cpp @@ -32,10 +32,15 @@ #include "core/io/resource_loader.h" #include "core/math/math_funcs.h" +#include "core/math/random_pcg.h" #include "core/os/os.h" #include "scene/main/node.h" //only so casting works void Resource::emit_changed() { + if (emit_changed_state != EMIT_CHANGED_UNBLOCKED) { + emit_changed_state = EMIT_CHANGED_BLOCKED_PENDING_EMIT; + return; + } if (ResourceLoader::is_within_load() && !Thread::is_main_thread()) { ResourceLoader::resource_changed_emit(this); return; @@ -44,6 +49,20 @@ void Resource::emit_changed() { emit_signal(CoreStringName(changed)); } +void Resource::_block_emit_changed() { + if (emit_changed_state == EMIT_CHANGED_UNBLOCKED) { + emit_changed_state = EMIT_CHANGED_BLOCKED; + } +} + +void Resource::_unblock_emit_changed() { + bool emit = (emit_changed_state == EMIT_CHANGED_BLOCKED_PENDING_EMIT); + emit_changed_state = EMIT_CHANGED_UNBLOCKED; + if (emit) { + emit_changed(); + } +} + void Resource::_resource_path_changed() { } @@ -95,7 +114,7 @@ void Resource::set_path_cache(const String &p_path) { GDVIRTUAL_CALL(_set_path_cache, p_path); } -static thread_local RandomPCG unique_id_gen(0, RandomPCG::DEFAULT_INC); +static thread_local RandomPCG unique_id_gen = RandomPCG(0); void Resource::seed_scene_unique_id(uint32_t p_seed) { unique_id_gen.seed(p_seed); @@ -205,6 +224,8 @@ Error Resource::copy_from(const Ref &p_resource) { return ERR_INVALID_PARAMETER; } + _block_emit_changed(); + reset_state(); // May want to reset state. List pi; @@ -220,6 +241,9 @@ Error Resource::copy_from(const Ref &p_resource) { set(E.name, p_resource->get(E.name)); } + + _unblock_emit_changed(); + return OK; } @@ -248,9 +272,7 @@ void Resource::_dupe_sub_resources(Variant &r_variant, Node *p_for_scene, HashMa } break; case Variant::DICTIONARY: { Dictionary d = r_variant; - List keys; - d.get_key_list(&keys); - for (Variant &k : keys) { + for (Variant &k : d.get_key_list()) { if (k.get_type() == Variant::OBJECT) { // Replace in dictionary key. Ref sr = k; @@ -322,11 +344,9 @@ void Resource::_find_sub_resources(const Variant &p_variant, HashSet keys; - d.get_key_list(&keys); - for (const Variant &k : keys) { - _find_sub_resources(k, p_resources_found); - _find_sub_resources(d[k], p_resources_found); + for (const KeyValue &kv : d) { + _find_sub_resources(kv.key, p_resources_found); + _find_sub_resources(kv.value, p_resources_found); } } break; case Variant::OBJECT: { diff --git a/engine/core/io/resource.h b/engine/core/io/resource.h index ebc82cee..14c08629 100644 --- a/engine/core/io/resource.h +++ b/engine/core/io/resource.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef RESOURCE_H -#define RESOURCE_H +#pragma once #include "core/io/resource_uid.h" #include "core/object/class_db.h" @@ -72,6 +71,12 @@ private: String import_path; #endif + enum EmitChangedState { + EMIT_CHANGED_UNBLOCKED, + EMIT_CHANGED_BLOCKED, + EMIT_CHANGED_BLOCKED_PENDING_EMIT, + }; + EmitChangedState emit_changed_state = EMIT_CHANGED_UNBLOCKED; bool local_to_scene = false; friend class SceneState; Node *local_scene = nullptr; @@ -85,6 +90,9 @@ protected: virtual void _resource_path_changed(); static void _bind_methods(); + void _block_emit_changed(); + void _unblock_emit_changed(); + void _set_path(const String &p_path); void _take_over_path(const String &p_path); @@ -179,5 +187,3 @@ public: static void get_cached_resources(List> *p_resources); static int get_cached_resource_count(); }; - -#endif // RESOURCE_H diff --git a/engine/core/io/resource_format_binary.cpp b/engine/core/io/resource_format_binary.cpp index 891510e3..98511f02 100644 --- a/engine/core/io/resource_format_binary.cpp +++ b/engine/core/io/resource_format_binary.cpp @@ -162,9 +162,7 @@ StringName ResourceLoaderBinary::_get_string() { return StringName(); } f->get_buffer((uint8_t *)&str_buf[0], len); - String s; - s.parse_utf8(&str_buf[0], len); - return s; + return String::utf8(&str_buf[0], len); } return string_map[id]; @@ -918,9 +916,7 @@ static String get_ustring(Ref f) { Vector str_buf; str_buf.resize(len); f->get_buffer((uint8_t *)&str_buf[0], len); - String s; - s.parse_utf8(&str_buf[0], len); - return s; + return String::utf8(&str_buf[0], len); } String ResourceLoaderBinary::get_unicode_string() { @@ -932,9 +928,7 @@ String ResourceLoaderBinary::get_unicode_string() { return String(); } f->get_buffer((uint8_t *)&str_buf[0], len); - String s; - s.parse_utf8(&str_buf[0], len); - return s; + return String::utf8(&str_buf[0], len); } void ResourceLoaderBinary::get_classes_used(Ref p_f, HashSet *p_classes) { @@ -1028,10 +1022,10 @@ void ResourceLoaderBinary::open(Ref p_f, bool p_no_resources, bool p print_bl("minor: " + itos(ver_minor)); print_bl("format: " + itos(ver_format)); - if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) { + if (ver_format > FORMAT_VERSION || ver_major > GODOT_VERSION_MAJOR) { f.unref(); ERR_FAIL_MSG(vformat("File '%s' can't be loaded, as it uses a format version (%d) or engine version (%d.%d) which are not supported by your engine version (%s).", - local_path, ver_format, ver_major, ver_minor, VERSION_BRANCH)); + local_path, ver_format, ver_major, ver_minor, GODOT_VERSION_BRANCH)); } type = get_unicode_string(); @@ -1155,7 +1149,7 @@ String ResourceLoaderBinary::recognize(Ref p_f) { f->get_32(); // ver_minor uint32_t ver_fmt = f->get_32(); - if (ver_fmt > FORMAT_VERSION || ver_major > VERSION_MAJOR) { + if (ver_fmt > FORMAT_VERSION || ver_major > GODOT_VERSION_MAJOR) { f.unref(); return ""; } @@ -1196,7 +1190,7 @@ String ResourceLoaderBinary::recognize_script_class(Ref p_f) { f->get_32(); // ver_minor uint32_t ver_fmt = f->get_32(); - if (ver_fmt > FORMAT_VERSION || ver_major > VERSION_MAJOR) { + if (ver_fmt > FORMAT_VERSION || ver_major > GODOT_VERSION_MAJOR) { f.unref(); return ""; } @@ -1348,13 +1342,10 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons bool use_real64 = f->get_32(); f->set_big_endian(big_endian != 0); //read big endian if saved as big endian -#ifdef BIG_ENDIAN_ENABLED - fw->store_32(!big_endian); -#else + fw->store_32(big_endian); -#endif - fw->set_big_endian(big_endian != 0); fw->store_32(use_real64); //use real64 + fw->set_big_endian(big_endian != 0); uint32_t ver_major = f->get_32(); uint32_t ver_minor = f->get_32(); @@ -1392,10 +1383,10 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons return ResourceFormatSaverBinary::singleton->save(res, p_path); } - if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) { + if (ver_format > FORMAT_VERSION || ver_major > GODOT_VERSION_MAJOR) { ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, vformat("File '%s' can't be loaded, as it uses a format version (%d) or engine version (%d.%d) which are not supported by your engine version (%s).", - local_path, ver_format, ver_major, ver_minor, VERSION_BRANCH)); + local_path, ver_format, ver_major, ver_minor, GODOT_VERSION_BRANCH)); } // Since we're not actually converting the file contents, leave the version @@ -1876,12 +1867,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(Ref f, const V Dictionary d = p_property; f->store_32(uint32_t(d.size())); - List keys; - d.get_key_list(&keys); - - for (const Variant &E : keys) { - write_variant(f, E, resource_map, external_resources, string_map); - write_variant(f, d[E], resource_map, external_resources, string_map); + for (const KeyValue &kv : d) { + write_variant(f, kv.key, resource_map, external_resources, string_map); + write_variant(f, kv.value, resource_map, external_resources, string_map); } } break; @@ -2086,12 +2074,9 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant Dictionary d = p_variant; _find_resources(d.get_typed_key_script()); _find_resources(d.get_typed_value_script()); - List keys; - d.get_key_list(&keys); - for (const Variant &E : keys) { - _find_resources(E); - Variant v = d[E]; - _find_resources(v); + for (const KeyValue &kv : d) { + _find_resources(kv.key); + _find_resources(kv.value); } } break; case Variant::NODE_PATH: { @@ -2180,14 +2165,14 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Refstore_32(1); - f->set_big_endian(true); } else { f->store_32(0); } - f->store_32(0); //64 bits file, false for now - f->store_32(VERSION_MAJOR); - f->store_32(VERSION_MINOR); + f->set_big_endian(big_endian); + + f->store_32(GODOT_VERSION_MAJOR); + f->store_32(GODOT_VERSION_MINOR); f->store_32(FORMAT_VERSION); if (f->get_error() != OK && f->get_error() != ERR_FILE_EOF) { @@ -2424,13 +2409,10 @@ Error ResourceFormatSaverBinaryInstance::set_uid(const String &p_path, ResourceU big_endian = f->get_32(); bool use_real64 = f->get_32(); f->set_big_endian(big_endian != 0); //read big endian if saved as big endian -#ifdef BIG_ENDIAN_ENABLED - fw->store_32(!big_endian); -#else + fw->store_32(big_endian); -#endif - fw->set_big_endian(big_endian != 0); fw->store_32(use_real64); //use real64 + fw->set_big_endian(big_endian != 0); uint32_t ver_major = f->get_32(); uint32_t ver_minor = f->get_32(); @@ -2450,10 +2432,10 @@ Error ResourceFormatSaverBinaryInstance::set_uid(const String &p_path, ResourceU return ERR_UNAVAILABLE; } - if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) { + if (ver_format > FORMAT_VERSION || ver_major > GODOT_VERSION_MAJOR) { ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, vformat("File '%s' can't be loaded, as it uses a format version (%d) or engine version (%d.%d) which are not supported by your engine version (%s).", - local_path, ver_format, ver_major, ver_minor, VERSION_BRANCH)); + local_path, ver_format, ver_major, ver_minor, GODOT_VERSION_BRANCH)); } // Since we're not actually converting the file contents, leave the version diff --git a/engine/core/io/resource_format_binary.h b/engine/core/io/resource_format_binary.h index ec8d7ead..dfd2cd6f 100644 --- a/engine/core/io/resource_format_binary.h +++ b/engine/core/io/resource_format_binary.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef RESOURCE_FORMAT_BINARY_H -#define RESOURCE_FORMAT_BINARY_H +#pragma once #include "core/io/file_access.h" #include "core/io/resource_loader.h" @@ -189,5 +188,3 @@ public: ResourceFormatSaverBinary(); }; - -#endif // RESOURCE_FORMAT_BINARY_H diff --git a/engine/core/io/resource_importer.cpp b/engine/core/io/resource_importer.cpp index b7a14f2b..81c3deb9 100644 --- a/engine/core/io/resource_importer.cpp +++ b/engine/core/io/resource_importer.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/io/config_file.h" +#include "core/io/image.h" #include "core/os/os.h" #include "core/variant/variant_parser.h" @@ -41,7 +42,7 @@ bool ResourceFormatImporter::SortImporterByName::operator()(const Refget_importer_name() < p_b->get_importer_name(); } -Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid) const { +Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool p_load, bool *r_valid) const { Error err; Ref f = FileAccess::open(p_path + ".import", FileAccess::READ, &err); @@ -65,7 +66,10 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy int lines = 0; String error_text; - bool path_found = false; //first match must have priority + bool path_found = false; // First match must have priority. + + String decomp_path; + bool decomp_path_found = false; while (true) { assign = Variant(); next_tag.fields.clear(); @@ -73,6 +77,11 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true); if (err == ERR_FILE_EOF) { + if (p_load && !path_found && decomp_path_found) { + print_verbose(vformat("No natively supported texture format found for %s, using decompressable format %s.", p_path, decomp_path)); + r_path_and_type.path = decomp_path; + } + return OK; } else if (err != OK) { ERR_PRINT(vformat("ResourceFormatImporter::load - %s.import:%d error: %s.", p_path, lines, error_text)); @@ -84,12 +93,15 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy String feature = assign.get_slicec('.', 1); if (OS::get_singleton()->has_feature(feature)) { r_path_and_type.path = value; - path_found = true; //first match must have priority + path_found = true; // First match must have priority. + } else if (p_load && Image::can_decompress(feature) && !decomp_path_found) { // When loading, check for decompressable formats and use first one found if nothing else is supported. + decomp_path = value; + decomp_path_found = true; // First match must have priority. } } else if (!path_found && assign == "path") { r_path_and_type.path = value; - path_found = true; //first match must have priority + path_found = true; // First match must have priority. } else if (assign == "type") { r_path_and_type.type = ClassDB::get_compatibility_remapped_class(value); } else if (assign == "importer") { @@ -154,7 +166,7 @@ Ref ResourceFormatImporter::load(const String &p_path, const String &p Ref ResourceFormatImporter::load_internal(const String &p_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode, bool p_silence_errors) { PathAndType pat; - Error err = _get_path_and_type(p_path, pat); + Error err = _get_path_and_type(p_path, pat, true); if (err != OK) { if (r_error) { @@ -244,13 +256,13 @@ Error ResourceFormatImporter::get_import_order_threads_and_importer(const String if (FileAccess::exists(p_path + ".import")) { PathAndType pat; - Error err = _get_path_and_type(p_path, pat); + Error err = _get_path_and_type(p_path, pat, false); if (err == OK) { importer = get_importer_by_name(pat.importer); } } else { - importer = get_importer_by_extension(p_path.get_extension().to_lower()); + importer = get_importer_by_file(p_path); } if (importer.is_valid()) { @@ -268,13 +280,13 @@ int ResourceFormatImporter::get_import_order(const String &p_path) const { if (FileAccess::exists(p_path + ".import")) { PathAndType pat; - Error err = _get_path_and_type(p_path, pat); + Error err = _get_path_and_type(p_path, pat, false); if (err == OK) { importer = get_importer_by_name(pat.importer); } } else { - importer = get_importer_by_extension(p_path.get_extension().to_lower()); + importer = get_importer_by_file(p_path); } if (importer.is_valid()) { @@ -300,7 +312,7 @@ bool ResourceFormatImporter::handles_type(const String &p_type) const { String ResourceFormatImporter::get_internal_resource_path(const String &p_path) const { PathAndType pat; - Error err = _get_path_and_type(p_path, pat); + Error err = _get_path_and_type(p_path, pat, false); if (err != OK) { return String(); @@ -354,20 +366,20 @@ void ResourceFormatImporter::get_internal_resource_path_list(const String &p_pat String ResourceFormatImporter::get_import_group_file(const String &p_path) const { bool valid = true; PathAndType pat; - _get_path_and_type(p_path, pat, &valid); + _get_path_and_type(p_path, pat, false, &valid); return valid ? pat.group_file : String(); } bool ResourceFormatImporter::is_import_valid(const String &p_path) const { bool valid = true; PathAndType pat; - _get_path_and_type(p_path, pat, &valid); + _get_path_and_type(p_path, pat, false, &valid); return valid; } String ResourceFormatImporter::get_resource_type(const String &p_path) const { PathAndType pat; - Error err = _get_path_and_type(p_path, pat); + Error err = _get_path_and_type(p_path, pat, false); if (err != OK) { return ""; @@ -378,7 +390,7 @@ String ResourceFormatImporter::get_resource_type(const String &p_path) const { ResourceUID::ID ResourceFormatImporter::get_resource_uid(const String &p_path) const { PathAndType pat; - Error err = _get_path_and_type(p_path, pat); + Error err = _get_path_and_type(p_path, pat, false); if (err != OK) { return ResourceUID::INVALID_ID; @@ -393,7 +405,7 @@ bool ResourceFormatImporter::has_custom_uid_support() const { Error ResourceFormatImporter::get_resource_import_info(const String &p_path, StringName &r_type, ResourceUID::ID &r_uid, String &r_import_group_file) const { PathAndType pat; - Error err = _get_path_and_type(p_path, pat); + Error err = _get_path_and_type(p_path, pat, false); if (err == OK) { r_type = pat.type; @@ -410,7 +422,7 @@ Error ResourceFormatImporter::get_resource_import_info(const String &p_path, Str Variant ResourceFormatImporter::get_resource_metadata(const String &p_path) const { PathAndType pat; - Error err = _get_path_and_type(p_path, pat); + Error err = _get_path_and_type(p_path, pat, false); if (err != OK) { return Variant(); @@ -420,7 +432,7 @@ Variant ResourceFormatImporter::get_resource_metadata(const String &p_path) cons } void ResourceFormatImporter::get_classes_used(const String &p_path, HashSet *r_classes) { PathAndType pat; - Error err = _get_path_and_type(p_path, pat); + Error err = _get_path_and_type(p_path, pat, false); if (err != OK) { return; @@ -431,7 +443,7 @@ void ResourceFormatImporter::get_classes_used(const String &p_path, HashSet *p_dependencies, bool p_add_types) { PathAndType pat; - Error err = _get_path_and_type(p_path, pat); + Error err = _get_path_and_type(p_path, pat, false); if (err != OK) { return; @@ -459,12 +471,12 @@ void ResourceFormatImporter::add_importer(const Ref &p_importe } } -void ResourceFormatImporter::get_importers_for_extension(const String &p_extension, List> *r_importers) { +void ResourceFormatImporter::get_importers_for_file(const String &p_file, List> *r_importers) { for (int i = 0; i < importers.size(); i++) { List local_exts; importers[i]->get_recognized_extensions(&local_exts); for (const String &F : local_exts) { - if (p_extension.to_lower() == F) { + if (p_file.right(F.length()).nocasecmp_to(F) == 0) { r_importers->push_back(importers[i]); break; } @@ -478,7 +490,7 @@ void ResourceFormatImporter::get_importers(List> *r_import } } -Ref ResourceFormatImporter::get_importer_by_extension(const String &p_extension) const { +Ref ResourceFormatImporter::get_importer_by_file(const String &p_file) const { Ref importer; float priority = 0; @@ -486,9 +498,10 @@ Ref ResourceFormatImporter::get_importer_by_extension(const St List local_exts; importers[i]->get_recognized_extensions(&local_exts); for (const String &F : local_exts) { - if (p_extension.to_lower() == F && importers[i]->get_priority() > priority) { + if (p_file.right(F.length()).nocasecmp_to(F) == 0 && importers[i]->get_priority() > priority) { importer = importers[i]; priority = importers[i]->get_priority(); + break; } } } @@ -503,7 +516,7 @@ String ResourceFormatImporter::get_import_base_path(const String &p_for_file) co bool ResourceFormatImporter::are_import_settings_valid(const String &p_path) const { bool valid = true; PathAndType pat; - _get_path_and_type(p_path, pat, &valid); + _get_path_and_type(p_path, pat, false, &valid); if (!valid) { return false; diff --git a/engine/core/io/resource_importer.h b/engine/core/io/resource_importer.h index 1d00ef3b..ff1baad9 100644 --- a/engine/core/io/resource_importer.h +++ b/engine/core/io/resource_importer.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef RESOURCE_IMPORTER_H -#define RESOURCE_IMPORTER_H +#pragma once #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" @@ -49,7 +48,7 @@ class ResourceFormatImporter : public ResourceFormatLoader { ResourceUID::ID uid = ResourceUID::INVALID_ID; }; - Error _get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid = nullptr) const; + Error _get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool p_load, bool *r_valid = nullptr) const; static ResourceFormatImporter *singleton; @@ -90,8 +89,8 @@ public: void remove_importer(const Ref &p_importer) { importers.erase(p_importer); } Ref get_importer_by_name(const String &p_name) const; - Ref get_importer_by_extension(const String &p_extension) const; - void get_importers_for_extension(const String &p_extension, List> *r_importers); + Ref get_importer_by_file(const String &p_file) const; + void get_importers_for_file(const String &p_file, List> *r_importers); void get_importers(List> *r_importers); bool are_import_settings_valid(const String &p_path) const; @@ -166,5 +165,3 @@ class ResourceFormatImporterSaver : public ResourceFormatSaver { public: virtual Error set_uid(const String &p_path, ResourceUID::ID p_uid) override; }; - -#endif // RESOURCE_IMPORTER_H diff --git a/engine/core/io/resource_loader.cpp b/engine/core/io/resource_loader.cpp index 04fd641f..869faa98 100644 --- a/engine/core/io/resource_loader.cpp +++ b/engine/core/io/resource_loader.cpp @@ -61,8 +61,6 @@ bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_ return ret; } - String extension = p_path.get_extension(); - List extensions; if (p_for_type.is_empty()) { get_recognized_extensions(&extensions); @@ -71,7 +69,8 @@ bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_ } for (const String &E : extensions) { - if (E.nocasecmp_to(extension) == 0) { + const String ext = !E.begins_with(".") ? "." + E : E; + if (p_path.right(ext.length()).nocasecmp_to(ext) == 0) { return true; } } @@ -264,6 +263,14 @@ void ResourceLoader::LoadToken::clear() { thread_load_tasks.erase(local_path); } local_path.clear(); // Mark as already cleared. + if (task_to_await) { + for (KeyValue &E : thread_load_tasks) { + if (E.value.task_id == task_to_await) { + task_to_await = 0; + break; // Same task is reused by nested loads, do not wait for completion here. + } + } + } } } @@ -322,7 +329,7 @@ Ref ResourceLoader::_load(const String &p_path, const String &p_origin #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { - if (ResourceFormatImporter::get_singleton()->get_importer_by_extension(p_path.get_extension()).is_valid()) { + if (ResourceFormatImporter::get_singleton()->get_importer_by_file(p_path).is_valid()) { // The format is known to the editor, but the file hasn't been imported // (otherwise, ResourceFormatImporter would have been found as a suitable loader). found = true; @@ -772,6 +779,10 @@ Ref ResourceLoader::_load_complete(LoadToken &p_load_token, Error *r_e return _load_complete_inner(p_load_token, r_error, thread_load_lock); } +void ResourceLoader::set_is_import_thread(bool p_import_thread) { + import_thread = p_import_thread; +} + Ref ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Error *r_error, MutexLock> &p_thread_load_lock) { if (r_error) { *r_error = OK; @@ -825,6 +836,12 @@ Ref ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro p_thread_load_lock.temp_relock(); load_task.awaited = true; + // Mark nested loads with the same task id as awaited. + for (KeyValue &E : thread_load_tasks) { + if (E.value.task_id == load_task.task_id) { + E.value.awaited = true; + } + } DEV_ASSERT(load_task.status == THREAD_LOAD_FAILED || load_task.status == THREAD_LOAD_LOADED); } else if (load_task.need_wait) { @@ -886,9 +903,11 @@ Ref ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro MessageQueue::get_main_singleton()->push_callable(callable_mp(rcc.source, &Resource::connect_changed).bind(rcc.callable, rcc.flags)); } } - core_bind::Semaphore done; - MessageQueue::get_main_singleton()->push_callable(callable_mp(&done, &core_bind::Semaphore::post).bind(1)); - done.wait(); + if (!import_thread) { // Main thread is blocked by initial resource reimport, do not wait. + CoreBind::Semaphore done; + MessageQueue::get_main_singleton()->push_callable(callable_mp(&done, &CoreBind::Semaphore::post).bind(1)); + done.wait(); + } } } } @@ -1339,10 +1358,8 @@ void ResourceLoader::load_translation_remaps() { } Dictionary remaps = GLOBAL_GET("internationalization/locale/translation_remaps"); - List keys; - remaps.get_key_list(&keys); - for (const Variant &E : keys) { - Array langs = remaps[E]; + for (const KeyValue &kv : remaps) { + Array langs = kv.value; Vector lang_remaps; lang_remaps.resize(langs.size()); String *lang_remaps_ptrw = lang_remaps.ptrw(); @@ -1350,7 +1367,7 @@ void ResourceLoader::load_translation_remaps() { *lang_remaps_ptrw++ = lang; } - translation_remaps[String(E)] = lang_remaps; + translation_remaps[String(kv.key)] = lang_remaps; } } @@ -1565,6 +1582,7 @@ bool ResourceLoader::create_missing_resources_if_class_unavailable = false; bool ResourceLoader::abort_on_missing_resource = true; bool ResourceLoader::timestamp_on_load = false; +thread_local bool ResourceLoader::import_thread = false; thread_local int ResourceLoader::load_nesting = 0; thread_local Vector ResourceLoader::load_paths_stack; thread_local HashMap>> ResourceLoader::res_ref_overrides; diff --git a/engine/core/io/resource_loader.h b/engine/core/io/resource_loader.h index 10a82e81..189f000e 100644 --- a/engine/core/io/resource_loader.h +++ b/engine/core/io/resource_loader.h @@ -28,15 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef RESOURCE_LOADER_H -#define RESOURCE_LOADER_H +#pragma once #include "core/io/resource.h" #include "core/object/gdvirtual.gen.inc" #include "core/object/worker_thread_pool.h" #include "core/os/thread.h" -namespace core_bind { +namespace CoreBind { class ResourceLoader; } @@ -105,7 +104,7 @@ typedef void (*ResourceLoadedCallback)(Ref p_resource, const String &p class ResourceLoader { friend class LoadToken; - friend class core_bind::ResourceLoader; + friend class CoreBind::ResourceLoader; enum { MAX_LOADERS = 64 @@ -205,6 +204,7 @@ private: static void _run_load_task(void *p_userdata); + static thread_local bool import_thread; static thread_local int load_nesting; static thread_local HashMap>> res_ref_overrides; // Outermost key is nesting level. static thread_local Vector load_paths_stack; @@ -254,6 +254,8 @@ public: static bool is_imported(const String &p_path); static int get_import_order(const String &p_path); + static void set_is_import_thread(bool p_import_thread); + static void set_timestamp_on_load(bool p_timestamp) { timestamp_on_load = p_timestamp; } static bool get_timestamp_on_load() { return timestamp_on_load; } @@ -316,5 +318,3 @@ public: static void initialize(); static void finalize(); }; - -#endif // RESOURCE_LOADER_H diff --git a/engine/core/io/resource_saver.h b/engine/core/io/resource_saver.h index 3e082192..5602a3a4 100644 --- a/engine/core/io/resource_saver.h +++ b/engine/core/io/resource_saver.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef RESOURCE_SAVER_H -#define RESOURCE_SAVER_H +#pragma once #include "core/io/resource.h" #include "core/object/gdvirtual.gen.inc" @@ -103,5 +102,3 @@ public: static void add_custom_savers(); static void remove_custom_savers(); }; - -#endif // RESOURCE_SAVER_H diff --git a/engine/core/io/resource_uid.cpp b/engine/core/io/resource_uid.cpp index a73adf9d..ef997f74 100644 --- a/engine/core/io/resource_uid.cpp +++ b/engine/core/io/resource_uid.cpp @@ -35,6 +35,7 @@ #include "core/io/dir_access.h" #include "core/io/file_access.h" #include "core/io/resource_loader.h" +#include "core/math/random_pcg.h" // These constants are off by 1, causing the 'z' and '9' characters never to be used. // This cannot be fixed without breaking compatibility; see GH-83843. @@ -46,7 +47,7 @@ String ResourceUID::get_cache_file() { } static constexpr uint8_t uuid_characters[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', '0', '1', '2', '3', '4', '5', '6', '7', '8' }; -static constexpr uint32_t uuid_characters_element_count = (sizeof(uuid_characters) / sizeof(*uuid_characters)); +static constexpr uint32_t uuid_characters_element_count = std::size(uuid_characters); static constexpr uint8_t max_uuid_number_length = 13; // Max 0x7FFFFFFFFFFFFFFF (uid://d4n4ub6itg400) size is 13 characters. String ResourceUID::id_to_text(ID p_id) const { @@ -121,10 +122,31 @@ ResourceUID::ID ResourceUID::create_id() { } } +ResourceUID::ID ResourceUID::create_id_for_path(const String &p_path) { + ID id = INVALID_ID; + RandomPCG rng; + + const String project_name = GLOBAL_GET("application/config/name"); + rng.seed(project_name.hash64() * p_path.hash64() * FileAccess::get_md5(p_path).hash64()); + + while (true) { + int64_t num1 = rng.rand(); + int64_t num2 = ((int64_t)rng.rand()) << 32; + id = (num1 | num2) & 0x7FFFFFFFFFFFFFFF; + + MutexLock lock(mutex); + if (!unique_ids.has(id)) { + break; + } + } + return id; +} + bool ResourceUID::has_id(ID p_id) const { MutexLock l(mutex); return unique_ids.has(p_id); } + void ResourceUID::add_id(ID p_id, const String &p_path) { MutexLock l(mutex); ERR_FAIL_COND(unique_ids.has(p_id)); @@ -311,7 +333,7 @@ String ResourceUID::get_path_from_cache(Ref &p_cache_file, const Str ERR_FAIL_COND_V(rl != len, String()); if (singleton->id_to_text(id) == p_uid_string) { - return String(cs); + return String::utf8(cs.get_data()); } } return String(); @@ -327,6 +349,7 @@ void ResourceUID::_bind_methods() { ClassDB::bind_method(D_METHOD("text_to_id", "text_id"), &ResourceUID::text_to_id); ClassDB::bind_method(D_METHOD("create_id"), &ResourceUID::create_id); + ClassDB::bind_method(D_METHOD("create_id_for_path", "path"), &ResourceUID::create_id_for_path); ClassDB::bind_method(D_METHOD("has_id", "id"), &ResourceUID::has_id); ClassDB::bind_method(D_METHOD("add_id", "id", "path"), &ResourceUID::add_id); diff --git a/engine/core/io/resource_uid.h b/engine/core/io/resource_uid.h index 2912168d..6ac4c9c9 100644 --- a/engine/core/io/resource_uid.h +++ b/engine/core/io/resource_uid.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef RESOURCE_UID_H -#define RESOURCE_UID_H +#pragma once #include "core/object/ref_counted.h" #include "core/string/string_name.h" @@ -71,6 +70,7 @@ public: ID text_to_id(const String &p_text) const; ID create_id(); + ID create_id_for_path(const String &p_path); bool has_id(ID p_id) const; void add_id(ID p_id, const String &p_path); void set_id(ID p_id, const String &p_path); @@ -93,5 +93,3 @@ public: ResourceUID(); ~ResourceUID(); }; - -#endif // RESOURCE_UID_H diff --git a/engine/core/io/stream_peer.cpp b/engine/core/io/stream_peer.cpp index bc7ea8a0..2f2c1d30 100644 --- a/engine/core/io/stream_peer.cpp +++ b/engine/core/io/stream_peer.cpp @@ -125,54 +125,90 @@ void StreamPeer::put_8(int8_t p_val) { } void StreamPeer::put_u16(uint16_t p_val) { +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + p_val = BSWAP16(p_val); + } +#else if (big_endian) { p_val = BSWAP16(p_val); } +#endif uint8_t buf[2]; encode_uint16(p_val, buf); put_data(buf, 2); } void StreamPeer::put_16(int16_t p_val) { +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + p_val = BSWAP16(p_val); + } +#else if (big_endian) { p_val = BSWAP16(p_val); } +#endif uint8_t buf[2]; encode_uint16(p_val, buf); put_data(buf, 2); } void StreamPeer::put_u32(uint32_t p_val) { +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + p_val = BSWAP32(p_val); + } +#else if (big_endian) { p_val = BSWAP32(p_val); } +#endif uint8_t buf[4]; encode_uint32(p_val, buf); put_data(buf, 4); } void StreamPeer::put_32(int32_t p_val) { +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + p_val = BSWAP32(p_val); + } +#else if (big_endian) { p_val = BSWAP32(p_val); } +#endif uint8_t buf[4]; encode_uint32(p_val, buf); put_data(buf, 4); } void StreamPeer::put_u64(uint64_t p_val) { +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + p_val = BSWAP64(p_val); + } +#else if (big_endian) { p_val = BSWAP64(p_val); } +#endif uint8_t buf[8]; encode_uint64(p_val, buf); put_data(buf, 8); } void StreamPeer::put_64(int64_t p_val) { +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + p_val = BSWAP64(p_val); + } +#else if (big_endian) { p_val = BSWAP64(p_val); } +#endif uint8_t buf[8]; encode_uint64(p_val, buf); put_data(buf, 8); @@ -183,9 +219,15 @@ void StreamPeer::put_half(float p_val) { encode_half(p_val, buf); uint16_t *p16 = (uint16_t *)buf; +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + *p16 = BSWAP16(*p16); + } +#else if (big_endian) { *p16 = BSWAP16(*p16); } +#endif put_data(buf, 2); } @@ -194,10 +236,17 @@ void StreamPeer::put_float(float p_val) { uint8_t buf[4]; encode_float(p_val, buf); +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + uint32_t *p32 = (uint32_t *)buf; + *p32 = BSWAP32(*p32); + } +#else if (big_endian) { uint32_t *p32 = (uint32_t *)buf; *p32 = BSWAP32(*p32); } +#endif put_data(buf, 4); } @@ -206,10 +255,17 @@ void StreamPeer::put_double(double p_val) { uint8_t buf[8]; encode_double(p_val, buf); +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + uint64_t *p64 = (uint64_t *)buf; + *p64 = BSWAP64(*p64); + } +#else if (big_endian) { uint64_t *p64 = (uint64_t *)buf; *p64 = BSWAP64(*p64); } +#endif put_data(buf, 8); } @@ -253,9 +309,15 @@ uint16_t StreamPeer::get_u16() { get_data(buf, 2); uint16_t r = decode_uint16(buf); +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + r = BSWAP16(r); + } +#else if (big_endian) { r = BSWAP16(r); } +#endif return r; } @@ -265,9 +327,15 @@ int16_t StreamPeer::get_16() { get_data(buf, 2); uint16_t r = decode_uint16(buf); +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + r = BSWAP16(r); + } +#else if (big_endian) { r = BSWAP16(r); } +#endif return int16_t(r); } @@ -277,9 +345,15 @@ uint32_t StreamPeer::get_u32() { get_data(buf, 4); uint32_t r = decode_uint32(buf); +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + r = BSWAP32(r); + } +#else if (big_endian) { r = BSWAP32(r); } +#endif return r; } @@ -289,9 +363,15 @@ int32_t StreamPeer::get_32() { get_data(buf, 4); uint32_t r = decode_uint32(buf); +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + r = BSWAP32(r); + } +#else if (big_endian) { r = BSWAP32(r); } +#endif return int32_t(r); } @@ -301,9 +381,15 @@ uint64_t StreamPeer::get_u64() { get_data(buf, 8); uint64_t r = decode_uint64(buf); +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + r = BSWAP64(r); + } +#else if (big_endian) { r = BSWAP64(r); } +#endif return r; } @@ -313,9 +399,15 @@ int64_t StreamPeer::get_64() { get_data(buf, 8); uint64_t r = decode_uint64(buf); +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + r = BSWAP64(r); + } +#else if (big_endian) { r = BSWAP64(r); } +#endif return int64_t(r); } @@ -324,10 +416,17 @@ float StreamPeer::get_half() { uint8_t buf[2]; get_data(buf, 2); +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + uint16_t *p16 = (uint16_t *)buf; + *p16 = BSWAP16(*p16); + } +#else if (big_endian) { uint16_t *p16 = (uint16_t *)buf; *p16 = BSWAP16(*p16); } +#endif return decode_half(buf); } @@ -336,10 +435,17 @@ float StreamPeer::get_float() { uint8_t buf[4]; get_data(buf, 4); +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + uint32_t *p32 = (uint32_t *)buf; + *p32 = BSWAP32(*p32); + } +#else if (big_endian) { uint32_t *p32 = (uint32_t *)buf; *p32 = BSWAP32(*p32); } +#endif return decode_float(buf); } @@ -348,10 +454,17 @@ double StreamPeer::get_double() { uint8_t buf[8]; get_data(buf, 8); +#ifdef BIG_ENDIAN_ENABLED + if (!big_endian) { + uint64_t *p64 = (uint64_t *)buf; + *p64 = BSWAP64(*p64); + } +#else if (big_endian) { uint64_t *p64 = (uint64_t *)buf; *p64 = BSWAP64(*p64); } +#endif return decode_double(buf); } @@ -383,9 +496,7 @@ String StreamPeer::get_utf8_string(int p_bytes) { err = get_data(buf.ptrw(), p_bytes); ERR_FAIL_COND_V(err != OK, String()); - String ret; - ret.parse_utf8((const char *)buf.ptr(), buf.size()); - return ret; + return String::utf8((const char *)buf.ptr(), buf.size()); } Variant StreamPeer::get_var(bool p_allow_objects) { diff --git a/engine/core/io/stream_peer.h b/engine/core/io/stream_peer.h index 44bbfbf1..a73e92d2 100644 --- a/engine/core/io/stream_peer.h +++ b/engine/core/io/stream_peer.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef STREAM_PEER_H -#define STREAM_PEER_H +#pragma once #include "core/object/ref_counted.h" @@ -50,7 +49,11 @@ protected: Array _get_data(int p_bytes); Array _get_partial_data(int p_bytes); +#ifdef BIG_ENDIAN_ENABLED + bool big_endian = true; +#else bool big_endian = false; +#endif public: virtual Error put_data(const uint8_t *p_data, int p_bytes) = 0; ///< put a whole chunk of data, blocking until it sent @@ -152,5 +155,3 @@ public: StreamPeerBuffer() {} }; - -#endif // STREAM_PEER_H diff --git a/engine/core/io/stream_peer_gzip.cpp b/engine/core/io/stream_peer_gzip.cpp index 514bcf59..ed247eaf 100644 --- a/engine/core/io/stream_peer_gzip.cpp +++ b/engine/core/io/stream_peer_gzip.cpp @@ -195,12 +195,12 @@ int StreamPeerGZIP::get_available_bytes() const { Error StreamPeerGZIP::finish() { ERR_FAIL_COND_V(!ctx || !compressing, ERR_UNAVAILABLE); // Ensure we have enough space in temporary buffer. - if (buffer.size() < 1024) { - buffer.resize(1024); // 1024 should be more than enough. + if (buffer.size() < get_available_bytes()) { + buffer.resize(get_available_bytes()); // get_available_bytes() is what we can store in RingBuffer. } int consumed = 0; int to_write = 0; - Error err = _process(buffer.ptrw(), 1024, nullptr, 0, consumed, to_write, true); // compress + Error err = _process(buffer.ptrw(), buffer.size(), nullptr, 0, consumed, to_write, true); // compress if (err != OK) { return err; } diff --git a/engine/core/io/stream_peer_gzip.h b/engine/core/io/stream_peer_gzip.h index a2e25ea4..394fd613 100644 --- a/engine/core/io/stream_peer_gzip.h +++ b/engine/core/io/stream_peer_gzip.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef STREAM_PEER_GZIP_H -#define STREAM_PEER_GZIP_H +#pragma once #include "core/io/stream_peer.h" @@ -72,5 +71,3 @@ public: StreamPeerGZIP(); ~StreamPeerGZIP(); }; - -#endif // STREAM_PEER_GZIP_H diff --git a/engine/core/io/stream_peer_tcp.h b/engine/core/io/stream_peer_tcp.h index d7da7503..80097a66 100644 --- a/engine/core/io/stream_peer_tcp.h +++ b/engine/core/io/stream_peer_tcp.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef STREAM_PEER_TCP_H -#define STREAM_PEER_TCP_H +#pragma once #include "core/io/ip.h" #include "core/io/ip_address.h" @@ -92,5 +91,3 @@ public: }; VARIANT_ENUM_CAST(StreamPeerTCP::Status); - -#endif // STREAM_PEER_TCP_H diff --git a/engine/core/io/stream_peer_tls.h b/engine/core/io/stream_peer_tls.h index 3e03e25a..80a48115 100644 --- a/engine/core/io/stream_peer_tls.h +++ b/engine/core/io/stream_peer_tls.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef STREAM_PEER_TLS_H -#define STREAM_PEER_TLS_H +#pragma once #include "core/crypto/crypto.h" #include "core/io/stream_peer.h" @@ -66,5 +65,3 @@ public: }; VARIANT_ENUM_CAST(StreamPeerTLS::Status); - -#endif // STREAM_PEER_TLS_H diff --git a/engine/core/io/tcp_server.h b/engine/core/io/tcp_server.h index 472d86f3..943d4c6f 100644 --- a/engine/core/io/tcp_server.h +++ b/engine/core/io/tcp_server.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef TCP_SERVER_H -#define TCP_SERVER_H +#pragma once #include "core/io/ip.h" #include "core/io/net_socket.h" @@ -59,5 +58,3 @@ public: TCPServer(); ~TCPServer(); }; - -#endif // TCP_SERVER_H diff --git a/engine/core/io/translation_loader_po.cpp b/engine/core/io/translation_loader_po.cpp index 1761d6fa..35773109 100644 --- a/engine/core/io/translation_loader_po.cpp +++ b/engine/core/io/translation_loader_po.cpp @@ -76,14 +76,17 @@ Ref TranslationLoaderPO::load_translation(Ref f, Error *r_ bool is_plural = false; for (uint32_t j = 0; j < str_len + 1; j++) { if (data[j] == 0x04) { - msg_context.parse_utf8((const char *)data.ptr(), j); + msg_context.clear(); + msg_context.append_utf8((const char *)data.ptr(), j); str_start = j + 1; } if (data[j] == 0x00) { if (is_plural) { - msg_id_plural.parse_utf8((const char *)(data.ptr() + str_start), j - str_start); + msg_id_plural.clear(); + msg_id_plural.append_utf8((const char *)(data.ptr() + str_start), j - str_start); } else { - msg_id.parse_utf8((const char *)(data.ptr() + str_start), j - str_start); + msg_id.clear(); + msg_id.append_utf8((const char *)(data.ptr() + str_start), j - str_start); is_plural = true; } str_start = j + 1; @@ -189,7 +192,7 @@ Ref TranslationLoaderPO::load_translation(Ref f, Error *r_ } } msg_context = ""; - l = l.substr(7, l.length()).strip_edges(); + l = l.substr(7).strip_edges(); status = STATUS_READING_CONTEXT; entered_context = true; } @@ -202,7 +205,7 @@ Ref TranslationLoaderPO::load_translation(Ref f, Error *r_ } // We don't record the message in "msgid_plural" itself as tr_n(), TTRN(), RTRN() interfaces provide the plural string already. // We just have to reset variables related to plurals for "msgstr[]" later on. - l = l.substr(12, l.length()).strip_edges(); + l = l.substr(12).strip_edges(); plural_index = -1; msgs_plural.clear(); msgs_plural.resize(plural_forms); @@ -230,7 +233,7 @@ Ref TranslationLoaderPO::load_translation(Ref f, Error *r_ } } - l = l.substr(5, l.length()).strip_edges(); + l = l.substr(5).strip_edges(); status = STATUS_READING_ID; // If we did not encounter msgctxt, we reset context to empty to reset it. if (!entered_context) { @@ -246,10 +249,10 @@ Ref TranslationLoaderPO::load_translation(Ref f, Error *r_ if (l.begins_with("msgstr[")) { ERR_FAIL_COND_V_MSG(status != STATUS_READING_PLURAL, Ref(), vformat("Unexpected 'msgstr[]', was expecting 'msgid_plural' before 'msgstr[]' while parsing: %s:%d.", path, line)); plural_index++; // Increment to add to the next slot in vector msgs_plural. - l = l.substr(9, l.length()).strip_edges(); + l = l.substr(9).strip_edges(); } else if (l.begins_with("msgstr")) { ERR_FAIL_COND_V_MSG(status != STATUS_READING_ID, Ref(), vformat("Unexpected 'msgstr', was expecting 'msgid' before 'msgstr' while parsing: %s:%d.", path, line)); - l = l.substr(6, l.length()).strip_edges(); + l = l.substr(6).strip_edges(); status = STATUS_READING_STRING; } @@ -263,7 +266,7 @@ Ref TranslationLoaderPO::load_translation(Ref f, Error *r_ ERR_FAIL_COND_V_MSG(!l.begins_with("\"") || status == STATUS_NONE, Ref(), vformat("Invalid line '%s' while parsing: %s:%d.", l, path, line)); - l = l.substr(1, l.length()); + l = l.substr(1); // Find final quote, ignoring escaped ones (\"). // The escape_next logic is necessary to properly parse things like \\" // where the backslash is the one being escaped, not the quote. @@ -329,7 +332,7 @@ Ref TranslationLoaderPO::load_translation(Ref f, Error *r_ continue; } String prop = c.substr(0, p).strip_edges(); - String value = c.substr(p + 1, c.length()).strip_edges(); + String value = c.substr(p + 1).strip_edges(); if (prop == "X-Language" || prop == "Language") { translation->set_locale(value); diff --git a/engine/core/io/translation_loader_po.h b/engine/core/io/translation_loader_po.h index 1f9782c4..5ed0e1f5 100644 --- a/engine/core/io/translation_loader_po.h +++ b/engine/core/io/translation_loader_po.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef TRANSLATION_LOADER_PO_H -#define TRANSLATION_LOADER_PO_H +#pragma once #include "core/io/file_access.h" #include "core/io/resource_loader.h" @@ -49,5 +48,3 @@ public: TranslationLoaderPO() {} }; - -#endif // TRANSLATION_LOADER_PO_H diff --git a/engine/core/io/udp_server.h b/engine/core/io/udp_server.h index 39b7fd98..9edf4318 100644 --- a/engine/core/io/udp_server.h +++ b/engine/core/io/udp_server.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef UDP_SERVER_H -#define UDP_SERVER_H +#pragma once #include "core/io/net_socket.h" #include "core/io/packet_peer_udp.h" @@ -76,5 +75,3 @@ public: UDPServer(); ~UDPServer(); }; - -#endif // UDP_SERVER_H diff --git a/engine/core/io/xml_parser.cpp b/engine/core/io/xml_parser.cpp index ed1f6f4e..a50a1723 100644 --- a/engine/core/io/xml_parser.cpp +++ b/engine/core/io/xml_parser.cpp @@ -95,7 +95,8 @@ void XMLParser::_ignore_definition() { while (*P && *P != '>') { next_char(); } - node_name.parse_utf8(F, P - F); + node_name.clear(); + node_name.append_utf8(F, P - F); if (*P) { next_char(); diff --git a/engine/core/io/xml_parser.h b/engine/core/io/xml_parser.h index a14bdee5..911d2b11 100644 --- a/engine/core/io/xml_parser.h +++ b/engine/core/io/xml_parser.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef XML_PARSER_H -#define XML_PARSER_H +#pragma once #include "core/object/ref_counted.h" #include "core/string/ustring.h" @@ -126,5 +125,3 @@ public: }; VARIANT_ENUM_CAST(XMLParser::NodeType); - -#endif // XML_PARSER_H diff --git a/engine/core/io/zip_io.cpp b/engine/core/io/zip_io.cpp index 972656e2..e01c181a 100644 --- a/engine/core/io/zip_io.cpp +++ b/engine/core/io/zip_io.cpp @@ -76,8 +76,7 @@ void *zipio_open(voidpf opaque, const char *p_fname, int mode) { Ref *fa = reinterpret_cast *>(opaque); ERR_FAIL_NULL_V(fa, nullptr); - String fname; - fname.parse_utf8(p_fname); + String fname = String::utf8(p_fname); int file_access_mode = 0; if (mode & ZLIB_FILEFUNC_MODE_READ) { diff --git a/engine/core/io/zip_io.h b/engine/core/io/zip_io.h index cd5c873c..82004d9c 100644 --- a/engine/core/io/zip_io.h +++ b/engine/core/io/zip_io.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef ZIP_IO_H -#define ZIP_IO_H +#pragma once #include "core/io/file_access.h" @@ -61,5 +60,3 @@ voidpf zipio_alloc(voidpf opaque, uInt items, uInt size); void zipio_free(voidpf opaque, voidpf address); zlib_filefunc_def zipio_create_io(Ref *p_data); - -#endif // ZIP_IO_H diff --git a/engine/core/math/a_star.cpp b/engine/core/math/a_star.cpp index 060b1bb1..9b6717c6 100644 --- a/engine/core/math/a_star.cpp +++ b/engine/core/math/a_star.cpp @@ -302,12 +302,7 @@ Vector3 AStar3D::get_closest_position_in_segment(const Vector3 &p_point) const { continue; } - Vector3 segment[2] = { - from_point->pos, - to_point->pos, - }; - - Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, segment); + Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, from_point->pos, to_point->pos); real_t d = p_point.distance_squared_to(p); if (d < closest_dist) { closest_point = p; diff --git a/engine/core/math/a_star.h b/engine/core/math/a_star.h index e510923b..d7e0f3fd 100644 --- a/engine/core/math/a_star.h +++ b/engine/core/math/a_star.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef A_STAR_H -#define A_STAR_H +#pragma once #include "core/object/gdvirtual.gen.inc" #include "core/object/ref_counted.h" @@ -222,5 +221,3 @@ public: AStar2D() {} ~AStar2D() {} }; - -#endif // A_STAR_H diff --git a/engine/core/math/a_star_grid_2d.cpp b/engine/core/math/a_star_grid_2d.cpp index 7e0e982c..8bde50ad 100644 --- a/engine/core/math/a_star_grid_2d.cpp +++ b/engine/core/math/a_star_grid_2d.cpp @@ -34,27 +34,27 @@ #include "core/variant/typed_array.h" static real_t heuristic_euclidean(const Vector2i &p_from, const Vector2i &p_to) { - real_t dx = (real_t)ABS(p_to.x - p_from.x); - real_t dy = (real_t)ABS(p_to.y - p_from.y); + real_t dx = (real_t)Math::abs(p_to.x - p_from.x); + real_t dy = (real_t)Math::abs(p_to.y - p_from.y); return (real_t)Math::sqrt(dx * dx + dy * dy); } static real_t heuristic_manhattan(const Vector2i &p_from, const Vector2i &p_to) { - real_t dx = (real_t)ABS(p_to.x - p_from.x); - real_t dy = (real_t)ABS(p_to.y - p_from.y); + real_t dx = (real_t)Math::abs(p_to.x - p_from.x); + real_t dy = (real_t)Math::abs(p_to.y - p_from.y); return dx + dy; } static real_t heuristic_octile(const Vector2i &p_from, const Vector2i &p_to) { - real_t dx = (real_t)ABS(p_to.x - p_from.x); - real_t dy = (real_t)ABS(p_to.y - p_from.y); - real_t F = Math_SQRT2 - 1; + real_t dx = (real_t)Math::abs(p_to.x - p_from.x); + real_t dy = (real_t)Math::abs(p_to.y - p_from.y); + real_t F = Math::SQRT2 - 1; return (dx < dy) ? F * dx + dy : F * dy + dx; } static real_t heuristic_chebyshev(const Vector2i &p_from, const Vector2i &p_to) { - real_t dx = (real_t)ABS(p_to.x - p_from.x); - real_t dy = (real_t)ABS(p_to.y - p_from.y); + real_t dx = (real_t)Math::abs(p_to.x - p_from.x); + real_t dy = (real_t)Math::abs(p_to.y - p_from.y); return MAX(dx, dy); } @@ -503,6 +503,7 @@ bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point, bool p_allow_ LocalVector open_list; SortArray sorter; + LocalVector nbors; p_begin_point->g_score = 0; p_begin_point->f_score = _estimate_cost(p_begin_point->id, p_end_point->id); @@ -528,7 +529,7 @@ bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point, bool p_allow_ open_list.remove_at(open_list.size() - 1); p->closed_pass = pass; // Mark the point as closed. - LocalVector nbors; + nbors.clear(); _get_nbors(p, nbors); for (Point *e : nbors) { diff --git a/engine/core/math/a_star_grid_2d.h b/engine/core/math/a_star_grid_2d.h index ae6f3a1f..4883c092 100644 --- a/engine/core/math/a_star_grid_2d.h +++ b/engine/core/math/a_star_grid_2d.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef A_STAR_GRID_2D_H -#define A_STAR_GRID_2D_H +#pragma once #include "core/object/gdvirtual.gen.inc" #include "core/object/ref_counted.h" @@ -230,5 +229,3 @@ public: VARIANT_ENUM_CAST(AStarGrid2D::DiagonalMode); VARIANT_ENUM_CAST(AStarGrid2D::Heuristic); VARIANT_ENUM_CAST(AStarGrid2D::CellShape) - -#endif // A_STAR_GRID_2D_H diff --git a/engine/core/math/aabb.cpp b/engine/core/math/aabb.cpp index 7d1d7c56..0e01771a 100644 --- a/engine/core/math/aabb.cpp +++ b/engine/core/math/aabb.cpp @@ -37,14 +37,6 @@ real_t AABB::get_volume() const { return size.x * size.y * size.z; } -bool AABB::operator==(const AABB &p_rval) const { - return ((position == p_rval.position) && (size == p_rval.size)); -} - -bool AABB::operator!=(const AABB &p_rval) const { - return ((position != p_rval.position) || (size != p_rval.size)); -} - void AABB::merge_with(const AABB &p_aabb) { #ifdef MATH_CHECKS if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) { @@ -76,6 +68,10 @@ bool AABB::is_equal_approx(const AABB &p_aabb) const { return position.is_equal_approx(p_aabb.position) && size.is_equal_approx(p_aabb.size); } +bool AABB::is_same(const AABB &p_aabb) const { + return position.is_same(p_aabb.position) && size.is_same(p_aabb.size); +} + bool AABB::is_finite() const { return position.is_finite() && size.is_finite(); } diff --git a/engine/core/math/aabb.h b/engine/core/math/aabb.h index 7a5581b5..4d78fed8 100644 --- a/engine/core/math/aabb.h +++ b/engine/core/math/aabb.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef AABB_H -#define AABB_H +#pragma once #include "core/math/plane.h" #include "core/math/vector3.h" @@ -59,10 +58,15 @@ struct [[nodiscard]] AABB { const Vector3 &get_size() const { return size; } void set_size(const Vector3 &p_size) { size = p_size; } - bool operator==(const AABB &p_rval) const; - bool operator!=(const AABB &p_rval) const; + constexpr bool operator==(const AABB &p_rval) const { + return position == p_rval.position && size == p_rval.size; + } + constexpr bool operator!=(const AABB &p_rval) const { + return position != p_rval.position || size != p_rval.size; + } bool is_equal_approx(const AABB &p_aabb) const; + bool is_same(const AABB &p_aabb) const; bool is_finite() const; _FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap _FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap @@ -129,8 +133,8 @@ struct [[nodiscard]] AABB { operator String() const; - _FORCE_INLINE_ AABB() {} - inline AABB(const Vector3 &p_pos, const Vector3 &p_size) : + AABB() = default; + constexpr AABB(const Vector3 &p_pos, const Vector3 &p_size) : position(p_pos), size(p_size) { } @@ -496,4 +500,5 @@ AABB AABB::quantized(real_t p_unit) const { return ret; } -#endif // AABB_H +template <> +struct is_zero_constructible : std::true_type {}; diff --git a/engine/core/math/audio_frame.h b/engine/core/math/audio_frame.h index e205126c..ff0f9a5b 100644 --- a/engine/core/math/audio_frame.h +++ b/engine/core/math/audio_frame.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef AUDIO_FRAME_H -#define AUDIO_FRAME_H +#pragma once #include "core/math/vector2.h" #include "core/typedefs.h" @@ -53,6 +52,7 @@ static const float AUDIO_MIN_PEAK_DB = -200.0f; // linear_to_db(AUDIO_PEAK_OFFSE struct AudioFrame { // Left and right samples. union { + // NOLINTBEGIN(modernize-use-default-member-init) struct { float left; float right; @@ -64,6 +64,7 @@ struct AudioFrame { }; #endif float levels[2] = { 0.0 }; + // NOLINTEND(modernize-use-default-member-init) }; _ALWAYS_INLINE_ const float &operator[](int p_idx) const { @@ -75,46 +76,46 @@ struct AudioFrame { return levels[p_idx]; } - _ALWAYS_INLINE_ AudioFrame operator+(const AudioFrame &p_frame) const { return AudioFrame(left + p_frame.left, right + p_frame.right); } - _ALWAYS_INLINE_ AudioFrame operator-(const AudioFrame &p_frame) const { return AudioFrame(left - p_frame.left, right - p_frame.right); } - _ALWAYS_INLINE_ AudioFrame operator*(const AudioFrame &p_frame) const { return AudioFrame(left * p_frame.left, right * p_frame.right); } - _ALWAYS_INLINE_ AudioFrame operator/(const AudioFrame &p_frame) const { return AudioFrame(left / p_frame.left, right / p_frame.right); } + constexpr AudioFrame operator+(const AudioFrame &p_frame) const { return AudioFrame(left + p_frame.left, right + p_frame.right); } + constexpr AudioFrame operator-(const AudioFrame &p_frame) const { return AudioFrame(left - p_frame.left, right - p_frame.right); } + constexpr AudioFrame operator*(const AudioFrame &p_frame) const { return AudioFrame(left * p_frame.left, right * p_frame.right); } + constexpr AudioFrame operator/(const AudioFrame &p_frame) const { return AudioFrame(left / p_frame.left, right / p_frame.right); } - _ALWAYS_INLINE_ AudioFrame operator+(float p_sample) const { return AudioFrame(left + p_sample, right + p_sample); } - _ALWAYS_INLINE_ AudioFrame operator-(float p_sample) const { return AudioFrame(left - p_sample, right - p_sample); } - _ALWAYS_INLINE_ AudioFrame operator*(float p_sample) const { return AudioFrame(left * p_sample, right * p_sample); } - _ALWAYS_INLINE_ AudioFrame operator/(float p_sample) const { return AudioFrame(left / p_sample, right / p_sample); } + constexpr AudioFrame operator+(float p_sample) const { return AudioFrame(left + p_sample, right + p_sample); } + constexpr AudioFrame operator-(float p_sample) const { return AudioFrame(left - p_sample, right - p_sample); } + constexpr AudioFrame operator*(float p_sample) const { return AudioFrame(left * p_sample, right * p_sample); } + constexpr AudioFrame operator/(float p_sample) const { return AudioFrame(left / p_sample, right / p_sample); } - _ALWAYS_INLINE_ void operator+=(const AudioFrame &p_frame) { + constexpr void operator+=(const AudioFrame &p_frame) { left += p_frame.left; right += p_frame.right; } - _ALWAYS_INLINE_ void operator-=(const AudioFrame &p_frame) { + constexpr void operator-=(const AudioFrame &p_frame) { left -= p_frame.left; right -= p_frame.right; } - _ALWAYS_INLINE_ void operator*=(const AudioFrame &p_frame) { + constexpr void operator*=(const AudioFrame &p_frame) { left *= p_frame.left; right *= p_frame.right; } - _ALWAYS_INLINE_ void operator/=(const AudioFrame &p_frame) { + constexpr void operator/=(const AudioFrame &p_frame) { left /= p_frame.left; right /= p_frame.right; } - _ALWAYS_INLINE_ void operator+=(float p_sample) { + constexpr void operator+=(float p_sample) { left += p_sample; right += p_sample; } - _ALWAYS_INLINE_ void operator-=(float p_sample) { + constexpr void operator-=(float p_sample) { left -= p_sample; right -= p_sample; } - _ALWAYS_INLINE_ void operator*=(float p_sample) { + constexpr void operator*=(float p_sample) { left *= p_sample; right *= p_sample; } - _ALWAYS_INLINE_ void operator/=(float p_sample) { + constexpr void operator/=(float p_sample) { left /= p_sample; right /= p_sample; } @@ -133,41 +134,41 @@ struct AudioFrame { return res; } - _ALWAYS_INLINE_ AudioFrame(float p_left, float p_right) { - left = p_left; - right = p_right; - } - _ALWAYS_INLINE_ AudioFrame(const AudioFrame &p_frame) { + // NOLINTBEGIN(cppcoreguidelines-pro-type-member-init) + constexpr AudioFrame(float p_left, float p_right) : + left(p_left), right(p_right) {} + constexpr AudioFrame(const AudioFrame &p_frame) : + left(p_frame.left), right(p_frame.right) {} + // NOLINTEND(cppcoreguidelines-pro-type-member-init) + + constexpr void operator=(const AudioFrame &p_frame) { left = p_frame.left; right = p_frame.right; } - _ALWAYS_INLINE_ void operator=(const AudioFrame &p_frame) { - left = p_frame.left; - right = p_frame.right; - } - - _ALWAYS_INLINE_ operator Vector2() const { + constexpr operator Vector2() const { return Vector2(left, right); } - _ALWAYS_INLINE_ AudioFrame(const Vector2 &p_v2) { - left = p_v2.x; - right = p_v2.y; - } - _ALWAYS_INLINE_ AudioFrame() {} + // NOLINTBEGIN(cppcoreguidelines-pro-type-member-init) + constexpr AudioFrame(const Vector2 &p_v2) : + left(p_v2.x), right(p_v2.y) {} + constexpr AudioFrame() : + left(0), right(0) {} + // NOLINTEND(cppcoreguidelines-pro-type-member-init) }; -_ALWAYS_INLINE_ AudioFrame operator*(float p_scalar, const AudioFrame &p_frame) { +constexpr AudioFrame operator*(float p_scalar, const AudioFrame &p_frame) { return AudioFrame(p_frame.left * p_scalar, p_frame.right * p_scalar); } -_ALWAYS_INLINE_ AudioFrame operator*(int32_t p_scalar, const AudioFrame &p_frame) { +constexpr AudioFrame operator*(int32_t p_scalar, const AudioFrame &p_frame) { return AudioFrame(p_frame.left * p_scalar, p_frame.right * p_scalar); } -_ALWAYS_INLINE_ AudioFrame operator*(int64_t p_scalar, const AudioFrame &p_frame) { +constexpr AudioFrame operator*(int64_t p_scalar, const AudioFrame &p_frame) { return AudioFrame(p_frame.left * p_scalar, p_frame.right * p_scalar); } -#endif // AUDIO_FRAME_H +template <> +struct is_zero_constructible : std::true_type {}; diff --git a/engine/core/math/basis.cpp b/engine/core/math/basis.cpp index 18959f3c..191f8a6a 100644 --- a/engine/core/math/basis.cpp +++ b/engine/core/math/basis.cpp @@ -186,7 +186,7 @@ Basis Basis::diagonalize() { // Compute the rotation angle real_t angle; if (Math::is_equal_approx(rows[j][j], rows[i][i])) { - angle = Math_PI / 4; + angle = Math::PI / 4; } else { angle = 0.5f * Math::atan(2 * rows[i][j] / (rows[j][j] - rows[i][i])); } @@ -486,12 +486,12 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { } } else { euler.x = Math::atan2(rows[2][1], rows[1][1]); - euler.y = -Math_PI / 2.0f; + euler.y = -Math::PI / 2.0f; euler.z = 0.0f; } } else { euler.x = Math::atan2(rows[2][1], rows[1][1]); - euler.y = Math_PI / 2.0f; + euler.y = Math::PI / 2.0f; euler.z = 0.0f; } return euler; @@ -515,13 +515,13 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { // It's -1 euler.x = -Math::atan2(rows[1][2], rows[2][2]); euler.y = 0.0f; - euler.z = Math_PI / 2.0f; + euler.z = Math::PI / 2.0f; } } else { // It's 1 euler.x = -Math::atan2(rows[1][2], rows[2][2]); euler.y = 0.0f; - euler.z = -Math_PI / 2.0f; + euler.z = -Math::PI / 2.0f; } return euler; } @@ -551,12 +551,12 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { euler.z = atan2(rows[1][0], rows[1][1]); } } else { // m12 == -1 - euler.x = Math_PI * 0.5f; + euler.x = Math::PI * 0.5f; euler.y = atan2(rows[0][1], rows[0][0]); euler.z = 0; } } else { // m12 == 1 - euler.x = -Math_PI * 0.5f; + euler.x = -Math::PI * 0.5f; euler.y = -atan2(rows[0][1], rows[0][0]); euler.z = 0; } @@ -582,13 +582,13 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { // It's -1 euler.x = Math::atan2(rows[2][1], rows[2][2]); euler.y = 0.0f; - euler.z = -Math_PI / 2.0f; + euler.z = -Math::PI / 2.0f; } } else { // It's 1 euler.x = Math::atan2(rows[2][1], rows[2][2]); euler.y = 0.0f; - euler.z = Math_PI / 2.0f; + euler.z = Math::PI / 2.0f; } return euler; } break; @@ -608,13 +608,13 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { euler.z = Math::atan2(-rows[0][1], rows[1][1]); } else { // It's -1 - euler.x = -Math_PI / 2.0f; + euler.x = -Math::PI / 2.0f; euler.y = Math::atan2(rows[0][2], rows[0][0]); euler.z = 0; } } else { // It's 1 - euler.x = Math_PI / 2.0f; + euler.x = Math::PI / 2.0f; euler.y = Math::atan2(rows[0][2], rows[0][0]); euler.z = 0; } @@ -637,13 +637,13 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { } else { // It's -1 euler.x = 0; - euler.y = Math_PI / 2.0f; + euler.y = Math::PI / 2.0f; euler.z = -Math::atan2(rows[0][1], rows[1][1]); } } else { // It's 1 euler.x = 0; - euler.y = -Math_PI / 2.0f; + euler.y = -Math::PI / 2.0f; euler.z = -Math::atan2(rows[0][1], rows[1][1]); } return euler; @@ -699,26 +699,14 @@ bool Basis::is_equal_approx(const Basis &p_basis) const { return rows[0].is_equal_approx(p_basis.rows[0]) && rows[1].is_equal_approx(p_basis.rows[1]) && rows[2].is_equal_approx(p_basis.rows[2]); } +bool Basis::is_same(const Basis &p_basis) const { + return rows[0].is_same(p_basis.rows[0]) && rows[1].is_same(p_basis.rows[1]) && rows[2].is_same(p_basis.rows[2]); +} + bool Basis::is_finite() const { return rows[0].is_finite() && rows[1].is_finite() && rows[2].is_finite(); } -bool Basis::operator==(const Basis &p_matrix) const { - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - if (rows[i][j] != p_matrix.rows[i][j]) { - return false; - } - } - } - - return true; -} - -bool Basis::operator!=(const Basis &p_matrix) const { - return (!(*this == p_matrix)); -} - Basis::operator String() const { return "[X: " + get_column(0).operator String() + ", Y: " + get_column(1).operator String() + @@ -790,8 +778,8 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { if ((xx > yy) && (xx > zz)) { // rows[0][0] is the largest diagonal term. if (xx < CMP_EPSILON) { x = 0; - y = Math_SQRT12; - z = Math_SQRT12; + y = Math::SQRT12; + z = Math::SQRT12; } else { x = Math::sqrt(xx); y = xy / x; @@ -799,9 +787,9 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { } } else if (yy > zz) { // rows[1][1] is the largest diagonal term. if (yy < CMP_EPSILON) { - x = Math_SQRT12; + x = Math::SQRT12; y = 0; - z = Math_SQRT12; + z = Math::SQRT12; } else { y = Math::sqrt(yy); x = xy / y; @@ -809,8 +797,8 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { } } else { // rows[2][2] is the largest diagonal term so base result on this. if (zz < CMP_EPSILON) { - x = Math_SQRT12; - y = Math_SQRT12; + x = Math::SQRT12; + y = Math::SQRT12; z = 0; } else { z = Math::sqrt(zz); @@ -819,7 +807,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { } } r_axis = Vector3(x, y, z); - r_angle = Math_PI; + r_angle = Math::PI; return; } // As we have reached here there are no singularities so we can handle normally. diff --git a/engine/core/math/basis.h b/engine/core/math/basis.h index 2d4994de..e85437e7 100644 --- a/engine/core/math/basis.h +++ b/engine/core/math/basis.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef BASIS_H -#define BASIS_H +#pragma once #include "core/math/quaternion.h" #include "core/math/vector3.h" @@ -41,10 +40,10 @@ struct [[nodiscard]] Basis { Vector3(0, 0, 1) }; - _FORCE_INLINE_ const Vector3 &operator[](int p_row) const { + constexpr const Vector3 &operator[](int p_row) const { return rows[p_row]; } - _FORCE_INLINE_ Vector3 &operator[](int p_row) { + constexpr Vector3 &operator[](int p_row) { return rows[p_row]; } @@ -121,23 +120,24 @@ struct [[nodiscard]] Basis { } bool is_equal_approx(const Basis &p_basis) const; + bool is_same(const Basis &p_basis) const; bool is_finite() const; - bool operator==(const Basis &p_matrix) const; - bool operator!=(const Basis &p_matrix) const; + constexpr bool operator==(const Basis &p_matrix) const; + constexpr bool operator!=(const Basis &p_matrix) const; _FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const; _FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_vector) const; _FORCE_INLINE_ void operator*=(const Basis &p_matrix); _FORCE_INLINE_ Basis operator*(const Basis &p_matrix) const; - _FORCE_INLINE_ void operator+=(const Basis &p_matrix); - _FORCE_INLINE_ Basis operator+(const Basis &p_matrix) const; - _FORCE_INLINE_ void operator-=(const Basis &p_matrix); - _FORCE_INLINE_ Basis operator-(const Basis &p_matrix) const; - _FORCE_INLINE_ void operator*=(real_t p_val); - _FORCE_INLINE_ Basis operator*(real_t p_val) const; - _FORCE_INLINE_ void operator/=(real_t p_val); - _FORCE_INLINE_ Basis operator/(real_t p_val) const; + constexpr void operator+=(const Basis &p_matrix); + constexpr Basis operator+(const Basis &p_matrix) const; + constexpr void operator-=(const Basis &p_matrix); + constexpr Basis operator-(const Basis &p_matrix) const; + constexpr void operator*=(real_t p_val); + constexpr Basis operator*(real_t p_val) const; + constexpr void operator/=(real_t p_val); + constexpr Basis operator/(real_t p_val) const; bool is_orthogonal() const; bool is_orthonormal() const; @@ -204,9 +204,12 @@ struct [[nodiscard]] Basis { rows[0].z * p_m[0].y + rows[1].z * p_m[1].y + rows[2].z * p_m[2].y, rows[0].z * p_m[0].z + rows[1].z * p_m[1].z + rows[2].z * p_m[2].z); } - Basis(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz) { - set(p_xx, p_xy, p_xz, p_yx, p_yy, p_yz, p_zx, p_zy, p_zz); - } + constexpr Basis(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz) : + rows{ + { p_xx, p_xy, p_xz }, + { p_yx, p_yy, p_yz }, + { p_zx, p_zy, p_zz }, + } {} void orthonormalize(); Basis orthonormalized() const; @@ -230,17 +233,36 @@ struct [[nodiscard]] Basis { Basis(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_angle, p_scale); } static Basis from_scale(const Vector3 &p_scale); - _FORCE_INLINE_ Basis(const Vector3 &p_x_axis, const Vector3 &p_y_axis, const Vector3 &p_z_axis) { - set_columns(p_x_axis, p_y_axis, p_z_axis); - } + constexpr Basis(const Vector3 &p_x_axis, const Vector3 &p_y_axis, const Vector3 &p_z_axis) : + rows{ + { p_x_axis.x, p_y_axis.x, p_z_axis.x }, + { p_x_axis.y, p_y_axis.y, p_z_axis.y }, + { p_x_axis.z, p_y_axis.z, p_z_axis.z }, + } {} - _FORCE_INLINE_ Basis() {} + Basis() = default; private: // Helper method. void _set_diagonal(const Vector3 &p_diag); }; +constexpr bool Basis::operator==(const Basis &p_matrix) const { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (rows[i][j] != p_matrix.rows[i][j]) { + return false; + } + } + } + + return true; +} + +constexpr bool Basis::operator!=(const Basis &p_matrix) const { + return (!(*this == p_matrix)); +} + _FORCE_INLINE_ void Basis::operator*=(const Basis &p_matrix) { set( p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]), @@ -255,49 +277,49 @@ _FORCE_INLINE_ Basis Basis::operator*(const Basis &p_matrix) const { p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2])); } -_FORCE_INLINE_ void Basis::operator+=(const Basis &p_matrix) { +constexpr void Basis::operator+=(const Basis &p_matrix) { rows[0] += p_matrix.rows[0]; rows[1] += p_matrix.rows[1]; rows[2] += p_matrix.rows[2]; } -_FORCE_INLINE_ Basis Basis::operator+(const Basis &p_matrix) const { +constexpr Basis Basis::operator+(const Basis &p_matrix) const { Basis ret(*this); ret += p_matrix; return ret; } -_FORCE_INLINE_ void Basis::operator-=(const Basis &p_matrix) { +constexpr void Basis::operator-=(const Basis &p_matrix) { rows[0] -= p_matrix.rows[0]; rows[1] -= p_matrix.rows[1]; rows[2] -= p_matrix.rows[2]; } -_FORCE_INLINE_ Basis Basis::operator-(const Basis &p_matrix) const { +constexpr Basis Basis::operator-(const Basis &p_matrix) const { Basis ret(*this); ret -= p_matrix; return ret; } -_FORCE_INLINE_ void Basis::operator*=(real_t p_val) { +constexpr void Basis::operator*=(real_t p_val) { rows[0] *= p_val; rows[1] *= p_val; rows[2] *= p_val; } -_FORCE_INLINE_ Basis Basis::operator*(real_t p_val) const { +constexpr Basis Basis::operator*(real_t p_val) const { Basis ret(*this); ret *= p_val; return ret; } -_FORCE_INLINE_ void Basis::operator/=(real_t p_val) { +constexpr void Basis::operator/=(real_t p_val) { rows[0] /= p_val; rows[1] /= p_val; rows[2] /= p_val; } -_FORCE_INLINE_ Basis Basis::operator/(real_t p_val) const { +constexpr Basis Basis::operator/(real_t p_val) const { Basis ret(*this); ret /= p_val; return ret; @@ -322,5 +344,3 @@ real_t Basis::determinant() const { rows[1][0] * (rows[0][1] * rows[2][2] - rows[2][1] * rows[0][2]) + rows[2][0] * (rows[0][1] * rows[1][2] - rows[1][1] * rows[0][2]); } - -#endif // BASIS_H diff --git a/engine/core/math/bvh.h b/engine/core/math/bvh.h index 4815466e..9a9dde17 100644 --- a/engine/core/math/bvh.h +++ b/engine/core/math/bvh.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef BVH_H -#define BVH_H +#pragma once // BVH // This class provides a wrapper around BVH tree, which contains most of the functionality @@ -52,6 +51,8 @@ // and pairable_mask is either 0 if static, or set to all if non static #include "bvh_tree.h" + +#include "core/math/geometry_3d.h" #include "core/os/mutex.h" #define BVHTREE_CLASS BVH_Tree @@ -405,7 +406,7 @@ public: } Vector convex_points = Geometry3D::compute_convex_mesh_points(&p_convex[0], p_convex.size()); - if (convex_points.size() == 0) { + if (convex_points.is_empty()) { return 0; } @@ -435,8 +436,6 @@ private: return; } - BOUNDS bb; - typename BVHTREE_CLASS::CullParams params; params.result_count_overall = 0; @@ -806,5 +805,3 @@ public: }; #undef BVHTREE_CLASS - -#endif // BVH_H diff --git a/engine/core/math/bvh_abb.h b/engine/core/math/bvh_abb.h index 3d32c250..b96ea085 100644 --- a/engine/core/math/bvh_abb.h +++ b/engine/core/math/bvh_abb.h @@ -28,8 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef BVH_ABB_H -#define BVH_ABB_H +#pragma once + +#include "core/math/aabb.h" // special optimized version of axis aligned bounding box template @@ -288,5 +289,3 @@ struct BVH_ABB { return false; } }; - -#endif // BVH_ABB_H diff --git a/engine/core/math/bvh_tree.h b/engine/core/math/bvh_tree.h index 2a2a6d67..76e5c999 100644 --- a/engine/core/math/bvh_tree.h +++ b/engine/core/math/bvh_tree.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef BVH_TREE_H -#define BVH_TREE_H +#pragma once // BVH Tree // This is an implementation of a dynamic BVH with templated leaf size. @@ -41,7 +40,6 @@ #include "core/math/aabb.h" #include "core/math/bvh_abb.h" -#include "core/math/geometry_3d.h" #include "core/math/vector3.h" #include "core/templates/local_vector.h" #include "core/templates/pooled_list.h" @@ -454,5 +452,3 @@ private: }; #undef VERBOSE_PRINT - -#endif // BVH_TREE_H diff --git a/engine/core/math/color.cpp b/engine/core/math/color.cpp index 4c31d814..d032a3fe 100644 --- a/engine/core/math/color.cpp +++ b/engine/core/math/color.cpp @@ -109,36 +109,27 @@ uint64_t Color::to_rgba64() const { return c; } -String _to_hex(float p_val) { +void _append_hex(float p_val, char32_t *string) { int v = Math::round(p_val * 255.0f); v = CLAMP(v, 0, 255); - String ret; - for (int i = 0; i < 2; i++) { - char32_t c[2] = { 0, 0 }; - int lv = v & 0xF; - if (lv < 10) { - c[0] = '0' + lv; - } else { - c[0] = 'a' + lv - 10; - } - - v >>= 4; - String cs = (const char32_t *)c; - ret = cs + ret; - } - - return ret; + string[0] = hex_char_table_lower[(v >> 4) & 0xF]; + string[1] = hex_char_table_lower[v & 0xF]; } String Color::to_html(bool p_alpha) const { String txt; - txt += _to_hex(r); - txt += _to_hex(g); - txt += _to_hex(b); + txt.resize(p_alpha ? 9 : 7); + char32_t *ptr = txt.ptrw(); + + _append_hex(r, ptr + 0); + _append_hex(g, ptr + 2); + _append_hex(b, ptr + 4); if (p_alpha) { - txt += _to_hex(a); + _append_hex(a, ptr + 6); } + ptr[txt.size() - 1] = '\0'; + return txt; } @@ -259,6 +250,10 @@ bool Color::is_equal_approx(const Color &p_color) const { return Math::is_equal_approx(r, p_color.r) && Math::is_equal_approx(g, p_color.g) && Math::is_equal_approx(b, p_color.b) && Math::is_equal_approx(a, p_color.a); } +bool Color::is_same(const Color &p_color) const { + return Math::is_same(r, p_color.r) && Math::is_same(g, p_color.g) && Math::is_same(b, p_color.b) && Math::is_same(a, p_color.a); +} + Color Color::clamp(const Color &p_min, const Color &p_max) const { return Color( CLAMP(r, p_min.r, p_max.r), @@ -321,47 +316,38 @@ Color Color::inverted() const { } Color Color::html(const String &p_rgba) { - String color = p_rgba; - if (color.length() == 0) { + if (p_rgba.is_empty()) { return Color(); } - if (color[0] == '#') { - color = color.substr(1); - } - // If enabled, use 1 hex digit per channel instead of 2. - // Other sizes aren't in the HTML/CSS spec but we could add them if desired. - bool is_shorthand = color.length() < 5; - bool alpha = false; + const int current_pos = (p_rgba[0] == '#') ? 1 : 0; + const int num_of_digits = p_rgba.length() - current_pos; - if (color.length() == 8) { - alpha = true; - } else if (color.length() == 6) { - alpha = false; - } else if (color.length() == 4) { - alpha = true; - } else if (color.length() == 3) { - alpha = false; + float r, g, b, a = 1.0f; + + if (num_of_digits == 3) { + // #rgb + r = _parse_col4(p_rgba, current_pos) / 15.0f; + g = _parse_col4(p_rgba, current_pos + 1) / 15.0f; + b = _parse_col4(p_rgba, current_pos + 2) / 15.0f; + } else if (num_of_digits == 4) { + r = _parse_col4(p_rgba, current_pos) / 15.0f; + g = _parse_col4(p_rgba, current_pos + 1) / 15.0f; + b = _parse_col4(p_rgba, current_pos + 2) / 15.0f; + a = _parse_col4(p_rgba, current_pos + 3) / 15.0f; + } else if (num_of_digits == 6) { + r = _parse_col8(p_rgba, current_pos) / 255.0f; + g = _parse_col8(p_rgba, current_pos + 2) / 255.0f; + b = _parse_col8(p_rgba, current_pos + 4) / 255.0f; + } else if (num_of_digits == 8) { + r = _parse_col8(p_rgba, current_pos) / 255.0f; + g = _parse_col8(p_rgba, current_pos + 2) / 255.0f; + b = _parse_col8(p_rgba, current_pos + 4) / 255.0f; + a = _parse_col8(p_rgba, current_pos + 6) / 255.0f; } else { ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_rgba + "."); } - float r, g, b, a = 1.0f; - if (is_shorthand) { - r = _parse_col4(color, 0) / 15.0f; - g = _parse_col4(color, 1) / 15.0f; - b = _parse_col4(color, 2) / 15.0f; - if (alpha) { - a = _parse_col4(color, 3) / 15.0f; - } - } else { - r = _parse_col8(color, 0) / 255.0f; - g = _parse_col8(color, 2) / 255.0f; - b = _parse_col8(color, 4) / 255.0f; - if (alpha) { - a = _parse_col8(color, 6) / 255.0f; - } - } ERR_FAIL_COND_V_MSG(r < 0.0f, Color(), "Invalid color code: " + p_rgba + "."); ERR_FAIL_COND_V_MSG(g < 0.0f, Color(), "Invalid color code: " + p_rgba + "."); ERR_FAIL_COND_V_MSG(b < 0.0f, Color(), "Invalid color code: " + p_rgba + "."); @@ -373,22 +359,20 @@ Color Color::html(const String &p_rgba) { bool Color::html_is_valid(const String &p_color) { String color = p_color; - if (color.length() == 0) { + if (color.is_empty()) { return false; } - if (color[0] == '#') { - color = color.substr(1); - } - // Check if the amount of hex digits is valid. - int len = color.length(); - if (!(len == 3 || len == 4 || len == 6 || len == 8)) { + const int current_pos = (color[0] == '#') ? 1 : 0; + const int len = color.length(); + const int num_of_digits = len - current_pos; + if (!(num_of_digits == 3 || num_of_digits == 4 || num_of_digits == 6 || num_of_digits == 8)) { return false; } // Check if each hex digit is valid. - for (int i = 0; i < len; i++) { - if (_parse_col4(color, i) == -1) { + for (int i = current_pos; i < len; i++) { + if (!is_hex_digit(p_color[i])) { return false; } } @@ -415,18 +399,14 @@ Color Color::named(const String &p_name, const Color &p_default) { int Color::find_named_color(const String &p_name) { String name = p_name; // Normalize name. - name = name.replace(" ", ""); - name = name.replace("-", ""); - name = name.replace("_", ""); - name = name.replace("'", ""); - name = name.replace(".", ""); + name = name.remove_chars(" -_'."); name = name.to_upper(); static HashMap named_colors_hashmap; if (unlikely(named_colors_hashmap.is_empty())) { const int named_color_count = get_named_color_count(); for (int i = 0; i < named_color_count; i++) { - named_colors_hashmap[String(named_colors[i].name).replace("_", "")] = i; + named_colors_hashmap[String(named_colors[i].name).remove_char('_')] = i; } } @@ -439,7 +419,7 @@ int Color::find_named_color(const String &p_name) { } int Color::get_named_color_count() { - return sizeof(named_colors) / sizeof(NamedColor); + return std::size(named_colors); } String Color::get_named_color_name(int p_idx) { @@ -490,104 +470,6 @@ Color::operator String() const { return "(" + String::num(r, 4) + ", " + String::num(g, 4) + ", " + String::num(b, 4) + ", " + String::num(a, 4) + ")"; } -Color Color::operator+(const Color &p_color) const { - return Color( - r + p_color.r, - g + p_color.g, - b + p_color.b, - a + p_color.a); -} - -void Color::operator+=(const Color &p_color) { - r = r + p_color.r; - g = g + p_color.g; - b = b + p_color.b; - a = a + p_color.a; -} - -Color Color::operator-(const Color &p_color) const { - return Color( - r - p_color.r, - g - p_color.g, - b - p_color.b, - a - p_color.a); -} - -void Color::operator-=(const Color &p_color) { - r = r - p_color.r; - g = g - p_color.g; - b = b - p_color.b; - a = a - p_color.a; -} - -Color Color::operator*(const Color &p_color) const { - return Color( - r * p_color.r, - g * p_color.g, - b * p_color.b, - a * p_color.a); -} - -Color Color::operator*(float p_scalar) const { - return Color( - r * p_scalar, - g * p_scalar, - b * p_scalar, - a * p_scalar); -} - -void Color::operator*=(const Color &p_color) { - r = r * p_color.r; - g = g * p_color.g; - b = b * p_color.b; - a = a * p_color.a; -} - -void Color::operator*=(float p_scalar) { - r = r * p_scalar; - g = g * p_scalar; - b = b * p_scalar; - a = a * p_scalar; -} - -Color Color::operator/(const Color &p_color) const { - return Color( - r / p_color.r, - g / p_color.g, - b / p_color.b, - a / p_color.a); -} - -Color Color::operator/(float p_scalar) const { - return Color( - r / p_scalar, - g / p_scalar, - b / p_scalar, - a / p_scalar); -} - -void Color::operator/=(const Color &p_color) { - r = r / p_color.r; - g = g / p_color.g; - b = b / p_color.b; - a = a / p_color.a; -} - -void Color::operator/=(float p_scalar) { - r = r / p_scalar; - g = g / p_scalar; - b = b / p_scalar; - a = a / p_scalar; -} - -Color Color::operator-() const { - return Color( - 1.0f - r, - 1.0f - g, - 1.0f - b, - 1.0f - a); -} - Color Color::from_ok_hsl(float p_h, float p_s, float p_l, float p_alpha) { Color c; c.set_ok_hsl(p_h, p_s, p_l, p_alpha); diff --git a/engine/core/math/color.h b/engine/core/math/color.h index c2ffde18..ae91677d 100644 --- a/engine/core/math/color.h +++ b/engine/core/math/color.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef COLOR_H -#define COLOR_H +#pragma once #include "core/math/math_funcs.h" @@ -37,6 +36,7 @@ class String; struct [[nodiscard]] Color { union { + // NOLINTBEGIN(modernize-use-default-member-init) struct { float r; float g; @@ -44,6 +44,7 @@ struct [[nodiscard]] Color { float a; }; float components[4] = { 0, 0, 0, 1.0 }; + // NOLINTEND(modernize-use-default-member-init) }; uint32_t to_rgba32() const; @@ -69,31 +70,32 @@ struct [[nodiscard]] Color { return components[p_idx]; } - bool operator==(const Color &p_color) const { + constexpr bool operator==(const Color &p_color) const { return (r == p_color.r && g == p_color.g && b == p_color.b && a == p_color.a); } - bool operator!=(const Color &p_color) const { + constexpr bool operator!=(const Color &p_color) const { return (r != p_color.r || g != p_color.g || b != p_color.b || a != p_color.a); } - Color operator+(const Color &p_color) const; - void operator+=(const Color &p_color); + constexpr Color operator+(const Color &p_color) const; + constexpr void operator+=(const Color &p_color); - Color operator-() const; - Color operator-(const Color &p_color) const; - void operator-=(const Color &p_color); + constexpr Color operator-() const; + constexpr Color operator-(const Color &p_color) const; + constexpr void operator-=(const Color &p_color); - Color operator*(const Color &p_color) const; - Color operator*(float p_scalar) const; - void operator*=(const Color &p_color); - void operator*=(float p_scalar); + constexpr Color operator*(const Color &p_color) const; + constexpr Color operator*(float p_scalar) const; + constexpr void operator*=(const Color &p_color); + constexpr void operator*=(float p_scalar); - Color operator/(const Color &p_color) const; - Color operator/(float p_scalar) const; - void operator/=(const Color &p_color); - void operator/=(float p_scalar); + constexpr Color operator/(const Color &p_color) const; + constexpr Color operator/(float p_scalar) const; + constexpr void operator/=(const Color &p_color); + constexpr void operator/=(float p_scalar); bool is_equal_approx(const Color &p_color) const; + bool is_same(const Color &p_color) const; Color clamp(const Color &p_min = Color(0, 0, 0, 0), const Color &p_max = Color(1, 1, 1, 1)) const; void invert(); @@ -215,7 +217,7 @@ struct [[nodiscard]] Color { static Color from_rgbe9995(uint32_t p_rgbe); static Color from_rgba8(int64_t p_r8, int64_t p_g8, int64_t p_b8, int64_t p_a8 = 255); - _FORCE_INLINE_ bool operator<(const Color &p_color) const; // Used in set keys. + constexpr bool operator<(const Color &p_color) const; // Used in set keys. operator String() const; // For the binder. @@ -235,39 +237,29 @@ struct [[nodiscard]] Color { _FORCE_INLINE_ void set_ok_hsl_s(float p_s) { set_ok_hsl(get_ok_hsl_h(), p_s, get_ok_hsl_l(), a); } _FORCE_INLINE_ void set_ok_hsl_l(float p_l) { set_ok_hsl(get_ok_hsl_h(), get_ok_hsl_s(), p_l, a); } - _FORCE_INLINE_ Color() {} + constexpr Color() : + r(0), g(0), b(0), a(1) {} /** * RGBA construct parameters. * Alpha is not optional as otherwise we can't bind the RGB version for scripting. */ - _FORCE_INLINE_ Color(float p_r, float p_g, float p_b, float p_a) { - r = p_r; - g = p_g; - b = p_b; - a = p_a; - } + constexpr Color(float p_r, float p_g, float p_b, float p_a) : + r(p_r), g(p_g), b(p_b), a(p_a) {} /** * RGB construct parameters. */ - _FORCE_INLINE_ Color(float p_r, float p_g, float p_b) { - r = p_r; - g = p_g; - b = p_b; - a = 1.0f; - } + constexpr Color(float p_r, float p_g, float p_b) : + r(p_r), g(p_g), b(p_b), a(1) {} /** * Construct a Color from another Color, but with the specified alpha value. */ - _FORCE_INLINE_ Color(const Color &p_c, float p_a) { - r = p_c.r; - g = p_c.g; - b = p_c.b; - a = p_a; - } + constexpr Color(const Color &p_c, float p_a) : + r(p_c.r), g(p_c.g), b(p_c.b), a(p_a) {} + // NOLINTBEGIN(cppcoreguidelines-pro-type-member-init) Color(const String &p_code) { if (html_is_valid(p_code)) { *this = html(p_code); @@ -280,9 +272,108 @@ struct [[nodiscard]] Color { *this = Color(p_code); a = p_a; } + // NOLINTEND(cppcoreguidelines-pro-type-member-init) }; -bool Color::operator<(const Color &p_color) const { +constexpr Color Color::operator+(const Color &p_color) const { + return Color( + r + p_color.r, + g + p_color.g, + b + p_color.b, + a + p_color.a); +} + +constexpr void Color::operator+=(const Color &p_color) { + r = r + p_color.r; + g = g + p_color.g; + b = b + p_color.b; + a = a + p_color.a; +} + +constexpr Color Color::operator-(const Color &p_color) const { + return Color( + r - p_color.r, + g - p_color.g, + b - p_color.b, + a - p_color.a); +} + +constexpr void Color::operator-=(const Color &p_color) { + r = r - p_color.r; + g = g - p_color.g; + b = b - p_color.b; + a = a - p_color.a; +} + +constexpr Color Color::operator*(const Color &p_color) const { + return Color( + r * p_color.r, + g * p_color.g, + b * p_color.b, + a * p_color.a); +} + +constexpr Color Color::operator*(float p_scalar) const { + return Color( + r * p_scalar, + g * p_scalar, + b * p_scalar, + a * p_scalar); +} + +constexpr void Color::operator*=(const Color &p_color) { + r = r * p_color.r; + g = g * p_color.g; + b = b * p_color.b; + a = a * p_color.a; +} + +constexpr void Color::operator*=(float p_scalar) { + r = r * p_scalar; + g = g * p_scalar; + b = b * p_scalar; + a = a * p_scalar; +} + +constexpr Color Color::operator/(const Color &p_color) const { + return Color( + r / p_color.r, + g / p_color.g, + b / p_color.b, + a / p_color.a); +} + +constexpr Color Color::operator/(float p_scalar) const { + return Color( + r / p_scalar, + g / p_scalar, + b / p_scalar, + a / p_scalar); +} + +constexpr void Color::operator/=(const Color &p_color) { + r = r / p_color.r; + g = g / p_color.g; + b = b / p_color.b; + a = a / p_color.a; +} + +constexpr void Color::operator/=(float p_scalar) { + r = r / p_scalar; + g = g / p_scalar; + b = b / p_scalar; + a = a / p_scalar; +} + +constexpr Color Color::operator-() const { + return Color( + 1.0f - r, + 1.0f - g, + 1.0f - b, + 1.0f - a); +} + +constexpr bool Color::operator<(const Color &p_color) const { if (r == p_color.r) { if (g == p_color.g) { if (b == p_color.b) { @@ -298,8 +389,6 @@ bool Color::operator<(const Color &p_color) const { } } -_FORCE_INLINE_ Color operator*(float p_scalar, const Color &p_color) { +constexpr Color operator*(float p_scalar, const Color &p_color) { return p_color * p_scalar; } - -#endif // COLOR_H diff --git a/engine/core/math/color_names.inc b/engine/core/math/color_names.inc index 6c0d2a4b..969acc68 100644 --- a/engine/core/math/color_names.inc +++ b/engine/core/math/color_names.inc @@ -28,12 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ +#pragma once + // Names from https://en.wikipedia.org/wiki/X11_color_names // So this in a way that does not require memory allocation // the old way leaked memory // this is not used as often as for more performance to make sense +#include "core/math/color.h" + struct NamedColor { const char *name; Color color; diff --git a/engine/core/math/convex_hull.cpp b/engine/core/math/convex_hull.cpp index 4052234f..fbd367b9 100644 --- a/engine/core/math/convex_hull.cpp +++ b/engine/core/math/convex_hull.cpp @@ -2237,7 +2237,7 @@ real_t ConvexHullComputer::compute(const Vector3 *p_coords, int32_t p_count, rea Error ConvexHullComputer::convex_hull(const Vector &p_points, Geometry3D::MeshData &r_mesh) { r_mesh = Geometry3D::MeshData(); // clear - if (p_points.size() == 0) { + if (p_points.is_empty()) { return FAILED; // matches QuickHull } diff --git a/engine/core/math/convex_hull.h b/engine/core/math/convex_hull.h index 75787f7b..9af39790 100644 --- a/engine/core/math/convex_hull.h +++ b/engine/core/math/convex_hull.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef CONVEX_HULL_H -#define CONVEX_HULL_H +#pragma once /* Copyright (c) 2011 Ole Kniemeyer, MAXON, www.maxon.net @@ -112,5 +111,3 @@ public: static Error convex_hull(const Vector &p_points, Geometry3D::MeshData &r_mesh); }; - -#endif // CONVEX_HULL_H diff --git a/engine/core/math/delaunay_2d.h b/engine/core/math/delaunay_2d.h index 0bc67a92..cb0eca2b 100644 --- a/engine/core/math/delaunay_2d.h +++ b/engine/core/math/delaunay_2d.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef DELAUNAY_2D_H -#define DELAUNAY_2D_H +#pragma once #include "core/math/rect2.h" #include "core/templates/vector.h" @@ -156,5 +155,3 @@ public: return triangles; } }; - -#endif // DELAUNAY_2D_H diff --git a/engine/core/math/delaunay_3d.h b/engine/core/math/delaunay_3d.h index 5bbdcc09..122ff945 100644 --- a/engine/core/math/delaunay_3d.h +++ b/engine/core/math/delaunay_3d.h @@ -28,17 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef DELAUNAY_3D_H -#define DELAUNAY_3D_H +#pragma once -#include "core/io/file_access.h" #include "core/math/aabb.h" #include "core/math/projection.h" #include "core/math/vector3.h" +#include "core/templates/list.h" #include "core/templates/local_vector.h" #include "core/templates/oa_hash_map.h" #include "core/templates/vector.h" -#include "core/variant/variant.h" #include "thirdparty/misc/r128.h" @@ -187,7 +185,7 @@ class Delaunay3D { Plane p(p_points[p_simplex.points[i]], p_points[p_simplex.points[(i + 1) % 4]], p_points[p_simplex.points[(i + 2) % 4]]); // This tolerance should not be smaller than the one used with // Plane::has_point() when creating the LightmapGI probe BSP tree. - if (ABS(p.distance_to(p_points[p_simplex.points[(i + 3) % 4]])) < 0.001) { + if (Math::abs(p.distance_to(p_points[p_simplex.points[(i + 3) % 4]])) < 0.001) { return true; } } @@ -389,5 +387,3 @@ public: return ret_simplices; } }; - -#endif // DELAUNAY_3D_H diff --git a/engine/core/math/disjoint_set.h b/engine/core/math/disjoint_set.h index 4348da99..9345375f 100644 --- a/engine/core/math/disjoint_set.h +++ b/engine/core/math/disjoint_set.h @@ -28,10 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef DISJOINT_SET_H -#define DISJOINT_SET_H +#pragma once -#include "core/templates/rb_map.h" +#include "core/templates/hash_map.h" #include "core/templates/vector.h" /* This DisjointSet class uses Find with path compression and Union by rank */ @@ -146,5 +145,3 @@ void DisjointSet::get_members(Vector &out_members, T representat } } } - -#endif // DISJOINT_SET_H diff --git a/engine/core/math/dynamic_bvh.cpp b/engine/core/math/dynamic_bvh.cpp index e1315d1c..1195072a 100644 --- a/engine/core/math/dynamic_bvh.cpp +++ b/engine/core/math/dynamic_bvh.cpp @@ -181,7 +181,7 @@ DynamicBVH::Volume DynamicBVH::_bounds(Node **leaves, int p_count) { void DynamicBVH::_bottom_up(Node **leaves, int p_count) { while (p_count > 1) { - real_t minsize = INFINITY; + real_t minsize = Math::INF; int minidx[2] = { -1, -1 }; for (int i = 0; i < p_count; ++i) { for (int j = i + 1; j < p_count; ++j) { diff --git a/engine/core/math/dynamic_bvh.h b/engine/core/math/dynamic_bvh.h index 26fc517f..10e4e063 100644 --- a/engine/core/math/dynamic_bvh.h +++ b/engine/core/math/dynamic_bvh.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef DYNAMIC_BVH_H -#define DYNAMIC_BVH_H +#pragma once #include "core/math/aabb.h" #include "core/templates/list.h" @@ -474,5 +473,3 @@ void DynamicBVH::ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResu } } while (depth > 0); } - -#endif // DYNAMIC_BVH_H diff --git a/engine/core/math/expression.cpp b/engine/core/math/expression.cpp index 26b773a2..0bfc8def 100644 --- a/engine/core/math/expression.cpp +++ b/engine/core/math/expression.cpp @@ -454,16 +454,16 @@ Error Expression::_get_token(Token &r_token) { r_token.value = false; } else if (id == "PI") { r_token.type = TK_CONSTANT; - r_token.value = Math_PI; + r_token.value = Math::PI; } else if (id == "TAU") { r_token.type = TK_CONSTANT; - r_token.value = Math_TAU; + r_token.value = Math::TAU; } else if (id == "INF") { r_token.type = TK_CONSTANT; - r_token.value = INFINITY; + r_token.value = Math::INF; } else if (id == "NAN") { r_token.type = TK_CONSTANT; - r_token.value = NAN; + r_token.value = Math::NaN; } else if (id == "not") { r_token.type = TK_OP_NOT; } else if (id == "or") { diff --git a/engine/core/math/expression.h b/engine/core/math/expression.h index 46bc3618..aea714cf 100644 --- a/engine/core/math/expression.h +++ b/engine/core/math/expression.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef EXPRESSION_H -#define EXPRESSION_H +#pragma once #include "core/object/ref_counted.h" @@ -271,5 +270,3 @@ public: Expression() {} ~Expression(); }; - -#endif // EXPRESSION_H diff --git a/engine/core/math/face3.cpp b/engine/core/math/face3.cpp index 1dff0ee4..b9ab85e4 100644 --- a/engine/core/math/face3.cpp +++ b/engine/core/math/face3.cpp @@ -263,7 +263,7 @@ void Face3::get_support(const Vector3 &p_normal, const Transform3D &p_transform, // check if edge is valid as a support real_t dot = (vertex[i] - vertex[(i + 1) % 3]).normalized().dot(n); - dot = ABS(dot); + dot = Math::abs(dot); if (dot < edge_support_threshold) { *p_count = MIN(2, p_max); diff --git a/engine/core/math/face3.h b/engine/core/math/face3.h index 519dcb64..b7472f9d 100644 --- a/engine/core/math/face3.h +++ b/engine/core/math/face3.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef FACE3_H -#define FACE3_H +#pragma once #include "core/math/aabb.h" #include "core/math/plane.h" @@ -79,12 +78,9 @@ struct [[nodiscard]] Face3 { _FORCE_INLINE_ bool intersects_aabb2(const AABB &p_aabb) const; operator String() const; - inline Face3() {} - inline Face3(const Vector3 &p_v1, const Vector3 &p_v2, const Vector3 &p_v3) { - vertex[0] = p_v1; - vertex[1] = p_v2; - vertex[2] = p_v3; - } + Face3() = default; + constexpr Face3(const Vector3 &p_v1, const Vector3 &p_v2, const Vector3 &p_v3) : + vertex{ p_v1, p_v2, p_v3 } {} }; bool Face3::intersects_aabb2(const AABB &p_aabb) const { @@ -238,4 +234,5 @@ bool Face3::intersects_aabb2(const AABB &p_aabb) const { return true; } -#endif // FACE3_H +template <> +struct is_zero_constructible : std::true_type {}; diff --git a/engine/core/math/geometry_2d.cpp b/engine/core/math/geometry_2d.cpp index 376d5d0b..30ea79a0 100644 --- a/engine/core/math/geometry_2d.cpp +++ b/engine/core/math/geometry_2d.cpp @@ -38,17 +38,63 @@ const int clipper_precision = 5; // Based on CMP_EPSILON. const double clipper_scale = Math::pow(10.0, clipper_precision); -Vector> Geometry2D::decompose_polygon_in_convex(const Vector &polygon) { +void Geometry2D::merge_many_polygons(const Vector> &p_polygons, Vector> &r_out_polygons, Vector> &r_out_holes) { + using namespace Clipper2Lib; + + PathsD subjects; + for (const Vector &polygon : p_polygons) { + PathD path(polygon.size()); + for (int i = 0; i < polygon.size(); i++) { + const Vector2 &point = polygon[i]; + path[i] = PointD(point.x, point.y); + } + subjects.push_back(path); + } + + PathsD solution = Union(subjects, FillRule::NonZero); + solution = SimplifyPaths(solution, 0.01); + + r_out_polygons.clear(); + r_out_holes.clear(); + for (PathsD::size_type i = 0; i < solution.size(); ++i) { + PathD &path = solution[i]; + + Vector output_polygon; + output_polygon.resize(path.size()); + for (PathsD::size_type j = 0; j < path.size(); ++j) { + output_polygon.set(j, Vector2(static_cast(path[j].x), static_cast(path[j].y))); + } + if (IsPositive(path)) { + r_out_polygons.push_back(output_polygon); + } else { + r_out_holes.push_back(output_polygon); + } + } +} + +Vector> Geometry2D::decompose_many_polygons_in_convex(const Vector> &p_polygons, const Vector> &p_holes) { Vector> decomp; List in_poly, out_poly; - TPPLPoly inp; - inp.Init(polygon.size()); - for (int i = 0; i < polygon.size(); i++) { - inp.GetPoint(i) = polygon[i]; + for (const Vector &polygon : p_polygons) { + TPPLPoly inp; + inp.Init(polygon.size()); + for (int i = 0; i < polygon.size(); i++) { + inp.GetPoint(i) = polygon[i]; + } + inp.SetOrientation(TPPL_ORIENTATION_CCW); + in_poly.push_back(inp); + } + for (const Vector &polygon : p_holes) { + TPPLPoly inp; + inp.Init(polygon.size()); + for (int i = 0; i < polygon.size(); i++) { + inp.GetPoint(i) = polygon[i]; + } + inp.SetOrientation(TPPL_ORIENTATION_CW); + inp.SetHole(true); + in_poly.push_back(inp); } - inp.SetOrientation(TPPL_ORIENTATION_CCW); - in_poly.push_back(inp); TPPLPartition tpart; if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { // Failed. ERR_PRINT("Convex decomposing failed!"); @@ -57,9 +103,7 @@ Vector> Geometry2D::decompose_polygon_in_convex(const Vector::Element *I = out_poly.front(); I; I = I->next()) { - TPPLPoly &tp = I->get(); - + for (TPPLPoly &tp : out_poly) { decomp.write[idx].resize(tp.GetNumPoints()); for (int64_t i = 0; i < tp.GetNumPoints(); i++) { @@ -72,6 +116,10 @@ Vector> Geometry2D::decompose_polygon_in_convex(const Vector> Geometry2D::decompose_polygon_in_convex(const Vector &p_polygon) { + return Geometry2D::decompose_many_polygons_in_convex({ p_polygon }, {}); +} + struct _AtlasWorkRect { Size2i s; Point2i p; diff --git a/engine/core/math/geometry_2d.h b/engine/core/math/geometry_2d.h index abd395d8..fa5b0f06 100644 --- a/engine/core/math/geometry_2d.h +++ b/engine/core/math/geometry_2d.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GEOMETRY_2D_H -#define GEOMETRY_2D_H +#pragma once #include "core/math/delaunay_2d.h" #include "core/math/math_funcs.h" @@ -100,27 +99,39 @@ public: return Math::sqrt((c1 - c2).dot(c1 - c2)); } +#ifndef DISABLE_DEPRECATED static Vector2 get_closest_point_to_segment(const Vector2 &p_point, const Vector2 *p_segment) { - Vector2 p = p_point - p_segment[0]; - Vector2 n = p_segment[1] - p_segment[0]; + return get_closest_point_to_segment(p_point, p_segment[0], p_segment[1]); + } +#endif // DISABLE_DEPRECATED + + static Vector2 get_closest_point_to_segment(const Vector2 &p_point, const Vector2 &p_segment_a, const Vector2 &p_segment_b) { + Vector2 p = p_point - p_segment_a; + Vector2 n = p_segment_b - p_segment_a; real_t l2 = n.length_squared(); if (l2 < 1e-20f) { - return p_segment[0]; // Both points are the same, just give any. + return p_segment_a; // Both points are the same, just give any. } real_t d = n.dot(p) / l2; if (d <= 0.0f) { - return p_segment[0]; // Before first point. + return p_segment_a; // Before first point. } else if (d >= 1.0f) { - return p_segment[1]; // After first point. + return p_segment_b; // After first point. } else { - return p_segment[0] + n * d; // Inside. + return p_segment_a + n * d; // Inside. } } +#ifndef DISABLE_DEPRECATED static real_t get_distance_to_segment(const Vector2 &p_point, const Vector2 *p_segment) { - return p_point.distance_to(get_closest_point_to_segment(p_point, p_segment)); + return get_distance_to_segment(p_point, p_segment[0], p_segment[1]); + } +#endif // DISABLE_DEPRECATED + + static real_t get_distance_to_segment(const Vector2 &p_point, const Vector2 &p_segment_a, const Vector2 &p_segment_b) { + return p_point.distance_to(get_closest_point_to_segment(p_point, p_segment_a, p_segment_b)); } static bool is_point_in_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) { @@ -137,24 +148,26 @@ public: return (cn.cross(an) > 0) == orientation; } +#ifndef DISABLE_DEPRECATED static Vector2 get_closest_point_to_segment_uncapped(const Vector2 &p_point, const Vector2 *p_segment) { - Vector2 p = p_point - p_segment[0]; - Vector2 n = p_segment[1] - p_segment[0]; + return get_closest_point_to_segment_uncapped(p_point, p_segment[0], p_segment[1]); + } +#endif // DISABLE_DEPRECATED + + static Vector2 get_closest_point_to_segment_uncapped(const Vector2 &p_point, const Vector2 &p_segment_a, const Vector2 &p_segment_b) { + Vector2 p = p_point - p_segment_a; + Vector2 n = p_segment_b - p_segment_a; real_t l2 = n.length_squared(); if (l2 < 1e-20f) { - return p_segment[0]; // Both points are the same, just give any. + return p_segment_a; // Both points are the same, just give any. } real_t d = n.dot(p) / l2; - return p_segment[0] + n * d; // Inside. + return p_segment_a + n * d; // Inside. } -// Disable False Positives in MSVC compiler; we correctly check for 0 here to prevent a division by 0. -// See: https://github.com/godotengine/godot/pull/44274 -#ifdef _MSC_VER -#pragma warning(disable : 4723) -#endif + GODOT_MSVC_WARNING_PUSH_AND_IGNORE(4723) // Potential divide by 0. False positive (see: GH-44274). static bool line_intersects_line(const Vector2 &p_from_a, const Vector2 &p_dir_a, const Vector2 &p_from_b, const Vector2 &p_dir_b, Vector2 &r_result) { // See http://paulbourke.net/geometry/pointlineplane/ @@ -170,10 +183,7 @@ public: return true; } -// Re-enable division by 0 warning -#ifdef _MSC_VER -#pragma warning(default : 4723) -#endif + GODOT_MSVC_WARNING_POP static bool segment_intersects_segment(const Vector2 &p_from_a, const Vector2 &p_to_a, const Vector2 &p_from_b, const Vector2 &p_to_b, Vector2 *r_result) { Vector2 B = p_to_a - p_from_a; @@ -489,7 +499,10 @@ public: return points; } - static Vector> decompose_polygon_in_convex(const Vector &polygon); + static void merge_many_polygons(const Vector> &p_polygons, Vector> &r_out_polygons, Vector> &r_out_holes); + static Vector> decompose_many_polygons_in_convex(const Vector> &p_polygons, const Vector> &p_holes); + + static Vector> decompose_polygon_in_convex(const Vector &p_polygon); static void make_atlas(const Vector &p_rects, Vector &r_result, Size2i &r_size); static Vector partial_pack_rects(const Vector &p_sizes, const Size2i &p_atlas_size); @@ -498,5 +511,3 @@ private: static Vector> _polypaths_do_operation(PolyBooleanOperation p_op, const Vector &p_polypath_a, const Vector &p_polypath_b, bool is_a_open = false); static Vector> _polypath_offset(const Vector &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type); }; - -#endif // GEOMETRY_2D_H diff --git a/engine/core/math/geometry_3d.cpp b/engine/core/math/geometry_3d.cpp index 361a0607..71559ead 100644 --- a/engine/core/math/geometry_3d.cpp +++ b/engine/core/math/geometry_3d.cpp @@ -30,6 +30,8 @@ #include "geometry_3d.h" +#include "core/templates/hash_map.h" + void Geometry3D::get_closest_points_between_segments(const Vector3 &p_p0, const Vector3 &p_p1, const Vector3 &p_q0, const Vector3 &p_q1, Vector3 &r_ps, Vector3 &r_qt) { // Based on David Eberly's Computation of Distance Between Line Segments algorithm. @@ -593,7 +595,7 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector &p_planes Vector3 ref = Vector3(0.0, 1.0, 0.0); - if (ABS(p.normal.dot(ref)) > 0.95f) { + if (Math::abs(p.normal.dot(ref)) > 0.95f) { ref = Vector3(0.0, 0.0, 1.0); // Change axis. } @@ -742,7 +744,7 @@ Vector Geometry3D::build_cylinder_planes(real_t p_radius, real_t p_height Vector planes; - const double sides_step = Math_TAU / p_sides; + const double sides_step = Math::TAU / p_sides; for (int i = 0; i < p_sides; i++) { Vector3 normal; normal[(p_axis + 1) % 3] = Math::cos(i * sides_step); @@ -773,7 +775,7 @@ Vector Geometry3D::build_sphere_planes(real_t p_radius, int p_lats, int p axis_neg[(p_axis + 2) % 3] = 1.0; axis_neg[p_axis] = -1.0; - const double lon_step = Math_TAU / p_lons; + const double lon_step = Math::TAU / p_lons; for (int i = 0; i < p_lons; i++) { Vector3 normal; normal[(p_axis + 1) % 3] = Math::cos(i * lon_step); @@ -804,7 +806,7 @@ Vector Geometry3D::build_capsule_planes(real_t p_radius, real_t p_height, axis_neg[(p_axis + 2) % 3] = 1.0; axis_neg[p_axis] = -1.0; - const double sides_step = Math_TAU / p_sides; + const double sides_step = Math::TAU / p_sides; for (int i = 0; i < p_sides; i++) { Vector3 normal; normal[(p_axis + 1) % 3] = Math::cos(i * sides_step); @@ -860,7 +862,6 @@ Vector Geometry3D::compute_convex_mesh_points(const Plane *p_planes, in } #define square(m_s) ((m_s) * (m_s)) -#define INF 1e20 /* dt of 1d function using squared distance */ static void edt(float *f, int stride, int n) { @@ -870,8 +871,8 @@ static void edt(float *f, int stride, int n) { int k = 0; v[0] = 0; - z[0] = -INF; - z[1] = +INF; + z[0] = -Math::INF; + z[1] = +Math::INF; for (int q = 1; q <= n - 1; q++) { float s = ((f[q * stride] + square(q)) - (f[v[k] * stride] + square(v[k]))) / (2 * q - 2 * v[k]); while (s <= z[k]) { @@ -882,7 +883,7 @@ static void edt(float *f, int stride, int n) { v[k] = q; z[k] = s; - z[k + 1] = +INF; + z[k + 1] = +Math::INF; } k = 0; @@ -907,7 +908,7 @@ Vector Geometry3D::generate_edf(const Vector &p_voxels, const Ve float *work_memory = memnew_arr(float, float_count); for (uint32_t i = 0; i < float_count; i++) { - work_memory[i] = INF; + work_memory[i] = Math::INF; } uint32_t y_mult = p_size.x; diff --git a/engine/core/math/geometry_3d.h b/engine/core/math/geometry_3d.h index ff39d825..bd8dbe43 100644 --- a/engine/core/math/geometry_3d.h +++ b/engine/core/math/geometry_3d.h @@ -28,12 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GEOMETRY_3D_H -#define GEOMETRY_3D_H +#pragma once #include "core/math/delaunay_3d.h" #include "core/math/face3.h" -#include "core/object/object.h" #include "core/templates/local_vector.h" #include "core/templates/vector.h" @@ -274,7 +272,7 @@ public: return true; } - static bool segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const Plane *p_planes, int p_plane_count, Vector3 *p_res, Vector3 *p_norm) { + static bool segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const Plane *p_planes, int p_plane_count, Vector3 *r_res, Vector3 *r_norm) { real_t min = -1e20, max = 1e20; Vector3 rel = p_to - p_from; @@ -317,46 +315,58 @@ public: return false; // No intersection. } - if (p_res) { - *p_res = p_from + dir * min; + if (r_res) { + *r_res = p_from + dir * min; } - if (p_norm) { - *p_norm = p_planes[min_index].normal; + if (r_norm) { + *r_norm = p_planes[min_index].normal; } return true; } +#ifndef DISABLE_DEPRECATED static Vector3 get_closest_point_to_segment(const Vector3 &p_point, const Vector3 *p_segment) { - Vector3 p = p_point - p_segment[0]; - Vector3 n = p_segment[1] - p_segment[0]; + return get_closest_point_to_segment(p_point, p_segment[0], p_segment[1]); + } +#endif // DISABLE_DEPRECATED + + static Vector3 get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_segment_a, const Vector3 &p_segment_b) { + Vector3 p = p_point - p_segment_a; + Vector3 n = p_segment_b - p_segment_a; real_t l2 = n.length_squared(); if (l2 < 1e-20f) { - return p_segment[0]; // Both points are the same, just give any. + return p_segment_a; // Both points are the same, just give any. } real_t d = n.dot(p) / l2; if (d <= 0.0f) { - return p_segment[0]; // Before first point. + return p_segment_a; // Before first point. } else if (d >= 1.0f) { - return p_segment[1]; // After first point. + return p_segment_b; // After first point. } else { - return p_segment[0] + n * d; // Inside. + return p_segment_a + n * d; // Inside. } } +#ifndef DISABLE_DEPRECATED static Vector3 get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 *p_segment) { - Vector3 p = p_point - p_segment[0]; - Vector3 n = p_segment[1] - p_segment[0]; + return get_closest_point_to_segment_uncapped(p_point, p_segment[0], p_segment[1]); + } +#endif // DISABLE_DEPRECATED + + static Vector3 get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_segment_a, const Vector3 &p_segment_b) { + Vector3 p = p_point - p_segment_a; + Vector3 n = p_segment_b - p_segment_a; real_t l2 = n.length_squared(); if (l2 < 1e-20f) { - return p_segment[0]; // Both points are the same, just give any. + return p_segment_a; // Both points are the same, just give any. } real_t d = n.dot(p) / l2; - return p_segment[0] + n * d; // Inside. + return p_segment_a + n * d; // Inside. } static inline bool point_in_projected_triangle(const Vector3 &p_point, const Vector3 &p_v1, const Vector3 &p_v2, const Vector3 &p_v3) { @@ -383,8 +393,14 @@ public: return true; } +#ifndef DISABLE_DEPRECATED static inline bool triangle_sphere_intersection_test(const Vector3 *p_triangle, const Vector3 &p_normal, const Vector3 &p_sphere_pos, real_t p_sphere_radius, Vector3 &r_triangle_contact, Vector3 &r_sphere_contact) { - real_t d = p_normal.dot(p_sphere_pos) - p_normal.dot(p_triangle[0]); + return triangle_sphere_intersection_test(p_triangle[0], p_triangle[1], p_triangle[2], p_normal, p_sphere_pos, p_sphere_radius, r_triangle_contact, r_sphere_contact); + } +#endif // DISABLE_DEPRECATED + + static inline bool triangle_sphere_intersection_test(const Vector3 &p_triangle_a, const Vector3 &p_triangle_b, const Vector3 &p_triangle_c, const Vector3 &p_normal, const Vector3 &p_sphere_pos, real_t p_sphere_radius, Vector3 &r_triangle_contact, Vector3 &r_sphere_contact) { + real_t d = p_normal.dot(p_sphere_pos) - p_normal.dot(p_triangle_a); if (d > p_sphere_radius || d < -p_sphere_radius) { // Not touching the plane of the face, return. @@ -395,7 +411,7 @@ public: /** 2nd) TEST INSIDE TRIANGLE **/ - if (Geometry3D::point_in_projected_triangle(contact, p_triangle[0], p_triangle[1], p_triangle[2])) { + if (Geometry3D::point_in_projected_triangle(contact, p_triangle_a, p_triangle_b, p_triangle_c)) { r_triangle_contact = contact; r_sphere_contact = p_sphere_pos - p_normal * p_sphere_radius; //printf("solved inside triangle\n"); @@ -404,7 +420,7 @@ public: /** 3rd TEST INSIDE EDGE CYLINDERS **/ - const Vector3 verts[4] = { p_triangle[0], p_triangle[1], p_triangle[2], p_triangle[0] }; // for() friendly + const Vector3 verts[4] = { p_triangle_a, p_triangle_b, p_triangle_c, p_triangle_a }; // for() friendly for (int i = 0; i < 3; i++) { // Check edge cylinder. @@ -420,7 +436,7 @@ public: real_t ad = axis.dot(n2); - if (ABS(ad) > p_sphere_radius) { + if (Math::abs(ad) > p_sphere_radius) { // No chance with this edge, too far away. continue; } @@ -468,7 +484,7 @@ public: LOC_OUTSIDE = -1 }; - if (polygon.size() == 0) { + if (polygon.is_empty()) { return polygon; } @@ -840,5 +856,3 @@ public: return n.normalized(); } }; - -#endif // GEOMETRY_3D_H diff --git a/engine/core/math/math_defs.h b/engine/core/math/math_defs.h index fe53121a..5a9be58c 100644 --- a/engine/core/math/math_defs.h +++ b/engine/core/math/math_defs.h @@ -28,8 +28,24 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef MATH_DEFS_H -#define MATH_DEFS_H +#pragma once + +#include "core/typedefs.h" + +#include + +namespace Math { +inline constexpr double SQRT2 = 1.4142135623730950488016887242; +inline constexpr double SQRT3 = 1.7320508075688772935274463415059; +inline constexpr double SQRT12 = 0.7071067811865475244008443621048490; +inline constexpr double SQRT13 = 0.57735026918962576450914878050196; +inline constexpr double LN2 = 0.6931471805599453094172321215; +inline constexpr double TAU = 6.2831853071795864769252867666; +inline constexpr double PI = 3.1415926535897932384626433833; +inline constexpr double E = 2.7182818284590452353602874714; +inline constexpr double INF = std::numeric_limits::infinity(); +inline constexpr double NaN = std::numeric_limits::quiet_NaN(); +} // namespace Math #define CMP_EPSILON 0.00001 #define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON) @@ -37,13 +53,6 @@ #define CMP_NORMALIZE_TOLERANCE 0.000001 #define CMP_POINT_IN_PLANE_EPSILON 0.00001 -#define Math_SQRT12 0.7071067811865475244008443621048490 -#define Math_SQRT2 1.4142135623730950488016887242 -#define Math_LN2 0.6931471805599453094172321215 -#define Math_TAU 6.2831853071795864769252867666 -#define Math_PI 3.1415926535897932384626433833 -#define Math_E 2.7182818284590452353602874714 - #ifdef DEBUG_ENABLED #define MATH_CHECKS #endif @@ -136,5 +145,3 @@ typedef double real_t; #else typedef float real_t; #endif - -#endif // MATH_DEFS_H diff --git a/engine/core/math/math_fieldwise.cpp b/engine/core/math/math_fieldwise.cpp index 4064e6aa..8e81e4cc 100644 --- a/engine/core/math/math_fieldwise.cpp +++ b/engine/core/math/math_fieldwise.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifdef TOOLS_ENABLED +#ifdef DEBUG_ENABLED #include "math_fieldwise.h" @@ -242,4 +242,4 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const /* clang-format on */ } -#endif // TOOLS_ENABLED +#endif // DEBUG_ENABLED diff --git a/engine/core/math/math_fieldwise.h b/engine/core/math/math_fieldwise.h index 6d222c15..2628beb4 100644 --- a/engine/core/math/math_fieldwise.h +++ b/engine/core/math/math_fieldwise.h @@ -28,15 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef MATH_FIELDWISE_H -#define MATH_FIELDWISE_H +#pragma once -#ifdef TOOLS_ENABLED +#ifdef DEBUG_ENABLED #include "core/variant/variant.h" Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const String &p_field); -#endif // TOOLS_ENABLED - -#endif // MATH_FIELDWISE_H +#endif // DEBUG_ENABLED diff --git a/engine/core/math/math_funcs.cpp b/engine/core/math/math_funcs.cpp index 0d5b0faa..76d9cd25 100644 --- a/engine/core/math/math_funcs.cpp +++ b/engine/core/math/math_funcs.cpp @@ -31,18 +31,19 @@ #include "math_funcs.h" #include "core/error/error_macros.h" +#include "core/math/random_pcg.h" -RandomPCG Math::default_rand(RandomPCG::DEFAULT_SEED, RandomPCG::DEFAULT_INC); +static RandomPCG default_rand; -uint32_t Math::rand_from_seed(uint64_t *seed) { - RandomPCG rng = RandomPCG(*seed, RandomPCG::DEFAULT_INC); +uint32_t Math::rand_from_seed(uint64_t *p_seed) { + RandomPCG rng = RandomPCG(*p_seed); uint32_t r = rng.rand(); - *seed = rng.get_seed(); + *p_seed = rng.get_seed(); return r; } -void Math::seed(uint64_t x) { - default_rand.seed(x); +void Math::seed(uint64_t p_value) { + default_rand.seed(p_value); } void Math::randomize() { @@ -53,8 +54,8 @@ uint32_t Math::rand() { return default_rand.rand(); } -double Math::randfn(double mean, double deviation) { - return default_rand.randfn(mean, deviation); +double Math::randfn(double p_mean, double p_deviation) { + return default_rand.randfn(p_mean, p_deviation); } int Math::step_decimals(double p_step) { @@ -168,14 +169,14 @@ uint32_t Math::larger_prime(uint32_t p_val) { } } -double Math::random(double from, double to) { - return default_rand.random(from, to); +double Math::random(double p_from, double p_to) { + return default_rand.random(p_from, p_to); } -float Math::random(float from, float to) { - return default_rand.random(from, to); +float Math::random(float p_from, float p_to) { + return default_rand.random(p_from, p_to); } -int Math::random(int from, int to) { - return default_rand.random(from, to); +int Math::random(int p_from, int p_to) { + return default_rand.random(p_from, p_to); } diff --git a/engine/core/math/math_funcs.h b/engine/core/math/math_funcs.h index 1afc5f4b..56027765 100644 --- a/engine/core/math/math_funcs.h +++ b/engine/core/math/math_funcs.h @@ -28,735 +28,851 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef MATH_FUNCS_H -#define MATH_FUNCS_H +#pragma once #include "core/error/error_macros.h" #include "core/math/math_defs.h" -#include "core/math/random_pcg.h" #include "core/typedefs.h" -#include "thirdparty/misc/pcg.h" - #include #include -class Math { - static RandomPCG default_rand; +namespace Math { -public: - Math() {} // useless to instance +_ALWAYS_INLINE_ double sin(double p_x) { + return ::sin(p_x); +} +_ALWAYS_INLINE_ float sin(float p_x) { + return ::sinf(p_x); +} - // Not using 'RANDOM_MAX' to avoid conflict with system headers on some OSes (at least NetBSD). - static const uint64_t RANDOM_32BIT_MAX = 0xFFFFFFFF; +_ALWAYS_INLINE_ double cos(double p_x) { + return ::cos(p_x); +} +_ALWAYS_INLINE_ float cos(float p_x) { + return ::cosf(p_x); +} - static _ALWAYS_INLINE_ double sin(double p_x) { return ::sin(p_x); } - static _ALWAYS_INLINE_ float sin(float p_x) { return ::sinf(p_x); } +_ALWAYS_INLINE_ double tan(double p_x) { + return ::tan(p_x); +} +_ALWAYS_INLINE_ float tan(float p_x) { + return ::tanf(p_x); +} - static _ALWAYS_INLINE_ double cos(double p_x) { return ::cos(p_x); } - static _ALWAYS_INLINE_ float cos(float p_x) { return ::cosf(p_x); } +_ALWAYS_INLINE_ double sinh(double p_x) { + return ::sinh(p_x); +} +_ALWAYS_INLINE_ float sinh(float p_x) { + return ::sinhf(p_x); +} - static _ALWAYS_INLINE_ double tan(double p_x) { return ::tan(p_x); } - static _ALWAYS_INLINE_ float tan(float p_x) { return ::tanf(p_x); } +_ALWAYS_INLINE_ double sinc(double p_x) { + return p_x == 0 ? 1 : sin(p_x) / p_x; +} +_ALWAYS_INLINE_ float sinc(float p_x) { + return p_x == 0 ? 1 : sin(p_x) / p_x; +} - static _ALWAYS_INLINE_ double sinh(double p_x) { return ::sinh(p_x); } - static _ALWAYS_INLINE_ float sinh(float p_x) { return ::sinhf(p_x); } +_ALWAYS_INLINE_ double sincn(double p_x) { + return sinc(PI * p_x); +} +_ALWAYS_INLINE_ float sincn(float p_x) { + return sinc((float)PI * p_x); +} - static _ALWAYS_INLINE_ float sinc(float p_x) { return p_x == 0 ? 1 : ::sin(p_x) / p_x; } - static _ALWAYS_INLINE_ double sinc(double p_x) { return p_x == 0 ? 1 : ::sin(p_x) / p_x; } +_ALWAYS_INLINE_ double cosh(double p_x) { + return ::cosh(p_x); +} +_ALWAYS_INLINE_ float cosh(float p_x) { + return ::coshf(p_x); +} - static _ALWAYS_INLINE_ float sincn(float p_x) { return sinc((float)Math_PI * p_x); } - static _ALWAYS_INLINE_ double sincn(double p_x) { return sinc(Math_PI * p_x); } +_ALWAYS_INLINE_ double tanh(double p_x) { + return ::tanh(p_x); +} +_ALWAYS_INLINE_ float tanh(float p_x) { + return ::tanhf(p_x); +} - static _ALWAYS_INLINE_ double cosh(double p_x) { return ::cosh(p_x); } - static _ALWAYS_INLINE_ float cosh(float p_x) { return ::coshf(p_x); } +// Always does clamping so always safe to use. +_ALWAYS_INLINE_ double asin(double p_x) { + return p_x < -1 ? (-PI / 2) : (p_x > 1 ? (PI / 2) : ::asin(p_x)); +} +_ALWAYS_INLINE_ float asin(float p_x) { + return p_x < -1 ? (-(float)PI / 2) : (p_x > 1 ? ((float)PI / 2) : ::asinf(p_x)); +} - static _ALWAYS_INLINE_ double tanh(double p_x) { return ::tanh(p_x); } - static _ALWAYS_INLINE_ float tanh(float p_x) { return ::tanhf(p_x); } +// Always does clamping so always safe to use. +_ALWAYS_INLINE_ double acos(double p_x) { + return p_x < -1 ? PI : (p_x > 1 ? 0 : ::acos(p_x)); +} +_ALWAYS_INLINE_ float acos(float p_x) { + return p_x < -1 ? (float)PI : (p_x > 1 ? 0 : ::acosf(p_x)); +} - // Always does clamping so always safe to use. - static _ALWAYS_INLINE_ double asin(double p_x) { return p_x < -1 ? (-Math_PI / 2) : (p_x > 1 ? (Math_PI / 2) : ::asin(p_x)); } - static _ALWAYS_INLINE_ float asin(float p_x) { return p_x < -1 ? (-Math_PI / 2) : (p_x > 1 ? (Math_PI / 2) : ::asinf(p_x)); } +_ALWAYS_INLINE_ double atan(double p_x) { + return ::atan(p_x); +} +_ALWAYS_INLINE_ float atan(float p_x) { + return ::atanf(p_x); +} - // Always does clamping so always safe to use. - static _ALWAYS_INLINE_ double acos(double p_x) { return p_x < -1 ? Math_PI : (p_x > 1 ? 0 : ::acos(p_x)); } - static _ALWAYS_INLINE_ float acos(float p_x) { return p_x < -1 ? Math_PI : (p_x > 1 ? 0 : ::acosf(p_x)); } +_ALWAYS_INLINE_ double atan2(double p_y, double p_x) { + return ::atan2(p_y, p_x); +} +_ALWAYS_INLINE_ float atan2(float p_y, float p_x) { + return ::atan2f(p_y, p_x); +} - static _ALWAYS_INLINE_ double atan(double p_x) { return ::atan(p_x); } - static _ALWAYS_INLINE_ float atan(float p_x) { return ::atanf(p_x); } +_ALWAYS_INLINE_ double asinh(double p_x) { + return ::asinh(p_x); +} +_ALWAYS_INLINE_ float asinh(float p_x) { + return ::asinhf(p_x); +} - static _ALWAYS_INLINE_ double atan2(double p_y, double p_x) { return ::atan2(p_y, p_x); } - static _ALWAYS_INLINE_ float atan2(float p_y, float p_x) { return ::atan2f(p_y, p_x); } +// Always does clamping so always safe to use. +_ALWAYS_INLINE_ double acosh(double p_x) { + return p_x < 1 ? 0 : ::acosh(p_x); +} +_ALWAYS_INLINE_ float acosh(float p_x) { + return p_x < 1 ? 0 : ::acoshf(p_x); +} - static _ALWAYS_INLINE_ double asinh(double p_x) { return ::asinh(p_x); } - static _ALWAYS_INLINE_ float asinh(float p_x) { return ::asinhf(p_x); } +// Always does clamping so always safe to use. +_ALWAYS_INLINE_ double atanh(double p_x) { + return p_x <= -1 ? -INF : (p_x >= 1 ? INF : ::atanh(p_x)); +} +_ALWAYS_INLINE_ float atanh(float p_x) { + return p_x <= -1 ? (float)-INF : (p_x >= 1 ? (float)INF : ::atanhf(p_x)); +} - // Always does clamping so always safe to use. - static _ALWAYS_INLINE_ double acosh(double p_x) { return p_x < 1 ? 0 : ::acosh(p_x); } - static _ALWAYS_INLINE_ float acosh(float p_x) { return p_x < 1 ? 0 : ::acoshf(p_x); } +_ALWAYS_INLINE_ double sqrt(double p_x) { + return ::sqrt(p_x); +} +_ALWAYS_INLINE_ float sqrt(float p_x) { + return ::sqrtf(p_x); +} - // Always does clamping so always safe to use. - static _ALWAYS_INLINE_ double atanh(double p_x) { return p_x <= -1 ? -INFINITY : (p_x >= 1 ? INFINITY : ::atanh(p_x)); } - static _ALWAYS_INLINE_ float atanh(float p_x) { return p_x <= -1 ? -INFINITY : (p_x >= 1 ? INFINITY : ::atanhf(p_x)); } +_ALWAYS_INLINE_ double fmod(double p_x, double p_y) { + return ::fmod(p_x, p_y); +} +_ALWAYS_INLINE_ float fmod(float p_x, float p_y) { + return ::fmodf(p_x, p_y); +} - static _ALWAYS_INLINE_ double sqrt(double p_x) { return ::sqrt(p_x); } - static _ALWAYS_INLINE_ float sqrt(float p_x) { return ::sqrtf(p_x); } +_ALWAYS_INLINE_ double modf(double p_x, double *r_y) { + return ::modf(p_x, r_y); +} +_ALWAYS_INLINE_ float modf(float p_x, float *r_y) { + return ::modff(p_x, r_y); +} - static _ALWAYS_INLINE_ double fmod(double p_x, double p_y) { return ::fmod(p_x, p_y); } - static _ALWAYS_INLINE_ float fmod(float p_x, float p_y) { return ::fmodf(p_x, p_y); } +_ALWAYS_INLINE_ double floor(double p_x) { + return ::floor(p_x); +} +_ALWAYS_INLINE_ float floor(float p_x) { + return ::floorf(p_x); +} - static _ALWAYS_INLINE_ double modf(double p_x, double *r_y) { return ::modf(p_x, r_y); } - static _ALWAYS_INLINE_ float modf(float p_x, float *r_y) { return ::modff(p_x, r_y); } +_ALWAYS_INLINE_ double ceil(double p_x) { + return ::ceil(p_x); +} +_ALWAYS_INLINE_ float ceil(float p_x) { + return ::ceilf(p_x); +} - static _ALWAYS_INLINE_ double floor(double p_x) { return ::floor(p_x); } - static _ALWAYS_INLINE_ float floor(float p_x) { return ::floorf(p_x); } +_ALWAYS_INLINE_ double pow(double p_x, double p_y) { + return ::pow(p_x, p_y); +} +_ALWAYS_INLINE_ float pow(float p_x, float p_y) { + return ::powf(p_x, p_y); +} - static _ALWAYS_INLINE_ double ceil(double p_x) { return ::ceil(p_x); } - static _ALWAYS_INLINE_ float ceil(float p_x) { return ::ceilf(p_x); } +_ALWAYS_INLINE_ double log(double p_x) { + return ::log(p_x); +} +_ALWAYS_INLINE_ float log(float p_x) { + return ::logf(p_x); +} - static _ALWAYS_INLINE_ double pow(double p_x, double p_y) { return ::pow(p_x, p_y); } - static _ALWAYS_INLINE_ float pow(float p_x, float p_y) { return ::powf(p_x, p_y); } +_ALWAYS_INLINE_ double log1p(double p_x) { + return ::log1p(p_x); +} +_ALWAYS_INLINE_ float log1p(float p_x) { + return ::log1pf(p_x); +} - static _ALWAYS_INLINE_ double log(double p_x) { return ::log(p_x); } - static _ALWAYS_INLINE_ float log(float p_x) { return ::logf(p_x); } +_ALWAYS_INLINE_ double log2(double p_x) { + return ::log2(p_x); +} +_ALWAYS_INLINE_ float log2(float p_x) { + return ::log2f(p_x); +} - static _ALWAYS_INLINE_ double log1p(double p_x) { return ::log1p(p_x); } - static _ALWAYS_INLINE_ float log1p(float p_x) { return ::log1pf(p_x); } +_ALWAYS_INLINE_ double exp(double p_x) { + return ::exp(p_x); +} +_ALWAYS_INLINE_ float exp(float p_x) { + return ::expf(p_x); +} - static _ALWAYS_INLINE_ double log2(double p_x) { return ::log2(p_x); } - static _ALWAYS_INLINE_ float log2(float p_x) { return ::log2f(p_x); } - - static _ALWAYS_INLINE_ double exp(double p_x) { return ::exp(p_x); } - static _ALWAYS_INLINE_ float exp(float p_x) { return ::expf(p_x); } - - static _ALWAYS_INLINE_ bool is_nan(double p_val) { +_ALWAYS_INLINE_ bool is_nan(double p_val) { #ifdef _MSC_VER - return _isnan(p_val); + return _isnan(p_val); #elif defined(__GNUC__) && __GNUC__ < 6 - union { - uint64_t u; - double f; - } ieee754; - ieee754.f = p_val; - // (unsigned)(0x7ff0000000000001 >> 32) : 0x7ff00000 - return ((((unsigned)(ieee754.u >> 32) & 0x7fffffff) + ((unsigned)ieee754.u != 0)) > 0x7ff00000); + union { + uint64_t u; + double f; + } ieee754; + ieee754.f = p_val; + // (unsigned)(0x7ff0000000000001 >> 32) : 0x7ff00000 + return ((((unsigned)(ieee754.u >> 32) & 0x7fffffff) + ((unsigned)ieee754.u != 0)) > 0x7ff00000); #else - return isnan(p_val); + return isnan(p_val); #endif - } +} - static _ALWAYS_INLINE_ bool is_nan(float p_val) { +_ALWAYS_INLINE_ bool is_nan(float p_val) { #ifdef _MSC_VER - return _isnan(p_val); + return _isnan(p_val); #elif defined(__GNUC__) && __GNUC__ < 6 - union { - uint32_t u; - float f; - } ieee754; - ieee754.f = p_val; - // ----------------------------------- - // (single-precision floating-point) - // NaN : s111 1111 1xxx xxxx xxxx xxxx xxxx xxxx - // : (> 0x7f800000) - // where, - // s : sign - // x : non-zero number - // ----------------------------------- - return ((ieee754.u & 0x7fffffff) > 0x7f800000); + union { + uint32_t u; + float f; + } ieee754; + ieee754.f = p_val; + // ----------------------------------- + // (single-precision floating-point) + // NaN : s111 1111 1xxx xxxx xxxx xxxx xxxx xxxx + // : (> 0x7f800000) + // where, + // s : sign + // x : non-zero number + // ----------------------------------- + return ((ieee754.u & 0x7fffffff) > 0x7f800000); #else - return isnan(p_val); + return isnan(p_val); #endif - } +} - static _ALWAYS_INLINE_ bool is_inf(double p_val) { +_ALWAYS_INLINE_ bool is_inf(double p_val) { #ifdef _MSC_VER - return !_finite(p_val); + return !_finite(p_val); // use an inline implementation of isinf as a workaround for problematic libstdc++ versions from gcc 5.x era #elif defined(__GNUC__) && __GNUC__ < 6 - union { - uint64_t u; - double f; - } ieee754; - ieee754.f = p_val; - return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && - ((unsigned)ieee754.u == 0); + union { + uint64_t u; + double f; + } ieee754; + ieee754.f = p_val; + return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && + ((unsigned)ieee754.u == 0); #else - return isinf(p_val); + return isinf(p_val); #endif - } +} - static _ALWAYS_INLINE_ bool is_inf(float p_val) { +_ALWAYS_INLINE_ bool is_inf(float p_val) { #ifdef _MSC_VER - return !_finite(p_val); + return !_finite(p_val); // use an inline implementation of isinf as a workaround for problematic libstdc++ versions from gcc 5.x era #elif defined(__GNUC__) && __GNUC__ < 6 - union { - uint32_t u; - float f; - } ieee754; - ieee754.f = p_val; - return (ieee754.u & 0x7fffffff) == 0x7f800000; + union { + uint32_t u; + float f; + } ieee754; + ieee754.f = p_val; + return (ieee754.u & 0x7fffffff) == 0x7f800000; #else - return isinf(p_val); + return isinf(p_val); #endif +} + +// These methods assume (p_num + p_den) doesn't overflow. +_ALWAYS_INLINE_ int32_t division_round_up(int32_t p_num, int32_t p_den) { + int32_t offset = (p_num < 0 && p_den < 0) ? 1 : -1; + return (p_num + p_den + offset) / p_den; +} +_ALWAYS_INLINE_ uint32_t division_round_up(uint32_t p_num, uint32_t p_den) { + return (p_num + p_den - 1) / p_den; +} +_ALWAYS_INLINE_ int64_t division_round_up(int64_t p_num, int64_t p_den) { + int32_t offset = (p_num < 0 && p_den < 0) ? 1 : -1; + return (p_num + p_den + offset) / p_den; +} +_ALWAYS_INLINE_ uint64_t division_round_up(uint64_t p_num, uint64_t p_den) { + return (p_num + p_den - 1) / p_den; +} + +_ALWAYS_INLINE_ bool is_finite(double p_val) { + return isfinite(p_val); +} +_ALWAYS_INLINE_ bool is_finite(float p_val) { + return isfinite(p_val); +} + +_ALWAYS_INLINE_ double absd(double p_value) { + return ::fabs(p_value); +} +_ALWAYS_INLINE_ float absf(float p_value) { + return ::fabsf(p_value); +} + +_ALWAYS_INLINE_ double abs(double p_value) { + return absd(p_value); +} +_ALWAYS_INLINE_ float abs(float p_value) { + return absf(p_value); +} +_ALWAYS_INLINE_ int8_t abs(int8_t p_value) { + return p_value > 0 ? p_value : -p_value; +} +_ALWAYS_INLINE_ int16_t abs(int16_t p_value) { + return p_value > 0 ? p_value : -p_value; +} +_ALWAYS_INLINE_ int32_t abs(int32_t p_value) { + return ::abs(p_value); +} +_ALWAYS_INLINE_ int64_t abs(int64_t p_value) { + return ::llabs(p_value); +} + +_ALWAYS_INLINE_ double fposmod(double p_x, double p_y) { + double value = fmod(p_x, p_y); + if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) { + value += p_y; } - - // These methods assume (p_num + p_den) doesn't overflow. - static _ALWAYS_INLINE_ int32_t division_round_up(int32_t p_num, int32_t p_den) { - int32_t offset = (p_num < 0 && p_den < 0) ? 1 : -1; - return (p_num + p_den + offset) / p_den; + value += 0.0; + return value; +} +_ALWAYS_INLINE_ float fposmod(float p_x, float p_y) { + float value = fmod(p_x, p_y); + if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) { + value += p_y; } - static _ALWAYS_INLINE_ uint32_t division_round_up(uint32_t p_num, uint32_t p_den) { - return (p_num + p_den - 1) / p_den; + value += 0.0f; + return value; +} + +_ALWAYS_INLINE_ double fposmodp(double p_x, double p_y) { + double value = fmod(p_x, p_y); + if (value < 0) { + value += p_y; } - static _ALWAYS_INLINE_ int64_t division_round_up(int64_t p_num, int64_t p_den) { - int32_t offset = (p_num < 0 && p_den < 0) ? 1 : -1; - return (p_num + p_den + offset) / p_den; + value += 0.0; + return value; +} +_ALWAYS_INLINE_ float fposmodp(float p_x, float p_y) { + float value = fmod(p_x, p_y); + if (value < 0) { + value += p_y; } - static _ALWAYS_INLINE_ uint64_t division_round_up(uint64_t p_num, uint64_t p_den) { - return (p_num + p_den - 1) / p_den; + value += 0.0f; + return value; +} + +_ALWAYS_INLINE_ int64_t posmod(int64_t p_x, int64_t p_y) { + ERR_FAIL_COND_V_MSG(p_y == 0, 0, "Division by zero in posmod is undefined. Returning 0 as fallback."); + int64_t value = p_x % p_y; + if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) { + value += p_y; } + return value; +} - static _ALWAYS_INLINE_ bool is_finite(double p_val) { return isfinite(p_val); } - static _ALWAYS_INLINE_ bool is_finite(float p_val) { return isfinite(p_val); } +_ALWAYS_INLINE_ double deg_to_rad(double p_y) { + return p_y * (PI / 180.0); +} +_ALWAYS_INLINE_ float deg_to_rad(float p_y) { + return p_y * ((float)PI / 180.0f); +} - static _ALWAYS_INLINE_ double abs(double g) { return absd(g); } - static _ALWAYS_INLINE_ float abs(float g) { return absf(g); } - static _ALWAYS_INLINE_ int abs(int g) { return g > 0 ? g : -g; } +_ALWAYS_INLINE_ double rad_to_deg(double p_y) { + return p_y * (180.0 / PI); +} +_ALWAYS_INLINE_ float rad_to_deg(float p_y) { + return p_y * (180.0f / (float)PI); +} - static _ALWAYS_INLINE_ double fposmod(double p_x, double p_y) { - double value = Math::fmod(p_x, p_y); - if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) { - value += p_y; - } - value += 0.0; - return value; +_ALWAYS_INLINE_ double lerp(double p_from, double p_to, double p_weight) { + return p_from + (p_to - p_from) * p_weight; +} +_ALWAYS_INLINE_ float lerp(float p_from, float p_to, float p_weight) { + return p_from + (p_to - p_from) * p_weight; +} + +_ALWAYS_INLINE_ double cubic_interpolate(double p_from, double p_to, double p_pre, double p_post, double p_weight) { + return 0.5 * + ((p_from * 2.0) + + (-p_pre + p_to) * p_weight + + (2.0 * p_pre - 5.0 * p_from + 4.0 * p_to - p_post) * (p_weight * p_weight) + + (-p_pre + 3.0 * p_from - 3.0 * p_to + p_post) * (p_weight * p_weight * p_weight)); +} +_ALWAYS_INLINE_ float cubic_interpolate(float p_from, float p_to, float p_pre, float p_post, float p_weight) { + return 0.5f * + ((p_from * 2.0f) + + (-p_pre + p_to) * p_weight + + (2.0f * p_pre - 5.0f * p_from + 4.0f * p_to - p_post) * (p_weight * p_weight) + + (-p_pre + 3.0f * p_from - 3.0f * p_to + p_post) * (p_weight * p_weight * p_weight)); +} + +_ALWAYS_INLINE_ double cubic_interpolate_angle(double p_from, double p_to, double p_pre, double p_post, double p_weight) { + double from_rot = fmod(p_from, TAU); + + double pre_diff = fmod(p_pre - from_rot, TAU); + double pre_rot = from_rot + fmod(2.0 * pre_diff, TAU) - pre_diff; + + double to_diff = fmod(p_to - from_rot, TAU); + double to_rot = from_rot + fmod(2.0 * to_diff, TAU) - to_diff; + + double post_diff = fmod(p_post - to_rot, TAU); + double post_rot = to_rot + fmod(2.0 * post_diff, TAU) - post_diff; + + return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight); +} + +_ALWAYS_INLINE_ float cubic_interpolate_angle(float p_from, float p_to, float p_pre, float p_post, float p_weight) { + float from_rot = fmod(p_from, (float)TAU); + + float pre_diff = fmod(p_pre - from_rot, (float)TAU); + float pre_rot = from_rot + fmod(2.0f * pre_diff, (float)TAU) - pre_diff; + + float to_diff = fmod(p_to - from_rot, (float)TAU); + float to_rot = from_rot + fmod(2.0f * to_diff, (float)TAU) - to_diff; + + float post_diff = fmod(p_post - to_rot, (float)TAU); + float post_rot = to_rot + fmod(2.0f * post_diff, (float)TAU) - post_diff; + + return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight); +} + +_ALWAYS_INLINE_ double cubic_interpolate_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight, + double p_to_t, double p_pre_t, double p_post_t) { + /* Barry-Goldman method */ + double t = lerp(0.0, p_to_t, p_weight); + double a1 = lerp(p_pre, p_from, p_pre_t == 0 ? 0.0 : (t - p_pre_t) / -p_pre_t); + double a2 = lerp(p_from, p_to, p_to_t == 0 ? 0.5 : t / p_to_t); + double a3 = lerp(p_to, p_post, p_post_t - p_to_t == 0 ? 1.0 : (t - p_to_t) / (p_post_t - p_to_t)); + double b1 = lerp(a1, a2, p_to_t - p_pre_t == 0 ? 0.0 : (t - p_pre_t) / (p_to_t - p_pre_t)); + double b2 = lerp(a2, a3, p_post_t == 0 ? 1.0 : t / p_post_t); + return lerp(b1, b2, p_to_t == 0 ? 0.5 : t / p_to_t); +} +_ALWAYS_INLINE_ float cubic_interpolate_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight, + float p_to_t, float p_pre_t, float p_post_t) { + /* Barry-Goldman method */ + float t = lerp(0.0f, p_to_t, p_weight); + float a1 = lerp(p_pre, p_from, p_pre_t == 0 ? 0.0f : (t - p_pre_t) / -p_pre_t); + float a2 = lerp(p_from, p_to, p_to_t == 0 ? 0.5f : t / p_to_t); + float a3 = lerp(p_to, p_post, p_post_t - p_to_t == 0 ? 1.0f : (t - p_to_t) / (p_post_t - p_to_t)); + float b1 = lerp(a1, a2, p_to_t - p_pre_t == 0 ? 0.0f : (t - p_pre_t) / (p_to_t - p_pre_t)); + float b2 = lerp(a2, a3, p_post_t == 0 ? 1.0f : t / p_post_t); + return lerp(b1, b2, p_to_t == 0 ? 0.5f : t / p_to_t); +} + +_ALWAYS_INLINE_ double cubic_interpolate_angle_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight, + double p_to_t, double p_pre_t, double p_post_t) { + double from_rot = fmod(p_from, TAU); + + double pre_diff = fmod(p_pre - from_rot, TAU); + double pre_rot = from_rot + fmod(2.0 * pre_diff, TAU) - pre_diff; + + double to_diff = fmod(p_to - from_rot, TAU); + double to_rot = from_rot + fmod(2.0 * to_diff, TAU) - to_diff; + + double post_diff = fmod(p_post - to_rot, TAU); + double post_rot = to_rot + fmod(2.0 * post_diff, TAU) - post_diff; + + return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t); +} +_ALWAYS_INLINE_ float cubic_interpolate_angle_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight, + float p_to_t, float p_pre_t, float p_post_t) { + float from_rot = fmod(p_from, (float)TAU); + + float pre_diff = fmod(p_pre - from_rot, (float)TAU); + float pre_rot = from_rot + fmod(2.0f * pre_diff, (float)TAU) - pre_diff; + + float to_diff = fmod(p_to - from_rot, (float)TAU); + float to_rot = from_rot + fmod(2.0f * to_diff, (float)TAU) - to_diff; + + float post_diff = fmod(p_post - to_rot, (float)TAU); + float post_rot = to_rot + fmod(2.0f * post_diff, (float)TAU) - post_diff; + + return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t); +} + +_ALWAYS_INLINE_ double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) { + /* Formula from Wikipedia article on Bezier curves. */ + double omt = (1.0 - p_t); + double omt2 = omt * omt; + double omt3 = omt2 * omt; + double t2 = p_t * p_t; + double t3 = t2 * p_t; + + return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3; +} +_ALWAYS_INLINE_ float bezier_interpolate(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) { + /* Formula from Wikipedia article on Bezier curves. */ + float omt = (1.0f - p_t); + float omt2 = omt * omt; + float omt3 = omt2 * omt; + float t2 = p_t * p_t; + float t3 = t2 * p_t; + + return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0f + p_control_2 * omt * t2 * 3.0f + p_end * t3; +} + +_ALWAYS_INLINE_ double bezier_derivative(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) { + /* Formula from Wikipedia article on Bezier curves. */ + double omt = (1.0 - p_t); + double omt2 = omt * omt; + double t2 = p_t * p_t; + + double d = (p_control_1 - p_start) * 3.0 * omt2 + (p_control_2 - p_control_1) * 6.0 * omt * p_t + (p_end - p_control_2) * 3.0 * t2; + return d; +} +_ALWAYS_INLINE_ float bezier_derivative(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) { + /* Formula from Wikipedia article on Bezier curves. */ + float omt = (1.0f - p_t); + float omt2 = omt * omt; + float t2 = p_t * p_t; + + float d = (p_control_1 - p_start) * 3.0f * omt2 + (p_control_2 - p_control_1) * 6.0f * omt * p_t + (p_end - p_control_2) * 3.0f * t2; + return d; +} + +_ALWAYS_INLINE_ double angle_difference(double p_from, double p_to) { + double difference = fmod(p_to - p_from, TAU); + return fmod(2.0 * difference, TAU) - difference; +} +_ALWAYS_INLINE_ float angle_difference(float p_from, float p_to) { + float difference = fmod(p_to - p_from, (float)TAU); + return fmod(2.0f * difference, (float)TAU) - difference; +} + +_ALWAYS_INLINE_ double lerp_angle(double p_from, double p_to, double p_weight) { + return p_from + angle_difference(p_from, p_to) * p_weight; +} +_ALWAYS_INLINE_ float lerp_angle(float p_from, float p_to, float p_weight) { + return p_from + angle_difference(p_from, p_to) * p_weight; +} + +_ALWAYS_INLINE_ double inverse_lerp(double p_from, double p_to, double p_value) { + return (p_value - p_from) / (p_to - p_from); +} +_ALWAYS_INLINE_ float inverse_lerp(float p_from, float p_to, float p_value) { + return (p_value - p_from) / (p_to - p_from); +} + +_ALWAYS_INLINE_ double remap(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { + return lerp(p_ostart, p_ostop, inverse_lerp(p_istart, p_istop, p_value)); +} +_ALWAYS_INLINE_ float remap(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { + return lerp(p_ostart, p_ostop, inverse_lerp(p_istart, p_istop, p_value)); +} + +_ALWAYS_INLINE_ bool is_equal_approx(double p_left, double p_right, double p_tolerance) { + // Check for exact equality first, required to handle "infinity" values. + if (p_left == p_right) { + return true; } - static _ALWAYS_INLINE_ float fposmod(float p_x, float p_y) { - float value = Math::fmod(p_x, p_y); - if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) { - value += p_y; - } - value += 0.0f; - return value; + // Then check for approximate equality. + return abs(p_left - p_right) < p_tolerance; +} +_ALWAYS_INLINE_ bool is_equal_approx(float p_left, float p_right, float p_tolerance) { + // Check for exact equality first, required to handle "infinity" values. + if (p_left == p_right) { + return true; } - static _ALWAYS_INLINE_ float fposmodp(float p_x, float p_y) { - float value = Math::fmod(p_x, p_y); - if (value < 0) { - value += p_y; - } - value += 0.0f; - return value; + // Then check for approximate equality. + return abs(p_left - p_right) < p_tolerance; +} + +_ALWAYS_INLINE_ bool is_equal_approx(double p_left, double p_right) { + // Check for exact equality first, required to handle "infinity" values. + if (p_left == p_right) { + return true; } - static _ALWAYS_INLINE_ double fposmodp(double p_x, double p_y) { - double value = Math::fmod(p_x, p_y); - if (value < 0) { - value += p_y; - } - value += 0.0; - return value; + // Then check for approximate equality. + double tolerance = CMP_EPSILON * abs(p_left); + if (tolerance < CMP_EPSILON) { + tolerance = CMP_EPSILON; } - - static _ALWAYS_INLINE_ int64_t posmod(int64_t p_x, int64_t p_y) { - ERR_FAIL_COND_V_MSG(p_y == 0, 0, "Division by zero in posmod is undefined. Returning 0 as fallback."); - int64_t value = p_x % p_y; - if (((value < 0) && (p_y > 0)) || ((value > 0) && (p_y < 0))) { - value += p_y; - } - return value; + return abs(p_left - p_right) < tolerance; +} +_ALWAYS_INLINE_ bool is_equal_approx(float p_left, float p_right) { + // Check for exact equality first, required to handle "infinity" values. + if (p_left == p_right) { + return true; } - - static _ALWAYS_INLINE_ double deg_to_rad(double p_y) { return p_y * (Math_PI / 180.0); } - static _ALWAYS_INLINE_ float deg_to_rad(float p_y) { return p_y * (float)(Math_PI / 180.0); } - - static _ALWAYS_INLINE_ double rad_to_deg(double p_y) { return p_y * (180.0 / Math_PI); } - static _ALWAYS_INLINE_ float rad_to_deg(float p_y) { return p_y * (float)(180.0 / Math_PI); } - - static _ALWAYS_INLINE_ double lerp(double p_from, double p_to, double p_weight) { return p_from + (p_to - p_from) * p_weight; } - static _ALWAYS_INLINE_ float lerp(float p_from, float p_to, float p_weight) { return p_from + (p_to - p_from) * p_weight; } - - static _ALWAYS_INLINE_ double cubic_interpolate(double p_from, double p_to, double p_pre, double p_post, double p_weight) { - return 0.5 * - ((p_from * 2.0) + - (-p_pre + p_to) * p_weight + - (2.0 * p_pre - 5.0 * p_from + 4.0 * p_to - p_post) * (p_weight * p_weight) + - (-p_pre + 3.0 * p_from - 3.0 * p_to + p_post) * (p_weight * p_weight * p_weight)); + // Then check for approximate equality. + float tolerance = (float)CMP_EPSILON * abs(p_left); + if (tolerance < (float)CMP_EPSILON) { + tolerance = (float)CMP_EPSILON; } - static _ALWAYS_INLINE_ float cubic_interpolate(float p_from, float p_to, float p_pre, float p_post, float p_weight) { - return 0.5f * - ((p_from * 2.0f) + - (-p_pre + p_to) * p_weight + - (2.0f * p_pre - 5.0f * p_from + 4.0f * p_to - p_post) * (p_weight * p_weight) + - (-p_pre + 3.0f * p_from - 3.0f * p_to + p_post) * (p_weight * p_weight * p_weight)); - } - - static _ALWAYS_INLINE_ double cubic_interpolate_angle(double p_from, double p_to, double p_pre, double p_post, double p_weight) { - double from_rot = fmod(p_from, Math_TAU); - - double pre_diff = fmod(p_pre - from_rot, Math_TAU); - double pre_rot = from_rot + fmod(2.0 * pre_diff, Math_TAU) - pre_diff; - - double to_diff = fmod(p_to - from_rot, Math_TAU); - double to_rot = from_rot + fmod(2.0 * to_diff, Math_TAU) - to_diff; - - double post_diff = fmod(p_post - to_rot, Math_TAU); - double post_rot = to_rot + fmod(2.0 * post_diff, Math_TAU) - post_diff; - - return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight); - } - - static _ALWAYS_INLINE_ float cubic_interpolate_angle(float p_from, float p_to, float p_pre, float p_post, float p_weight) { - float from_rot = fmod(p_from, (float)Math_TAU); - - float pre_diff = fmod(p_pre - from_rot, (float)Math_TAU); - float pre_rot = from_rot + fmod(2.0f * pre_diff, (float)Math_TAU) - pre_diff; - - float to_diff = fmod(p_to - from_rot, (float)Math_TAU); - float to_rot = from_rot + fmod(2.0f * to_diff, (float)Math_TAU) - to_diff; - - float post_diff = fmod(p_post - to_rot, (float)Math_TAU); - float post_rot = to_rot + fmod(2.0f * post_diff, (float)Math_TAU) - post_diff; - - return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight); - } - - static _ALWAYS_INLINE_ double cubic_interpolate_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight, - double p_to_t, double p_pre_t, double p_post_t) { - /* Barry-Goldman method */ - double t = Math::lerp(0.0, p_to_t, p_weight); - double a1 = Math::lerp(p_pre, p_from, p_pre_t == 0 ? 0.0 : (t - p_pre_t) / -p_pre_t); - double a2 = Math::lerp(p_from, p_to, p_to_t == 0 ? 0.5 : t / p_to_t); - double a3 = Math::lerp(p_to, p_post, p_post_t - p_to_t == 0 ? 1.0 : (t - p_to_t) / (p_post_t - p_to_t)); - double b1 = Math::lerp(a1, a2, p_to_t - p_pre_t == 0 ? 0.0 : (t - p_pre_t) / (p_to_t - p_pre_t)); - double b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0 : t / p_post_t); - return Math::lerp(b1, b2, p_to_t == 0 ? 0.5 : t / p_to_t); - } - - static _ALWAYS_INLINE_ float cubic_interpolate_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight, - float p_to_t, float p_pre_t, float p_post_t) { - /* Barry-Goldman method */ - float t = Math::lerp(0.0f, p_to_t, p_weight); - float a1 = Math::lerp(p_pre, p_from, p_pre_t == 0 ? 0.0f : (t - p_pre_t) / -p_pre_t); - float a2 = Math::lerp(p_from, p_to, p_to_t == 0 ? 0.5f : t / p_to_t); - float a3 = Math::lerp(p_to, p_post, p_post_t - p_to_t == 0 ? 1.0f : (t - p_to_t) / (p_post_t - p_to_t)); - float b1 = Math::lerp(a1, a2, p_to_t - p_pre_t == 0 ? 0.0f : (t - p_pre_t) / (p_to_t - p_pre_t)); - float b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0f : t / p_post_t); - return Math::lerp(b1, b2, p_to_t == 0 ? 0.5f : t / p_to_t); - } - - static _ALWAYS_INLINE_ double cubic_interpolate_angle_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight, - double p_to_t, double p_pre_t, double p_post_t) { - double from_rot = fmod(p_from, Math_TAU); - - double pre_diff = fmod(p_pre - from_rot, Math_TAU); - double pre_rot = from_rot + fmod(2.0 * pre_diff, Math_TAU) - pre_diff; - - double to_diff = fmod(p_to - from_rot, Math_TAU); - double to_rot = from_rot + fmod(2.0 * to_diff, Math_TAU) - to_diff; - - double post_diff = fmod(p_post - to_rot, Math_TAU); - double post_rot = to_rot + fmod(2.0 * post_diff, Math_TAU) - post_diff; - - return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t); - } - - static _ALWAYS_INLINE_ float cubic_interpolate_angle_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight, - float p_to_t, float p_pre_t, float p_post_t) { - float from_rot = fmod(p_from, (float)Math_TAU); - - float pre_diff = fmod(p_pre - from_rot, (float)Math_TAU); - float pre_rot = from_rot + fmod(2.0f * pre_diff, (float)Math_TAU) - pre_diff; - - float to_diff = fmod(p_to - from_rot, (float)Math_TAU); - float to_rot = from_rot + fmod(2.0f * to_diff, (float)Math_TAU) - to_diff; - - float post_diff = fmod(p_post - to_rot, (float)Math_TAU); - float post_rot = to_rot + fmod(2.0f * post_diff, (float)Math_TAU) - post_diff; - - return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t); - } - - static _ALWAYS_INLINE_ double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) { - /* Formula from Wikipedia article on Bezier curves. */ - double omt = (1.0 - p_t); - double omt2 = omt * omt; - double omt3 = omt2 * omt; - double t2 = p_t * p_t; - double t3 = t2 * p_t; - - return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3; - } - - static _ALWAYS_INLINE_ float bezier_interpolate(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) { - /* Formula from Wikipedia article on Bezier curves. */ - float omt = (1.0f - p_t); - float omt2 = omt * omt; - float omt3 = omt2 * omt; - float t2 = p_t * p_t; - float t3 = t2 * p_t; - - return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0f + p_control_2 * omt * t2 * 3.0f + p_end * t3; - } - - static _ALWAYS_INLINE_ double bezier_derivative(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) { - /* Formula from Wikipedia article on Bezier curves. */ - double omt = (1.0 - p_t); - double omt2 = omt * omt; - double t2 = p_t * p_t; - - double d = (p_control_1 - p_start) * 3.0 * omt2 + (p_control_2 - p_control_1) * 6.0 * omt * p_t + (p_end - p_control_2) * 3.0 * t2; - return d; - } - - static _ALWAYS_INLINE_ float bezier_derivative(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) { - /* Formula from Wikipedia article on Bezier curves. */ - float omt = (1.0f - p_t); - float omt2 = omt * omt; - float t2 = p_t * p_t; - - float d = (p_control_1 - p_start) * 3.0f * omt2 + (p_control_2 - p_control_1) * 6.0f * omt * p_t + (p_end - p_control_2) * 3.0f * t2; - return d; - } - - static _ALWAYS_INLINE_ double angle_difference(double p_from, double p_to) { - double difference = fmod(p_to - p_from, Math_TAU); - return fmod(2.0 * difference, Math_TAU) - difference; - } - static _ALWAYS_INLINE_ float angle_difference(float p_from, float p_to) { - float difference = fmod(p_to - p_from, (float)Math_TAU); - return fmod(2.0f * difference, (float)Math_TAU) - difference; - } - - static _ALWAYS_INLINE_ double lerp_angle(double p_from, double p_to, double p_weight) { - return p_from + Math::angle_difference(p_from, p_to) * p_weight; - } - static _ALWAYS_INLINE_ float lerp_angle(float p_from, float p_to, float p_weight) { - return p_from + Math::angle_difference(p_from, p_to) * p_weight; - } - - static _ALWAYS_INLINE_ double inverse_lerp(double p_from, double p_to, double p_value) { - return (p_value - p_from) / (p_to - p_from); - } - static _ALWAYS_INLINE_ float inverse_lerp(float p_from, float p_to, float p_value) { - return (p_value - p_from) / (p_to - p_from); - } - - static _ALWAYS_INLINE_ double remap(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { - return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); - } - static _ALWAYS_INLINE_ float remap(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { - return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); - } - - static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_s) { - if (is_equal_approx(p_from, p_to)) { - if (likely(p_from <= p_to)) { - return p_s <= p_from ? 0.0 : 1.0; - } else { - return p_s <= p_to ? 1.0 : 0.0; - } - } - double s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0, 1.0); - return s * s * (3.0 - 2.0 * s); - } - static _ALWAYS_INLINE_ float smoothstep(float p_from, float p_to, float p_s) { - if (is_equal_approx(p_from, p_to)) { - if (likely(p_from <= p_to)) { - return p_s <= p_from ? 0.0f : 1.0f; - } else { - return p_s <= p_to ? 1.0f : 0.0f; - } - } - float s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0f, 1.0f); - return s * s * (3.0f - 2.0f * s); - } - - static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) { - return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; - } - static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { - return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; - } - - static _ALWAYS_INLINE_ double rotate_toward(double p_from, double p_to, double p_delta) { - double difference = Math::angle_difference(p_from, p_to); - double abs_difference = Math::abs(difference); - // When `p_delta < 0` move no further than to PI radians away from `p_to` (as PI is the max possible angle distance). - return p_from + CLAMP(p_delta, abs_difference - Math_PI, abs_difference) * (difference >= 0.0 ? 1.0 : -1.0); - } - static _ALWAYS_INLINE_ float rotate_toward(float p_from, float p_to, float p_delta) { - float difference = Math::angle_difference(p_from, p_to); - float abs_difference = Math::abs(difference); - // When `p_delta < 0` move no further than to PI radians away from `p_to` (as PI is the max possible angle distance). - return p_from + CLAMP(p_delta, abs_difference - (float)Math_PI, abs_difference) * (difference >= 0.0f ? 1.0f : -1.0f); - } - - static _ALWAYS_INLINE_ double linear_to_db(double p_linear) { - return Math::log(p_linear) * 8.6858896380650365530225783783321; - } - static _ALWAYS_INLINE_ float linear_to_db(float p_linear) { - return Math::log(p_linear) * (float)8.6858896380650365530225783783321; - } - - static _ALWAYS_INLINE_ double db_to_linear(double p_db) { - return Math::exp(p_db * 0.11512925464970228420089957273422); - } - static _ALWAYS_INLINE_ float db_to_linear(float p_db) { - return Math::exp(p_db * (float)0.11512925464970228420089957273422); - } - - static _ALWAYS_INLINE_ double round(double p_val) { return ::round(p_val); } - static _ALWAYS_INLINE_ float round(float p_val) { return ::roundf(p_val); } - - static _ALWAYS_INLINE_ int64_t wrapi(int64_t value, int64_t min, int64_t max) { - int64_t range = max - min; - return range == 0 ? min : min + ((((value - min) % range) + range) % range); - } - static _ALWAYS_INLINE_ double wrapf(double value, double min, double max) { - double range = max - min; - if (is_zero_approx(range)) { - return min; - } - double result = value - (range * Math::floor((value - min) / range)); - if (is_equal_approx(result, max)) { - return min; - } - return result; - } - static _ALWAYS_INLINE_ float wrapf(float value, float min, float max) { - float range = max - min; - if (is_zero_approx(range)) { - return min; - } - float result = value - (range * Math::floor((value - min) / range)); - if (is_equal_approx(result, max)) { - return min; - } - return result; - } - - static _ALWAYS_INLINE_ float fract(float value) { - return value - floor(value); - } - static _ALWAYS_INLINE_ double fract(double value) { - return value - floor(value); - } - static _ALWAYS_INLINE_ float pingpong(float value, float length) { - return (length != 0.0f) ? abs(fract((value - length) / (length * 2.0f)) * length * 2.0f - length) : 0.0f; - } - static _ALWAYS_INLINE_ double pingpong(double value, double length) { - return (length != 0.0) ? abs(fract((value - length) / (length * 2.0)) * length * 2.0 - length) : 0.0; - } - - // double only, as these functions are mainly used by the editor and not performance-critical, - static double ease(double p_x, double p_c); - static int step_decimals(double p_step); - static int range_step_decimals(double p_step); // For editor use only. - static double snapped(double p_value, double p_step); - - static uint32_t larger_prime(uint32_t p_val); - - static void seed(uint64_t x); - static void randomize(); - static uint32_t rand_from_seed(uint64_t *seed); - static uint32_t rand(); - static _ALWAYS_INLINE_ double randd() { return (double)rand() / (double)Math::RANDOM_32BIT_MAX; } - static _ALWAYS_INLINE_ float randf() { return (float)rand() / (float)Math::RANDOM_32BIT_MAX; } - static double randfn(double mean, double deviation); - - static double random(double from, double to); - static float random(float from, float to); - static int random(int from, int to); - - static _ALWAYS_INLINE_ bool is_equal_approx(float a, float b) { - // Check for exact equality first, required to handle "infinity" values. - if (a == b) { - return true; - } - // Then check for approximate equality. - float tolerance = (float)CMP_EPSILON * abs(a); - if (tolerance < (float)CMP_EPSILON) { - tolerance = (float)CMP_EPSILON; - } - return abs(a - b) < tolerance; - } - - static _ALWAYS_INLINE_ bool is_equal_approx(float a, float b, float tolerance) { - // Check for exact equality first, required to handle "infinity" values. - if (a == b) { - return true; - } - // Then check for approximate equality. - return abs(a - b) < tolerance; - } - - static _ALWAYS_INLINE_ bool is_zero_approx(float s) { - return abs(s) < (float)CMP_EPSILON; - } - - static _ALWAYS_INLINE_ bool is_equal_approx(double a, double b) { - // Check for exact equality first, required to handle "infinity" values. - if (a == b) { - return true; - } - // Then check for approximate equality. - double tolerance = CMP_EPSILON * abs(a); - if (tolerance < CMP_EPSILON) { - tolerance = CMP_EPSILON; - } - return abs(a - b) < tolerance; - } - - static _ALWAYS_INLINE_ bool is_equal_approx(double a, double b, double tolerance) { - // Check for exact equality first, required to handle "infinity" values. - if (a == b) { - return true; - } - // Then check for approximate equality. - return abs(a - b) < tolerance; - } - - static _ALWAYS_INLINE_ bool is_zero_approx(double s) { - return abs(s) < CMP_EPSILON; - } - - static _ALWAYS_INLINE_ float absf(float g) { - union { - float f; - uint32_t i; - } u; - - u.f = g; - u.i &= 2147483647u; - return u.f; - } - - static _ALWAYS_INLINE_ double absd(double g) { - union { - double d; - uint64_t i; - } u; - u.d = g; - u.i &= (uint64_t)9223372036854775807ll; - return u.d; - } - - // This function should be as fast as possible and rounding mode should not matter. - static _ALWAYS_INLINE_ int fast_ftoi(float a) { - // Assuming every supported compiler has `lrint()`. - return lrintf(a); - } - - static _ALWAYS_INLINE_ uint32_t halfbits_to_floatbits(uint16_t h) { - uint16_t h_exp, h_sig; - uint32_t f_sgn, f_exp, f_sig; - - h_exp = (h & 0x7c00u); - f_sgn = ((uint32_t)h & 0x8000u) << 16; - switch (h_exp) { - case 0x0000u: /* 0 or subnormal */ - h_sig = (h & 0x03ffu); - /* Signed zero */ - if (h_sig == 0) { - return f_sgn; - } - /* Subnormal */ - h_sig <<= 1; - while ((h_sig & 0x0400u) == 0) { - h_sig <<= 1; - h_exp++; - } - f_exp = ((uint32_t)(127 - 15 - h_exp)) << 23; - f_sig = ((uint32_t)(h_sig & 0x03ffu)) << 13; - return f_sgn + f_exp + f_sig; - case 0x7c00u: /* inf or NaN */ - /* All-ones exponent and a copy of the significand */ - return f_sgn + 0x7f800000u + (((uint32_t)(h & 0x03ffu)) << 13); - default: /* normalized */ - /* Just need to adjust the exponent and shift */ - return f_sgn + (((uint32_t)(h & 0x7fffu) + 0x1c000u) << 13); - } - } - - static _ALWAYS_INLINE_ float halfptr_to_float(const uint16_t *h) { - union { - uint32_t u32; - float f32; - } u; - - u.u32 = halfbits_to_floatbits(*h); - return u.f32; - } - - static _ALWAYS_INLINE_ float half_to_float(const uint16_t h) { - return halfptr_to_float(&h); - } - - static _ALWAYS_INLINE_ uint16_t make_half_float(float f) { - union { - float fv; - uint32_t ui; - } ci; - ci.fv = f; - - uint32_t x = ci.ui; - uint32_t sign = (unsigned short)(x >> 31); - uint32_t mantissa; - uint32_t exponent; - uint16_t hf; - - // get mantissa - mantissa = x & ((1 << 23) - 1); - // get exponent bits - exponent = x & (0xFF << 23); - if (exponent >= 0x47800000) { - // check if the original single precision float number is a NaN - if (mantissa && (exponent == (0xFF << 23))) { - // we have a single precision NaN - mantissa = (1 << 23) - 1; - } else { - // 16-bit half-float representation stores number as Inf - mantissa = 0; - } - hf = (((uint16_t)sign) << 15) | (uint16_t)((0x1F << 10)) | - (uint16_t)(mantissa >> 13); - } - // check if exponent is <= -15 - else if (exponent <= 0x38000000) { - /* - // store a denorm half-float value or zero - exponent = (0x38000000 - exponent) >> 23; - mantissa >>= (14 + exponent); - - hf = (((uint16_t)sign) << 15) | (uint16_t)(mantissa); - */ - hf = 0; //denormals do not work for 3D, convert to zero + return abs(p_left - p_right) < tolerance; +} + +_ALWAYS_INLINE_ bool is_zero_approx(double p_value) { + return abs(p_value) < CMP_EPSILON; +} +_ALWAYS_INLINE_ bool is_zero_approx(float p_value) { + return abs(p_value) < (float)CMP_EPSILON; +} + +_ALWAYS_INLINE_ bool is_same(double p_left, double p_right) { + return (p_left == p_right) || (is_nan(p_left) && is_nan(p_right)); +} +_ALWAYS_INLINE_ bool is_same(float p_left, float p_right) { + return (p_left == p_right) || (is_nan(p_left) && is_nan(p_right)); +} + +_ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_s) { + if (is_equal_approx(p_from, p_to)) { + if (likely(p_from <= p_to)) { + return p_s <= p_from ? 0.0 : 1.0; } else { - hf = (((uint16_t)sign) << 15) | - (uint16_t)((exponent - 0x38000000) >> 13) | - (uint16_t)(mantissa >> 13); + return p_s <= p_to ? 1.0 : 0.0; } - - return hf; } - - static _ALWAYS_INLINE_ float snap_scalar(float p_offset, float p_step, float p_target) { - return p_step != 0 ? Math::snapped(p_target - p_offset, p_step) + p_offset : p_target; + double s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0, 1.0); + return s * s * (3.0 - 2.0 * s); +} +_ALWAYS_INLINE_ float smoothstep(float p_from, float p_to, float p_s) { + if (is_equal_approx(p_from, p_to)) { + if (likely(p_from <= p_to)) { + return p_s <= p_from ? 0.0f : 1.0f; + } else { + return p_s <= p_to ? 1.0f : 0.0f; + } } + float s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0f, 1.0f); + return s * s * (3.0f - 2.0f * s); +} - static _ALWAYS_INLINE_ float snap_scalar_separation(float p_offset, float p_step, float p_target, float p_separation) { - if (p_step != 0) { - float a = Math::snapped(p_target - p_offset, p_step + p_separation) + p_offset; - float b = a; - if (p_target >= 0) { - b -= p_separation; - } else { - b += p_step; +_ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) { + return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; +} +_ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { + return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; +} + +_ALWAYS_INLINE_ double rotate_toward(double p_from, double p_to, double p_delta) { + double difference = angle_difference(p_from, p_to); + double abs_difference = abs(difference); + // When `p_delta < 0` move no further than to PI radians away from `p_to` (as PI is the max possible angle distance). + return p_from + CLAMP(p_delta, abs_difference - PI, abs_difference) * (difference >= 0.0 ? 1.0 : -1.0); +} +_ALWAYS_INLINE_ float rotate_toward(float p_from, float p_to, float p_delta) { + float difference = angle_difference(p_from, p_to); + float abs_difference = abs(difference); + // When `p_delta < 0` move no further than to PI radians away from `p_to` (as PI is the max possible angle distance). + return p_from + CLAMP(p_delta, abs_difference - (float)PI, abs_difference) * (difference >= 0.0f ? 1.0f : -1.0f); +} + +_ALWAYS_INLINE_ double linear_to_db(double p_linear) { + return log(p_linear) * 8.6858896380650365530225783783321; +} +_ALWAYS_INLINE_ float linear_to_db(float p_linear) { + return log(p_linear) * (float)8.6858896380650365530225783783321; +} + +_ALWAYS_INLINE_ double db_to_linear(double p_db) { + return exp(p_db * 0.11512925464970228420089957273422); +} +_ALWAYS_INLINE_ float db_to_linear(float p_db) { + return exp(p_db * (float)0.11512925464970228420089957273422); +} + +_ALWAYS_INLINE_ double round(double p_val) { + return ::round(p_val); +} +_ALWAYS_INLINE_ float round(float p_val) { + return ::roundf(p_val); +} + +_ALWAYS_INLINE_ double wrapf(double p_value, double p_min, double p_max) { + double range = p_max - p_min; + if (is_zero_approx(range)) { + return p_min; + } + double result = p_value - (range * floor((p_value - p_min) / range)); + if (is_equal_approx(result, p_max)) { + return p_min; + } + return result; +} +_ALWAYS_INLINE_ float wrapf(float p_value, float p_min, float p_max) { + float range = p_max - p_min; + if (is_zero_approx(range)) { + return p_min; + } + float result = p_value - (range * floor((p_value - p_min) / range)); + if (is_equal_approx(result, p_max)) { + return p_min; + } + return result; +} + +_ALWAYS_INLINE_ int64_t wrapi(int64_t p_value, int64_t p_min, int64_t p_max) { + int64_t range = p_max - p_min; + return range == 0 ? p_min : p_min + ((((p_value - p_min) % range) + range) % range); +} + +_ALWAYS_INLINE_ double fract(double p_value) { + return p_value - floor(p_value); +} +_ALWAYS_INLINE_ float fract(float p_value) { + return p_value - floor(p_value); +} + +_ALWAYS_INLINE_ double pingpong(double p_value, double p_length) { + return (p_length != 0.0) ? abs(fract((p_value - p_length) / (p_length * 2.0)) * p_length * 2.0 - p_length) : 0.0; +} +_ALWAYS_INLINE_ float pingpong(float p_value, float p_length) { + return (p_length != 0.0f) ? abs(fract((p_value - p_length) / (p_length * 2.0f)) * p_length * 2.0f - p_length) : 0.0f; +} + +// double only, as these functions are mainly used by the editor and not performance-critical, +double ease(double p_x, double p_c); +int step_decimals(double p_step); +int range_step_decimals(double p_step); // For editor use only. +double snapped(double p_value, double p_step); + +uint32_t larger_prime(uint32_t p_val); + +void seed(uint64_t p_seed); +void randomize(); +uint32_t rand_from_seed(uint64_t *p_seed); +uint32_t rand(); +_ALWAYS_INLINE_ double randd() { + return (double)rand() / (double)UINT32_MAX; +} +_ALWAYS_INLINE_ float randf() { + return (float)rand() / (float)UINT32_MAX; +} +double randfn(double p_mean, double p_deviation); + +double random(double p_from, double p_to); +float random(float p_from, float p_to); +int random(int p_from, int p_to); + +// This function should be as fast as possible and rounding mode should not matter. +_ALWAYS_INLINE_ int fast_ftoi(float p_value) { + // Assuming every supported compiler has `lrint()`. + return lrintf(p_value); +} + +_ALWAYS_INLINE_ uint32_t halfbits_to_floatbits(uint16_t p_half) { + uint16_t h_exp, h_sig; + uint32_t f_sgn, f_exp, f_sig; + + h_exp = (p_half & 0x7c00u); + f_sgn = ((uint32_t)p_half & 0x8000u) << 16; + switch (h_exp) { + case 0x0000u: /* 0 or subnormal */ + h_sig = (p_half & 0x03ffu); + /* Signed zero */ + if (h_sig == 0) { + return f_sgn; } - return (Math::abs(p_target - a) < Math::abs(p_target - b)) ? a : b; - } - return p_target; + /* Subnormal */ + h_sig <<= 1; + while ((h_sig & 0x0400u) == 0) { + h_sig <<= 1; + h_exp++; + } + f_exp = ((uint32_t)(127 - 15 - h_exp)) << 23; + f_sig = ((uint32_t)(h_sig & 0x03ffu)) << 13; + return f_sgn + f_exp + f_sig; + case 0x7c00u: /* inf or NaN */ + /* All-ones exponent and a copy of the significand */ + return f_sgn + 0x7f800000u + (((uint32_t)(p_half & 0x03ffu)) << 13); + default: /* normalized */ + /* Just need to adjust the exponent and shift */ + return f_sgn + (((uint32_t)(p_half & 0x7fffu) + 0x1c000u) << 13); } -}; +} -#endif // MATH_FUNCS_H +_ALWAYS_INLINE_ float halfptr_to_float(const uint16_t *p_half) { + union { + uint32_t u32; + float f32; + } u; + + u.u32 = halfbits_to_floatbits(*p_half); + return u.f32; +} + +_ALWAYS_INLINE_ float half_to_float(const uint16_t p_half) { + return halfptr_to_float(&p_half); +} + +_ALWAYS_INLINE_ uint16_t make_half_float(float p_value) { + union { + float fv; + uint32_t ui; + } ci; + ci.fv = p_value; + + uint32_t x = ci.ui; + uint32_t sign = (unsigned short)(x >> 31); + uint32_t mantissa; + uint32_t exponent; + uint16_t hf; + + // get mantissa + mantissa = x & ((1 << 23) - 1); + // get exponent bits + exponent = x & (0xFF << 23); + if (exponent >= 0x47800000) { + // check if the original single precision float number is a NaN + if (mantissa && (exponent == (0xFF << 23))) { + // we have a single precision NaN + mantissa = (1 << 23) - 1; + } else { + // 16-bit half-float representation stores number as Inf + mantissa = 0; + } + hf = (((uint16_t)sign) << 15) | (uint16_t)((0x1F << 10)) | + (uint16_t)(mantissa >> 13); + } + // check if exponent is <= -15 + else if (exponent <= 0x38000000) { + /* + // store a denorm half-float value or zero + exponent = (0x38000000 - exponent) >> 23; + mantissa >>= (14 + exponent); + + hf = (((uint16_t)sign) << 15) | (uint16_t)(mantissa); + */ + hf = 0; //denormals do not work for 3D, convert to zero + } else { + hf = (((uint16_t)sign) << 15) | + (uint16_t)((exponent - 0x38000000) >> 13) | + (uint16_t)(mantissa >> 13); + } + + return hf; +} + +_ALWAYS_INLINE_ float snap_scalar(float p_offset, float p_step, float p_target) { + return p_step != 0 ? snapped(p_target - p_offset, p_step) + p_offset : p_target; +} + +_ALWAYS_INLINE_ float snap_scalar_separation(float p_offset, float p_step, float p_target, float p_separation) { + if (p_step != 0) { + float a = snapped(p_target - p_offset, p_step + p_separation) + p_offset; + float b = a; + if (p_target >= 0) { + b -= p_separation; + } else { + b += p_step; + } + return (abs(p_target - a) < abs(p_target - b)) ? a : b; + } + return p_target; +} + +}; // namespace Math diff --git a/engine/core/math/plane.cpp b/engine/core/math/plane.cpp index 6b9bcea0..74783b2a 100644 --- a/engine/core/math/plane.cpp +++ b/engine/core/math/plane.cpp @@ -58,7 +58,7 @@ Vector3 Plane::get_any_perpendicular_normal() const { static const Vector3 p2 = Vector3(0, 1, 0); Vector3 p; - if (ABS(normal.dot(p1)) > 0.99f) { // if too similar to p1 + if (Math::abs(normal.dot(p1)) > 0.99f) { // if too similar to p1 p = p2; // use p2 } else { p = p1; // use p1 @@ -172,6 +172,10 @@ bool Plane::is_equal_approx(const Plane &p_plane) const { return normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d); } +bool Plane::is_same(const Plane &p_plane) const { + return normal.is_same(p_plane.normal) && Math::is_same(d, p_plane.d); +} + bool Plane::is_finite() const { return normal.is_finite() && Math::is_finite(d); } diff --git a/engine/core/math/plane.h b/engine/core/math/plane.h index 65783ff4..77a53e57 100644 --- a/engine/core/math/plane.h +++ b/engine/core/math/plane.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef PLANE_H -#define PLANE_H +#pragma once #include "core/math/vector3.h" @@ -71,21 +70,22 @@ struct [[nodiscard]] Plane { /* misc */ - Plane operator-() const { return Plane(-normal, -d); } + constexpr Plane operator-() const { return Plane(-normal, -d); } bool is_equal_approx(const Plane &p_plane) const; + bool is_same(const Plane &p_plane) const; bool is_equal_approx_any_side(const Plane &p_plane) const; bool is_finite() const; - _FORCE_INLINE_ bool operator==(const Plane &p_plane) const; - _FORCE_INLINE_ bool operator!=(const Plane &p_plane) const; + constexpr bool operator==(const Plane &p_plane) const; + constexpr bool operator!=(const Plane &p_plane) const; operator String() const; - _FORCE_INLINE_ Plane() {} - _FORCE_INLINE_ Plane(real_t p_a, real_t p_b, real_t p_c, real_t p_d) : + Plane() = default; + constexpr Plane(real_t p_a, real_t p_b, real_t p_c, real_t p_d) : normal(p_a, p_b, p_c), d(p_d) {} - _FORCE_INLINE_ Plane(const Vector3 &p_normal, real_t p_d = 0.0); + constexpr Plane(const Vector3 &p_normal, real_t p_d = 0.0); _FORCE_INLINE_ Plane(const Vector3 &p_normal, const Vector3 &p_point); _FORCE_INLINE_ Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_point3, ClockDirection p_dir = CLOCKWISE); }; @@ -100,11 +100,11 @@ real_t Plane::distance_to(const Vector3 &p_point) const { bool Plane::has_point(const Vector3 &p_point, real_t p_tolerance) const { real_t dist = normal.dot(p_point) - d; - dist = ABS(dist); + dist = Math::abs(dist); return (dist <= p_tolerance); } -Plane::Plane(const Vector3 &p_normal, real_t p_d) : +constexpr Plane::Plane(const Vector3 &p_normal, real_t p_d) : normal(p_normal), d(p_d) { } @@ -125,12 +125,13 @@ Plane::Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_ d = normal.dot(p_point1); } -bool Plane::operator==(const Plane &p_plane) const { +constexpr bool Plane::operator==(const Plane &p_plane) const { return normal == p_plane.normal && d == p_plane.d; } -bool Plane::operator!=(const Plane &p_plane) const { +constexpr bool Plane::operator!=(const Plane &p_plane) const { return normal != p_plane.normal || d != p_plane.d; } -#endif // PLANE_H +template <> +struct is_zero_constructible : std::true_type {}; diff --git a/engine/core/math/projection.cpp b/engine/core/math/projection.cpp index 20638826..a71e44d9 100644 --- a/engine/core/math/projection.cpp +++ b/engine/core/math/projection.cpp @@ -402,82 +402,35 @@ void Projection::set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, r } real_t Projection::get_z_far() const { - const real_t *matrix = (const real_t *)columns; - Plane new_plane = Plane(matrix[3] - matrix[2], - matrix[7] - matrix[6], - matrix[11] - matrix[10], - matrix[15] - matrix[14]); - - new_plane.normalize(); - - return new_plane.d; + // NOTE: This assumes z-facing near and far planes, i.e. that : + // - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0) + // - near and far planes are z-facing (i.e. columns[0][2] and [1][2] == 0) + return (columns[3][3] - columns[3][2]) / (columns[2][3] - columns[2][2]); } real_t Projection::get_z_near() const { - const real_t *matrix = (const real_t *)columns; - Plane new_plane = Plane(matrix[3] + matrix[2], - matrix[7] + matrix[6], - matrix[11] + matrix[10], - -matrix[15] - matrix[14]); - - new_plane.normalize(); - return new_plane.d; + // NOTE: This assumes z-facing near and far planes, i.e. that : + // - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0) + // - near and far planes are z-facing (i.e. columns[0][2] and [1][2] == 0) + return (columns[3][3] + columns[3][2]) / (columns[2][3] + columns[2][2]); } Vector2 Projection::get_viewport_half_extents() const { - const real_t *matrix = (const real_t *)columns; - ///////--- Near Plane ---/////// - Plane near_plane = Plane(matrix[3] + matrix[2], - matrix[7] + matrix[6], - matrix[11] + matrix[10], - -matrix[15] - matrix[14]); - near_plane.normalize(); - - ///////--- Right Plane ---/////// - Plane right_plane = Plane(matrix[3] - matrix[0], - matrix[7] - matrix[4], - matrix[11] - matrix[8], - -matrix[15] + matrix[12]); - right_plane.normalize(); - - Plane top_plane = Plane(matrix[3] - matrix[1], - matrix[7] - matrix[5], - matrix[11] - matrix[9], - -matrix[15] + matrix[13]); - top_plane.normalize(); - - Vector3 res; - near_plane.intersect_3(right_plane, top_plane, &res); - - return Vector2(res.x, res.y); + // NOTE: This assumes a symmetrical frustum, i.e. that : + // - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0) + // - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0) + // - there is no offset / skew (i.e. columns[2][0] == columns[2][1] == 0) + real_t w = -get_z_near() * columns[2][3] + columns[3][3]; + return Vector2(w / columns[0][0], w / columns[1][1]); } Vector2 Projection::get_far_plane_half_extents() const { - const real_t *matrix = (const real_t *)columns; - ///////--- Far Plane ---/////// - Plane far_plane = Plane(matrix[3] - matrix[2], - matrix[7] - matrix[6], - matrix[11] - matrix[10], - -matrix[15] + matrix[14]); - far_plane.normalize(); - - ///////--- Right Plane ---/////// - Plane right_plane = Plane(matrix[3] - matrix[0], - matrix[7] - matrix[4], - matrix[11] - matrix[8], - -matrix[15] + matrix[12]); - right_plane.normalize(); - - Plane top_plane = Plane(matrix[3] - matrix[1], - matrix[7] - matrix[5], - matrix[11] - matrix[9], - -matrix[15] + matrix[13]); - top_plane.normalize(); - - Vector3 res; - far_plane.intersect_3(right_plane, top_plane, &res); - - return Vector2(res.x, res.y); + // NOTE: This assumes a symmetrical frustum, i.e. that : + // - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0) + // - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0) + // - there is no offset / skew (i.e. columns[2][0] == columns[2][1] == 0) + real_t w = -get_z_far() * columns[2][3] + columns[3][3]; + return Vector2(w / columns[0][0], w / columns[1][1]); } bool Projection::get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const { @@ -827,24 +780,8 @@ void Projection::flip_y() { } } -Projection::Projection() { - set_identity(); -} - -Projection Projection::operator*(const Projection &p_matrix) const { - Projection new_matrix; - - for (int j = 0; j < 4; j++) { - for (int i = 0; i < 4; i++) { - real_t ab = 0; - for (int k = 0; k < 4; k++) { - ab += columns[k][i] * p_matrix.columns[j][k]; - } - new_matrix.columns[j][i] = ab; - } - } - - return new_matrix; +bool Projection::is_same(const Projection &p_cam) const { + return columns[0].is_same(p_cam.columns[0]) && columns[1].is_same(p_cam.columns[1]) && columns[2].is_same(p_cam.columns[2]) && columns[3].is_same(p_cam.columns[3]); } void Projection::set_depth_correction(bool p_flip_y, bool p_reverse_z, bool p_remap_z) { @@ -919,53 +856,45 @@ Projection::operator String() const { } real_t Projection::get_aspect() const { - Vector2 vp_he = get_viewport_half_extents(); - return vp_he.x / vp_he.y; + // NOTE: This assumes a rectangular projection plane, i.e. that : + // - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0) + // - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0) + return columns[1][1] / columns[0][0]; } int Projection::get_pixels_per_meter(int p_for_pixel_width) const { - Vector3 result = xform(Vector3(1, 0, -1)); - - return int((result.x * 0.5 + 0.5) * p_for_pixel_width); + // NOTE: This assumes a rectangular projection plane, i.e. that : + // - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0) + // - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0) + real_t width = 2 * (-get_z_near() * columns[2][3] + columns[3][3]) / columns[0][0]; + return p_for_pixel_width / width; // Note : return type should be real_t (kept as int for compatibility for now). } bool Projection::is_orthogonal() const { - return columns[3][3] == 1.0; + // NOTE: This assumes that the matrix is a projection across z-axis + // i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0 + return columns[2][3] == 0.0; } real_t Projection::get_fov() const { - const real_t *matrix = (const real_t *)columns; - - Plane right_plane = Plane(matrix[3] - matrix[0], - matrix[7] - matrix[4], - matrix[11] - matrix[8], - -matrix[15] + matrix[12]); - right_plane.normalize(); - - if ((matrix[8] == 0) && (matrix[9] == 0)) { - return Math::rad_to_deg(Math::acos(Math::abs(right_plane.normal.x))) * 2.0; + // NOTE: This assumes a rectangular projection plane, i.e. that : + // - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0) + // - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0) + if (columns[2][0] == 0) { + return Math::rad_to_deg(2 * Math::atan2(1, columns[0][0])); } else { - // our frustum is asymmetrical need to calculate the left planes angle separately.. - Plane left_plane = Plane(matrix[3] + matrix[0], - matrix[7] + matrix[4], - matrix[11] + matrix[8], - matrix[15] + matrix[12]); - left_plane.normalize(); - - return Math::rad_to_deg(Math::acos(Math::abs(left_plane.normal.x))) + Math::rad_to_deg(Math::acos(Math::abs(right_plane.normal.x))); + // The frustum is asymmetrical so we need to calculate the left and right angles separately. + real_t right = Math::atan2(columns[2][0] + 1, columns[0][0]); + real_t left = Math::atan2(columns[2][0] - 1, columns[0][0]); + return Math::rad_to_deg(right - left); } } real_t Projection::get_lod_multiplier() const { - if (is_orthogonal()) { - return get_viewport_half_extents().x; - } else { - const real_t zn = get_z_near(); - const real_t width = get_viewport_half_extents().x * 2.0f; - return 1.0f / (zn / width); - } - - // Usage is lod_size / (lod_distance * multiplier) < threshold + // NOTE: This assumes a rectangular projection plane, i.e. that : + // - the matrix is a projection across z-axis (i.e. is invertible and columns[0][1], [0][3], [1][0] and [1][3] == 0) + // - the projection plane is rectangular (i.e. columns[0][2] and [1][2] == 0 if columns[2][3] != 0) + return 2 / columns[0][0]; } void Projection::make_scale(const Vector3 &p_scale) { @@ -1028,13 +957,6 @@ Projection::operator Transform3D() const { return tr; } -Projection::Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w) { - columns[0] = p_x; - columns[1] = p_y; - columns[2] = p_z; - columns[3] = p_w; -} - Projection::Projection(const Transform3D &p_transform) { const Transform3D &tr = p_transform; real_t *m = &columns[0][0]; @@ -1056,6 +978,3 @@ Projection::Projection(const Transform3D &p_transform) { m[14] = tr.origin.z; m[15] = 1.0; } - -Projection::~Projection() { -} diff --git a/engine/core/math/projection.h b/engine/core/math/projection.h index 5af43561..6d5f585c 100644 --- a/engine/core/math/projection.h +++ b/engine/core/math/projection.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef PROJECTION_H -#define PROJECTION_H +#pragma once #include "core/math/vector3.h" #include "core/math/vector4.h" @@ -53,14 +52,19 @@ struct [[nodiscard]] Projection { PLANE_BOTTOM }; - Vector4 columns[4]; + Vector4 columns[4] = { + { 1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 }, + }; - _FORCE_INLINE_ const Vector4 &operator[](int p_axis) const { + constexpr const Vector4 &operator[](int p_axis) const { DEV_ASSERT((unsigned int)p_axis < 4); return columns[p_axis]; } - _FORCE_INLINE_ Vector4 &operator[](int p_axis) { + constexpr Vector4 &operator[](int p_axis) { DEV_ASSERT((unsigned int)p_axis < 4); return columns[p_axis]; } @@ -115,7 +119,7 @@ struct [[nodiscard]] Projection { void invert(); Projection inverse() const; - Projection operator*(const Projection &p_matrix) const; + constexpr Projection operator*(const Projection &p_matrix) const; Plane xform4(const Plane &p_vec4) const; _FORCE_INLINE_ Vector3 xform(const Vector3 &p_vec3) const; @@ -133,7 +137,9 @@ struct [[nodiscard]] Projection { void flip_y(); - bool operator==(const Projection &p_cam) const { + bool is_same(const Projection &p_cam) const; + + constexpr bool operator==(const Projection &p_cam) const { for (uint32_t i = 0; i < 4; i++) { for (uint32_t j = 0; j < 4; j++) { if (columns[i][j] != p_cam.columns[i][j]) { @@ -144,18 +150,41 @@ struct [[nodiscard]] Projection { return true; } - bool operator!=(const Projection &p_cam) const { + constexpr bool operator!=(const Projection &p_cam) const { return !(*this == p_cam); } real_t get_lod_multiplier() const; - Projection(); - Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w); + Projection() = default; + constexpr Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w) : + columns{ p_x, p_y, p_z, p_w } {} + constexpr Projection(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_xw, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_yw, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_zw, real_t p_wx, real_t p_wy, real_t p_wz, real_t p_ww) : + columns{ + { p_xx, p_xy, p_xz, p_xw }, + { p_yx, p_yy, p_yz, p_yw }, + { p_zx, p_zy, p_zz, p_zw }, + { p_wx, p_wy, p_wz, p_ww }, + } {} Projection(const Transform3D &p_transform); - ~Projection(); }; +constexpr Projection Projection::operator*(const Projection &p_matrix) const { + Projection new_matrix; + + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 4; i++) { + real_t ab = 0; + for (int k = 0; k < 4; k++) { + ab += columns[k][i] * p_matrix.columns[j][k]; + } + new_matrix.columns[j][i] = ab; + } + } + + return new_matrix; +} + Vector3 Projection::xform(const Vector3 &p_vec3) const { Vector3 ret; ret.x = columns[0][0] * p_vec3.x + columns[1][0] * p_vec3.y + columns[2][0] * p_vec3.z + columns[3][0]; @@ -164,5 +193,3 @@ Vector3 Projection::xform(const Vector3 &p_vec3) const { real_t w = columns[0][3] * p_vec3.x + columns[1][3] * p_vec3.y + columns[2][3] * p_vec3.z + columns[3][3]; return ret / w; } - -#endif // PROJECTION_H diff --git a/engine/core/math/quaternion.cpp b/engine/core/math/quaternion.cpp index 08eac14b..6c0b491a 100644 --- a/engine/core/math/quaternion.cpp +++ b/engine/core/math/quaternion.cpp @@ -46,26 +46,14 @@ Vector3 Quaternion::get_euler(EulerOrder p_order) const { return Basis(*this).get_euler(p_order); } -void Quaternion::operator*=(const Quaternion &p_q) { - real_t xx = w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y; - real_t yy = w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z; - real_t zz = w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x; - w = w * p_q.w - x * p_q.x - y * p_q.y - z * p_q.z; - x = xx; - y = yy; - z = zz; -} - -Quaternion Quaternion::operator*(const Quaternion &p_q) const { - Quaternion r = *this; - r *= p_q; - return r; -} - bool Quaternion::is_equal_approx(const Quaternion &p_quaternion) const { return Math::is_equal_approx(x, p_quaternion.x) && Math::is_equal_approx(y, p_quaternion.y) && Math::is_equal_approx(z, p_quaternion.z) && Math::is_equal_approx(w, p_quaternion.w); } +bool Quaternion::is_same(const Quaternion &p_quaternion) const { + return Math::is_same(x, p_quaternion.x) && Math::is_same(y, p_quaternion.y) && Math::is_same(z, p_quaternion.z) && Math::is_same(w, p_quaternion.w); +} + bool Quaternion::is_finite() const { return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z) && Math::is_finite(w); } diff --git a/engine/core/math/quaternion.h b/engine/core/math/quaternion.h index 58a4ec5b..6dae7a79 100644 --- a/engine/core/math/quaternion.h +++ b/engine/core/math/quaternion.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef QUATERNION_H -#define QUATERNION_H +#pragma once #include "core/math/math_funcs.h" #include "core/math/vector3.h" @@ -37,6 +36,7 @@ struct [[nodiscard]] Quaternion { union { + // NOLINTBEGIN(modernize-use-default-member-init) struct { real_t x; real_t y; @@ -44,6 +44,7 @@ struct [[nodiscard]] Quaternion { real_t w; }; real_t components[4] = { 0, 0, 0, 1.0 }; + // NOLINTEND(modernize-use-default-member-init) }; _FORCE_INLINE_ real_t &operator[](int p_idx) { @@ -54,6 +55,7 @@ struct [[nodiscard]] Quaternion { } _FORCE_INLINE_ real_t length_squared() const; bool is_equal_approx(const Quaternion &p_quaternion) const; + bool is_same(const Quaternion &p_quaternion) const; bool is_finite() const; real_t length() const; void normalize(); @@ -84,8 +86,8 @@ struct [[nodiscard]] Quaternion { r_axis.z = z * r; } - void operator*=(const Quaternion &p_q); - Quaternion operator*(const Quaternion &p_q) const; + constexpr void operator*=(const Quaternion &p_q); + constexpr Quaternion operator*(const Quaternion &p_q) const; _FORCE_INLINE_ Vector3 xform(const Vector3 &p_v) const { #ifdef MATH_CHECKS @@ -100,40 +102,33 @@ struct [[nodiscard]] Quaternion { return inverse().xform(p_v); } - _FORCE_INLINE_ void operator+=(const Quaternion &p_q); - _FORCE_INLINE_ void operator-=(const Quaternion &p_q); - _FORCE_INLINE_ void operator*=(real_t p_s); - _FORCE_INLINE_ void operator/=(real_t p_s); - _FORCE_INLINE_ Quaternion operator+(const Quaternion &p_q2) const; - _FORCE_INLINE_ Quaternion operator-(const Quaternion &p_q2) const; - _FORCE_INLINE_ Quaternion operator-() const; - _FORCE_INLINE_ Quaternion operator*(real_t p_s) const; - _FORCE_INLINE_ Quaternion operator/(real_t p_s) const; + constexpr void operator+=(const Quaternion &p_q); + constexpr void operator-=(const Quaternion &p_q); + constexpr void operator*=(real_t p_s); + constexpr void operator/=(real_t p_s); + constexpr Quaternion operator+(const Quaternion &p_q2) const; + constexpr Quaternion operator-(const Quaternion &p_q2) const; + constexpr Quaternion operator-() const; + constexpr Quaternion operator*(real_t p_s) const; + constexpr Quaternion operator/(real_t p_s) const; - _FORCE_INLINE_ bool operator==(const Quaternion &p_quaternion) const; - _FORCE_INLINE_ bool operator!=(const Quaternion &p_quaternion) const; + constexpr bool operator==(const Quaternion &p_quaternion) const; + constexpr bool operator!=(const Quaternion &p_quaternion) const; operator String() const; - _FORCE_INLINE_ Quaternion() {} + constexpr Quaternion() : + x(0), y(0), z(0), w(1) {} - _FORCE_INLINE_ Quaternion(real_t p_x, real_t p_y, real_t p_z, real_t p_w) : - x(p_x), - y(p_y), - z(p_z), - w(p_w) { - } + constexpr Quaternion(real_t p_x, real_t p_y, real_t p_z, real_t p_w) : + x(p_x), y(p_y), z(p_z), w(p_w) {} Quaternion(const Vector3 &p_axis, real_t p_angle); - Quaternion(const Quaternion &p_q) : - x(p_q.x), - y(p_q.y), - z(p_q.z), - w(p_q.w) { - } + constexpr Quaternion(const Quaternion &p_q) : + x(p_q.x), y(p_q.y), z(p_q.z), w(p_q.w) {} - void operator=(const Quaternion &p_q) { + constexpr void operator=(const Quaternion &p_q) { x = p_q.x; y = p_q.y; z = p_q.z; @@ -178,64 +173,78 @@ real_t Quaternion::length_squared() const { return dot(*this); } -void Quaternion::operator+=(const Quaternion &p_q) { +constexpr void Quaternion::operator+=(const Quaternion &p_q) { x += p_q.x; y += p_q.y; z += p_q.z; w += p_q.w; } -void Quaternion::operator-=(const Quaternion &p_q) { +constexpr void Quaternion::operator-=(const Quaternion &p_q) { x -= p_q.x; y -= p_q.y; z -= p_q.z; w -= p_q.w; } -void Quaternion::operator*=(real_t p_s) { +constexpr void Quaternion::operator*=(real_t p_s) { x *= p_s; y *= p_s; z *= p_s; w *= p_s; } -void Quaternion::operator/=(real_t p_s) { - *this *= 1.0f / p_s; +constexpr void Quaternion::operator/=(real_t p_s) { + *this *= (1 / p_s); } -Quaternion Quaternion::operator+(const Quaternion &p_q2) const { +constexpr Quaternion Quaternion::operator+(const Quaternion &p_q2) const { const Quaternion &q1 = *this; return Quaternion(q1.x + p_q2.x, q1.y + p_q2.y, q1.z + p_q2.z, q1.w + p_q2.w); } -Quaternion Quaternion::operator-(const Quaternion &p_q2) const { +constexpr Quaternion Quaternion::operator-(const Quaternion &p_q2) const { const Quaternion &q1 = *this; return Quaternion(q1.x - p_q2.x, q1.y - p_q2.y, q1.z - p_q2.z, q1.w - p_q2.w); } -Quaternion Quaternion::operator-() const { +constexpr Quaternion Quaternion::operator-() const { const Quaternion &q2 = *this; return Quaternion(-q2.x, -q2.y, -q2.z, -q2.w); } -Quaternion Quaternion::operator*(real_t p_s) const { +constexpr Quaternion Quaternion::operator*(real_t p_s) const { return Quaternion(x * p_s, y * p_s, z * p_s, w * p_s); } -Quaternion Quaternion::operator/(real_t p_s) const { - return *this * (1.0f / p_s); +constexpr Quaternion Quaternion::operator/(real_t p_s) const { + return *this * (1 / p_s); } -bool Quaternion::operator==(const Quaternion &p_quaternion) const { +constexpr bool Quaternion::operator==(const Quaternion &p_quaternion) const { return x == p_quaternion.x && y == p_quaternion.y && z == p_quaternion.z && w == p_quaternion.w; } -bool Quaternion::operator!=(const Quaternion &p_quaternion) const { +constexpr bool Quaternion::operator!=(const Quaternion &p_quaternion) const { return x != p_quaternion.x || y != p_quaternion.y || z != p_quaternion.z || w != p_quaternion.w; } -_FORCE_INLINE_ Quaternion operator*(real_t p_real, const Quaternion &p_quaternion) { - return p_quaternion * p_real; +constexpr void Quaternion::operator*=(const Quaternion &p_q) { + real_t xx = w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y; + real_t yy = w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z; + real_t zz = w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x; + w = w * p_q.w - x * p_q.x - y * p_q.y - z * p_q.z; + x = xx; + y = yy; + z = zz; } -#endif // QUATERNION_H +constexpr Quaternion Quaternion::operator*(const Quaternion &p_q) const { + Quaternion r = *this; + r *= p_q; + return r; +} + +constexpr Quaternion operator*(real_t p_real, const Quaternion &p_quaternion) { + return p_quaternion * p_real; +} diff --git a/engine/core/math/quick_hull.cpp b/engine/core/math/quick_hull.cpp index 34a0c021..360b272e 100644 --- a/engine/core/math/quick_hull.cpp +++ b/engine/core/math/quick_hull.cpp @@ -30,6 +30,9 @@ #include "quick_hull.h" +#include "core/templates/hash_map.h" +#include "core/templates/hash_set.h" + uint32_t QuickHull::debug_stop_after = 0xFFFFFFFF; Error QuickHull::build(const Vector &p_points, Geometry3D::MeshData &r_mesh) { @@ -320,7 +323,7 @@ Error QuickHull::build(const Vector &p_points, Geometry3D::MeshData &r_ for (List::Element *&E : new_faces) { Face &f2 = E->get(); - if (f2.points_over.size() == 0) { + if (f2.points_over.is_empty()) { faces.move_to_front(E); } } diff --git a/engine/core/math/quick_hull.h b/engine/core/math/quick_hull.h index f4891a7c..e374211d 100644 --- a/engine/core/math/quick_hull.h +++ b/engine/core/math/quick_hull.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef QUICK_HULL_H -#define QUICK_HULL_H +#pragma once #include "core/math/geometry_3d.h" #include "core/templates/list.h" @@ -89,5 +88,3 @@ public: static uint32_t debug_stop_after; static Error build(const Vector &p_points, Geometry3D::MeshData &r_mesh); }; - -#endif // QUICK_HULL_H diff --git a/engine/core/math/random_number_generator.h b/engine/core/math/random_number_generator.h index 7ec4cdff..aa21b41a 100644 --- a/engine/core/math/random_number_generator.h +++ b/engine/core/math/random_number_generator.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef RANDOM_NUMBER_GENERATOR_H -#define RANDOM_NUMBER_GENERATOR_H +#pragma once #include "core/math/random_pcg.h" #include "core/object/ref_counted.h" @@ -61,5 +60,3 @@ public: RandomNumberGenerator() { randbase.randomize(); } }; - -#endif // RANDOM_NUMBER_GENERATOR_H diff --git a/engine/core/math/random_pcg.h b/engine/core/math/random_pcg.h index 6bad7005..f39cd7ab 100644 --- a/engine/core/math/random_pcg.h +++ b/engine/core/math/random_pcg.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef RANDOM_PCG_H -#define RANDOM_PCG_H +#pragma once #include "core/math/math_defs.h" @@ -135,19 +134,17 @@ public: if (temp < CMP_EPSILON) { temp += CMP_EPSILON; // To prevent generating of INF value in log function, resulting to return NaN value from this function. } - return p_mean + p_deviation * (cos(Math_TAU * randd()) * sqrt(-2.0 * log(temp))); // Box-Muller transform. + return p_mean + p_deviation * (cos(Math::TAU * randd()) * sqrt(-2.0 * log(temp))); // Box-Muller transform. } _FORCE_INLINE_ float randfn(float p_mean, float p_deviation) { float temp = randf(); if (temp < CMP_EPSILON) { temp += CMP_EPSILON; // To prevent generating of INF value in log function, resulting to return NaN value from this function. } - return p_mean + p_deviation * (cos((float)Math_TAU * randf()) * sqrt(-2.0 * log(temp))); // Box-Muller transform. + return p_mean + p_deviation * (cos((float)Math::TAU * randf()) * sqrt(-2.0 * log(temp))); // Box-Muller transform. } double random(double p_from, double p_to); float random(float p_from, float p_to); int random(int p_from, int p_to); }; - -#endif // RANDOM_PCG_H diff --git a/engine/core/math/rect2.cpp b/engine/core/math/rect2.cpp index 7f77b078..102a9e4b 100644 --- a/engine/core/math/rect2.cpp +++ b/engine/core/math/rect2.cpp @@ -38,6 +38,10 @@ bool Rect2::is_equal_approx(const Rect2 &p_rect) const { return position.is_equal_approx(p_rect.position) && size.is_equal_approx(p_rect.size); } +bool Rect2::is_same(const Rect2 &p_rect) const { + return position.is_same(p_rect.position) && size.is_same(p_rect.size); +} + bool Rect2::is_finite() const { return position.is_finite() && size.is_finite(); } diff --git a/engine/core/math/rect2.h b/engine/core/math/rect2.h index 817923c1..27a701e9 100644 --- a/engine/core/math/rect2.h +++ b/engine/core/math/rect2.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef RECT2_H -#define RECT2_H +#pragma once #include "core/error/error_macros.h" #include "core/math/vector2.h" @@ -203,10 +202,11 @@ struct [[nodiscard]] Rect2 { } bool is_equal_approx(const Rect2 &p_rect) const; + bool is_same(const Rect2 &p_rect) const; bool is_finite() const; - bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; } - bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; } + constexpr bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; } + constexpr bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; } inline Rect2 grow(real_t p_amount) const { Rect2 g = *this; @@ -361,15 +361,16 @@ struct [[nodiscard]] Rect2 { operator String() const; operator Rect2i() const; - Rect2() {} - Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) : + Rect2() = default; + constexpr Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) : position(Point2(p_x, p_y)), size(Size2(p_width, p_height)) { } - Rect2(const Point2 &p_pos, const Size2 &p_size) : + constexpr Rect2(const Point2 &p_pos, const Size2 &p_size) : position(p_pos), size(p_size) { } }; -#endif // RECT2_H +template <> +struct is_zero_constructible : std::true_type {}; diff --git a/engine/core/math/rect2i.h b/engine/core/math/rect2i.h index 5f3a3d54..d0b8b5e7 100644 --- a/engine/core/math/rect2i.h +++ b/engine/core/math/rect2i.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef RECT2I_H -#define RECT2I_H +#pragma once #include "core/error/error_macros.h" #include "core/math/vector2i.h" @@ -144,8 +143,8 @@ struct [[nodiscard]] Rect2i { return true; } - bool operator==(const Rect2i &p_rect) const { return position == p_rect.position && size == p_rect.size; } - bool operator!=(const Rect2i &p_rect) const { return position != p_rect.position || size != p_rect.size; } + constexpr bool operator==(const Rect2i &p_rect) const { return position == p_rect.position && size == p_rect.size; } + constexpr bool operator!=(const Rect2i &p_rect) const { return position != p_rect.position || size != p_rect.size; } Rect2i grow(int p_amount) const { Rect2i g = *this; @@ -227,15 +226,16 @@ struct [[nodiscard]] Rect2i { operator String() const; operator Rect2() const; - Rect2i() {} - Rect2i(int p_x, int p_y, int p_width, int p_height) : + Rect2i() = default; + constexpr Rect2i(int p_x, int p_y, int p_width, int p_height) : position(Point2i(p_x, p_y)), size(Size2i(p_width, p_height)) { } - Rect2i(const Point2i &p_pos, const Size2i &p_size) : + constexpr Rect2i(const Point2i &p_pos, const Size2i &p_size) : position(p_pos), size(p_size) { } }; -#endif // RECT2I_H +template <> +struct is_zero_constructible : std::true_type {}; diff --git a/engine/core/math/static_raycaster.h b/engine/core/math/static_raycaster.h index 74e4b751..fbb5194c 100644 --- a/engine/core/math/static_raycaster.h +++ b/engine/core/math/static_raycaster.h @@ -28,21 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef STATIC_RAYCASTER_H -#define STATIC_RAYCASTER_H +#pragma once #include "core/object/ref_counted.h" -#if !defined(__aligned) - -#if defined(_WIN32) && defined(_MSC_VER) -#define __aligned(...) __declspec(align(__VA_ARGS__)) -#else -#define __aligned(...) __attribute__((aligned(__VA_ARGS__))) -#endif - -#endif - class StaticRaycaster : public RefCounted { GDCLASS(StaticRaycaster, RefCounted) protected: @@ -50,7 +39,7 @@ protected: public: // Compatible with embree4 rays. - struct __aligned(16) Ray { + struct alignas(16) Ray { const static unsigned int INVALID_GEOMETRY_ID = ((unsigned int)-1); // from rtcore_common.h /*! Default construction does nothing. */ @@ -62,7 +51,7 @@ public: _FORCE_INLINE_ Ray(const Vector3 &p_org, const Vector3 &p_dir, float p_tnear = 0.0f, - float p_tfar = INFINITY) : + float p_tfar = Math::INF) : org(p_org), tnear(p_tnear), dir(p_dir), @@ -107,5 +96,3 @@ public: static Ref create(); }; - -#endif // STATIC_RAYCASTER_H diff --git a/engine/core/math/transform_2d.cpp b/engine/core/math/transform_2d.cpp index f6525fe5..b5a971e7 100644 --- a/engine/core/math/transform_2d.cpp +++ b/engine/core/math/transform_2d.cpp @@ -71,12 +71,12 @@ void Transform2D::rotate(real_t p_angle) { real_t Transform2D::get_skew() const { real_t det = determinant(); - return Math::acos(columns[0].normalized().dot(SIGN(det) * columns[1].normalized())) - (real_t)Math_PI * 0.5f; + return Math::acos(columns[0].normalized().dot(SIGN(det) * columns[1].normalized())) - (real_t)Math::PI * 0.5f; } void Transform2D::set_skew(real_t p_angle) { real_t det = determinant(); - columns[1] = SIGN(det) * columns[0].rotated(((real_t)Math_PI * 0.5f + p_angle)).normalized() * columns[1].length(); + columns[1] = SIGN(det) * columns[0].rotated(((real_t)Math::PI * 0.5f + p_angle)).normalized() * columns[1].length(); } real_t Transform2D::get_rotation() const { @@ -180,6 +180,10 @@ bool Transform2D::is_equal_approx(const Transform2D &p_transform) const { return columns[0].is_equal_approx(p_transform.columns[0]) && columns[1].is_equal_approx(p_transform.columns[1]) && columns[2].is_equal_approx(p_transform.columns[2]); } +bool Transform2D::is_same(const Transform2D &p_transform) const { + return columns[0].is_same(p_transform.columns[0]) && columns[1].is_same(p_transform.columns[1]) && columns[2].is_same(p_transform.columns[2]); +} + bool Transform2D::is_finite() const { return columns[0].is_finite() && columns[1].is_finite() && columns[2].is_finite(); } @@ -191,26 +195,6 @@ Transform2D Transform2D::looking_at(const Vector2 &p_target) const { return return_trans; } -bool Transform2D::operator==(const Transform2D &p_transform) const { - for (int i = 0; i < 3; i++) { - if (columns[i] != p_transform.columns[i]) { - return false; - } - } - - return true; -} - -bool Transform2D::operator!=(const Transform2D &p_transform) const { - for (int i = 0; i < 3; i++) { - if (columns[i] != p_transform.columns[i]) { - return true; - } - } - - return false; -} - void Transform2D::operator*=(const Transform2D &p_transform) { columns[2] = xform(p_transform.columns[2]); @@ -283,30 +267,6 @@ Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, real_t get_origin().lerp(p_transform.get_origin(), p_weight)); } -void Transform2D::operator*=(real_t p_val) { - columns[0] *= p_val; - columns[1] *= p_val; - columns[2] *= p_val; -} - -Transform2D Transform2D::operator*(real_t p_val) const { - Transform2D ret(*this); - ret *= p_val; - return ret; -} - -void Transform2D::operator/=(real_t p_val) { - columns[0] /= p_val; - columns[1] /= p_val; - columns[2] /= p_val; -} - -Transform2D Transform2D::operator/(real_t p_val) const { - Transform2D ret(*this); - ret /= p_val; - return ret; -} - Transform2D::operator String() const { return "[X: " + columns[0].operator String() + ", Y: " + columns[1].operator String() + diff --git a/engine/core/math/transform_2d.h b/engine/core/math/transform_2d.h index 1ee7d3d8..27eebe1a 100644 --- a/engine/core/math/transform_2d.h +++ b/engine/core/math/transform_2d.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef TRANSFORM_2D_H -#define TRANSFORM_2D_H +#pragma once #include "core/math/math_funcs.h" #include "core/math/rect2.h" @@ -53,13 +52,17 @@ struct [[nodiscard]] Transform2D { // WARNING: Be aware that unlike 3D code, 2D code uses a left-handed coordinate system: // Y-axis points down, and angle is measure from +X to +Y in a clockwise-fashion. - Vector2 columns[3]; + Vector2 columns[3] = { + { 1, 0 }, + { 0, 1 }, + { 0, 0 }, + }; _FORCE_INLINE_ real_t tdotx(const Vector2 &p_v) const { return columns[0][0] * p_v.x + columns[1][0] * p_v.y; } _FORCE_INLINE_ real_t tdoty(const Vector2 &p_v) const { return columns[0][1] * p_v.x + columns[1][1] * p_v.y; } - const Vector2 &operator[](int p_idx) const { return columns[p_idx]; } - Vector2 &operator[](int p_idx) { return columns[p_idx]; } + constexpr const Vector2 &operator[](int p_idx) const { return columns[p_idx]; } + constexpr Vector2 &operator[](int p_idx) { return columns[p_idx]; } void invert(); Transform2D inverse() const; @@ -101,19 +104,20 @@ struct [[nodiscard]] Transform2D { Transform2D orthonormalized() const; bool is_conformal() const; bool is_equal_approx(const Transform2D &p_transform) const; + bool is_same(const Transform2D &p_transform) const; bool is_finite() const; Transform2D looking_at(const Vector2 &p_target) const; - bool operator==(const Transform2D &p_transform) const; - bool operator!=(const Transform2D &p_transform) const; + constexpr bool operator==(const Transform2D &p_transform) const; + constexpr bool operator!=(const Transform2D &p_transform) const; void operator*=(const Transform2D &p_transform); Transform2D operator*(const Transform2D &p_transform) const; - void operator*=(real_t p_val); - Transform2D operator*(real_t p_val) const; - void operator/=(real_t p_val); - Transform2D operator/(real_t p_val) const; + constexpr void operator*=(real_t p_val); + constexpr Transform2D operator*(real_t p_val) const; + constexpr void operator/=(real_t p_val); + constexpr Transform2D operator/(real_t p_val) const; Transform2D interpolate_with(const Transform2D &p_transform, real_t p_c) const; @@ -128,31 +132,67 @@ struct [[nodiscard]] Transform2D { operator String() const; - Transform2D(real_t p_xx, real_t p_xy, real_t p_yx, real_t p_yy, real_t p_ox, real_t p_oy) { - columns[0][0] = p_xx; - columns[0][1] = p_xy; - columns[1][0] = p_yx; - columns[1][1] = p_yy; - columns[2][0] = p_ox; - columns[2][1] = p_oy; - } + constexpr Transform2D(real_t p_xx, real_t p_xy, real_t p_yx, real_t p_yy, real_t p_ox, real_t p_oy) : + columns{ + { p_xx, p_xy }, + { p_yx, p_yy }, + { p_ox, p_oy }, + } {} - Transform2D(const Vector2 &p_x, const Vector2 &p_y, const Vector2 &p_origin) { - columns[0] = p_x; - columns[1] = p_y; - columns[2] = p_origin; - } + constexpr Transform2D(const Vector2 &p_x, const Vector2 &p_y, const Vector2 &p_origin) : + columns{ p_x, p_y, p_origin } {} Transform2D(real_t p_rot, const Vector2 &p_pos); Transform2D(real_t p_rot, const Size2 &p_scale, real_t p_skew, const Vector2 &p_pos); - Transform2D() { - columns[0][0] = 1.0; - columns[1][1] = 1.0; - } + Transform2D() = default; }; +constexpr bool Transform2D::operator==(const Transform2D &p_transform) const { + for (int i = 0; i < 3; i++) { + if (columns[i] != p_transform.columns[i]) { + return false; + } + } + + return true; +} + +constexpr bool Transform2D::operator!=(const Transform2D &p_transform) const { + for (int i = 0; i < 3; i++) { + if (columns[i] != p_transform.columns[i]) { + return true; + } + } + + return false; +} + +constexpr void Transform2D::operator*=(real_t p_val) { + columns[0] *= p_val; + columns[1] *= p_val; + columns[2] *= p_val; +} + +constexpr Transform2D Transform2D::operator*(real_t p_val) const { + Transform2D ret(*this); + ret *= p_val; + return ret; +} + +constexpr void Transform2D::operator/=(real_t p_val) { + columns[0] /= p_val; + columns[1] /= p_val; + columns[2] /= p_val; +} + +constexpr Transform2D Transform2D::operator/(real_t p_val) const { + Transform2D ret(*this); + ret /= p_val; + return ret; +} + Vector2 Transform2D::basis_xform(const Vector2 &p_vec) const { return Vector2( tdotx(p_vec), @@ -249,5 +289,3 @@ Vector Transform2D::xform_inv(const Vector &p_array) const { } return array; } - -#endif // TRANSFORM_2D_H diff --git a/engine/core/math/transform_3d.cpp b/engine/core/math/transform_3d.cpp index d4673851..b4d02408 100644 --- a/engine/core/math/transform_3d.cpp +++ b/engine/core/math/transform_3d.cpp @@ -173,18 +173,14 @@ bool Transform3D::is_equal_approx(const Transform3D &p_transform) const { return basis.is_equal_approx(p_transform.basis) && origin.is_equal_approx(p_transform.origin); } +bool Transform3D::is_same(const Transform3D &p_transform) const { + return basis.is_same(p_transform.basis) && origin.is_same(p_transform.origin); +} + bool Transform3D::is_finite() const { return basis.is_finite() && origin.is_finite(); } -bool Transform3D::operator==(const Transform3D &p_transform) const { - return (basis == p_transform.basis && origin == p_transform.origin); -} - -bool Transform3D::operator!=(const Transform3D &p_transform) const { - return (basis != p_transform.basis || origin != p_transform.origin); -} - void Transform3D::operator*=(const Transform3D &p_transform) { origin = xform(p_transform.origin); basis *= p_transform.basis; @@ -196,48 +192,9 @@ Transform3D Transform3D::operator*(const Transform3D &p_transform) const { return t; } -void Transform3D::operator*=(real_t p_val) { - origin *= p_val; - basis *= p_val; -} - -Transform3D Transform3D::operator*(real_t p_val) const { - Transform3D ret(*this); - ret *= p_val; - return ret; -} - -void Transform3D::operator/=(real_t p_val) { - basis /= p_val; - origin /= p_val; -} - -Transform3D Transform3D::operator/(real_t p_val) const { - Transform3D ret(*this); - ret /= p_val; - return ret; -} - Transform3D::operator String() const { return "[X: " + basis.get_column(0).operator String() + ", Y: " + basis.get_column(1).operator String() + ", Z: " + basis.get_column(2).operator String() + ", O: " + origin.operator String() + "]"; } - -Transform3D::Transform3D(const Basis &p_basis, const Vector3 &p_origin) : - basis(p_basis), - origin(p_origin) { -} - -Transform3D::Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) : - origin(p_origin) { - basis.set_column(0, p_x); - basis.set_column(1, p_y); - basis.set_column(2, p_z); -} - -Transform3D::Transform3D(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_ox, real_t p_oy, real_t p_oz) { - basis = Basis(p_xx, p_xy, p_xz, p_yx, p_yy, p_yz, p_zx, p_zy, p_zz); - origin = Vector3(p_ox, p_oy, p_oz); -} diff --git a/engine/core/math/transform_3d.h b/engine/core/math/transform_3d.h index b1de2334..0d5cbb0f 100644 --- a/engine/core/math/transform_3d.h +++ b/engine/core/math/transform_3d.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef TRANSFORM_3D_H -#define TRANSFORM_3D_H +#pragma once #include "core/math/aabb.h" #include "core/math/basis.h" @@ -75,10 +74,11 @@ struct [[nodiscard]] Transform3D { void orthogonalize(); Transform3D orthogonalized() const; bool is_equal_approx(const Transform3D &p_transform) const; + bool is_same(const Transform3D &p_transform) const; bool is_finite() const; - bool operator==(const Transform3D &p_transform) const; - bool operator!=(const Transform3D &p_transform) const; + constexpr bool operator==(const Transform3D &p_transform) const; + constexpr bool operator!=(const Transform3D &p_transform) const; _FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const; _FORCE_INLINE_ AABB xform(const AABB &p_aabb) const; @@ -102,10 +102,10 @@ struct [[nodiscard]] Transform3D { void operator*=(const Transform3D &p_transform); Transform3D operator*(const Transform3D &p_transform) const; - void operator*=(real_t p_val); - Transform3D operator*(real_t p_val) const; - void operator/=(real_t p_val); - Transform3D operator/(real_t p_val) const; + constexpr void operator*=(real_t p_val); + constexpr Transform3D operator*(real_t p_val) const; + constexpr void operator/=(real_t p_val); + constexpr Transform3D operator/(real_t p_val) const; Transform3D interpolate_with(const Transform3D &p_transform, real_t p_c) const; @@ -124,12 +124,48 @@ struct [[nodiscard]] Transform3D { operator String() const; - Transform3D() {} - Transform3D(const Basis &p_basis, const Vector3 &p_origin = Vector3()); - Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin); - Transform3D(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_ox, real_t p_oy, real_t p_oz); + Transform3D() = default; + constexpr Transform3D(const Basis &p_basis, const Vector3 &p_origin = Vector3()) : + basis(p_basis), + origin(p_origin) {} + constexpr Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) : + basis(p_x, p_y, p_z), + origin(p_origin) {} + constexpr Transform3D(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_ox, real_t p_oy, real_t p_oz) : + basis(p_xx, p_xy, p_xz, p_yx, p_yy, p_yz, p_zx, p_zy, p_zz), + origin(p_ox, p_oy, p_oz) {} }; +constexpr bool Transform3D::operator==(const Transform3D &p_transform) const { + return (basis == p_transform.basis && origin == p_transform.origin); +} + +constexpr bool Transform3D::operator!=(const Transform3D &p_transform) const { + return (basis != p_transform.basis || origin != p_transform.origin); +} + +constexpr void Transform3D::operator*=(real_t p_val) { + origin *= p_val; + basis *= p_val; +} + +constexpr Transform3D Transform3D::operator*(real_t p_val) const { + Transform3D ret(*this); + ret *= p_val; + return ret; +} + +constexpr void Transform3D::operator/=(real_t p_val) { + basis /= p_val; + origin /= p_val; +} + +constexpr Transform3D Transform3D::operator/(real_t p_val) const { + Transform3D ret(*this); + ret /= p_val; + return ret; +} + _FORCE_INLINE_ Vector3 Transform3D::xform(const Vector3 &p_vector) const { return Vector3( basis[0].dot(p_vector) + origin.x, @@ -269,5 +305,3 @@ _FORCE_INLINE_ Plane Transform3D::xform_inv_fast(const Plane &p_plane, const Tra real_t d = normal.dot(point); return Plane(normal, d); } - -#endif // TRANSFORM_3D_H diff --git a/engine/core/math/transform_interpolator.h b/engine/core/math/transform_interpolator.h index cc556707..d80876d9 100644 --- a/engine/core/math/transform_interpolator.h +++ b/engine/core/math/transform_interpolator.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef TRANSFORM_INTERPOLATOR_H -#define TRANSFORM_INTERPOLATOR_H +#pragma once #include "core/math/math_defs.h" #include "core/math/vector3.h" @@ -91,5 +90,3 @@ public: static Method find_method(const Basis &p_a, const Basis &p_b); }; - -#endif // TRANSFORM_INTERPOLATOR_H diff --git a/engine/core/math/triangle_mesh.cpp b/engine/core/math/triangle_mesh.cpp index 01b73318..3b24b351 100644 --- a/engine/core/math/triangle_mesh.cpp +++ b/engine/core/math/triangle_mesh.cpp @@ -182,7 +182,11 @@ void TriangleMesh::create(const Vector &p_faces, const Vector valid = true; } -bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index) const { +bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index, int32_t *r_face_index) const { + if (!valid) { + return false; + } + uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth); enum { @@ -234,6 +238,9 @@ bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_en if (r_surf_index) { *r_surf_index = s.surface_index; } + if (r_face_index) { + *r_face_index = b.face_index; + } inters = true; } } @@ -283,7 +290,11 @@ bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_en return inters; } -bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index) const { +bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index, int32_t *r_face_index) const { + if (!valid) { + return false; + } + uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth); enum { @@ -335,6 +346,9 @@ bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, V if (r_surf_index) { *r_surf_index = s.surface_index; } + if (r_face_index) { + *r_face_index = b.face_index; + } inters = true; } } @@ -385,6 +399,10 @@ bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, V } bool TriangleMesh::inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, Vector3 p_scale) const { + if (!valid) { + return false; + } + uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth); enum { @@ -503,6 +521,85 @@ Vector TriangleMesh::get_faces() const { return faces; } +bool TriangleMesh::create_from_faces(const Vector &p_faces) { + create(p_faces); + return is_valid(); +} + +Dictionary TriangleMesh::intersect_segment_scriptwrap(const Vector3 &p_begin, const Vector3 &p_end) const { + if (!valid) { + return Dictionary(); + } + + Vector3 r_point; + Vector3 r_normal; + int32_t r_face_index = -1; + + bool intersected = intersect_segment(p_begin, p_end, r_point, r_normal, nullptr, &r_face_index); + if (!intersected) { + return Dictionary(); + } + + Dictionary result; + result["position"] = r_point; + result["normal"] = r_normal; + result["face_index"] = r_face_index; + + return result; +} + +Dictionary TriangleMesh::intersect_ray_scriptwrap(const Vector3 &p_begin, const Vector3 &p_dir) const { + if (!valid) { + return Dictionary(); + } + + Vector3 r_point; + Vector3 r_normal; + int32_t r_face_index = -1; + + bool intersected = intersect_ray(p_begin, p_dir, r_point, r_normal, nullptr, &r_face_index); + if (!intersected) { + return Dictionary(); + } + + Dictionary result; + result["position"] = r_point; + result["normal"] = r_normal; + result["face_index"] = r_face_index; + + return result; +} + +Vector TriangleMesh::get_faces_scriptwrap() const { + if (!valid) { + return Vector(); + } + + Vector faces; + int ts = triangles.size(); + faces.resize(triangles.size() * 3); + + Vector3 *w = faces.ptrw(); + const Triangle *r = triangles.ptr(); + const Vector3 *rv = vertices.ptr(); + + for (int i = 0; i < ts; i++) { + for (int j = 0; j < 3; j++) { + w[i * 3 + j] = rv[r[i].indices[j]]; + } + } + + return faces; +} + +void TriangleMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("create_from_faces", "faces"), &TriangleMesh::create_from_faces); + ClassDB::bind_method(D_METHOD("get_faces"), &TriangleMesh::get_faces_scriptwrap); + + ClassDB::bind_method(D_METHOD("intersect_segment", "begin", "end"), &TriangleMesh::intersect_segment_scriptwrap); + ClassDB::bind_method(D_METHOD("intersect_ray", "begin", "dir"), &TriangleMesh::intersect_ray_scriptwrap); +} + TriangleMesh::TriangleMesh() { valid = false; max_depth = 0; diff --git a/engine/core/math/triangle_mesh.h b/engine/core/math/triangle_mesh.h index 24fc12dd..65fd0ff9 100644 --- a/engine/core/math/triangle_mesh.h +++ b/engine/core/math/triangle_mesh.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef TRIANGLE_MESH_H -#define TRIANGLE_MESH_H +#pragma once #include "core/math/face3.h" #include "core/object/ref_counted.h" @@ -41,9 +40,12 @@ public: struct Triangle { Vector3 normal; int indices[3]; - int32_t surface_index; + int32_t surface_index = 0; }; +protected: + static void _bind_methods(); + private: Vector triangles; Vector vertices; @@ -51,10 +53,10 @@ private: struct BVH { AABB aabb; Vector3 center; //used for sorting - int left; - int right; + int left = -1; + int right = -1; - int face_index; + int32_t face_index = -1; }; struct BVHCmpX { @@ -77,13 +79,13 @@ private: int _create_bvh(BVH *p_bvh, BVH **p_bb, int p_from, int p_size, int p_depth, int &max_depth, int &max_alloc); Vector bvh; - int max_depth; - bool valid; + int max_depth = 0; + bool valid = false; public: bool is_valid() const; - bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr) const; - bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr) const; + bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr, int32_t *r_face_index = nullptr) const; + bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr, int32_t *r_face_index = nullptr) const; bool inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, Vector3 p_scale = Vector3(1, 1, 1)) const; Vector get_faces() const; @@ -92,7 +94,13 @@ public: void get_indices(Vector *r_triangles_indices) const; void create(const Vector &p_faces, const Vector &p_surface_indices = Vector()); + + // Wrapped functions for compatibility with method bindings + // and user exposed script api that can't use more native types. + bool create_from_faces(const Vector &p_faces); + Dictionary intersect_segment_scriptwrap(const Vector3 &p_begin, const Vector3 &p_end) const; + Dictionary intersect_ray_scriptwrap(const Vector3 &p_begin, const Vector3 &p_dir) const; + Vector get_faces_scriptwrap() const; + TriangleMesh(); }; - -#endif // TRIANGLE_MESH_H diff --git a/engine/core/math/triangulate.h b/engine/core/math/triangulate.h index 0b88f7ec..87cdbd4f 100644 --- a/engine/core/math/triangulate.h +++ b/engine/core/math/triangulate.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef TRIANGULATE_H -#define TRIANGULATE_H +#pragma once #include "core/math/vector2.h" #include "core/templates/vector.h" @@ -58,5 +57,3 @@ public: private: static bool snip(const Vector &p_contour, int u, int v, int w, int n, const Vector &V, bool relaxed); }; - -#endif // TRIANGULATE_H diff --git a/engine/core/math/vector2.cpp b/engine/core/math/vector2.cpp index 0590ee8a..7a51c139 100644 --- a/engine/core/math/vector2.cpp +++ b/engine/core/math/vector2.cpp @@ -194,6 +194,10 @@ bool Vector2::is_equal_approx(const Vector2 &p_v) const { return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y); } +bool Vector2::is_same(const Vector2 &p_v) const { + return Math::is_same(x, p_v.x) && Math::is_same(y, p_v.y); +} + bool Vector2::is_zero_approx() const { return Math::is_zero_approx(x) && Math::is_zero_approx(y); } diff --git a/engine/core/math/vector2.h b/engine/core/math/vector2.h index edb47db6..3f6dbefc 100644 --- a/engine/core/math/vector2.h +++ b/engine/core/math/vector2.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef VECTOR2_H -#define VECTOR2_H +#pragma once #include "core/error/error_macros.h" #include "core/math/math_funcs.h" @@ -46,18 +45,19 @@ struct [[nodiscard]] Vector2 { }; union { + // NOLINTBEGIN(modernize-use-default-member-init) struct { - union { - real_t x; - real_t width; - }; - union { - real_t y; - real_t height; - }; + real_t x; + real_t y; + }; + + struct { + real_t width; + real_t height; }; real_t coord[2] = { 0 }; + // NOLINTEND(modernize-use-default-member-init) }; _FORCE_INLINE_ real_t &operator[](int p_axis) { @@ -129,35 +129,36 @@ struct [[nodiscard]] Vector2 { Vector2 reflect(const Vector2 &p_normal) const; bool is_equal_approx(const Vector2 &p_v) const; + bool is_same(const Vector2 &p_v) const; bool is_zero_approx() const; bool is_finite() const; - Vector2 operator+(const Vector2 &p_v) const; - void operator+=(const Vector2 &p_v); - Vector2 operator-(const Vector2 &p_v) const; - void operator-=(const Vector2 &p_v); - Vector2 operator*(const Vector2 &p_v1) const; + constexpr Vector2 operator+(const Vector2 &p_v) const; + constexpr void operator+=(const Vector2 &p_v); + constexpr Vector2 operator-(const Vector2 &p_v) const; + constexpr void operator-=(const Vector2 &p_v); + constexpr Vector2 operator*(const Vector2 &p_v1) const; - Vector2 operator*(real_t p_rvalue) const; - void operator*=(real_t p_rvalue); - void operator*=(const Vector2 &p_rvalue) { *this = *this * p_rvalue; } + constexpr Vector2 operator*(real_t p_rvalue) const; + constexpr void operator*=(real_t p_rvalue); + constexpr void operator*=(const Vector2 &p_rvalue) { *this = *this * p_rvalue; } - Vector2 operator/(const Vector2 &p_v1) const; + constexpr Vector2 operator/(const Vector2 &p_v1) const; - Vector2 operator/(real_t p_rvalue) const; + constexpr Vector2 operator/(real_t p_rvalue) const; - void operator/=(real_t p_rvalue); - void operator/=(const Vector2 &p_rvalue) { *this = *this / p_rvalue; } + constexpr void operator/=(real_t p_rvalue); + constexpr void operator/=(const Vector2 &p_rvalue) { *this = *this / p_rvalue; } - Vector2 operator-() const; + constexpr Vector2 operator-() const; - bool operator==(const Vector2 &p_vec2) const; - bool operator!=(const Vector2 &p_vec2) const; + constexpr bool operator==(const Vector2 &p_vec2) const; + constexpr bool operator!=(const Vector2 &p_vec2) const; - bool operator<(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y < p_vec2.y) : (x < p_vec2.x); } - bool operator>(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y > p_vec2.y) : (x > p_vec2.x); } - bool operator<=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y <= p_vec2.y) : (x < p_vec2.x); } - bool operator>=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); } + constexpr bool operator<(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y < p_vec2.y) : (x < p_vec2.x); } + constexpr bool operator>(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y > p_vec2.y) : (x > p_vec2.x); } + constexpr bool operator<=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y <= p_vec2.y) : (x < p_vec2.x); } + constexpr bool operator>=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); } real_t angle() const; static Vector2 from_angle(real_t p_angle); @@ -184,70 +185,71 @@ struct [[nodiscard]] Vector2 { operator String() const; operator Vector2i() const; - _FORCE_INLINE_ Vector2() {} - _FORCE_INLINE_ Vector2(real_t p_x, real_t p_y) { - x = p_x; - y = p_y; - } + // NOLINTBEGIN(cppcoreguidelines-pro-type-member-init) + constexpr Vector2() : + x(0), y(0) {} + constexpr Vector2(real_t p_x, real_t p_y) : + x(p_x), y(p_y) {} + // NOLINTEND(cppcoreguidelines-pro-type-member-init) }; _FORCE_INLINE_ Vector2 Vector2::plane_project(real_t p_d, const Vector2 &p_vec) const { return p_vec - *this * (dot(p_vec) - p_d); } -_FORCE_INLINE_ Vector2 Vector2::operator+(const Vector2 &p_v) const { +constexpr Vector2 Vector2::operator+(const Vector2 &p_v) const { return Vector2(x + p_v.x, y + p_v.y); } -_FORCE_INLINE_ void Vector2::operator+=(const Vector2 &p_v) { +constexpr void Vector2::operator+=(const Vector2 &p_v) { x += p_v.x; y += p_v.y; } -_FORCE_INLINE_ Vector2 Vector2::operator-(const Vector2 &p_v) const { +constexpr Vector2 Vector2::operator-(const Vector2 &p_v) const { return Vector2(x - p_v.x, y - p_v.y); } -_FORCE_INLINE_ void Vector2::operator-=(const Vector2 &p_v) { +constexpr void Vector2::operator-=(const Vector2 &p_v) { x -= p_v.x; y -= p_v.y; } -_FORCE_INLINE_ Vector2 Vector2::operator*(const Vector2 &p_v1) const { +constexpr Vector2 Vector2::operator*(const Vector2 &p_v1) const { return Vector2(x * p_v1.x, y * p_v1.y); } -_FORCE_INLINE_ Vector2 Vector2::operator*(real_t p_rvalue) const { +constexpr Vector2 Vector2::operator*(real_t p_rvalue) const { return Vector2(x * p_rvalue, y * p_rvalue); } -_FORCE_INLINE_ void Vector2::operator*=(real_t p_rvalue) { +constexpr void Vector2::operator*=(real_t p_rvalue) { x *= p_rvalue; y *= p_rvalue; } -_FORCE_INLINE_ Vector2 Vector2::operator/(const Vector2 &p_v1) const { +constexpr Vector2 Vector2::operator/(const Vector2 &p_v1) const { return Vector2(x / p_v1.x, y / p_v1.y); } -_FORCE_INLINE_ Vector2 Vector2::operator/(real_t p_rvalue) const { +constexpr Vector2 Vector2::operator/(real_t p_rvalue) const { return Vector2(x / p_rvalue, y / p_rvalue); } -_FORCE_INLINE_ void Vector2::operator/=(real_t p_rvalue) { +constexpr void Vector2::operator/=(real_t p_rvalue) { x /= p_rvalue; y /= p_rvalue; } -_FORCE_INLINE_ Vector2 Vector2::operator-() const { +constexpr Vector2 Vector2::operator-() const { return Vector2(-x, -y); } -_FORCE_INLINE_ bool Vector2::operator==(const Vector2 &p_vec2) const { +constexpr bool Vector2::operator==(const Vector2 &p_vec2) const { return x == p_vec2.x && y == p_vec2.y; } -_FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const { +constexpr bool Vector2::operator!=(const Vector2 &p_vec2) const { return x != p_vec2.x || y != p_vec2.y; } @@ -308,23 +310,24 @@ Vector2 Vector2::direction_to(const Vector2 &p_to) const { // Multiplication operators required to workaround issues with LLVM using implicit conversion // to Vector2i instead for integers where it should not. -_FORCE_INLINE_ Vector2 operator*(float p_scalar, const Vector2 &p_vec) { +constexpr Vector2 operator*(float p_scalar, const Vector2 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector2 operator*(double p_scalar, const Vector2 &p_vec) { +constexpr Vector2 operator*(double p_scalar, const Vector2 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector2 operator*(int32_t p_scalar, const Vector2 &p_vec) { +constexpr Vector2 operator*(int32_t p_scalar, const Vector2 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector2 operator*(int64_t p_scalar, const Vector2 &p_vec) { +constexpr Vector2 operator*(int64_t p_scalar, const Vector2 &p_vec) { return p_vec * p_scalar; } typedef Vector2 Size2; typedef Vector2 Point2; -#endif // VECTOR2_H +template <> +struct is_zero_constructible : std::true_type {}; diff --git a/engine/core/math/vector2i.cpp b/engine/core/math/vector2i.cpp index 790f5647..cef55185 100644 --- a/engine/core/math/vector2i.cpp +++ b/engine/core/math/vector2i.cpp @@ -65,75 +65,6 @@ double Vector2i::length() const { return Math::sqrt((double)length_squared()); } -Vector2i Vector2i::operator+(const Vector2i &p_v) const { - return Vector2i(x + p_v.x, y + p_v.y); -} - -void Vector2i::operator+=(const Vector2i &p_v) { - x += p_v.x; - y += p_v.y; -} - -Vector2i Vector2i::operator-(const Vector2i &p_v) const { - return Vector2i(x - p_v.x, y - p_v.y); -} - -void Vector2i::operator-=(const Vector2i &p_v) { - x -= p_v.x; - y -= p_v.y; -} - -Vector2i Vector2i::operator*(const Vector2i &p_v1) const { - return Vector2i(x * p_v1.x, y * p_v1.y); -} - -Vector2i Vector2i::operator*(int32_t p_rvalue) const { - return Vector2i(x * p_rvalue, y * p_rvalue); -} - -void Vector2i::operator*=(int32_t p_rvalue) { - x *= p_rvalue; - y *= p_rvalue; -} - -Vector2i Vector2i::operator/(const Vector2i &p_v1) const { - return Vector2i(x / p_v1.x, y / p_v1.y); -} - -Vector2i Vector2i::operator/(int32_t p_rvalue) const { - return Vector2i(x / p_rvalue, y / p_rvalue); -} - -void Vector2i::operator/=(int32_t p_rvalue) { - x /= p_rvalue; - y /= p_rvalue; -} - -Vector2i Vector2i::operator%(const Vector2i &p_v1) const { - return Vector2i(x % p_v1.x, y % p_v1.y); -} - -Vector2i Vector2i::operator%(int32_t p_rvalue) const { - return Vector2i(x % p_rvalue, y % p_rvalue); -} - -void Vector2i::operator%=(int32_t p_rvalue) { - x %= p_rvalue; - y %= p_rvalue; -} - -Vector2i Vector2i::operator-() const { - return Vector2i(-x, -y); -} - -bool Vector2i::operator==(const Vector2i &p_vec2) const { - return x == p_vec2.x && y == p_vec2.y; -} - -bool Vector2i::operator!=(const Vector2i &p_vec2) const { - return x != p_vec2.x || y != p_vec2.y; -} - Vector2i::operator String() const { return "(" + itos(x) + ", " + itos(y) + ")"; } diff --git a/engine/core/math/vector2i.h b/engine/core/math/vector2i.h index fff9b0a6..5ce0b93b 100644 --- a/engine/core/math/vector2i.h +++ b/engine/core/math/vector2i.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef VECTOR2I_H -#define VECTOR2I_H +#pragma once #include "core/error/error_macros.h" #include "core/math/math_funcs.h" @@ -46,18 +45,19 @@ struct [[nodiscard]] Vector2i { }; union { + // NOLINTBEGIN(modernize-use-default-member-init) struct { - union { - int32_t x; - int32_t width; - }; - union { - int32_t y; - int32_t height; - }; + int32_t x; + int32_t y; + }; + + struct { + int32_t width; + int32_t height; }; int32_t coord[2] = { 0 }; + // NOLINTEND(modernize-use-default-member-init) }; _FORCE_INLINE_ int32_t &operator[](int p_axis) { @@ -101,32 +101,32 @@ struct [[nodiscard]] Vector2i { return (p_to - *this).length_squared(); } - Vector2i operator+(const Vector2i &p_v) const; - void operator+=(const Vector2i &p_v); - Vector2i operator-(const Vector2i &p_v) const; - void operator-=(const Vector2i &p_v); - Vector2i operator*(const Vector2i &p_v1) const; + constexpr Vector2i operator+(const Vector2i &p_v) const; + constexpr void operator+=(const Vector2i &p_v); + constexpr Vector2i operator-(const Vector2i &p_v) const; + constexpr void operator-=(const Vector2i &p_v); + constexpr Vector2i operator*(const Vector2i &p_v1) const; - Vector2i operator*(int32_t p_rvalue) const; - void operator*=(int32_t p_rvalue); + constexpr Vector2i operator*(int32_t p_rvalue) const; + constexpr void operator*=(int32_t p_rvalue); - Vector2i operator/(const Vector2i &p_v1) const; - Vector2i operator/(int32_t p_rvalue) const; - void operator/=(int32_t p_rvalue); + constexpr Vector2i operator/(const Vector2i &p_v1) const; + constexpr Vector2i operator/(int32_t p_rvalue) const; + constexpr void operator/=(int32_t p_rvalue); - Vector2i operator%(const Vector2i &p_v1) const; - Vector2i operator%(int32_t p_rvalue) const; - void operator%=(int32_t p_rvalue); + constexpr Vector2i operator%(const Vector2i &p_v1) const; + constexpr Vector2i operator%(int32_t p_rvalue) const; + constexpr void operator%=(int32_t p_rvalue); - Vector2i operator-() const; - bool operator<(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); } - bool operator>(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y > p_vec2.y) : (x > p_vec2.x); } + constexpr Vector2i operator-() const; + constexpr bool operator<(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); } + constexpr bool operator>(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y > p_vec2.y) : (x > p_vec2.x); } - bool operator<=(const Vector2i &p_vec2) const { return x == p_vec2.x ? (y <= p_vec2.y) : (x < p_vec2.x); } - bool operator>=(const Vector2i &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); } + constexpr bool operator<=(const Vector2i &p_vec2) const { return x == p_vec2.x ? (y <= p_vec2.y) : (x < p_vec2.x); } + constexpr bool operator>=(const Vector2i &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); } - bool operator==(const Vector2i &p_vec2) const; - bool operator!=(const Vector2i &p_vec2) const; + constexpr bool operator==(const Vector2i &p_vec2) const; + constexpr bool operator!=(const Vector2i &p_vec2) const; int64_t length_squared() const; double length() const; @@ -142,32 +142,103 @@ struct [[nodiscard]] Vector2i { operator String() const; operator Vector2() const; - inline Vector2i() {} - inline Vector2i(int32_t p_x, int32_t p_y) { - x = p_x; - y = p_y; - } + // NOLINTBEGIN(cppcoreguidelines-pro-type-member-init) + constexpr Vector2i() : + x(0), y(0) {} + constexpr Vector2i(int32_t p_x, int32_t p_y) : + x(p_x), y(p_y) {} + // NOLINTEND(cppcoreguidelines-pro-type-member-init) }; +constexpr Vector2i Vector2i::operator+(const Vector2i &p_v) const { + return Vector2i(x + p_v.x, y + p_v.y); +} + +constexpr void Vector2i::operator+=(const Vector2i &p_v) { + x += p_v.x; + y += p_v.y; +} + +constexpr Vector2i Vector2i::operator-(const Vector2i &p_v) const { + return Vector2i(x - p_v.x, y - p_v.y); +} + +constexpr void Vector2i::operator-=(const Vector2i &p_v) { + x -= p_v.x; + y -= p_v.y; +} + +constexpr Vector2i Vector2i::operator*(const Vector2i &p_v1) const { + return Vector2i(x * p_v1.x, y * p_v1.y); +} + +constexpr Vector2i Vector2i::operator*(int32_t p_rvalue) const { + return Vector2i(x * p_rvalue, y * p_rvalue); +} + +constexpr void Vector2i::operator*=(int32_t p_rvalue) { + x *= p_rvalue; + y *= p_rvalue; +} + +constexpr Vector2i Vector2i::operator/(const Vector2i &p_v1) const { + return Vector2i(x / p_v1.x, y / p_v1.y); +} + +constexpr Vector2i Vector2i::operator/(int32_t p_rvalue) const { + return Vector2i(x / p_rvalue, y / p_rvalue); +} + +constexpr void Vector2i::operator/=(int32_t p_rvalue) { + x /= p_rvalue; + y /= p_rvalue; +} + +constexpr Vector2i Vector2i::operator%(const Vector2i &p_v1) const { + return Vector2i(x % p_v1.x, y % p_v1.y); +} + +constexpr Vector2i Vector2i::operator%(int32_t p_rvalue) const { + return Vector2i(x % p_rvalue, y % p_rvalue); +} + +constexpr void Vector2i::operator%=(int32_t p_rvalue) { + x %= p_rvalue; + y %= p_rvalue; +} + +constexpr Vector2i Vector2i::operator-() const { + return Vector2i(-x, -y); +} + +constexpr bool Vector2i::operator==(const Vector2i &p_vec2) const { + return x == p_vec2.x && y == p_vec2.y; +} + +constexpr bool Vector2i::operator!=(const Vector2i &p_vec2) const { + return x != p_vec2.x || y != p_vec2.y; +} + // Multiplication operators required to workaround issues with LLVM using implicit conversion. -_FORCE_INLINE_ Vector2i operator*(int32_t p_scalar, const Vector2i &p_vector) { +constexpr Vector2i operator*(int32_t p_scalar, const Vector2i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector2i operator*(int64_t p_scalar, const Vector2i &p_vector) { +constexpr Vector2i operator*(int64_t p_scalar, const Vector2i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector2i operator*(float p_scalar, const Vector2i &p_vector) { +constexpr Vector2i operator*(float p_scalar, const Vector2i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector2i operator*(double p_scalar, const Vector2i &p_vector) { +constexpr Vector2i operator*(double p_scalar, const Vector2i &p_vector) { return p_vector * p_scalar; } typedef Vector2i Size2i; typedef Vector2i Point2i; -#endif // VECTOR2I_H +template <> +struct is_zero_constructible : std::true_type {}; diff --git a/engine/core/math/vector3.cpp b/engine/core/math/vector3.cpp index e18ac3b0..24422c57 100644 --- a/engine/core/math/vector3.cpp +++ b/engine/core/math/vector3.cpp @@ -156,6 +156,10 @@ bool Vector3::is_equal_approx(const Vector3 &p_v) const { return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y) && Math::is_equal_approx(z, p_v.z); } +bool Vector3::is_same(const Vector3 &p_v) const { + return Math::is_same(x, p_v.x) && Math::is_same(y, p_v.y) && Math::is_same(z, p_v.z); +} + bool Vector3::is_zero_approx() const { return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z); } diff --git a/engine/core/math/vector3.h b/engine/core/math/vector3.h index fd0dec35..4ddfac64 100644 --- a/engine/core/math/vector3.h +++ b/engine/core/math/vector3.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef VECTOR3_H -#define VECTOR3_H +#pragma once #include "core/error/error_macros.h" #include "core/math/math_funcs.h" @@ -49,6 +48,7 @@ struct [[nodiscard]] Vector3 { }; union { + // NOLINTBEGIN(modernize-use-default-member-init) struct { real_t x; real_t y; @@ -56,6 +56,7 @@ struct [[nodiscard]] Vector3 { }; real_t coord[3] = { 0 }; + // NOLINTEND(modernize-use-default-member-init) }; _FORCE_INLINE_ const real_t &operator[](int p_axis) const { @@ -156,43 +157,42 @@ struct [[nodiscard]] Vector3 { _FORCE_INLINE_ Vector3 reflect(const Vector3 &p_normal) const; bool is_equal_approx(const Vector3 &p_v) const; + bool is_same(const Vector3 &p_v) const; bool is_zero_approx() const; bool is_finite() const; /* Operators */ - _FORCE_INLINE_ Vector3 &operator+=(const Vector3 &p_v); - _FORCE_INLINE_ Vector3 operator+(const Vector3 &p_v) const; - _FORCE_INLINE_ Vector3 &operator-=(const Vector3 &p_v); - _FORCE_INLINE_ Vector3 operator-(const Vector3 &p_v) const; - _FORCE_INLINE_ Vector3 &operator*=(const Vector3 &p_v); - _FORCE_INLINE_ Vector3 operator*(const Vector3 &p_v) const; - _FORCE_INLINE_ Vector3 &operator/=(const Vector3 &p_v); - _FORCE_INLINE_ Vector3 operator/(const Vector3 &p_v) const; + constexpr Vector3 &operator+=(const Vector3 &p_v); + constexpr Vector3 operator+(const Vector3 &p_v) const; + constexpr Vector3 &operator-=(const Vector3 &p_v); + constexpr Vector3 operator-(const Vector3 &p_v) const; + constexpr Vector3 &operator*=(const Vector3 &p_v); + constexpr Vector3 operator*(const Vector3 &p_v) const; + constexpr Vector3 &operator/=(const Vector3 &p_v); + constexpr Vector3 operator/(const Vector3 &p_v) const; - _FORCE_INLINE_ Vector3 &operator*=(real_t p_scalar); - _FORCE_INLINE_ Vector3 operator*(real_t p_scalar) const; - _FORCE_INLINE_ Vector3 &operator/=(real_t p_scalar); - _FORCE_INLINE_ Vector3 operator/(real_t p_scalar) const; + constexpr Vector3 &operator*=(real_t p_scalar); + constexpr Vector3 operator*(real_t p_scalar) const; + constexpr Vector3 &operator/=(real_t p_scalar); + constexpr Vector3 operator/(real_t p_scalar) const; - _FORCE_INLINE_ Vector3 operator-() const; + constexpr Vector3 operator-() const; - _FORCE_INLINE_ bool operator==(const Vector3 &p_v) const; - _FORCE_INLINE_ bool operator!=(const Vector3 &p_v) const; - _FORCE_INLINE_ bool operator<(const Vector3 &p_v) const; - _FORCE_INLINE_ bool operator<=(const Vector3 &p_v) const; - _FORCE_INLINE_ bool operator>(const Vector3 &p_v) const; - _FORCE_INLINE_ bool operator>=(const Vector3 &p_v) const; + constexpr bool operator==(const Vector3 &p_v) const; + constexpr bool operator!=(const Vector3 &p_v) const; + constexpr bool operator<(const Vector3 &p_v) const; + constexpr bool operator<=(const Vector3 &p_v) const; + constexpr bool operator>(const Vector3 &p_v) const; + constexpr bool operator>=(const Vector3 &p_v) const; operator String() const; operator Vector3i() const; - _FORCE_INLINE_ Vector3() {} - _FORCE_INLINE_ Vector3(real_t p_x, real_t p_y, real_t p_z) { - x = p_x; - y = p_y; - z = p_z; - } + constexpr Vector3() : + x(0), y(0), z(0) {} + constexpr Vector3(real_t p_x, real_t p_y, real_t p_z) : + x(p_x), y(p_y), z(p_z) {} }; Vector3 Vector3::cross(const Vector3 &p_with) const { @@ -339,51 +339,51 @@ Vector3 Vector3::get_any_perpendicular() const { /* Operators */ -Vector3 &Vector3::operator+=(const Vector3 &p_v) { +constexpr Vector3 &Vector3::operator+=(const Vector3 &p_v) { x += p_v.x; y += p_v.y; z += p_v.z; return *this; } -Vector3 Vector3::operator+(const Vector3 &p_v) const { +constexpr Vector3 Vector3::operator+(const Vector3 &p_v) const { return Vector3(x + p_v.x, y + p_v.y, z + p_v.z); } -Vector3 &Vector3::operator-=(const Vector3 &p_v) { +constexpr Vector3 &Vector3::operator-=(const Vector3 &p_v) { x -= p_v.x; y -= p_v.y; z -= p_v.z; return *this; } -Vector3 Vector3::operator-(const Vector3 &p_v) const { +constexpr Vector3 Vector3::operator-(const Vector3 &p_v) const { return Vector3(x - p_v.x, y - p_v.y, z - p_v.z); } -Vector3 &Vector3::operator*=(const Vector3 &p_v) { +constexpr Vector3 &Vector3::operator*=(const Vector3 &p_v) { x *= p_v.x; y *= p_v.y; z *= p_v.z; return *this; } -Vector3 Vector3::operator*(const Vector3 &p_v) const { +constexpr Vector3 Vector3::operator*(const Vector3 &p_v) const { return Vector3(x * p_v.x, y * p_v.y, z * p_v.z); } -Vector3 &Vector3::operator/=(const Vector3 &p_v) { +constexpr Vector3 &Vector3::operator/=(const Vector3 &p_v) { x /= p_v.x; y /= p_v.y; z /= p_v.z; return *this; } -Vector3 Vector3::operator/(const Vector3 &p_v) const { +constexpr Vector3 Vector3::operator/(const Vector3 &p_v) const { return Vector3(x / p_v.x, y / p_v.y, z / p_v.z); } -Vector3 &Vector3::operator*=(real_t p_scalar) { +constexpr Vector3 &Vector3::operator*=(real_t p_scalar) { x *= p_scalar; y *= p_scalar; z *= p_scalar; @@ -393,50 +393,50 @@ Vector3 &Vector3::operator*=(real_t p_scalar) { // Multiplication operators required to workaround issues with LLVM using implicit conversion // to Vector3i instead for integers where it should not. -_FORCE_INLINE_ Vector3 operator*(float p_scalar, const Vector3 &p_vec) { +constexpr Vector3 operator*(float p_scalar, const Vector3 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector3 operator*(double p_scalar, const Vector3 &p_vec) { +constexpr Vector3 operator*(double p_scalar, const Vector3 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector3 operator*(int32_t p_scalar, const Vector3 &p_vec) { +constexpr Vector3 operator*(int32_t p_scalar, const Vector3 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector3 operator*(int64_t p_scalar, const Vector3 &p_vec) { +constexpr Vector3 operator*(int64_t p_scalar, const Vector3 &p_vec) { return p_vec * p_scalar; } -Vector3 Vector3::operator*(real_t p_scalar) const { +constexpr Vector3 Vector3::operator*(real_t p_scalar) const { return Vector3(x * p_scalar, y * p_scalar, z * p_scalar); } -Vector3 &Vector3::operator/=(real_t p_scalar) { +constexpr Vector3 &Vector3::operator/=(real_t p_scalar) { x /= p_scalar; y /= p_scalar; z /= p_scalar; return *this; } -Vector3 Vector3::operator/(real_t p_scalar) const { +constexpr Vector3 Vector3::operator/(real_t p_scalar) const { return Vector3(x / p_scalar, y / p_scalar, z / p_scalar); } -Vector3 Vector3::operator-() const { +constexpr Vector3 Vector3::operator-() const { return Vector3(-x, -y, -z); } -bool Vector3::operator==(const Vector3 &p_v) const { +constexpr bool Vector3::operator==(const Vector3 &p_v) const { return x == p_v.x && y == p_v.y && z == p_v.z; } -bool Vector3::operator!=(const Vector3 &p_v) const { +constexpr bool Vector3::operator!=(const Vector3 &p_v) const { return x != p_v.x || y != p_v.y || z != p_v.z; } -bool Vector3::operator<(const Vector3 &p_v) const { +constexpr bool Vector3::operator<(const Vector3 &p_v) const { if (x == p_v.x) { if (y == p_v.y) { return z < p_v.z; @@ -446,7 +446,7 @@ bool Vector3::operator<(const Vector3 &p_v) const { return x < p_v.x; } -bool Vector3::operator>(const Vector3 &p_v) const { +constexpr bool Vector3::operator>(const Vector3 &p_v) const { if (x == p_v.x) { if (y == p_v.y) { return z > p_v.z; @@ -456,7 +456,7 @@ bool Vector3::operator>(const Vector3 &p_v) const { return x > p_v.x; } -bool Vector3::operator<=(const Vector3 &p_v) const { +constexpr bool Vector3::operator<=(const Vector3 &p_v) const { if (x == p_v.x) { if (y == p_v.y) { return z <= p_v.z; @@ -466,7 +466,7 @@ bool Vector3::operator<=(const Vector3 &p_v) const { return x < p_v.x; } -bool Vector3::operator>=(const Vector3 &p_v) const { +constexpr bool Vector3::operator>=(const Vector3 &p_v) const { if (x == p_v.x) { if (y == p_v.y) { return z >= p_v.z; @@ -550,4 +550,5 @@ Vector3 Vector3::reflect(const Vector3 &p_normal) const { return 2.0f * p_normal * dot(p_normal) - *this; } -#endif // VECTOR3_H +template <> +struct is_zero_constructible : std::true_type {}; diff --git a/engine/core/math/vector3i.h b/engine/core/math/vector3i.h index 40d0700b..d7d1455e 100644 --- a/engine/core/math/vector3i.h +++ b/engine/core/math/vector3i.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef VECTOR3I_H -#define VECTOR3I_H +#pragma once #include "core/error/error_macros.h" #include "core/math/math_funcs.h" @@ -47,6 +46,7 @@ struct [[nodiscard]] Vector3i { }; union { + // NOLINTBEGIN(modernize-use-default-member-init) struct { int32_t x; int32_t y; @@ -54,6 +54,7 @@ struct [[nodiscard]] Vector3i { }; int32_t coord[3] = { 0 }; + // NOLINTEND(modernize-use-default-member-init) }; _FORCE_INLINE_ const int32_t &operator[](int p_axis) const { @@ -102,42 +103,40 @@ struct [[nodiscard]] Vector3i { /* Operators */ - _FORCE_INLINE_ Vector3i &operator+=(const Vector3i &p_v); - _FORCE_INLINE_ Vector3i operator+(const Vector3i &p_v) const; - _FORCE_INLINE_ Vector3i &operator-=(const Vector3i &p_v); - _FORCE_INLINE_ Vector3i operator-(const Vector3i &p_v) const; - _FORCE_INLINE_ Vector3i &operator*=(const Vector3i &p_v); - _FORCE_INLINE_ Vector3i operator*(const Vector3i &p_v) const; - _FORCE_INLINE_ Vector3i &operator/=(const Vector3i &p_v); - _FORCE_INLINE_ Vector3i operator/(const Vector3i &p_v) const; - _FORCE_INLINE_ Vector3i &operator%=(const Vector3i &p_v); - _FORCE_INLINE_ Vector3i operator%(const Vector3i &p_v) const; + constexpr Vector3i &operator+=(const Vector3i &p_v); + constexpr Vector3i operator+(const Vector3i &p_v) const; + constexpr Vector3i &operator-=(const Vector3i &p_v); + constexpr Vector3i operator-(const Vector3i &p_v) const; + constexpr Vector3i &operator*=(const Vector3i &p_v); + constexpr Vector3i operator*(const Vector3i &p_v) const; + constexpr Vector3i &operator/=(const Vector3i &p_v); + constexpr Vector3i operator/(const Vector3i &p_v) const; + constexpr Vector3i &operator%=(const Vector3i &p_v); + constexpr Vector3i operator%(const Vector3i &p_v) const; - _FORCE_INLINE_ Vector3i &operator*=(int32_t p_scalar); - _FORCE_INLINE_ Vector3i operator*(int32_t p_scalar) const; - _FORCE_INLINE_ Vector3i &operator/=(int32_t p_scalar); - _FORCE_INLINE_ Vector3i operator/(int32_t p_scalar) const; - _FORCE_INLINE_ Vector3i &operator%=(int32_t p_scalar); - _FORCE_INLINE_ Vector3i operator%(int32_t p_scalar) const; + constexpr Vector3i &operator*=(int32_t p_scalar); + constexpr Vector3i operator*(int32_t p_scalar) const; + constexpr Vector3i &operator/=(int32_t p_scalar); + constexpr Vector3i operator/(int32_t p_scalar) const; + constexpr Vector3i &operator%=(int32_t p_scalar); + constexpr Vector3i operator%(int32_t p_scalar) const; - _FORCE_INLINE_ Vector3i operator-() const; + constexpr Vector3i operator-() const; - _FORCE_INLINE_ bool operator==(const Vector3i &p_v) const; - _FORCE_INLINE_ bool operator!=(const Vector3i &p_v) const; - _FORCE_INLINE_ bool operator<(const Vector3i &p_v) const; - _FORCE_INLINE_ bool operator<=(const Vector3i &p_v) const; - _FORCE_INLINE_ bool operator>(const Vector3i &p_v) const; - _FORCE_INLINE_ bool operator>=(const Vector3i &p_v) const; + constexpr bool operator==(const Vector3i &p_v) const; + constexpr bool operator!=(const Vector3i &p_v) const; + constexpr bool operator<(const Vector3i &p_v) const; + constexpr bool operator<=(const Vector3i &p_v) const; + constexpr bool operator>(const Vector3i &p_v) const; + constexpr bool operator>=(const Vector3i &p_v) const; operator String() const; operator Vector3() const; - _FORCE_INLINE_ Vector3i() {} - _FORCE_INLINE_ Vector3i(int32_t p_x, int32_t p_y, int32_t p_z) { - x = p_x; - y = p_y; - z = p_z; - } + constexpr Vector3i() : + x(0), y(0), z(0) {} + constexpr Vector3i(int32_t p_x, int32_t p_y, int32_t p_z) : + x(p_x), y(p_y), z(p_z) {} }; int64_t Vector3i::length_squared() const { @@ -166,125 +165,125 @@ int64_t Vector3i::distance_squared_to(const Vector3i &p_to) const { /* Operators */ -Vector3i &Vector3i::operator+=(const Vector3i &p_v) { +constexpr Vector3i &Vector3i::operator+=(const Vector3i &p_v) { x += p_v.x; y += p_v.y; z += p_v.z; return *this; } -Vector3i Vector3i::operator+(const Vector3i &p_v) const { +constexpr Vector3i Vector3i::operator+(const Vector3i &p_v) const { return Vector3i(x + p_v.x, y + p_v.y, z + p_v.z); } -Vector3i &Vector3i::operator-=(const Vector3i &p_v) { +constexpr Vector3i &Vector3i::operator-=(const Vector3i &p_v) { x -= p_v.x; y -= p_v.y; z -= p_v.z; return *this; } -Vector3i Vector3i::operator-(const Vector3i &p_v) const { +constexpr Vector3i Vector3i::operator-(const Vector3i &p_v) const { return Vector3i(x - p_v.x, y - p_v.y, z - p_v.z); } -Vector3i &Vector3i::operator*=(const Vector3i &p_v) { +constexpr Vector3i &Vector3i::operator*=(const Vector3i &p_v) { x *= p_v.x; y *= p_v.y; z *= p_v.z; return *this; } -Vector3i Vector3i::operator*(const Vector3i &p_v) const { +constexpr Vector3i Vector3i::operator*(const Vector3i &p_v) const { return Vector3i(x * p_v.x, y * p_v.y, z * p_v.z); } -Vector3i &Vector3i::operator/=(const Vector3i &p_v) { +constexpr Vector3i &Vector3i::operator/=(const Vector3i &p_v) { x /= p_v.x; y /= p_v.y; z /= p_v.z; return *this; } -Vector3i Vector3i::operator/(const Vector3i &p_v) const { +constexpr Vector3i Vector3i::operator/(const Vector3i &p_v) const { return Vector3i(x / p_v.x, y / p_v.y, z / p_v.z); } -Vector3i &Vector3i::operator%=(const Vector3i &p_v) { +constexpr Vector3i &Vector3i::operator%=(const Vector3i &p_v) { x %= p_v.x; y %= p_v.y; z %= p_v.z; return *this; } -Vector3i Vector3i::operator%(const Vector3i &p_v) const { +constexpr Vector3i Vector3i::operator%(const Vector3i &p_v) const { return Vector3i(x % p_v.x, y % p_v.y, z % p_v.z); } -Vector3i &Vector3i::operator*=(int32_t p_scalar) { +constexpr Vector3i &Vector3i::operator*=(int32_t p_scalar) { x *= p_scalar; y *= p_scalar; z *= p_scalar; return *this; } -Vector3i Vector3i::operator*(int32_t p_scalar) const { +constexpr Vector3i Vector3i::operator*(int32_t p_scalar) const { return Vector3i(x * p_scalar, y * p_scalar, z * p_scalar); } // Multiplication operators required to workaround issues with LLVM using implicit conversion. -_FORCE_INLINE_ Vector3i operator*(int32_t p_scalar, const Vector3i &p_vector) { +constexpr Vector3i operator*(int32_t p_scalar, const Vector3i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector3i operator*(int64_t p_scalar, const Vector3i &p_vector) { +constexpr Vector3i operator*(int64_t p_scalar, const Vector3i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector3i operator*(float p_scalar, const Vector3i &p_vector) { +constexpr Vector3i operator*(float p_scalar, const Vector3i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector3i operator*(double p_scalar, const Vector3i &p_vector) { +constexpr Vector3i operator*(double p_scalar, const Vector3i &p_vector) { return p_vector * p_scalar; } -Vector3i &Vector3i::operator/=(int32_t p_scalar) { +constexpr Vector3i &Vector3i::operator/=(int32_t p_scalar) { x /= p_scalar; y /= p_scalar; z /= p_scalar; return *this; } -Vector3i Vector3i::operator/(int32_t p_scalar) const { +constexpr Vector3i Vector3i::operator/(int32_t p_scalar) const { return Vector3i(x / p_scalar, y / p_scalar, z / p_scalar); } -Vector3i &Vector3i::operator%=(int32_t p_scalar) { +constexpr Vector3i &Vector3i::operator%=(int32_t p_scalar) { x %= p_scalar; y %= p_scalar; z %= p_scalar; return *this; } -Vector3i Vector3i::operator%(int32_t p_scalar) const { +constexpr Vector3i Vector3i::operator%(int32_t p_scalar) const { return Vector3i(x % p_scalar, y % p_scalar, z % p_scalar); } -Vector3i Vector3i::operator-() const { +constexpr Vector3i Vector3i::operator-() const { return Vector3i(-x, -y, -z); } -bool Vector3i::operator==(const Vector3i &p_v) const { +constexpr bool Vector3i::operator==(const Vector3i &p_v) const { return (x == p_v.x && y == p_v.y && z == p_v.z); } -bool Vector3i::operator!=(const Vector3i &p_v) const { +constexpr bool Vector3i::operator!=(const Vector3i &p_v) const { return (x != p_v.x || y != p_v.y || z != p_v.z); } -bool Vector3i::operator<(const Vector3i &p_v) const { +constexpr bool Vector3i::operator<(const Vector3i &p_v) const { if (x == p_v.x) { if (y == p_v.y) { return z < p_v.z; @@ -296,7 +295,7 @@ bool Vector3i::operator<(const Vector3i &p_v) const { } } -bool Vector3i::operator>(const Vector3i &p_v) const { +constexpr bool Vector3i::operator>(const Vector3i &p_v) const { if (x == p_v.x) { if (y == p_v.y) { return z > p_v.z; @@ -308,7 +307,7 @@ bool Vector3i::operator>(const Vector3i &p_v) const { } } -bool Vector3i::operator<=(const Vector3i &p_v) const { +constexpr bool Vector3i::operator<=(const Vector3i &p_v) const { if (x == p_v.x) { if (y == p_v.y) { return z <= p_v.z; @@ -320,7 +319,7 @@ bool Vector3i::operator<=(const Vector3i &p_v) const { } } -bool Vector3i::operator>=(const Vector3i &p_v) const { +constexpr bool Vector3i::operator>=(const Vector3i &p_v) const { if (x == p_v.x) { if (y == p_v.y) { return z >= p_v.z; @@ -336,4 +335,5 @@ void Vector3i::zero() { x = y = z = 0; } -#endif // VECTOR3I_H +template <> +struct is_zero_constructible : std::true_type {}; diff --git a/engine/core/math/vector4.cpp b/engine/core/math/vector4.cpp index 8ac2c4bf..e4fa1769 100644 --- a/engine/core/math/vector4.cpp +++ b/engine/core/math/vector4.cpp @@ -62,6 +62,10 @@ bool Vector4::is_equal_approx(const Vector4 &p_vec4) const { return Math::is_equal_approx(x, p_vec4.x) && Math::is_equal_approx(y, p_vec4.y) && Math::is_equal_approx(z, p_vec4.z) && Math::is_equal_approx(w, p_vec4.w); } +bool Vector4::is_same(const Vector4 &p_vec4) const { + return Math::is_same(x, p_vec4.x) && Math::is_same(y, p_vec4.y) && Math::is_same(z, p_vec4.z) && Math::is_same(w, p_vec4.w); +} + bool Vector4::is_zero_approx() const { return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z) && Math::is_zero_approx(w); } diff --git a/engine/core/math/vector4.h b/engine/core/math/vector4.h index 9197e358..c8356413 100644 --- a/engine/core/math/vector4.h +++ b/engine/core/math/vector4.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef VECTOR4_H -#define VECTOR4_H +#pragma once #include "core/error/error_macros.h" #include "core/math/math_defs.h" @@ -49,6 +48,7 @@ struct [[nodiscard]] Vector4 { }; union { + // NOLINTBEGIN(modernize-use-default-member-init) struct { real_t x; real_t y; @@ -56,6 +56,7 @@ struct [[nodiscard]] Vector4 { real_t w; }; real_t coord[4] = { 0, 0, 0, 0 }; + // NOLINTEND(modernize-use-default-member-init) }; _FORCE_INLINE_ real_t &operator[](int p_axis) { @@ -89,6 +90,7 @@ struct [[nodiscard]] Vector4 { _FORCE_INLINE_ real_t length_squared() const; bool is_equal_approx(const Vector4 &p_vec4) const; bool is_zero_approx() const; + bool is_same(const Vector4 &p_vec4) const; bool is_finite() const; real_t length() const; void normalize(); @@ -120,37 +122,34 @@ struct [[nodiscard]] Vector4 { Vector4 inverse() const; _FORCE_INLINE_ real_t dot(const Vector4 &p_vec4) const; - _FORCE_INLINE_ void operator+=(const Vector4 &p_vec4); - _FORCE_INLINE_ void operator-=(const Vector4 &p_vec4); - _FORCE_INLINE_ void operator*=(const Vector4 &p_vec4); - _FORCE_INLINE_ void operator/=(const Vector4 &p_vec4); - _FORCE_INLINE_ void operator*=(real_t p_s); - _FORCE_INLINE_ void operator/=(real_t p_s); - _FORCE_INLINE_ Vector4 operator+(const Vector4 &p_vec4) const; - _FORCE_INLINE_ Vector4 operator-(const Vector4 &p_vec4) const; - _FORCE_INLINE_ Vector4 operator*(const Vector4 &p_vec4) const; - _FORCE_INLINE_ Vector4 operator/(const Vector4 &p_vec4) const; - _FORCE_INLINE_ Vector4 operator-() const; - _FORCE_INLINE_ Vector4 operator*(real_t p_s) const; - _FORCE_INLINE_ Vector4 operator/(real_t p_s) const; + constexpr void operator+=(const Vector4 &p_vec4); + constexpr void operator-=(const Vector4 &p_vec4); + constexpr void operator*=(const Vector4 &p_vec4); + constexpr void operator/=(const Vector4 &p_vec4); + constexpr void operator*=(real_t p_s); + constexpr void operator/=(real_t p_s); + constexpr Vector4 operator+(const Vector4 &p_vec4) const; + constexpr Vector4 operator-(const Vector4 &p_vec4) const; + constexpr Vector4 operator*(const Vector4 &p_vec4) const; + constexpr Vector4 operator/(const Vector4 &p_vec4) const; + constexpr Vector4 operator-() const; + constexpr Vector4 operator*(real_t p_s) const; + constexpr Vector4 operator/(real_t p_s) const; - _FORCE_INLINE_ bool operator==(const Vector4 &p_vec4) const; - _FORCE_INLINE_ bool operator!=(const Vector4 &p_vec4) const; - _FORCE_INLINE_ bool operator>(const Vector4 &p_vec4) const; - _FORCE_INLINE_ bool operator<(const Vector4 &p_vec4) const; - _FORCE_INLINE_ bool operator>=(const Vector4 &p_vec4) const; - _FORCE_INLINE_ bool operator<=(const Vector4 &p_vec4) const; + constexpr bool operator==(const Vector4 &p_vec4) const; + constexpr bool operator!=(const Vector4 &p_vec4) const; + constexpr bool operator>(const Vector4 &p_vec4) const; + constexpr bool operator<(const Vector4 &p_vec4) const; + constexpr bool operator>=(const Vector4 &p_vec4) const; + constexpr bool operator<=(const Vector4 &p_vec4) const; operator String() const; operator Vector4i() const; - _FORCE_INLINE_ Vector4() {} - _FORCE_INLINE_ Vector4(real_t p_x, real_t p_y, real_t p_z, real_t p_w) { - x = p_x; - y = p_y; - z = p_z; - w = p_w; - } + constexpr Vector4() : + x(0), y(0), z(0), w(0) {} + constexpr Vector4(real_t p_x, real_t p_y, real_t p_z, real_t p_w) : + x(p_x), y(p_y), z(p_z), w(p_w) {} }; real_t Vector4::dot(const Vector4 &p_vec4) const { @@ -161,81 +160,81 @@ real_t Vector4::length_squared() const { return dot(*this); } -void Vector4::operator+=(const Vector4 &p_vec4) { +constexpr void Vector4::operator+=(const Vector4 &p_vec4) { x += p_vec4.x; y += p_vec4.y; z += p_vec4.z; w += p_vec4.w; } -void Vector4::operator-=(const Vector4 &p_vec4) { +constexpr void Vector4::operator-=(const Vector4 &p_vec4) { x -= p_vec4.x; y -= p_vec4.y; z -= p_vec4.z; w -= p_vec4.w; } -void Vector4::operator*=(const Vector4 &p_vec4) { +constexpr void Vector4::operator*=(const Vector4 &p_vec4) { x *= p_vec4.x; y *= p_vec4.y; z *= p_vec4.z; w *= p_vec4.w; } -void Vector4::operator/=(const Vector4 &p_vec4) { +constexpr void Vector4::operator/=(const Vector4 &p_vec4) { x /= p_vec4.x; y /= p_vec4.y; z /= p_vec4.z; w /= p_vec4.w; } -void Vector4::operator*=(real_t p_s) { +constexpr void Vector4::operator*=(real_t p_s) { x *= p_s; y *= p_s; z *= p_s; w *= p_s; } -void Vector4::operator/=(real_t p_s) { - *this *= 1.0f / p_s; +constexpr void Vector4::operator/=(real_t p_s) { + *this *= (1 / p_s); } -Vector4 Vector4::operator+(const Vector4 &p_vec4) const { +constexpr Vector4 Vector4::operator+(const Vector4 &p_vec4) const { return Vector4(x + p_vec4.x, y + p_vec4.y, z + p_vec4.z, w + p_vec4.w); } -Vector4 Vector4::operator-(const Vector4 &p_vec4) const { +constexpr Vector4 Vector4::operator-(const Vector4 &p_vec4) const { return Vector4(x - p_vec4.x, y - p_vec4.y, z - p_vec4.z, w - p_vec4.w); } -Vector4 Vector4::operator*(const Vector4 &p_vec4) const { +constexpr Vector4 Vector4::operator*(const Vector4 &p_vec4) const { return Vector4(x * p_vec4.x, y * p_vec4.y, z * p_vec4.z, w * p_vec4.w); } -Vector4 Vector4::operator/(const Vector4 &p_vec4) const { +constexpr Vector4 Vector4::operator/(const Vector4 &p_vec4) const { return Vector4(x / p_vec4.x, y / p_vec4.y, z / p_vec4.z, w / p_vec4.w); } -Vector4 Vector4::operator-() const { +constexpr Vector4 Vector4::operator-() const { return Vector4(-x, -y, -z, -w); } -Vector4 Vector4::operator*(real_t p_s) const { +constexpr Vector4 Vector4::operator*(real_t p_s) const { return Vector4(x * p_s, y * p_s, z * p_s, w * p_s); } -Vector4 Vector4::operator/(real_t p_s) const { - return *this * (1.0f / p_s); +constexpr Vector4 Vector4::operator/(real_t p_s) const { + return *this * (1 / p_s); } -bool Vector4::operator==(const Vector4 &p_vec4) const { +constexpr bool Vector4::operator==(const Vector4 &p_vec4) const { return x == p_vec4.x && y == p_vec4.y && z == p_vec4.z && w == p_vec4.w; } -bool Vector4::operator!=(const Vector4 &p_vec4) const { +constexpr bool Vector4::operator!=(const Vector4 &p_vec4) const { return x != p_vec4.x || y != p_vec4.y || z != p_vec4.z || w != p_vec4.w; } -bool Vector4::operator<(const Vector4 &p_v) const { +constexpr bool Vector4::operator<(const Vector4 &p_v) const { if (x == p_v.x) { if (y == p_v.y) { if (z == p_v.z) { @@ -248,7 +247,7 @@ bool Vector4::operator<(const Vector4 &p_v) const { return x < p_v.x; } -bool Vector4::operator>(const Vector4 &p_v) const { +constexpr bool Vector4::operator>(const Vector4 &p_v) const { if (x == p_v.x) { if (y == p_v.y) { if (z == p_v.z) { @@ -261,7 +260,7 @@ bool Vector4::operator>(const Vector4 &p_v) const { return x > p_v.x; } -bool Vector4::operator<=(const Vector4 &p_v) const { +constexpr bool Vector4::operator<=(const Vector4 &p_v) const { if (x == p_v.x) { if (y == p_v.y) { if (z == p_v.z) { @@ -274,7 +273,7 @@ bool Vector4::operator<=(const Vector4 &p_v) const { return x < p_v.x; } -bool Vector4::operator>=(const Vector4 &p_v) const { +constexpr bool Vector4::operator>=(const Vector4 &p_v) const { if (x == p_v.x) { if (y == p_v.y) { if (z == p_v.z) { @@ -287,20 +286,21 @@ bool Vector4::operator>=(const Vector4 &p_v) const { return x > p_v.x; } -_FORCE_INLINE_ Vector4 operator*(float p_scalar, const Vector4 &p_vec) { +constexpr Vector4 operator*(float p_scalar, const Vector4 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector4 operator*(double p_scalar, const Vector4 &p_vec) { +constexpr Vector4 operator*(double p_scalar, const Vector4 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector4 operator*(int32_t p_scalar, const Vector4 &p_vec) { +constexpr Vector4 operator*(int32_t p_scalar, const Vector4 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector4 operator*(int64_t p_scalar, const Vector4 &p_vec) { +constexpr Vector4 operator*(int64_t p_scalar, const Vector4 &p_vec) { return p_vec * p_scalar; } -#endif // VECTOR4_H +template <> +struct is_zero_constructible : std::true_type {}; diff --git a/engine/core/math/vector4i.h b/engine/core/math/vector4i.h index a9036d68..56ae3f22 100644 --- a/engine/core/math/vector4i.h +++ b/engine/core/math/vector4i.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef VECTOR4I_H -#define VECTOR4I_H +#pragma once #include "core/error/error_macros.h" #include "core/math/math_funcs.h" @@ -48,6 +47,7 @@ struct [[nodiscard]] Vector4i { }; union { + // NOLINTBEGIN(modernize-use-default-member-init) struct { int32_t x; int32_t y; @@ -56,6 +56,7 @@ struct [[nodiscard]] Vector4i { }; int32_t coord[4] = { 0 }; + // NOLINTEND(modernize-use-default-member-init) }; _FORCE_INLINE_ const int32_t &operator[](int p_axis) const { @@ -104,44 +105,41 @@ struct [[nodiscard]] Vector4i { /* Operators */ - _FORCE_INLINE_ Vector4i &operator+=(const Vector4i &p_v); - _FORCE_INLINE_ Vector4i operator+(const Vector4i &p_v) const; - _FORCE_INLINE_ Vector4i &operator-=(const Vector4i &p_v); - _FORCE_INLINE_ Vector4i operator-(const Vector4i &p_v) const; - _FORCE_INLINE_ Vector4i &operator*=(const Vector4i &p_v); - _FORCE_INLINE_ Vector4i operator*(const Vector4i &p_v) const; - _FORCE_INLINE_ Vector4i &operator/=(const Vector4i &p_v); - _FORCE_INLINE_ Vector4i operator/(const Vector4i &p_v) const; - _FORCE_INLINE_ Vector4i &operator%=(const Vector4i &p_v); - _FORCE_INLINE_ Vector4i operator%(const Vector4i &p_v) const; + constexpr Vector4i &operator+=(const Vector4i &p_v); + constexpr Vector4i operator+(const Vector4i &p_v) const; + constexpr Vector4i &operator-=(const Vector4i &p_v); + constexpr Vector4i operator-(const Vector4i &p_v) const; + constexpr Vector4i &operator*=(const Vector4i &p_v); + constexpr Vector4i operator*(const Vector4i &p_v) const; + constexpr Vector4i &operator/=(const Vector4i &p_v); + constexpr Vector4i operator/(const Vector4i &p_v) const; + constexpr Vector4i &operator%=(const Vector4i &p_v); + constexpr Vector4i operator%(const Vector4i &p_v) const; - _FORCE_INLINE_ Vector4i &operator*=(int32_t p_scalar); - _FORCE_INLINE_ Vector4i operator*(int32_t p_scalar) const; - _FORCE_INLINE_ Vector4i &operator/=(int32_t p_scalar); - _FORCE_INLINE_ Vector4i operator/(int32_t p_scalar) const; - _FORCE_INLINE_ Vector4i &operator%=(int32_t p_scalar); - _FORCE_INLINE_ Vector4i operator%(int32_t p_scalar) const; + constexpr Vector4i &operator*=(int32_t p_scalar); + constexpr Vector4i operator*(int32_t p_scalar) const; + constexpr Vector4i &operator/=(int32_t p_scalar); + constexpr Vector4i operator/(int32_t p_scalar) const; + constexpr Vector4i &operator%=(int32_t p_scalar); + constexpr Vector4i operator%(int32_t p_scalar) const; - _FORCE_INLINE_ Vector4i operator-() const; + constexpr Vector4i operator-() const; - _FORCE_INLINE_ bool operator==(const Vector4i &p_v) const; - _FORCE_INLINE_ bool operator!=(const Vector4i &p_v) const; - _FORCE_INLINE_ bool operator<(const Vector4i &p_v) const; - _FORCE_INLINE_ bool operator<=(const Vector4i &p_v) const; - _FORCE_INLINE_ bool operator>(const Vector4i &p_v) const; - _FORCE_INLINE_ bool operator>=(const Vector4i &p_v) const; + constexpr bool operator==(const Vector4i &p_v) const; + constexpr bool operator!=(const Vector4i &p_v) const; + constexpr bool operator<(const Vector4i &p_v) const; + constexpr bool operator<=(const Vector4i &p_v) const; + constexpr bool operator>(const Vector4i &p_v) const; + constexpr bool operator>=(const Vector4i &p_v) const; operator String() const; operator Vector4() const; - _FORCE_INLINE_ Vector4i() {} + constexpr Vector4i() : + x(0), y(0), z(0), w(0) {} Vector4i(const Vector4 &p_vec4); - _FORCE_INLINE_ Vector4i(int32_t p_x, int32_t p_y, int32_t p_z, int32_t p_w) { - x = p_x; - y = p_y; - z = p_z; - w = p_w; - } + constexpr Vector4i(int32_t p_x, int32_t p_y, int32_t p_z, int32_t p_w) : + x(p_x), y(p_y), z(p_z), w(p_w) {} }; int64_t Vector4i::length_squared() const { @@ -170,7 +168,7 @@ Vector4i Vector4i::sign() const { /* Operators */ -Vector4i &Vector4i::operator+=(const Vector4i &p_v) { +constexpr Vector4i &Vector4i::operator+=(const Vector4i &p_v) { x += p_v.x; y += p_v.y; z += p_v.z; @@ -178,11 +176,11 @@ Vector4i &Vector4i::operator+=(const Vector4i &p_v) { return *this; } -Vector4i Vector4i::operator+(const Vector4i &p_v) const { +constexpr Vector4i Vector4i::operator+(const Vector4i &p_v) const { return Vector4i(x + p_v.x, y + p_v.y, z + p_v.z, w + p_v.w); } -Vector4i &Vector4i::operator-=(const Vector4i &p_v) { +constexpr Vector4i &Vector4i::operator-=(const Vector4i &p_v) { x -= p_v.x; y -= p_v.y; z -= p_v.z; @@ -190,11 +188,11 @@ Vector4i &Vector4i::operator-=(const Vector4i &p_v) { return *this; } -Vector4i Vector4i::operator-(const Vector4i &p_v) const { +constexpr Vector4i Vector4i::operator-(const Vector4i &p_v) const { return Vector4i(x - p_v.x, y - p_v.y, z - p_v.z, w - p_v.w); } -Vector4i &Vector4i::operator*=(const Vector4i &p_v) { +constexpr Vector4i &Vector4i::operator*=(const Vector4i &p_v) { x *= p_v.x; y *= p_v.y; z *= p_v.z; @@ -202,11 +200,11 @@ Vector4i &Vector4i::operator*=(const Vector4i &p_v) { return *this; } -Vector4i Vector4i::operator*(const Vector4i &p_v) const { +constexpr Vector4i Vector4i::operator*(const Vector4i &p_v) const { return Vector4i(x * p_v.x, y * p_v.y, z * p_v.z, w * p_v.w); } -Vector4i &Vector4i::operator/=(const Vector4i &p_v) { +constexpr Vector4i &Vector4i::operator/=(const Vector4i &p_v) { x /= p_v.x; y /= p_v.y; z /= p_v.z; @@ -214,11 +212,11 @@ Vector4i &Vector4i::operator/=(const Vector4i &p_v) { return *this; } -Vector4i Vector4i::operator/(const Vector4i &p_v) const { +constexpr Vector4i Vector4i::operator/(const Vector4i &p_v) const { return Vector4i(x / p_v.x, y / p_v.y, z / p_v.z, w / p_v.w); } -Vector4i &Vector4i::operator%=(const Vector4i &p_v) { +constexpr Vector4i &Vector4i::operator%=(const Vector4i &p_v) { x %= p_v.x; y %= p_v.y; z %= p_v.z; @@ -226,11 +224,11 @@ Vector4i &Vector4i::operator%=(const Vector4i &p_v) { return *this; } -Vector4i Vector4i::operator%(const Vector4i &p_v) const { +constexpr Vector4i Vector4i::operator%(const Vector4i &p_v) const { return Vector4i(x % p_v.x, y % p_v.y, z % p_v.z, w % p_v.w); } -Vector4i &Vector4i::operator*=(int32_t p_scalar) { +constexpr Vector4i &Vector4i::operator*=(int32_t p_scalar) { x *= p_scalar; y *= p_scalar; z *= p_scalar; @@ -238,29 +236,29 @@ Vector4i &Vector4i::operator*=(int32_t p_scalar) { return *this; } -Vector4i Vector4i::operator*(int32_t p_scalar) const { +constexpr Vector4i Vector4i::operator*(int32_t p_scalar) const { return Vector4i(x * p_scalar, y * p_scalar, z * p_scalar, w * p_scalar); } // Multiplication operators required to workaround issues with LLVM using implicit conversion. -_FORCE_INLINE_ Vector4i operator*(int32_t p_scalar, const Vector4i &p_vector) { +constexpr Vector4i operator*(int32_t p_scalar, const Vector4i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector4i operator*(int64_t p_scalar, const Vector4i &p_vector) { +constexpr Vector4i operator*(int64_t p_scalar, const Vector4i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector4i operator*(float p_scalar, const Vector4i &p_vector) { +constexpr Vector4i operator*(float p_scalar, const Vector4i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector4i operator*(double p_scalar, const Vector4i &p_vector) { +constexpr Vector4i operator*(double p_scalar, const Vector4i &p_vector) { return p_vector * p_scalar; } -Vector4i &Vector4i::operator/=(int32_t p_scalar) { +constexpr Vector4i &Vector4i::operator/=(int32_t p_scalar) { x /= p_scalar; y /= p_scalar; z /= p_scalar; @@ -268,11 +266,11 @@ Vector4i &Vector4i::operator/=(int32_t p_scalar) { return *this; } -Vector4i Vector4i::operator/(int32_t p_scalar) const { +constexpr Vector4i Vector4i::operator/(int32_t p_scalar) const { return Vector4i(x / p_scalar, y / p_scalar, z / p_scalar, w / p_scalar); } -Vector4i &Vector4i::operator%=(int32_t p_scalar) { +constexpr Vector4i &Vector4i::operator%=(int32_t p_scalar) { x %= p_scalar; y %= p_scalar; z %= p_scalar; @@ -280,23 +278,23 @@ Vector4i &Vector4i::operator%=(int32_t p_scalar) { return *this; } -Vector4i Vector4i::operator%(int32_t p_scalar) const { +constexpr Vector4i Vector4i::operator%(int32_t p_scalar) const { return Vector4i(x % p_scalar, y % p_scalar, z % p_scalar, w % p_scalar); } -Vector4i Vector4i::operator-() const { +constexpr Vector4i Vector4i::operator-() const { return Vector4i(-x, -y, -z, -w); } -bool Vector4i::operator==(const Vector4i &p_v) const { +constexpr bool Vector4i::operator==(const Vector4i &p_v) const { return (x == p_v.x && y == p_v.y && z == p_v.z && w == p_v.w); } -bool Vector4i::operator!=(const Vector4i &p_v) const { +constexpr bool Vector4i::operator!=(const Vector4i &p_v) const { return (x != p_v.x || y != p_v.y || z != p_v.z || w != p_v.w); } -bool Vector4i::operator<(const Vector4i &p_v) const { +constexpr bool Vector4i::operator<(const Vector4i &p_v) const { if (x == p_v.x) { if (y == p_v.y) { if (z == p_v.z) { @@ -312,7 +310,7 @@ bool Vector4i::operator<(const Vector4i &p_v) const { } } -bool Vector4i::operator>(const Vector4i &p_v) const { +constexpr bool Vector4i::operator>(const Vector4i &p_v) const { if (x == p_v.x) { if (y == p_v.y) { if (z == p_v.z) { @@ -328,7 +326,7 @@ bool Vector4i::operator>(const Vector4i &p_v) const { } } -bool Vector4i::operator<=(const Vector4i &p_v) const { +constexpr bool Vector4i::operator<=(const Vector4i &p_v) const { if (x == p_v.x) { if (y == p_v.y) { if (z == p_v.z) { @@ -344,7 +342,7 @@ bool Vector4i::operator<=(const Vector4i &p_v) const { } } -bool Vector4i::operator>=(const Vector4i &p_v) const { +constexpr bool Vector4i::operator>=(const Vector4i &p_v) const { if (x == p_v.x) { if (y == p_v.y) { if (z == p_v.z) { @@ -364,4 +362,5 @@ void Vector4i::zero() { x = y = z = w = 0; } -#endif // VECTOR4I_H +template <> +struct is_zero_constructible : std::true_type {}; diff --git a/engine/core/object/callable_method_pointer.h b/engine/core/object/callable_method_pointer.h index a12db51c..7462316d 100644 --- a/engine/core/object/callable_method_pointer.h +++ b/engine/core/object/callable_method_pointer.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef CALLABLE_METHOD_POINTER_H -#define CALLABLE_METHOD_POINTER_H +#pragma once #include "core/object/object.h" #include "core/variant/binder_common.h" @@ -82,8 +81,7 @@ class CallableCustomMethodPointer : public CallableCustomMethodPointerBase { struct Data { T *instance; uint64_t object_id; - R(T::*method) - (P...); + R (T::*method)(P...); } data; public: @@ -152,8 +150,7 @@ class CallableCustomMethodPointerC : public CallableCustomMethodPointerBase { struct Data { T *instance; uint64_t object_id; - R(T::*method) - (P...) const; + R (T::*method)(P...) const; } data; public: @@ -226,8 +223,7 @@ Callable create_custom_callable_function_pointer(T *p_instance, template class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase { struct Data { - R(*method) - (P...); + R (*method)(P...); } data; public: @@ -292,5 +288,3 @@ Callable create_custom_callable_static_function_pointer( #else #define callable_mp_static(M) create_custom_callable_static_function_pointer(M) #endif - -#endif // CALLABLE_METHOD_POINTER_H diff --git a/engine/core/object/class_db.cpp b/engine/core/object/class_db.cpp index e6536fe8..fbc5fcda 100644 --- a/engine/core/object/class_db.cpp +++ b/engine/core/object/class_db.cpp @@ -35,9 +35,6 @@ #include "core/object/script_language.h" #include "core/version.h" -#define OBJTYPE_RLOCK RWLockRead _rw_lockr_(lock); -#define OBJTYPE_WLOCK RWLockWrite _rw_lockw_(lock); - #ifdef DEBUG_METHODS_ENABLED MethodDefinition D_METHODP(const char *p_name, const char *const **p_args, uint32_t p_argcount) { @@ -238,13 +235,13 @@ bool ClassDB::_is_parent_class(const StringName &p_class, const StringName &p_in } bool ClassDB::is_parent_class(const StringName &p_class, const StringName &p_inherits) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); return _is_parent_class(p_class, p_inherits); } void ClassDB::get_class_list(List *p_classes) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); for (const KeyValue &E : classes) { p_classes->push_back(E.key); @@ -255,7 +252,7 @@ void ClassDB::get_class_list(List *p_classes) { #ifdef TOOLS_ENABLED void ClassDB::get_extensions_class_list(List *p_classes) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); for (const KeyValue &E : classes) { if (E.value.api != API_EXTENSION && E.value.api != API_EDITOR_EXTENSION) { @@ -268,7 +265,7 @@ void ClassDB::get_extensions_class_list(List *p_classes) { } void ClassDB::get_extension_class_list(const Ref &p_extension, List *p_classes) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); for (const KeyValue &E : classes) { if (E.value.api != API_EXTENSION && E.value.api != API_EDITOR_EXTENSION) { @@ -284,28 +281,28 @@ void ClassDB::get_extension_class_list(const Ref &p_extension, List } #endif -void ClassDB::get_inheriters_from_class(const StringName &p_class, List *p_classes) { - OBJTYPE_RLOCK; +void ClassDB::get_inheriters_from_class(const StringName &p_class, LocalVector &p_classes) { + Locker::Lock lock(Locker::STATE_READ); for (const KeyValue &E : classes) { if (E.key != p_class && _is_parent_class(E.key, p_class)) { - p_classes->push_back(E.key); + p_classes.push_back(E.key); } } } void ClassDB::get_direct_inheriters_from_class(const StringName &p_class, List *p_classes) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); for (const KeyValue &E : classes) { - if (E.key != p_class && _get_parent_class(E.key) == p_class) { + if (E.value.inherits == p_class) { p_classes->push_back(E.key); } } } StringName ClassDB::get_parent_class_nocheck(const StringName &p_class) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *ti = classes.getptr(p_class); if (!ti) { @@ -315,7 +312,7 @@ StringName ClassDB::get_parent_class_nocheck(const StringName &p_class) { } bool ClassDB::get_inheritance_chain_nocheck(const StringName &p_class, Vector &r_result) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *start = classes.getptr(p_class); if (!start) { @@ -356,13 +353,13 @@ StringName ClassDB::_get_parent_class(const StringName &p_class) { } StringName ClassDB::get_parent_class(const StringName &p_class) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); return _get_parent_class(p_class); } ClassDB::APIType ClassDB::get_api_type(const StringName &p_class) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *ti = classes.getptr(p_class); @@ -372,13 +369,13 @@ ClassDB::APIType ClassDB::get_api_type(const StringName &p_class) { uint32_t ClassDB::get_api_hash(APIType p_api) { #ifdef DEBUG_METHODS_ENABLED - OBJTYPE_WLOCK; + Locker::Lock lock(Locker::STATE_WRITE); if (api_hashes_cache.has(p_api)) { return api_hashes_cache[p_api]; } - uint64_t hash = hash_murmur3_one_64(HashMapHasherDefault::hash(VERSION_FULL_CONFIG)); + uint64_t hash = hash_murmur3_one_64(HashMapHasherDefault::hash(GODOT_VERSION_FULL_CONFIG)); List class_list; for (const KeyValue &E : classes) { @@ -520,12 +517,12 @@ uint32_t ClassDB::get_api_hash(APIType p_api) { } bool ClassDB::class_exists(const StringName &p_class) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); return classes.has(p_class); } void ClassDB::add_compatibility_class(const StringName &p_class, const StringName &p_fallback) { - OBJTYPE_WLOCK; + Locker::Lock lock(Locker::STATE_WRITE); compat_classes[p_class] = p_fallback; } @@ -536,18 +533,21 @@ StringName ClassDB::get_compatibility_class(const StringName &p_class) { return StringName(); } -Object *ClassDB::_instantiate_internal(const StringName &p_class, bool p_require_real_class, bool p_notify_postinitialize) { +Object *ClassDB::_instantiate_internal(const StringName &p_class, bool p_require_real_class, bool p_notify_postinitialize, bool p_exposed_only) { ClassInfo *ti; { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ti = classes.getptr(p_class); - if (!_can_instantiate(ti)) { + if (!_can_instantiate(ti, p_exposed_only)) { if (compat_classes.has(p_class)) { ti = classes.getptr(compat_classes[p_class]); } } ERR_FAIL_NULL_V_MSG(ti, nullptr, vformat("Cannot get class '%s'.", String(p_class))); ERR_FAIL_COND_V_MSG(ti->disabled, nullptr, vformat("Class '%s' is disabled.", String(p_class))); + if (p_exposed_only) { + ERR_FAIL_COND_V_MSG(!ti->exposed, nullptr, vformat("Class '%s' isn't exposed.", String(p_class))); + } ERR_FAIL_NULL_V_MSG(ti->creation_func, nullptr, vformat("Class '%s' or its base class cannot be instantiated.", String(p_class))); } @@ -599,11 +599,15 @@ Object *ClassDB::_instantiate_internal(const StringName &p_class, bool p_require } } -bool ClassDB::_can_instantiate(ClassInfo *p_class_info) { +bool ClassDB::_can_instantiate(ClassInfo *p_class_info, bool p_exposed_only) { if (!p_class_info) { return false; } + if (p_exposed_only && !p_class_info->exposed) { + return false; + } + if (p_class_info->disabled || !p_class_info->creation_func) { return false; } @@ -645,7 +649,7 @@ ObjectGDExtension *ClassDB::get_placeholder_extension(const StringName &p_class) ClassInfo *ti; { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ti = classes.getptr(p_class); if (!_can_instantiate(ti)) { if (compat_classes.has(p_class)) { @@ -730,7 +734,7 @@ void ClassDB::set_object_extension_instance(Object *p_object, const StringName & ERR_FAIL_NULL(p_object); ClassInfo *ti; { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ti = classes.getptr(p_class); if (!_can_instantiate(ti)) { if (compat_classes.has(p_class)) { @@ -755,7 +759,7 @@ void ClassDB::set_object_extension_instance(Object *p_object, const StringName & bool ClassDB::can_instantiate(const StringName &p_class) { String script_path; { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *ti = classes.getptr(p_class); if (!ti) { @@ -781,7 +785,7 @@ use_script: bool ClassDB::is_abstract(const StringName &p_class) { String script_path; { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *ti = classes.getptr(p_class); if (!ti) { @@ -813,7 +817,7 @@ use_script: bool ClassDB::is_virtual(const StringName &p_class) { String script_path; { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *ti = classes.getptr(p_class); if (!ti) { @@ -836,8 +840,8 @@ use_script: return scr.is_valid() && scr->is_valid() && scr->is_abstract(); } -void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) { - OBJTYPE_WLOCK; +void ClassDB::_add_class(const StringName &p_class, const StringName &p_inherits) { + Locker::Lock lock(Locker::STATE_WRITE); const StringName &name = p_class; @@ -880,7 +884,7 @@ static MethodInfo info_from_bind(MethodBind *p_method) { } void ClassDB::get_method_list(const StringName &p_class, List *p_methods, bool p_no_inheritance, bool p_exclude_from_properties) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); @@ -926,7 +930,7 @@ void ClassDB::get_method_list(const StringName &p_class, List *p_met } void ClassDB::get_method_list_with_compatibility(const StringName &p_class, List> *p_methods, bool p_no_inheritance, bool p_exclude_from_properties) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); @@ -986,7 +990,7 @@ void ClassDB::get_method_list_with_compatibility(const StringName &p_class, List } bool ClassDB::get_method_info(const StringName &p_class, const StringName &p_method, MethodInfo *r_info, bool p_no_inheritance, bool p_exclude_from_properties) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); @@ -1036,7 +1040,7 @@ bool ClassDB::get_method_info(const StringName &p_class, const StringName &p_met } MethodBind *ClassDB::get_method(const StringName &p_class, const StringName &p_name) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); @@ -1051,7 +1055,7 @@ MethodBind *ClassDB::get_method(const StringName &p_class, const StringName &p_n } Vector ClassDB::get_method_compatibility_hashes(const StringName &p_class, const StringName &p_name) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); @@ -1070,7 +1074,7 @@ Vector ClassDB::get_method_compatibility_hashes(const StringName &p_cl } MethodBind *ClassDB::get_method_with_compatibility(const StringName &p_class, const StringName &p_name, uint64_t p_hash, bool *r_method_exists, bool *r_is_deprecated) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); @@ -1105,7 +1109,7 @@ MethodBind *ClassDB::get_method_with_compatibility(const StringName &p_class, co } void ClassDB::bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int64_t p_constant, bool p_is_bitfield) { - OBJTYPE_WLOCK; + Locker::Lock lock(Locker::STATE_WRITE); ClassInfo *type = classes.getptr(p_class); @@ -1142,7 +1146,7 @@ void ClassDB::bind_integer_constant(const StringName &p_class, const StringName } void ClassDB::get_integer_constant_list(const StringName &p_class, List *p_constants, bool p_no_inheritance) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); @@ -1167,7 +1171,7 @@ void ClassDB::get_integer_constant_list(const StringName &p_class, List } int64_t ClassDB::get_integer_constant(const StringName &p_class, const StringName &p_name, bool *p_success) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); @@ -1191,7 +1195,7 @@ int64_t ClassDB::get_integer_constant(const StringName &p_class, const StringNam } bool ClassDB::has_integer_constant(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); @@ -1210,7 +1214,7 @@ bool ClassDB::has_integer_constant(const StringName &p_class, const StringName & } StringName ClassDB::get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); @@ -1234,7 +1238,7 @@ StringName ClassDB::get_integer_constant_enum(const StringName &p_class, const S } void ClassDB::get_enum_list(const StringName &p_class, List *p_enums, bool p_no_inheritance) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); @@ -1252,7 +1256,7 @@ void ClassDB::get_enum_list(const StringName &p_class, List *p_enums } void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_enum, List *p_constants, bool p_no_inheritance) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); @@ -1275,7 +1279,7 @@ void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_ void ClassDB::set_method_error_return_values(const StringName &p_class, const StringName &p_method, const Vector &p_values) { #ifdef DEBUG_METHODS_ENABLED - OBJTYPE_WLOCK; + Locker::Lock lock(Locker::STATE_WRITE); ClassInfo *type = classes.getptr(p_class); ERR_FAIL_NULL(type); @@ -1286,7 +1290,7 @@ void ClassDB::set_method_error_return_values(const StringName &p_class, const St Vector ClassDB::get_method_error_return_values(const StringName &p_class, const StringName &p_method) { #ifdef DEBUG_METHODS_ENABLED - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); ERR_FAIL_NULL_V(type, Vector()); @@ -1301,7 +1305,7 @@ Vector ClassDB::get_method_error_return_values(const StringName &p_class, } bool ClassDB::has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); @@ -1320,7 +1324,7 @@ bool ClassDB::has_enum(const StringName &p_class, const StringName &p_name, bool } bool ClassDB::is_enum_bitfield(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); @@ -1339,7 +1343,7 @@ bool ClassDB::is_enum_bitfield(const StringName &p_class, const StringName &p_na } void ClassDB::add_signal(const StringName &p_class, const MethodInfo &p_signal) { - OBJTYPE_WLOCK; + Locker::Lock lock(Locker::STATE_WRITE); ClassInfo *type = classes.getptr(p_class); ERR_FAIL_NULL(type); @@ -1358,7 +1362,7 @@ void ClassDB::add_signal(const StringName &p_class, const MethodInfo &p_signal) } void ClassDB::get_signal_list(const StringName &p_class, List *p_signals, bool p_no_inheritance) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); ERR_FAIL_NULL(type); @@ -1379,7 +1383,7 @@ void ClassDB::get_signal_list(const StringName &p_class, List *p_sig } bool ClassDB::has_signal(const StringName &p_class, const StringName &p_signal, bool p_no_inheritance) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); ClassInfo *check = type; while (check) { @@ -1396,7 +1400,7 @@ bool ClassDB::has_signal(const StringName &p_class, const StringName &p_signal, } bool ClassDB::get_signal(const StringName &p_class, const StringName &p_signal, MethodInfo *r_signal) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); ClassInfo *check = type; while (check) { @@ -1413,7 +1417,7 @@ bool ClassDB::get_signal(const StringName &p_class, const StringName &p_signal, } void ClassDB::add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix, int p_indent_depth) { - OBJTYPE_WLOCK; + Locker::Lock lock(Locker::STATE_WRITE); ClassInfo *type = classes.getptr(p_class); ERR_FAIL_NULL(type); @@ -1426,7 +1430,7 @@ void ClassDB::add_property_group(const StringName &p_class, const String &p_name } void ClassDB::add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix, int p_indent_depth) { - OBJTYPE_WLOCK; + Locker::Lock lock(Locker::STATE_WRITE); ClassInfo *type = classes.getptr(p_class); ERR_FAIL_NULL(type); @@ -1443,7 +1447,7 @@ void ClassDB::add_property_array_count(const StringName &p_class, const String & } void ClassDB::add_property_array(const StringName &p_class, const StringName &p_path, const String &p_array_element_prefix) { - OBJTYPE_WLOCK; + Locker::Lock lock(Locker::STATE_WRITE); ClassInfo *type = classes.getptr(p_class); ERR_FAIL_NULL(type); @@ -1452,9 +1456,9 @@ void ClassDB::add_property_array(const StringName &p_class, const StringName &p_ // NOTE: For implementation simplicity reasons, this method doesn't allow setters to have optional arguments at the end. void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) { - lock.read_lock(); + Locker::Lock lock(Locker::STATE_WRITE); + ClassInfo *type = classes.getptr(p_class); - lock.read_unlock(); ERR_FAIL_NULL(type); @@ -1486,8 +1490,6 @@ void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinf ERR_FAIL_COND_MSG(type->property_setget.has(p_pinfo.name), vformat("Object '%s' already has property '%s'.", p_class, p_pinfo.name)); #endif - OBJTYPE_WLOCK - type->property_list.push_back(p_pinfo); type->property_map[p_pinfo.name] = p_pinfo; #ifdef DEBUG_METHODS_ENABLED @@ -1518,7 +1520,7 @@ void ClassDB::set_property_default_value(const StringName &p_class, const String void ClassDB::add_linked_property(const StringName &p_class, const String &p_property, const String &p_linked_property) { #ifdef TOOLS_ENABLED - OBJTYPE_WLOCK; + Locker::Lock lock(Locker::STATE_WRITE); ClassInfo *type = classes.getptr(p_class); ERR_FAIL_NULL(type); @@ -1534,7 +1536,7 @@ void ClassDB::add_linked_property(const StringName &p_class, const String &p_pro } void ClassDB::get_property_list(const StringName &p_class, List *p_list, bool p_no_inheritance, const Object *p_validator) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); ClassInfo *check = type; @@ -1577,7 +1579,7 @@ void ClassDB::get_linked_properties_info(const StringName &p_class, const String } bool ClassDB::get_property_info(const StringName &p_class, const StringName &p_property, PropertyInfo *r_info, bool p_no_inheritance, const Object *p_validator) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *check = classes.getptr(p_class); while (check) { @@ -1800,7 +1802,7 @@ bool ClassDB::has_property(const StringName &p_class, const StringName &p_proper } void ClassDB::set_method_flags(const StringName &p_class, const StringName &p_method, int p_flags) { - OBJTYPE_WLOCK; + Locker::Lock lock(Locker::STATE_WRITE); ClassInfo *type = classes.getptr(p_class); ClassInfo *check = type; ERR_FAIL_NULL(check); @@ -1825,7 +1827,7 @@ bool ClassDB::has_method(const StringName &p_class, const StringName &p_method, } int ClassDB::get_method_argument_count(const StringName &p_class, const StringName &p_method, bool *r_is_valid, bool p_no_inheritance) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); @@ -1864,7 +1866,7 @@ void ClassDB::_bind_compatibility(ClassInfo *type, MethodBind *p_method) { } void ClassDB::_bind_method_custom(const StringName &p_class, MethodBind *p_method, bool p_compatibility) { - OBJTYPE_WLOCK; + Locker::Lock lock(Locker::STATE_WRITE); StringName method_name = p_method->get_name(); @@ -1933,7 +1935,7 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, bool p_ StringName mdname = StaticCString::create(method_name); #endif - OBJTYPE_WLOCK; + Locker::Lock lock(Locker::STATE_WRITE); ERR_FAIL_NULL_V(p_bind, nullptr); p_bind->set_name(mdname); @@ -1996,7 +1998,7 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, bool p_ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual, const Vector &p_arg_names, bool p_object_core) { ERR_FAIL_COND_MSG(!classes.has(p_class), vformat("Request for nonexistent class '%s'.", p_class)); - OBJTYPE_WLOCK; + Locker::Lock lock(Locker::STATE_WRITE); #ifdef DEBUG_METHODS_ENABLED MethodInfo mi = p_method; @@ -2011,9 +2013,8 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_ if (p_arg_names.size() != mi.arguments.size()) { WARN_PRINT(vformat("Mismatch argument name count for virtual method: '%s::%s'.", String(p_class), p_method.name)); } else { - List::Iterator itr = mi.arguments.begin(); - for (int i = 0; i < p_arg_names.size(); ++itr, ++i) { - itr->name = p_arg_names[i]; + for (int64_t i = 0; i < p_arg_names.size(); ++i) { + mi.arguments.write[i].name = p_arg_names[i]; } } } @@ -2031,7 +2032,7 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_ void ClassDB::add_virtual_compatibility_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual, const Vector &p_arg_names, bool p_object_core) { ERR_FAIL_COND_MSG(!classes.has(p_class), vformat("Request for nonexistent class '%s'.", p_class)); - OBJTYPE_WLOCK; + Locker::Lock lock(Locker::STATE_WRITE); HashMap> &virtual_methods_compat = classes[p_class].virtual_methods_compat; @@ -2066,7 +2067,7 @@ void ClassDB::get_virtual_methods(const StringName &p_class, List *p } Vector ClassDB::get_virtual_method_compatibility_hashes(const StringName &p_class, const StringName &p_name) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *type = classes.getptr(p_class); @@ -2107,14 +2108,14 @@ void ClassDB::add_extension_class_virtual_method(const StringName &p_class, cons } void ClassDB::set_class_enabled(const StringName &p_class, bool p_enable) { - OBJTYPE_WLOCK; + Locker::Lock lock(Locker::STATE_WRITE); ERR_FAIL_COND_MSG(!classes.has(p_class), vformat("Request for nonexistent class '%s'.", p_class)); classes[p_class].disabled = !p_enable; } bool ClassDB::is_class_enabled(const StringName &p_class) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *ti = classes.getptr(p_class); if (!ti || !ti->creation_func) { @@ -2128,7 +2129,7 @@ bool ClassDB::is_class_enabled(const StringName &p_class) { } bool ClassDB::is_class_exposed(const StringName &p_class) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *ti = classes.getptr(p_class); ERR_FAIL_NULL_V_MSG(ti, false, vformat("Cannot get class '%s'.", String(p_class))); @@ -2136,7 +2137,7 @@ bool ClassDB::is_class_exposed(const StringName &p_class) { } bool ClassDB::is_class_reloadable(const StringName &p_class) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *ti = classes.getptr(p_class); ERR_FAIL_NULL_V_MSG(ti, false, vformat("Cannot get class '%s'.", String(p_class))); @@ -2144,7 +2145,7 @@ bool ClassDB::is_class_reloadable(const StringName &p_class) { } bool ClassDB::is_class_runtime(const StringName &p_class) { - OBJTYPE_RLOCK; + Locker::Lock lock(Locker::STATE_READ); ClassInfo *ti = classes.getptr(p_class); ERR_FAIL_NULL_V_MSG(ti, false, vformat("Cannot get class '%s'.", String(p_class))); @@ -2342,7 +2343,9 @@ uint64_t ClassDB::get_native_struct_size(const StringName &p_name) { return native_structs[p_name].struct_size; } -RWLock ClassDB::lock; +Object *ClassDB::_instantiate_allow_unexposed(const StringName &p_class) { + return _instantiate_internal(p_class, false, true, false); +} void ClassDB::cleanup_defaults() { default_values.clear(); @@ -2379,3 +2382,32 @@ bool ClassDB::is_default_array_arg(const Array &p_array) { } // + +ClassDB::Locker::Lock::Lock(Locker::State p_state) { + DEV_ASSERT(p_state != STATE_UNLOCKED); + if (p_state == STATE_READ) { + if (Locker::thread_state == STATE_UNLOCKED) { + state = STATE_READ; + Locker::thread_state = STATE_READ; + Locker::lock.read_lock(); + } + } else if (p_state == STATE_WRITE) { + if (Locker::thread_state == STATE_UNLOCKED) { + state = STATE_WRITE; + Locker::thread_state = STATE_WRITE; + Locker::lock.write_lock(); + } else if (Locker::thread_state == STATE_READ) { + CRASH_NOW_MSG("Lock can't be upgraded from read to write."); + } + } +} + +ClassDB::Locker::Lock::~Lock() { + if (state == STATE_READ) { + Locker::lock.read_unlock(); + Locker::thread_state = STATE_UNLOCKED; + } else if (state == STATE_WRITE) { + Locker::lock.write_unlock(); + Locker::thread_state = STATE_UNLOCKED; + } +} diff --git a/engine/core/object/class_db.h b/engine/core/object/class_db.h index ed9550cc..f90b691b 100644 --- a/engine/core/object/class_db.h +++ b/engine/core/object/class_db.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef CLASS_DB_H -#define CLASS_DB_H +#pragma once #include "core/object/method_bind.h" #include "core/object/object.h" @@ -79,6 +78,8 @@ MethodDefinition D_METHOD(const char *p_name, const VarArgs... p_args) { #endif class ClassDB { + friend class Object; + public: enum APIType { API_CORE, @@ -153,7 +154,30 @@ public: return ret; } - static RWLock lock; + // We need a recursive r/w lock because there are various code paths + // that may in turn invoke other entry points with require locking. + class Locker { + public: + enum State { + STATE_UNLOCKED, + STATE_READ, + STATE_WRITE, + }; + + private: + inline static RWLock lock; + inline thread_local static State thread_state = STATE_UNLOCKED; + + public: + class Lock { + State state = STATE_UNLOCKED; + + public: + explicit Lock(State p_state); + ~Lock(); + }; + }; + static HashMap classes; static HashMap resource_base_extensions; static HashMap compat_classes; @@ -171,7 +195,7 @@ public: static APIType current_api; static HashMap api_hashes_cache; - static void _add_class2(const StringName &p_class, const StringName &p_inherits); + static void _add_class(const StringName &p_class, const StringName &p_inherits); static HashMap> default_values; static HashSet default_values_cached; @@ -194,20 +218,14 @@ private: static MethodBind *_bind_vararg_method(MethodBind *p_bind, const StringName &p_name, const Vector &p_default_args, bool p_compatibility); static void _bind_method_custom(const StringName &p_class, MethodBind *p_method, bool p_compatibility); - static Object *_instantiate_internal(const StringName &p_class, bool p_require_real_class = false, bool p_notify_postinitialize = true); + static Object *_instantiate_internal(const StringName &p_class, bool p_require_real_class = false, bool p_notify_postinitialize = true, bool p_exposed_only = true); - static bool _can_instantiate(ClassInfo *p_class_info); + static bool _can_instantiate(ClassInfo *p_class_info, bool p_exposed_only = true); public: - // DO NOT USE THIS!!!!!! NEEDS TO BE PUBLIC BUT DO NOT USE NO MATTER WHAT!!! - template - static void _add_class() { - _add_class2(T::get_class_static(), T::get_parent_class_static()); - } - template static void register_class(bool p_virtual = false) { - GLOBAL_LOCK_FUNCTION; + Locker::Lock lock(Locker::STATE_WRITE); static_assert(std::is_same_v, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); @@ -222,7 +240,7 @@ public: template static void register_abstract_class() { - GLOBAL_LOCK_FUNCTION; + Locker::Lock lock(Locker::STATE_WRITE); static_assert(std::is_same_v, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); @@ -235,7 +253,7 @@ public: template static void register_internal_class() { - GLOBAL_LOCK_FUNCTION; + Locker::Lock lock(Locker::STATE_WRITE); static_assert(std::is_same_v, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); @@ -250,7 +268,7 @@ public: template static void register_runtime_class() { - GLOBAL_LOCK_FUNCTION; + Locker::Lock lock(Locker::STATE_WRITE); static_assert(std::is_same_v, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); @@ -275,7 +293,7 @@ public: template static void register_custom_instance_class() { - GLOBAL_LOCK_FUNCTION; + Locker::Lock lock(Locker::STATE_WRITE); static_assert(std::is_same_v, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); @@ -293,7 +311,7 @@ public: static void get_extension_class_list(const Ref &p_extension, List *p_classes); static ObjectGDExtension *get_placeholder_extension(const StringName &p_class); #endif - static void get_inheriters_from_class(const StringName &p_class, List *p_classes); + static void get_inheriters_from_class(const StringName &p_class, LocalVector &p_classes); static void get_direct_inheriters_from_class(const StringName &p_class, List *p_classes); static StringName get_parent_class_nocheck(const StringName &p_class); static bool get_inheritance_chain_nocheck(const StringName &p_class, Vector &r_result); @@ -391,7 +409,7 @@ public: template static MethodBind *bind_vararg_method(uint32_t p_flags, const StringName &p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const Vector &p_default_args = Vector(), bool p_return_nil_is_variant = true) { - GLOBAL_LOCK_FUNCTION; + Locker::Lock lock(Locker::STATE_WRITE); MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant); ERR_FAIL_NULL_V(bind, nullptr); @@ -404,7 +422,7 @@ public: template static MethodBind *bind_compatibility_vararg_method(uint32_t p_flags, const StringName &p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const Vector &p_default_args = Vector(), bool p_return_nil_is_variant = true) { - GLOBAL_LOCK_FUNCTION; + Locker::Lock lock(Locker::STATE_WRITE); MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant); ERR_FAIL_NULL_V(bind, nullptr); @@ -498,6 +516,8 @@ public: static void get_native_struct_list(List *r_names); static String get_native_struct_code(const StringName &p_name); static uint64_t get_native_struct_size(const StringName &p_name); // Used for asserting + + static Object *_instantiate_allow_unexposed(const StringName &p_class); // Used to create unexposed classes from GDExtension, typically for unexposed EditorPlugin. }; #define BIND_ENUM_CONSTANT(m_constant) \ @@ -563,7 +583,3 @@ _FORCE_INLINE_ Vector errarray(P... p_args) { } #define GDREGISTER_NATIVE_STRUCT(m_class, m_code) ClassDB::register_native_struct(#m_class, m_code, sizeof(m_class)) - -#include "core/disabled_classes.gen.h" - -#endif // CLASS_DB_H diff --git a/engine/core/object/make_virtuals.py b/engine/core/object/make_virtuals.py index 13775ecd..e130edbc 100644 --- a/engine/core/object/make_virtuals.py +++ b/engine/core/object/make_virtuals.py @@ -15,57 +15,65 @@ script_has_method = """ScriptInstance *_script_instance = ((Object *)(this))->ge }""" proto = """#define GDVIRTUAL$VER($ALIAS $RET m_name $ARG)\\ - StringName _gdvirtual_##$VARNAME##_sn = #m_name;\\ - mutable bool _gdvirtual_##$VARNAME##_initialized = false;\\ mutable void *_gdvirtual_##$VARNAME = nullptr;\\ _FORCE_INLINE_ bool _gdvirtual_##$VARNAME##_call($CALLARGS) $CONST {\\ + static const StringName _gdvirtual_##$VARNAME##_sn = _scs_create(#m_name, true);\\ $SCRIPTCALL\\ - if (unlikely(_get_extension() && !_gdvirtual_##$VARNAME##_initialized)) {\\ - MethodInfo mi = _gdvirtual_##$VARNAME##_get_method_info();\\ - uint32_t hash = mi.get_compatibility_hash();\\ - _gdvirtual_##$VARNAME = nullptr;\\ - if (_get_extension()->get_virtual_call_data2 && _get_extension()->call_virtual_with_data) {\\ - _gdvirtual_##$VARNAME = _get_extension()->get_virtual_call_data2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\ - } else if (_get_extension()->get_virtual2) {\\ - _gdvirtual_##$VARNAME = (void *)_get_extension()->get_virtual2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\ + if (_get_extension()) {\\ + if (unlikely(!_gdvirtual_##$VARNAME)) {\\ + MethodInfo mi = _gdvirtual_##$VARNAME##_get_method_info();\\ + uint32_t hash = mi.get_compatibility_hash();\\ + _gdvirtual_##$VARNAME = nullptr;\\ + if (_get_extension()->get_virtual_call_data2 && _get_extension()->call_virtual_with_data) {\\ + _gdvirtual_##$VARNAME = _get_extension()->get_virtual_call_data2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\ + } else if (_get_extension()->get_virtual2) {\\ + _gdvirtual_##$VARNAME = (void *)_get_extension()->get_virtual2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\ + }\\ + _GDVIRTUAL_GET_DEPRECATED(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_sn, $COMPAT)\\ + _GDVIRTUAL_TRACK(_gdvirtual_##$VARNAME);\\ + if (_gdvirtual_##$VARNAME == nullptr) {\\ + _gdvirtual_##$VARNAME = reinterpret_cast(_INVALID_GDVIRTUAL_FUNC_ADDR);\\ + }\\ }\\ - _GDVIRTUAL_GET_DEPRECATED(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_sn, $COMPAT)\\ - _GDVIRTUAL_TRACK(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_initialized);\\ - _gdvirtual_##$VARNAME##_initialized = true;\\ - }\\ - if (_gdvirtual_##$VARNAME) {\\ - $CALLPTRARGS\\ - $CALLPTRRETDEF\\ - if (_get_extension()->call_virtual_with_data) {\\ - _get_extension()->call_virtual_with_data(_get_extension_instance(), &_gdvirtual_##$VARNAME##_sn, _gdvirtual_##$VARNAME, $CALLPTRARGPASS, $CALLPTRRETPASS);\\ - $CALLPTRRET\\ - } else {\\ - ((GDExtensionClassCallVirtual)_gdvirtual_##$VARNAME)(_get_extension_instance(), $CALLPTRARGPASS, $CALLPTRRETPASS);\\ - $CALLPTRRET\\ + if (_gdvirtual_##$VARNAME != reinterpret_cast(_INVALID_GDVIRTUAL_FUNC_ADDR)) {\\ + $CALLPTRARGS\\ + $CALLPTRRETDEF\\ + if (_get_extension()->call_virtual_with_data) {\\ + _get_extension()->call_virtual_with_data(_get_extension_instance(), &_gdvirtual_##$VARNAME##_sn, _gdvirtual_##$VARNAME, $CALLPTRARGPASS, $CALLPTRRETPASS);\\ + $CALLPTRRET\\ + } else {\\ + ((GDExtensionClassCallVirtual)_gdvirtual_##$VARNAME)(_get_extension_instance(), $CALLPTRARGPASS, $CALLPTRRETPASS);\\ + $CALLPTRRET\\ + }\\ + return true;\\ }\\ - return true;\\ }\\ $REQCHECK\\ $RVOID\\ return false;\\ }\\ _FORCE_INLINE_ bool _gdvirtual_##$VARNAME##_overridden() const {\\ + static const StringName _gdvirtual_##$VARNAME##_sn = _scs_create(#m_name, true);\\ $SCRIPTHASMETHOD\\ - if (unlikely(_get_extension() && !_gdvirtual_##$VARNAME##_initialized)) {\\ - MethodInfo mi = _gdvirtual_##$VARNAME##_get_method_info();\\ - uint32_t hash = mi.get_compatibility_hash();\\ - _gdvirtual_##$VARNAME = nullptr;\\ - if (_get_extension()->get_virtual_call_data2 && _get_extension()->call_virtual_with_data) {\\ - _gdvirtual_##$VARNAME = _get_extension()->get_virtual_call_data2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\ - } else if (_get_extension()->get_virtual2) {\\ - _gdvirtual_##$VARNAME = (void *)_get_extension()->get_virtual2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\ + if (_get_extension()) {\\ + if (unlikely(!_gdvirtual_##$VARNAME)) {\\ + MethodInfo mi = _gdvirtual_##$VARNAME##_get_method_info();\\ + uint32_t hash = mi.get_compatibility_hash();\\ + _gdvirtual_##$VARNAME = nullptr;\\ + if (_get_extension()->get_virtual_call_data2 && _get_extension()->call_virtual_with_data) {\\ + _gdvirtual_##$VARNAME = _get_extension()->get_virtual_call_data2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\ + } else if (_get_extension()->get_virtual2) {\\ + _gdvirtual_##$VARNAME = (void *)_get_extension()->get_virtual2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\ + }\\ + _GDVIRTUAL_GET_DEPRECATED(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_sn, $COMPAT)\\ + _GDVIRTUAL_TRACK(_gdvirtual_##$VARNAME);\\ + if (_gdvirtual_##$VARNAME == nullptr) {\\ + _gdvirtual_##$VARNAME = reinterpret_cast(_INVALID_GDVIRTUAL_FUNC_ADDR);\\ + }\\ + }\\ + if (_gdvirtual_##$VARNAME != reinterpret_cast(_INVALID_GDVIRTUAL_FUNC_ADDR)) {\\ + return true;\\ }\\ - _GDVIRTUAL_GET_DEPRECATED(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_sn, $COMPAT)\\ - _GDVIRTUAL_TRACK(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_initialized);\\ - _gdvirtual_##$VARNAME##_initialized = true;\\ - }\\ - if (_gdvirtual_##$VARNAME) {\\ - return true;\\ }\\ return false;\\ }\\ @@ -207,24 +215,22 @@ def run(target, source, env): max_versions = 12 txt = """/* THIS FILE IS GENERATED DO NOT EDIT */ -#ifndef GDVIRTUAL_GEN_H -#define GDVIRTUAL_GEN_H +#pragma once #include "core/object/script_instance.h" -#include +inline constexpr uintptr_t _INVALID_GDVIRTUAL_FUNC_ADDR = static_cast(-1); #ifdef TOOLS_ENABLED -#define _GDVIRTUAL_TRACK(m_virtual, m_initialized)\\ +#define _GDVIRTUAL_TRACK(m_virtual)\\ if (_get_extension()->reloadable) {\\ VirtualMethodTracker *tracker = memnew(VirtualMethodTracker);\\ tracker->method = (void **)&m_virtual;\\ - tracker->initialized = &m_initialized;\\ tracker->next = virtual_method_list;\\ virtual_method_list = tracker;\\ } #else -#define _GDVIRTUAL_TRACK(m_virtual, m_initialized) +#define _GDVIRTUAL_TRACK(m_virtual) #endif #ifndef DISABLE_DEPRECATED @@ -257,7 +263,5 @@ def run(target, source, env): txt += generate_version(i, True, False, False, True) txt += generate_version(i, True, True, False, True) - txt += "#endif // GDVIRTUAL_GEN_H\n" - with open(str(target[0]), "w", encoding="utf-8", newline="\n") as f: f.write(txt) diff --git a/engine/core/object/message_queue.cpp b/engine/core/object/message_queue.cpp index 4b0b1ce6..673e60d6 100644 --- a/engine/core/object/message_queue.cpp +++ b/engine/core/object/message_queue.cpp @@ -226,7 +226,7 @@ void CallQueue::_call_function(const Callable &p_callable, const Variant *p_args Error CallQueue::flush() { LOCK_MUTEX; - if (pages.size() == 0) { + if (pages.is_empty()) { // Never allocated UNLOCK_MUTEX; return OK; // Do nothing. @@ -308,7 +308,7 @@ Error CallQueue::flush() { void CallQueue::clear() { LOCK_MUTEX; - if (pages.size() == 0) { + if (pages.is_empty()) { UNLOCK_MUTEX; return; // Nothing to clear. } diff --git a/engine/core/object/message_queue.h b/engine/core/object/message_queue.h index 64e244bd..8a66d0c1 100644 --- a/engine/core/object/message_queue.h +++ b/engine/core/object/message_queue.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef MESSAGE_QUEUE_H -#define MESSAGE_QUEUE_H +#pragma once #include "core/object/object_id.h" #include "core/os/thread_safe.h" @@ -171,5 +170,3 @@ public: MessageQueue(); ~MessageQueue(); }; - -#endif // MESSAGE_QUEUE_H diff --git a/engine/core/object/method_bind.h b/engine/core/object/method_bind.h index a07824a0..93683ee6 100644 --- a/engine/core/object/method_bind.h +++ b/engine/core/object/method_bind.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef METHOD_BIND_H -#define METHOD_BIND_H +#pragma once #include "core/variant/binder_common.h" @@ -143,8 +142,7 @@ public: template class MethodBindVarArgBase : public MethodBind { protected: - R(T::*method) - (const Variant **, int, Callable::CallError &); + R (T::*method)(const Variant **, int, Callable::CallError &); MethodInfo method_info; public: @@ -152,7 +150,7 @@ public: if (p_arg < 0) { return _gen_return_type_info(); } else if (p_arg < method_info.arguments.size()) { - return method_info.arguments.get(p_arg); + return method_info.arguments[p_arg]; } else { return PropertyInfo(Variant::NIL, "arg_" + itos(p_arg), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT); } @@ -193,11 +191,10 @@ public: Vector names; names.resize(method_info.arguments.size()); #endif - int i = 0; - for (List::ConstIterator itr = method_info.arguments.begin(); itr != method_info.arguments.end(); ++itr, ++i) { - at[i + 1] = itr->type; + for (int64_t i = 0; i < method_info.arguments.size(); ++i) { + at[i + 1] = method_info.arguments[i].type; #ifdef DEBUG_METHODS_ENABLED - names.write[i] = itr->name; + names.write[i] = method_info.arguments[i].name; #endif } @@ -259,11 +256,8 @@ class MethodBindVarArgTR : public MethodBindVarArgBase, friend class MethodBindVarArgBase, T, R, true>; public: -#if defined(SANITIZERS_ENABLED) && defined(__GNUC__) && !defined(__clang__) - // Workaround GH-66343 raised only with UBSAN, seems to be a false positive. -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#endif + GODOT_GCC_WARNING_PUSH_AND_IGNORE("-Wmaybe-uninitialized") // Workaround GH-66343 raised only with UBSAN, seems to be a false positive. + virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override { #ifdef TOOLS_ENABLED ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == MethodBind::get_instance_class(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); @@ -271,9 +265,7 @@ public: return (static_cast(p_object)->*MethodBindVarArgBase, T, R, true>::method)(p_args, p_arg_count, r_error); } -#if defined(SANITIZERS_ENABLED) && defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif + GODOT_GCC_WARNING_POP MethodBindVarArgTR( R (T::*p_method)(const Variant **, int, Callable::CallError &), @@ -480,8 +472,7 @@ template template #endif class MethodBindTR : public MethodBind { - R(MB_T::*method) - (P...); + R (MB_T::*method)(P...); protected: virtual Variant::Type _gen_argument_type(int p_arg) const override { @@ -576,8 +567,7 @@ template template #endif class MethodBindTRC : public MethodBind { - R(MB_T::*method) - (P...) const; + R (MB_T::*method)(P...) const; protected: virtual Variant::Type _gen_argument_type(int p_arg) const override { @@ -728,8 +718,7 @@ MethodBind *create_static_method_bind(void (*p_method)(P...)) { template class MethodBindTRS : public MethodBind { - R(*function) - (P...); + R (*function)(P...); protected: virtual Variant::Type _gen_argument_type(int p_arg) const override { @@ -790,5 +779,3 @@ MethodBind *create_static_method_bind(R (*p_method)(P...)) { MethodBind *a = memnew((MethodBindTRS)(p_method)); return a; } - -#endif // METHOD_BIND_H diff --git a/engine/core/object/object.cpp b/engine/core/object/object.cpp index 8df107ec..852d877f 100644 --- a/engine/core/object/object.cpp +++ b/engine/core/object/object.cpp @@ -115,10 +115,19 @@ TypedArray convert_property_list(const List *p_list) { return va; } +TypedArray convert_property_list(const Vector &p_vector) { + TypedArray va; + for (const PropertyInfo &E : p_vector) { + va.push_back(Dictionary(E)); + } + + return va; +} + MethodInfo::operator Dictionary() const { Dictionary d; d["name"] = name; - d["args"] = convert_property_list(&arguments); + d["args"] = convert_property_list(arguments); Array da; for (int i = 0; i < default_arguments.size(); i++) { da.push_back(default_arguments[i]); @@ -240,21 +249,15 @@ void Object::cancel_free() { } void Object::_initialize() { - _class_name_ptr = _get_class_namev(); // Set the direct pointer, which is much faster to obtain, but can only happen after _initialize. + // Cache the class name in the object for quick reference. + _class_name_ptr = _get_class_namev(); _initialize_classv(); - _class_name_ptr = nullptr; // May have been called from a constructor. } void Object::_postinitialize() { notification(NOTIFICATION_POSTINITIALIZE); } -void Object::get_valid_parents_static(List *p_parents) { -} - -void Object::_get_valid_parents_static(List *p_parents) { -} - void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid) { #ifdef TOOLS_ENABLED @@ -902,18 +905,14 @@ Variant Object::call_const(const StringName &p_method, const Variant **p_args, i return ret; } -void Object::notification(int p_notification, bool p_reversed) { - if (p_reversed) { - if (script_instance) { - script_instance->notification(p_notification, p_reversed); - } - } else { - _notificationv(p_notification, p_reversed); - } +void Object::_notification_forward(int p_notification) { + // Notify classes starting with Object and ending with most derived subclass. + // e.g. Object -> Node -> Node3D + _notification_forwardv(p_notification); if (_extension) { if (_extension->notification2) { - _extension->notification2(_extension_instance, p_notification, static_cast(p_reversed)); + _extension->notification2(_extension_instance, p_notification, static_cast(false)); #ifndef DISABLE_DEPRECATED } else if (_extension->notification) { _extension->notification(_extension_instance, p_notification); @@ -921,13 +920,29 @@ void Object::notification(int p_notification, bool p_reversed) { } } - if (p_reversed) { - _notificationv(p_notification, p_reversed); - } else { - if (script_instance) { - script_instance->notification(p_notification, p_reversed); + if (script_instance) { + script_instance->notification(p_notification, false); + } +} + +void Object::_notification_backward(int p_notification) { + if (script_instance) { + script_instance->notification(p_notification, true); + } + + if (_extension) { + if (_extension->notification2) { + _extension->notification2(_extension_instance, p_notification, static_cast(true)); +#ifndef DISABLE_DEPRECATED + } else if (_extension->notification) { + _extension->notification(_extension_instance, p_notification); +#endif // DISABLE_DEPRECATED } } + + // Notify classes starting with most derived subclass and ending in Object. + // e.g. Node3D -> Node -> Object + _notification_backwardv(p_notification); } String Object::to_string() { @@ -1080,8 +1095,8 @@ TypedArray Object::_get_method_list_bind() const { get_method_list(&ml); TypedArray ret; - for (List::Element *E = ml.front(); E; E = E->next()) { - Dictionary d = E->get(); + for (const MethodInfo &mi : ml) { + Dictionary d = mi; //va.push_back(d); ret.push_back(d); } @@ -1575,7 +1590,7 @@ void Object::initialize_class() { if (initialized) { return; } - ClassDB::_add_class(); + _add_class_to_classdb(get_class_static(), StringName()); _bind_methods(); _bind_compatibility_methods(); initialized = true; @@ -1640,12 +1655,10 @@ void Object::_clear_internal_resource_paths(const Variant &p_var) { } break; case Variant::DICTIONARY: { Dictionary d = p_var; - List keys; - d.get_key_list(&keys); - for (const Variant &E : keys) { - _clear_internal_resource_paths(E); - _clear_internal_resource_paths(d[E]); + for (const KeyValue &kv : d) { + _clear_internal_resource_paths(kv.key); + _clear_internal_resource_paths(kv.value); } } break; default: { @@ -1653,9 +1666,20 @@ void Object::_clear_internal_resource_paths(const Variant &p_var) { } } +void Object::_add_class_to_classdb(const StringName &p_class, const StringName &p_inherits) { + ClassDB::_add_class(p_class, p_inherits); +} + +void Object::_get_property_list_from_classdb(const StringName &p_class, List *p_list, bool p_no_inheritance, const Object *p_validator) { + ClassDB::get_property_list(p_class, p_list, p_no_inheritance, p_validator); +} + #ifdef TOOLS_ENABLED -void Object::editor_set_section_unfold(const String &p_section, bool p_unfolded) { - set_edited(true); +void Object::editor_set_section_unfold(const String &p_section, bool p_unfolded, bool p_initializing) { + if (!p_initializing) { + set_edited(true); + } + if (p_unfolded) { editor_section_folding.insert(p_section); } else { @@ -1878,7 +1902,7 @@ Variant::Type Object::get_static_property_type(const StringName &p_property, boo } Variant::Type Object::get_static_property_type_indexed(const Vector &p_path, bool *r_valid) const { - if (p_path.size() == 0) { + if (p_path.is_empty()) { if (r_valid) { *r_valid = false; } @@ -1945,6 +1969,20 @@ uint32_t Object::get_edited_version() const { } #endif +const StringName &Object::get_class_name() const { + if (_extension) { + // Can't put inside the unlikely as constructor can run it. + return _extension->class_name; + } + + if (unlikely(!_class_name_ptr)) { + // While class is initializing / deinitializing, constructors and destructors + // need access to the proper class at the proper stage. + return *_get_class_namev(); + } + return *_class_name_ptr; +} + StringName Object::get_class_name_for_extension(const GDExtension *p_library) const { #ifdef TOOLS_ENABLED // If this is the library this extension comes from and it's a placeholder, we @@ -2092,7 +2130,6 @@ void Object::clear_internal_extension() { // Clear the virtual methods. while (virtual_method_list) { (*virtual_method_list->method) = nullptr; - (*virtual_method_list->initialized) = false; virtual_method_list = virtual_method_list->next; } } diff --git a/engine/core/object/object.h b/engine/core/object/object.h index 16d8e19e..1607f827 100644 --- a/engine/core/object/object.h +++ b/engine/core/object/object.h @@ -28,9 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef OBJECT_H -#define OBJECT_H +#pragma once +#include "core/disabled_classes.gen.h" #include "core/extension/gdextension_interface.h" #include "core/object/message_queue.h" #include "core/object/object_id.h" @@ -47,6 +47,9 @@ template class TypedArray; +template +class Ref; + enum PropertyHint { PROPERTY_HINT_NONE, ///< no hint provided. PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_less][,hide_slider][,radians_as_degrees][,degrees][,exp][,suffix:] range. @@ -129,6 +132,9 @@ enum PropertyUsageFlags { PROPERTY_USAGE_NO_EDITOR = PROPERTY_USAGE_STORAGE, }; +// Respective values are defined by disabled_classes.gen.h +#define GD_IS_CLASS_ENABLED(m_class) m_class::_class_is_enabled + #define ADD_SIGNAL(m_signal) ::ClassDB::add_signal(get_class_static(), m_signal) #define ADD_PROPERTY(m_property, m_setter, m_getter) ::ClassDB::add_property(get_class_static(), m_property, _scs_create(m_setter), _scs_create(m_getter)) #define ADD_PROPERTYI(m_property, m_setter, m_getter, m_index) ::ClassDB::add_property(get_class_static(), m_property, _scs_create(m_setter), _scs_create(m_getter), m_index) @@ -209,6 +215,7 @@ struct PropertyInfo { }; TypedArray convert_property_list(const List *p_list); +TypedArray convert_property_list(const Vector &p_vector); enum MethodFlags { METHOD_FLAG_NORMAL = 1, @@ -227,7 +234,7 @@ struct MethodInfo { PropertyInfo return_val; uint32_t flags = METHOD_FLAGS_DEFAULT; int id = 0; - List arguments; + Vector arguments; Vector default_arguments; int return_val_metadata = 0; Vector arguments_metadata; @@ -256,8 +263,8 @@ struct MethodInfo { return_val(PropertyInfo(pinfo.return_value)), flags(pinfo.flags), id(pinfo.id) { - for (uint32_t j = 0; j < pinfo.argument_count; j++) { - arguments.push_back(PropertyInfo(pinfo.arguments[j])); + for (uint32_t i = 0; i < pinfo.argument_count; i++) { + arguments.push_back(PropertyInfo(pinfo.arguments[i])); } const Variant *def_values = (const Variant *)pinfo.default_arguments; for (uint32_t j = 0; j < pinfo.default_argument_count; j++) { @@ -265,22 +272,12 @@ struct MethodInfo { } } - void _push_params(const PropertyInfo &p_param) { - arguments.push_back(p_param); - } - - template - void _push_params(const PropertyInfo &p_param, VarArgs... p_params) { - arguments.push_back(p_param); - _push_params(p_params...); - } - MethodInfo(const String &p_name) { name = p_name; } template MethodInfo(const String &p_name, VarArgs... p_params) { name = p_name; - _push_params(p_params...); + arguments = Vector{ p_params... }; } MethodInfo(Variant::Type ret) { return_val.type = ret; } @@ -293,7 +290,7 @@ struct MethodInfo { MethodInfo(Variant::Type ret, const String &p_name, VarArgs... p_params) { name = p_name; return_val.type = ret; - _push_params(p_params...); + arguments = Vector{ p_params... }; } MethodInfo(const PropertyInfo &p_ret, const String &p_name) { @@ -305,7 +302,7 @@ struct MethodInfo { MethodInfo(const PropertyInfo &p_ret, const String &p_name, VarArgs... p_params) { return_val = p_ret; name = p_name; - _push_params(p_params...); + arguments = Vector{ p_params... }; } }; @@ -396,57 +393,46 @@ struct ObjectGDExtension { * much alone defines the object model. */ +// This is a barebones version of GDCLASS, +// only intended for simple classes deriving from Object +// so that they can support the `Object::cast_to()` method. +#define GDSOFTCLASS(m_class, m_inherits) \ +public: \ + using self_type = m_class; \ + using super_type = m_inherits; \ + static _FORCE_INLINE_ void *get_class_ptr_static() { \ + static int ptr; \ + return &ptr; \ + } \ + virtual bool is_class_ptr(void *p_ptr) const override { \ + return (p_ptr == get_class_ptr_static()) || m_inherits::is_class_ptr(p_ptr); \ + } \ + \ +private: + #define GDCLASS(m_class, m_inherits) \ + GDSOFTCLASS(m_class, m_inherits) \ private: \ void operator=(const m_class &p_rval) {} \ friend class ::ClassDB; \ \ public: \ - typedef m_class self_type; \ static constexpr bool _class_is_enabled = !bool(GD_IS_DEFINED(ClassDB_Disable_##m_class)) && m_inherits::_class_is_enabled; \ - virtual String get_class() const override { \ - if (_get_extension()) { \ - return _get_extension()->class_name.operator String(); \ - } \ - return String(#m_class); \ - } \ virtual const StringName *_get_class_namev() const override { \ + return &get_class_static(); \ + } \ + static const StringName &get_class_static() { \ static StringName _class_name_static; \ if (unlikely(!_class_name_static)) { \ StringName::assign_static_unique_class_name(&_class_name_static, #m_class); \ } \ - return &_class_name_static; \ - } \ - static _FORCE_INLINE_ void *get_class_ptr_static() { \ - static int ptr; \ - return &ptr; \ - } \ - static _FORCE_INLINE_ String get_class_static() { \ - return String(#m_class); \ - } \ - static _FORCE_INLINE_ String get_parent_class_static() { \ - return m_inherits::get_class_static(); \ - } \ - static void get_inheritance_list_static(List *p_inheritance_list) { \ - m_inherits::get_inheritance_list_static(p_inheritance_list); \ - p_inheritance_list->push_back(String(#m_class)); \ + return _class_name_static; \ } \ virtual bool is_class(const String &p_class) const override { \ if (_get_extension() && _get_extension()->is_class(p_class)) { \ return true; \ } \ return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); \ - } \ - virtual bool is_class_ptr(void *p_ptr) const override { \ - return (p_ptr == get_class_ptr_static()) ? true : m_inherits::is_class_ptr(p_ptr); \ - } \ - \ - static void get_valid_parents_static(List *p_parents) { \ - if (m_class::_get_valid_parents_static != m_inherits::_get_valid_parents_static) { \ - m_class::_get_valid_parents_static(p_parents); \ - } \ - \ - m_inherits::get_valid_parents_static(p_parents); \ } \ \ protected: \ @@ -464,7 +450,7 @@ public: return; \ } \ m_inherits::initialize_class(); \ - ::ClassDB::_add_class(); \ + _add_class_to_classdb(get_class_static(), super_type::get_class_static()); \ if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \ _bind_methods(); \ } \ @@ -479,7 +465,7 @@ protected: initialize_class(); \ } \ _FORCE_INLINE_ bool (Object::*_get_get() const)(const StringName &p_name, Variant &) const { \ - return (bool(Object::*)(const StringName &, Variant &) const) & m_class::_get; \ + return (bool (Object::*)(const StringName &, Variant &) const) & m_class::_get; \ } \ virtual bool _getv(const StringName &p_name, Variant &r_ret) const override { \ if (m_class::_get_get() != m_inherits::_get_get()) { \ @@ -490,7 +476,7 @@ protected: return m_inherits::_getv(p_name, r_ret); \ } \ _FORCE_INLINE_ bool (Object::*_get_set() const)(const StringName &p_name, const Variant &p_property) { \ - return (bool(Object::*)(const StringName &, const Variant &)) & m_class::_set; \ + return (bool (Object::*)(const StringName &, const Variant &)) & m_class::_set; \ } \ virtual bool _setv(const StringName &p_name, const Variant &p_property) override { \ if (m_inherits::_setv(p_name, p_property)) { \ @@ -502,14 +488,14 @@ protected: return false; \ } \ _FORCE_INLINE_ void (Object::*_get_get_property_list() const)(List * p_list) const { \ - return (void(Object::*)(List *) const) & m_class::_get_property_list; \ + return (void (Object::*)(List *) const) & m_class::_get_property_list; \ } \ virtual void _get_property_listv(List *p_list, bool p_reversed) const override { \ if (!p_reversed) { \ m_inherits::_get_property_listv(p_list, p_reversed); \ } \ p_list->push_back(PropertyInfo(Variant::NIL, get_class_static(), PROPERTY_HINT_NONE, get_class_static(), PROPERTY_USAGE_CATEGORY)); \ - ::ClassDB::get_property_list(#m_class, p_list, true, this); \ + _get_property_list_from_classdb(#m_class, p_list, true, this); \ if (m_class::_get_get_property_list() != m_inherits::_get_get_property_list()) { \ _get_property_list(p_list); \ } \ @@ -518,7 +504,7 @@ protected: } \ } \ _FORCE_INLINE_ void (Object::*_get_validate_property() const)(PropertyInfo & p_property) const { \ - return (void(Object::*)(PropertyInfo &) const) & m_class::_validate_property; \ + return (void (Object::*)(PropertyInfo &) const) & m_class::_validate_property; \ } \ virtual void _validate_propertyv(PropertyInfo &p_property) const override { \ m_inherits::_validate_propertyv(p_property); \ @@ -527,7 +513,7 @@ protected: } \ } \ _FORCE_INLINE_ bool (Object::*_get_property_can_revert() const)(const StringName &p_name) const { \ - return (bool(Object::*)(const StringName &) const) & m_class::_property_can_revert; \ + return (bool (Object::*)(const StringName &) const) & m_class::_property_can_revert; \ } \ virtual bool _property_can_revertv(const StringName &p_name) const override { \ if (m_class::_get_property_can_revert() != m_inherits::_get_property_can_revert()) { \ @@ -538,7 +524,7 @@ protected: return m_inherits::_property_can_revertv(p_name); \ } \ _FORCE_INLINE_ bool (Object::*_get_property_get_revert() const)(const StringName &p_name, Variant &) const { \ - return (bool(Object::*)(const StringName &, Variant &) const) & m_class::_property_get_revert; \ + return (bool (Object::*)(const StringName &, Variant &) const) & m_class::_property_get_revert; \ } \ virtual bool _property_get_revertv(const StringName &p_name, Variant &r_ret) const override { \ if (m_class::_get_property_get_revert() != m_inherits::_get_property_get_revert()) { \ @@ -549,18 +535,19 @@ protected: return m_inherits::_property_get_revertv(p_name, r_ret); \ } \ _FORCE_INLINE_ void (Object::*_get_notification() const)(int) { \ - return (void(Object::*)(int)) & m_class::_notification; \ + return (void (Object::*)(int)) & m_class::_notification; \ } \ - virtual void _notificationv(int p_notification, bool p_reversed) override { \ - if (!p_reversed) { \ - m_inherits::_notificationv(p_notification, p_reversed); \ - } \ + virtual void _notification_forwardv(int p_notification) override { \ + m_inherits::_notification_forwardv(p_notification); \ if (m_class::_get_notification() != m_inherits::_get_notification()) { \ _notification(p_notification); \ } \ - if (p_reversed) { \ - m_inherits::_notificationv(p_notification, p_reversed); \ + } \ + virtual void _notification_backwardv(int p_notification) override { \ + if (m_class::_get_notification() != m_inherits::_get_notification()) { \ + _notification(p_notification); \ } \ + m_inherits::_notification_backwardv(p_notification); \ } \ \ private: @@ -704,7 +691,11 @@ protected: virtual void _validate_propertyv(PropertyInfo &p_property) const {} virtual bool _property_can_revertv(const StringName &p_name) const { return false; } virtual bool _property_get_revertv(const StringName &p_name, Variant &r_property) const { return false; } - virtual void _notificationv(int p_notification, bool p_reversed) {} + + void _notification_forward(int p_notification); + void _notification_backward(int p_notification); + virtual void _notification_forwardv(int p_notification) {} + virtual void _notification_backwardv(int p_notification) {} static void _bind_methods(); static void _bind_compatibility_methods() {} @@ -743,18 +734,12 @@ protected: _FORCE_INLINE_ void (Object::*_get_notification() const)(int) { return &Object::_notification; } - static void get_valid_parents_static(List *p_parents); - static void _get_valid_parents_static(List *p_parents); Variant _call_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); Variant _call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); virtual const StringName *_get_class_namev() const { - static StringName _class_name_static; - if (unlikely(!_class_name_static)) { - StringName::assign_static_unique_class_name(&_class_name_static, "Object"); - } - return &_class_name_static; + return &get_class_static(); } TypedArray _get_meta_list_bind() const; @@ -766,12 +751,14 @@ protected: friend class ClassDB; friend class PlaceholderExtensionInstance; + static void _add_class_to_classdb(const StringName &p_class, const StringName &p_inherits); + static void _get_property_list_from_classdb(const StringName &p_class, List *p_list, bool p_no_inheritance, const Object *p_validator); + bool _disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force = false); #ifdef TOOLS_ENABLED struct VirtualMethodTracker { void **method; - bool *initialized; VirtualMethodTracker *next; }; @@ -797,12 +784,18 @@ public: template static T *cast_to(Object *p_object) { - return p_object ? dynamic_cast(p_object) : nullptr; + // This is like dynamic_cast, but faster. + // The reason is that we can assume no virtual and multiple inheritance. + static_assert(std::is_base_of_v, "T must be derived from Object"); + static_assert(std::is_same_v, typename T::self_type>, "T must use GDCLASS or GDSOFTCLASS"); + return p_object && p_object->is_class_ptr(T::get_class_ptr_static()) ? static_cast(p_object) : nullptr; } template static const T *cast_to(const Object *p_object) { - return p_object ? dynamic_cast(p_object) : nullptr; + static_assert(std::is_base_of_v, "T must be derived from Object"); + static_assert(std::is_same_v, typename T::self_type>, "T must use GDCLASS or GDSOFTCLASS"); + return p_object && p_object->is_class_ptr(T::get_class_ptr_static()) ? static_cast(p_object) : nullptr; } enum { @@ -814,17 +807,16 @@ public: }; /* TYPE API */ - static void get_inheritance_list_static(List *p_inheritance_list) { p_inheritance_list->push_back("Object"); } - - static String get_class_static() { return "Object"; } - static String get_parent_class_static() { return String(); } - - virtual String get_class() const { - if (_extension) { - return _extension->class_name.operator String(); + static const StringName &get_class_static() { + static StringName _class_name_static; + if (unlikely(!_class_name_static)) { + StringName::assign_static_unique_class_name(&_class_name_static, "Object"); } - return "Object"; + return _class_name_static; } + + _FORCE_INLINE_ String get_class() const { return get_class_name(); } + virtual String get_save_class() const { return get_class(); } //class stored when saving virtual bool is_class(const String &p_class) const { @@ -835,19 +827,7 @@ public: } virtual bool is_class_ptr(void *p_ptr) const { return get_class_ptr_static() == p_ptr; } - _FORCE_INLINE_ const StringName &get_class_name() const { - if (_extension) { - // Can't put inside the unlikely as constructor can run it - return _extension->class_name; - } - - if (unlikely(!_class_name_ptr)) { - // While class is initializing / deinitializing, constructors and destructurs - // need access to the proper class at the proper stage. - return *_get_class_namev(); - } - return *_class_name_ptr; - } + const StringName &get_class_name() const; StringName get_class_name_for_extension(const GDExtension *p_library) const; @@ -882,7 +862,17 @@ public: return (cerr.error == Callable::CallError::CALL_OK) ? ret : Variant(); } - void notification(int p_notification, bool p_reversed = false); + // Depending on the boolean, we call either the virtual function _notification_backward or _notification_forward. + // - Forward calls subclasses in descending order (e.g. Object -> Node -> Node3D -> extension -> script). + // Backward calls subclasses in descending order (e.g. script -> extension -> Node3D -> Node -> Object). + _FORCE_INLINE_ void notification(int p_notification, bool p_reversed = false) { + if (p_reversed) { + _notification_backward(p_notification); + } else { + _notification_forward(p_notification); + } + } + virtual String to_string(); // Used mainly by script, get and set all INCLUDING string. @@ -974,7 +964,7 @@ public: #ifdef TOOLS_ENABLED virtual void get_argument_options(const StringName &p_function, int p_idx, List *r_options) const; - void editor_set_section_unfold(const String &p_section, bool p_unfolded); + void editor_set_section_unfold(const String &p_section, bool p_unfolded, bool p_initializing = false); bool editor_is_section_unfolded(const String &p_section); const HashSet &editor_get_section_folding() const { return editor_section_folding; } void editor_clear_section_folding() { editor_section_folding.clear(); } @@ -1062,8 +1052,15 @@ public: return object; } + + template + _ALWAYS_INLINE_ static T *get_instance(ObjectID p_instance_id) { + return Object::cast_to(get_instance(p_instance_id)); + } + + template + _ALWAYS_INLINE_ static Ref get_ref(ObjectID p_instance_id); // Defined in ref_counted.h + static void debug_objects(DebugFunc p_func); static int get_object_count(); }; - -#endif // OBJECT_H diff --git a/engine/core/object/object_id.h b/engine/core/object/object_id.h index b04e2df1..2fc66beb 100644 --- a/engine/core/object/object_id.h +++ b/engine/core/object/object_id.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef OBJECT_ID_H -#define OBJECT_ID_H +#pragma once #include "core/typedefs.h" @@ -60,4 +59,5 @@ public: _ALWAYS_INLINE_ explicit ObjectID(const int64_t p_id) { id = p_id; } }; -#endif // OBJECT_ID_H +template <> +struct is_zero_constructible : std::true_type {}; diff --git a/engine/core/object/ref_counted.h b/engine/core/object/ref_counted.h index 927e457d..3bd2b062 100644 --- a/engine/core/object/ref_counted.h +++ b/engine/core/object/ref_counted.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef REF_COUNTED_H -#define REF_COUNTED_H +#pragma once #include "core/object/class_db.h" #include "core/templates/safe_refcount.h" @@ -86,6 +85,10 @@ class Ref { //virtual RefCounted * get_reference() const { return reference; } public: + static _FORCE_INLINE_ String get_class_static() { + return T::get_class_static(); + } + _FORCE_INLINE_ bool operator==(const T *p_ptr) const { return reference == p_ptr; } @@ -128,6 +131,15 @@ public: ref(p_from); } + void operator=(Ref &&p_from) { + if (reference == p_from.reference) { + return; + } + unref(); + reference = p_from.reference; + p_from.reference = nullptr; + } + template void operator=(const Ref &p_from) { ref_pointer(Object::cast_to(p_from.ptr())); @@ -160,6 +172,11 @@ public: this->operator=(p_from); } + Ref(Ref &&p_from) { + reference = p_from.reference; + p_from.reference = nullptr; + } + template Ref(const Ref &p_from) { this->operator=(p_from); @@ -181,10 +198,15 @@ public: // do a lot of referencing on references and stuff // mutexes will avoid more crashes? - if (reference && reference->unreference()) { - memdelete(reference); + if (reference) { + // NOTE: `reinterpret_cast` is "safe" here because we know `T` has simple linear + // inheritance to `RefCounted`. This guarantees that `T * == `RefCounted *`, which + // allows us to declare `Ref` with forward declared `T` types. + if (reinterpret_cast(reference)->unreference()) { + memdelete(reinterpret_cast(reference)); + } + reference = nullptr; } - reference = nullptr; } template @@ -233,19 +255,6 @@ struct PtrToArg> { } }; -template -struct PtrToArg &> { - typedef Ref EncodeT; - - _FORCE_INLINE_ static Ref convert(const void *p_ptr) { - if (p_ptr == nullptr) { - return Ref(); - } - // p_ptr points to a RefCounted object - return Ref(*((T *const *)p_ptr)); - } -}; - template struct GetTypeInfo> { static const Variant::Type VARIANT_TYPE = Variant::OBJECT; @@ -256,26 +265,17 @@ struct GetTypeInfo> { } }; -template -struct GetTypeInfo &> { - static const Variant::Type VARIANT_TYPE = Variant::OBJECT; - static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; - - static inline PropertyInfo get_class_info() { - return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static()); - } -}; - template struct VariantInternalAccessor> { static _FORCE_INLINE_ Ref get(const Variant *v) { return Ref(*VariantInternal::get_object(v)); } static _FORCE_INLINE_ void set(Variant *v, const Ref &p_ref) { VariantInternal::object_assign(v, p_ref); } }; +// Zero-constructing Ref initializes reference to nullptr (and thus empty). template -struct VariantInternalAccessor &> { - static _FORCE_INLINE_ Ref get(const Variant *v) { return Ref(*VariantInternal::get_object(v)); } - static _FORCE_INLINE_ void set(Variant *v, const Ref &p_ref) { VariantInternal::object_assign(v, p_ref); } -}; +struct is_zero_constructible> : std::true_type {}; -#endif // REF_COUNTED_H +template +Ref ObjectDB::get_ref(ObjectID p_instance_id) { + return Ref(get_instance(p_instance_id)); +} diff --git a/engine/core/object/script_instance.h b/engine/core/object/script_instance.h index 2c8132ec..59b7199c 100644 --- a/engine/core/object/script_instance.h +++ b/engine/core/object/script_instance.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef SCRIPT_INSTANCE_H -#define SCRIPT_INSTANCE_H +#pragma once #include "core/object/ref_counted.h" @@ -96,5 +95,3 @@ public: virtual ScriptLanguage *get_language() = 0; virtual ~ScriptInstance(); }; - -#endif // SCRIPT_INSTANCE_H diff --git a/engine/core/object/script_language.cpp b/engine/core/object/script_language.cpp index 33bf7ab4..a2c738b6 100644 --- a/engine/core/object/script_language.cpp +++ b/engine/core/object/script_language.cpp @@ -633,6 +633,7 @@ void ScriptLanguage::_bind_methods() { BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_PASCAL_CASE); BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_SNAKE_CASE); BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_KEBAB_CASE); + BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_CAMEL_CASE); } bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_value) { diff --git a/engine/core/object/script_language.h b/engine/core/object/script_language.h index 8158d633..c724177f 100644 --- a/engine/core/object/script_language.h +++ b/engine/core/object/script_language.h @@ -28,8 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef SCRIPT_LANGUAGE_H -#define SCRIPT_LANGUAGE_H +#pragma once #include "core/doc_data.h" #include "core/io/resource.h" @@ -247,6 +246,7 @@ public: SCRIPT_NAME_CASING_PASCAL_CASE, SCRIPT_NAME_CASING_SNAKE_CASE, SCRIPT_NAME_CASING_KEBAB_CASE, + SCRIPT_NAME_CASING_CAMEL_CASE, }; struct ScriptTemplate { @@ -505,5 +505,3 @@ public: PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref + +