diff --git a/.clang-format b/.clang-format index 46923aae03d2..dd0e5447d5f6 100644 --- a/.clang-format +++ b/.clang-format @@ -44,7 +44,7 @@ AllowAllParametersOfDeclarationOnNextLine: false # AllowShortBlocksOnASingleLine: Never # AllowShortCaseLabelsOnASingleLine: false # AllowShortEnumsOnASingleLine: true -# AllowShortFunctionsOnASingleLine: All +AllowShortFunctionsOnASingleLine: Inline # AllowShortIfStatementsOnASingleLine: Never # AllowShortLambdasOnASingleLine: All # AllowShortLoopsOnASingleLine: false @@ -88,7 +88,7 @@ BreakConstructorInitializers: AfterColon # BreakInheritanceList: BeforeColon # BreakStringLiterals: true ColumnLimit: 0 -# CommentPragmas: '^ IWYU pragma:' +# CommentPragmas: "^ IWYU pragma:" # CompactNamespaces: false ConstructorInitializerIndentWidth: 8 ContinuationIndentWidth: 8 @@ -114,7 +114,7 @@ IncludeCategories: - Regex: ^<.*>$ Priority: 3 # IncludeIsMainRegex: (Test)?$ -# IncludeIsMainSourceRegex: '' +# IncludeIsMainSourceRegex: "" # IndentAccessModifiers: false # IndentCaseBlocks: false IndentCaseLabels: true @@ -149,8 +149,8 @@ KeepEmptyLinesAtTheStartOfBlocks: false # LambdaBodyIndentation: Signature # Language: Cpp # LineEnding: DeriveLF -# MacroBlockBegin: '' -# MacroBlockEnd: '' +# MacroBlockBegin: "" +# MacroBlockEnd: "" # MaxEmptyLinesToKeep: 1 # NamespaceIndentation: None # ObjCBinPackProtocolList: Auto diff --git a/.clang-tidy b/.clang-tidy index 1eb974f3f86c..04c48cf89253 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -7,7 +7,7 @@ Checks: - modernize-use-nullptr - readability-braces-around-statements - readability-redundant-member-init -HeaderFileExtensions: ['', h, hh, hpp, hxx, inc, glsl] +HeaderFileExtensions: ["", h, hh, hpp, hxx, inc, glsl] ImplementationFileExtensions: [c, cc, cpp, cxx, m, mm, java] HeaderFilterRegex: (core|doc|drivers|editor|main|modules|platform|scene|servers|tests)/ FormatStyle: file diff --git a/.clangd b/.clangd new file mode 100644 index 000000000000..95a1e90766cf --- /dev/null +++ b/.clangd @@ -0,0 +1,31 @@ +# https://clangd.llvm.org/config +--- +# Default conditions, apply everywhere. + +Diagnostics: + Includes: + IgnoreHeader: + - core/typedefs\.h # Our "main" header, featuring transitive includes; allow everywhere. + - \.compat\.inc +--- +# Header-specific conditions. + +If: + PathMatch: .*\.(h|hh|hpp|hxx|inc) + +# Exclude certain, noisy warnings that lack full context. Replace with lowered severity if/when +# clangd gets diagnostic severity support. (See: https://github.com/clangd/clangd/issues/1937) +CompileFlags: + Add: + - -Wno-unneeded-internal-declaration + - -Wno-unused-const-variable + - -Wno-unused-function + - -Wno-unused-variable +--- +# Suppress all third-party warnings. + +If: + PathMatch: thirdparty/.* + +Diagnostics: + Suppress: "*" diff --git a/.editorconfig b/.editorconfig index 523ff713072c..91784612cf17 100644 --- a/.editorconfig +++ b/.editorconfig @@ -18,7 +18,7 @@ indent_style = space indent_size = 4 # YAML requires indentation with spaces instead of tabs. -[*.{yml,yaml}] +[{*.{yml,yaml},.clang{-format,-tidy,d}}] indent_style = space indent_size = 2 diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index f149078d5d5c..d54ff3093770 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -63,3 +63,6 @@ b37fc1014abf7adda70dc30b0822d775b3a4433f # Style: Apply clang-tidy fixes (superficial) bb5f390fb9b466be35a5df7651323d7e66afca31 + +# Style: Enforce `AllowShortFunctionsOnASingleLine` +e06d83860d798b6766b23d6eae48557387a7db85 diff --git a/.github/actions/godot-build/action.yml b/.github/actions/godot-build/action.yml index ebc301dd0f4a..2405cc22be22 100644 --- a/.github/actions/godot-build/action.yml +++ b/.github/actions/godot-build/action.yml @@ -14,7 +14,7 @@ inputs: required: false sconsflags: description: Additional SCons flags. - default: '' + default: "" required: false scons-cache: description: The SCons cache path. diff --git a/.github/workflows/android_builds.yml b/.github/workflows/android_builds.yml index 2803ff4b5e88..025c4b2a9409 100644 --- a/.github/workflows/android_builds.yml +++ b/.github/workflows/android_builds.yml @@ -8,10 +8,6 @@ env: GODOT_BASE_BRANCH: master SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no module_text_server_fb_enabled=yes strict_checks=yes -concurrency: - group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-android - cancel-in-progress: true - jobs: build-android: runs-on: ubuntu-24.04 diff --git a/.github/workflows/godot_cpp_test.yml b/.github/workflows/godot_cpp_test.yml index ae2fc9388c37..e4013f04938e 100644 --- a/.github/workflows/godot_cpp_test.yml +++ b/.github/workflows/godot_cpp_test.yml @@ -9,10 +9,6 @@ env: # Used for the godot-cpp checkout. GODOT_CPP_BRANCH: 4.3 -concurrency: - group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-cpp-tests - cancel-in-progress: true - jobs: godot-cpp-tests: runs-on: ubuntu-24.04 diff --git a/.github/workflows/ios_builds.yml b/.github/workflows/ios_builds.yml index 270204ebe507..b1b96e56eb7a 100644 --- a/.github/workflows/ios_builds.yml +++ b/.github/workflows/ios_builds.yml @@ -8,10 +8,6 @@ env: GODOT_BASE_BRANCH: master SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no module_text_server_fb_enabled=yes strict_checks=yes -concurrency: - group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-ios - cancel-in-progress: true - jobs: ios-template: runs-on: macos-latest diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml index e5c28cab34b3..e2e6e57de127 100644 --- a/.github/workflows/linux_builds.yml +++ b/.github/workflows/linux_builds.yml @@ -12,10 +12,6 @@ env: TSAN_OPTIONS: suppressions=misc/error_suppressions/tsan.txt UBSAN_OPTIONS: suppressions=misc/error_suppressions/ubsan.txt -concurrency: - group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-linux - cancel-in-progress: true - jobs: build-linux: # Stay one LTS before latest to increase portability of Linux artifacts. @@ -129,7 +125,7 @@ jobs: continue-on-error: true - name: Setup Python and SCons - if: '!matrix.legacy-scons' + if: "!matrix.legacy-scons" uses: ./.github/actions/godot-deps - name: Setup Python and SCons (legacy versions) @@ -150,7 +146,7 @@ jobs: uses: actions/setup-dotnet@v4 with: # Targeting the oldest version we want to support to ensure it still builds. - dotnet-version: '8.0.100' + dotnet-version: 8.0.100 - name: Compilation uses: ./.github/actions/godot-build diff --git a/.github/workflows/macos_builds.yml b/.github/workflows/macos_builds.yml index 3fedc2a5c9a9..7e302d98759f 100644 --- a/.github/workflows/macos_builds.yml +++ b/.github/workflows/macos_builds.yml @@ -8,10 +8,6 @@ env: GODOT_BASE_BRANCH: master SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes strict_checks=yes -concurrency: - group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-macos - cancel-in-progress: true - jobs: build-macos: runs-on: macos-latest diff --git a/.github/workflows/runner.yml b/.github/workflows/runner.yml index fd5e74b914ad..937f0e895d79 100644 --- a/.github/workflows/runner.yml +++ b/.github/workflows/runner.yml @@ -2,14 +2,14 @@ name: 🔗 GHA on: [push, pull_request, merge_group] concurrency: - group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-runner + group: ${{ github.workflow }}|${{ github.ref_name }} cancel-in-progress: true jobs: # First stage: Only static checks, fast and prevent expensive builds from running. static-checks: - if: '!vars.DISABLE_GODOT_CI' + if: "!vars.DISABLE_GODOT_CI" name: 📊 Static checks uses: ./.github/workflows/static_checks.yml diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml index e832faaca477..27580f7c7f12 100644 --- a/.github/workflows/static_checks.yml +++ b/.github/workflows/static_checks.yml @@ -2,10 +2,6 @@ name: 📊 Static Checks on: workflow_call: -concurrency: - group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-static - cancel-in-progress: true - jobs: static-checks: name: Code style, file formatting, and docs diff --git a/.github/workflows/web_builds.yml b/.github/workflows/web_builds.yml index dac6270b2bd6..2f253fb82ffb 100644 --- a/.github/workflows/web_builds.yml +++ b/.github/workflows/web_builds.yml @@ -9,10 +9,6 @@ env: SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no use_closure_compiler=yes strict_checks=yes EM_VERSION: 3.1.64 -concurrency: - group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-web - cancel-in-progress: true - jobs: web-template: runs-on: ubuntu-24.04 diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml index c407ae12d099..843d39dcb23c 100644 --- a/.github/workflows/windows_builds.yml +++ b/.github/workflows/windows_builds.yml @@ -10,10 +10,6 @@ env: SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes d3d12=yes strict_checks=yes "angle_libs=${{ github.workspace }}/" SCONS_CACHE_MSVC_CONFIG: true -concurrency: - group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-windows - cancel-in-progress: true - jobs: build-windows: # Windows 10 with latest image diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0b02b440dfde..9127ad86e082 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,8 +4,10 @@ default_language_version: exclude: | (?x)^( .*thirdparty/.*| - .*-so_wrap\.(h|c)$ - ) + .*-so_wrap\.(h|c)| + 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 @@ -14,23 +16,13 @@ repos: - id: clang-format files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java)$ types_or: [text] - exclude: | - (?x)^( - tests/python_build/.*| - platform/android/java/editor/src/main/java/com/android/.*| - platform/android/java/lib/src/com/.* - ) + exclude: ^tests/python_build/.* - id: clang-format name: clang-format-glsl files: \.glsl$ types_or: [text] - exclude: | - (?x)^( - tests/python_build/.*| - platform/android/java/editor/src/main/java/com/android/.*| - platform/android/java/lib/src/com/.* - ) - args: ['-style=file:misc/utility/.clang-format-glsl'] + exclude: ^tests/python_build/.* + args: [-style=file:misc/utility/clang_format_glsl.yml] - repo: https://github.com/pocc/pre-commit-hooks rev: v1.3.5 @@ -39,12 +31,7 @@ repos: files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java|glsl)$ args: [--fix, --quiet, --use-color] types_or: [text] - exclude: | - (?x)^( - tests/python_build/.*| - platform/android/java/editor/src/main/java/com/android/.*| - platform/android/java/lib/src/com/.* - ) + exclude: ^tests/python_build/.* additional_dependencies: [clang-tidy==19.1.0] require_serial: true stages: [manual] # Not automatically triggered, invoked via `pre-commit run --hook-stage manual clang-tidy` @@ -71,11 +58,6 @@ repos: rev: v2.3.0 hooks: - id: codespell - exclude: | - (?x)^( - platform/android/java/editor/src/main/java/com/android/.*| - platform/android/java/lib/src/com/.* - ) additional_dependencies: [tomli] ### Requires Docker; look into alternative implementation. @@ -118,10 +100,10 @@ repos: - --config - platform/web/eslint.config.cjs additional_dependencies: - - '@eslint/js@^9.3.0' - - '@html-eslint/eslint-plugin@^0.24.1' - - '@html-eslint/parser@^0.24.1' - - '@stylistic/eslint-plugin@^2.1.0' + - "@eslint/js@^9.3.0" + - "@html-eslint/eslint-plugin@^0.24.1" + - "@html-eslint/parser@^0.24.1" + - "@stylistic/eslint-plugin@^2.1.0" - eslint@^9.3.0 - eslint-plugin-html@^8.1.1 - globals@^15.3.0 @@ -139,7 +121,7 @@ repos: - platform/web/js/engine/config.js - platform/web/js/engine/features.js - --destination - - '' + - "" - -d - dry-run pass_filenames: false @@ -160,14 +142,12 @@ repos: files: \.(c|h|cpp|hpp|cc|hh|cxx|hxx|m|mm|inc|java)$ exclude: | (?x)^( - core/math/bvh_.*\.inc$| + core/math/bvh_.*\.inc| platform/(?!android|ios|linuxbsd|macos|web|windows)\w+/.*| - platform/android/java/editor/src/main/java/com/android/.*| - platform/android/java/lib/src/com/.*| - platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView\.java$| - platform/android/java/lib/src/org/godotengine/godot/gl/EGLLogWrapper\.java$| - platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix\.java$ - ) + platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView\.java| + platform/android/java/lib/src/org/godotengine/godot/gl/EGLLogWrapper\.java| + platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix\.java + )$ - id: header-guards name: header-guards @@ -183,17 +163,15 @@ repos: types_or: [text] exclude: | (?x)^( - .*\.test\.txt$| - .*\.svg$| - .*\.patch$| - .*\.out$| - modules/gdscript/tests/scripts/parser/features/mixed_indentation_on_blank_lines\.gd$| - modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment\.norun\.gd$| - modules/gdscript/tests/scripts/parser/warnings/empty_file_newline\.norun\.gd$| - platform/android/java/editor/src/main/java/com/android/.*| - platform/android/java/lib/src/com/google/.*| - tests/data/.*\.bin$ - ) + .*\.test\.txt| + .*\.svg| + .*\.patch| + .*\.out| + modules/gdscript/tests/scripts/parser/features/mixed_indentation_on_blank_lines\.gd| + modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment\.norun\.gd| + modules/gdscript/tests/scripts/parser/warnings/empty_file_newline\.norun\.gd| + tests/data/.*\.bin + )$ - id: dotnet-format name: dotnet-format diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index ee87e604eb58..e90f81d08528 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1578,7 +1578,7 @@ ProjectSettings::ProjectSettings() { // installed by the scripts provided in the repository // (check `misc/scripts/install_d3d12_sdk_windows.py`). // For example, if the script installs 1.613.3, the default value must be 613. - GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/agility_sdk_version"), 613); + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/agility_sdk_version", PROPERTY_HINT_RANGE, "0,10000,1,or_greater,hide_slider"), 613); GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), 1); GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM, "Disable,Enable,Mirror"), 0); diff --git a/core/io/resource.h b/core/io/resource.h index 015f7ad197b0..ebc82ceebf9c 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -40,11 +40,15 @@ class Node; -#define RES_BASE_EXTENSION(m_ext) \ -public: \ - static void register_custom_data_to_otdb() { ClassDB::add_resource_base_extension(m_ext, get_class_static()); } \ - virtual String get_base_extension() const override { return m_ext; } \ - \ +#define RES_BASE_EXTENSION(m_ext) \ +public: \ + static void register_custom_data_to_otdb() { \ + ClassDB::add_resource_base_extension(m_ext, get_class_static()); \ + } \ + virtual String get_base_extension() const override { \ + return m_ext; \ + } \ + \ private: class Resource : public RefCounted { diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp index 135d5559443b..3a0e2aa090d3 100644 --- a/core/io/resource_uid.cpp +++ b/core/io/resource_uid.cpp @@ -229,7 +229,7 @@ Error ResourceUID::load_from_cache(bool p_reset) { int32_t len = f->get_32(); Cache c; c.cs.resize(len + 1); - ERR_FAIL_COND_V(c.cs.size() != len + 1, ERR_FILE_CORRUPT); // out of memory + ERR_FAIL_COND_V(c.cs.size() != len + 1, ERR_FILE_CORRUPT); // Out of memory. c.cs[len] = 0; int32_t rl = f->get_buffer((uint8_t *)c.cs.ptrw(), len); ERR_FAIL_COND_V(rl != len, ERR_FILE_CORRUPT); @@ -257,7 +257,7 @@ Error ResourceUID::update_cache() { for (KeyValue &E : unique_ids) { if (!E.value.saved_to_cache) { if (f.is_null()) { - f = FileAccess::open(get_cache_file(), FileAccess::READ_WRITE); //append + f = FileAccess::open(get_cache_file(), FileAccess::READ_WRITE); // Append. if (f.is_null()) { return ERR_CANT_OPEN; } @@ -282,6 +282,25 @@ Error ResourceUID::update_cache() { return OK; } +String ResourceUID::get_path_from_cache(Ref &p_cache_file, const String &p_uid_string) { + const uint32_t entry_count = p_cache_file->get_32(); + CharString cs; + for (uint32_t i = 0; i < entry_count; i++) { + int64_t id = p_cache_file->get_64(); + int32_t len = p_cache_file->get_32(); + cs.resize(len + 1); + ERR_FAIL_COND_V(cs.size() != len + 1, String()); + cs[len] = 0; + int32_t rl = p_cache_file->get_buffer((uint8_t *)cs.ptrw(), len); + ERR_FAIL_COND_V(rl != len, String()); + + if (singleton->id_to_text(id) == p_uid_string) { + return String(cs); + } + } + return String(); +} + void ResourceUID::clear() { cache_entries = 0; unique_ids.clear(); diff --git a/core/io/resource_uid.h b/core/io/resource_uid.h index bdbd87dcad53..6d96953fcc1d 100644 --- a/core/io/resource_uid.h +++ b/core/io/resource_uid.h @@ -35,6 +35,8 @@ #include "core/string/string_name.h" #include "core/templates/hash_map.h" +class FileAccess; + class ResourceUID : public Object { GDCLASS(ResourceUID, Object) public: @@ -78,6 +80,7 @@ class ResourceUID : public Object { Error load_from_cache(bool p_reset); Error save_to_cache(); Error update_cache(); + static String get_path_from_cache(Ref &p_cache_file, const String &p_uid_string); void clear(); diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 34ed1c2d855f..e5f3431eef84 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -1049,9 +1049,10 @@ Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up, bool p_use v_z = -v_z; } Vector3 v_x = p_up.cross(v_z); -#ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(v_x.is_zero_approx(), Basis(), "The target vector and up vector can't be parallel to each other."); -#endif + if (v_x.is_zero_approx()) { + WARN_PRINT("Target and up vectors are colinear. This is not advised as it may cause unwanted rotation around local Z axis."); + v_x = p_up.get_any_perpendicular(); // Vectors are almost parallel. + } v_x.normalize(); Vector3 v_y = v_z.cross(v_x); diff --git a/core/math/color.cpp b/core/math/color.cpp index 1638acd74d8b..4c31d8149d8a 100644 --- a/core/math/color.cpp +++ b/core/math/color.cpp @@ -482,6 +482,10 @@ Color Color::from_rgbe9995(uint32_t p_rgbe) { return Color(rd, gd, bd, 1.0f); } +Color Color::from_rgba8(int64_t p_r8, int64_t p_g8, int64_t p_b8, int64_t p_a8) { + return Color(p_r8 / 255.0f, p_g8 / 255.0f, p_b8 / 255.0f, p_a8 / 255.0f); +} + Color::operator String() const { return "(" + String::num(r, 4) + ", " + String::num(g, 4) + ", " + String::num(b, 4) + ", " + String::num(a, 4) + ")"; } diff --git a/core/math/color.h b/core/math/color.h index 3943d5ada656..c2ffde1849ca 100644 --- a/core/math/color.h +++ b/core/math/color.h @@ -213,6 +213,7 @@ struct [[nodiscard]] Color { static Color from_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f); static Color from_ok_hsl(float p_h, float p_s, float p_l, float p_alpha = 1.0f); 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. operator String() const; diff --git a/core/math/quaternion.h b/core/math/quaternion.h index 655e55e0a209..605035c21438 100644 --- a/core/math/quaternion.h +++ b/core/math/quaternion.h @@ -142,14 +142,15 @@ struct [[nodiscard]] Quaternion { Quaternion(const Vector3 &p_v0, const Vector3 &p_v1) { // Shortest arc. Vector3 c = p_v0.cross(p_v1); - real_t d = p_v0.dot(p_v1); - if (d < -1.0f + (real_t)CMP_EPSILON) { - x = 0; - y = 1; - z = 0; + if (c.is_zero_approx()) { + Vector3 axis = p_v0.get_any_perpendicular(); + x = axis.x; + y = axis.y; + z = axis.z; w = 0; } else { + real_t d = p_v0.dot(p_v1); real_t s = Math::sqrt((1.0f + d) * 2.0f); real_t rs = 1.0f / s; diff --git a/core/math/vector3.h b/core/math/vector3.h index 14bc44c4e79d..fd0dec3550d5 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -130,6 +130,7 @@ struct [[nodiscard]] Vector3 { _FORCE_INLINE_ Vector3 cross(const Vector3 &p_with) const; _FORCE_INLINE_ real_t dot(const Vector3 &p_with) const; Basis outer(const Vector3 &p_with) const; + _FORCE_INLINE_ Vector3 get_any_perpendicular() const; _FORCE_INLINE_ Vector3 abs() const; _FORCE_INLINE_ Vector3 floor() const; @@ -326,6 +327,16 @@ Vector3 Vector3::direction_to(const Vector3 &p_to) const { return ret; } +Vector3 Vector3::get_any_perpendicular() const { + // Return the any perpendicular vector by cross product with the Vector3.RIGHT or Vector3.UP, + // whichever has the greater angle to the current vector with the sign of each element positive. + // The only essence is "to avoid being parallel to the current vector", and there is no mathematical basis for using Vector3.RIGHT and Vector3.UP, + // since it could be a different vector depending on the prior branching code Math::abs(x) <= Math::abs(y) && Math::abs(x) <= Math::abs(z). + // However, it would be reasonable to use any of the axes of the basis, as it is simpler to calculate. + ERR_FAIL_COND_V_MSG(is_zero_approx(), Vector3(0, 0, 0), "The Vector3 must not be zero."); + return cross((Math::abs(x) <= Math::abs(y) && Math::abs(x) <= Math::abs(z)) ? Vector3(1, 0, 0) : Vector3(0, 1, 0)).normalized(); +} + /* Operators */ Vector3 &Vector3::operator+=(const Vector3 &p_v) { diff --git a/core/object/object.h b/core/object/object.h index 1d23311dd22c..916efdd73cad 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -389,177 +389,181 @@ struct ObjectGDExtension { * much alone defines the object model. */ -#define GDCLASS(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 { \ - 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)); \ - } \ - 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: \ - _FORCE_INLINE_ static void (*_get_bind_methods())() { \ - return &m_class::_bind_methods; \ - } \ - _FORCE_INLINE_ static void (*_get_bind_compatibility_methods())() { \ - return &m_class::_bind_compatibility_methods; \ - } \ - \ -public: \ - static void initialize_class() { \ - static bool initialized = false; \ - if (initialized) { \ - return; \ - } \ - m_inherits::initialize_class(); \ - ::ClassDB::_add_class(); \ - if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \ - _bind_methods(); \ - } \ - if (m_class::_get_bind_compatibility_methods() != m_inherits::_get_bind_compatibility_methods()) { \ - _bind_compatibility_methods(); \ - } \ - initialized = true; \ - } \ - \ -protected: \ - virtual void _initialize_classv() override { \ - 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; \ - } \ - virtual bool _getv(const StringName &p_name, Variant &r_ret) const override { \ - if (m_class::_get_get() != m_inherits::_get_get()) { \ - if (_get(p_name, r_ret)) { \ - return true; \ - } \ - } \ - 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; \ - } \ - virtual bool _setv(const StringName &p_name, const Variant &p_property) override { \ - if (m_inherits::_setv(p_name, p_property)) { \ - return true; \ - } \ - if (m_class::_get_set() != m_inherits::_get_set()) { \ - return _set(p_name, p_property); \ - } \ - 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; \ - } \ - 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); \ - if (m_class::_get_get_property_list() != m_inherits::_get_get_property_list()) { \ - _get_property_list(p_list); \ - } \ - if (p_reversed) { \ - m_inherits::_get_property_listv(p_list, p_reversed); \ - } \ - } \ - _FORCE_INLINE_ void (Object::*_get_validate_property() const)(PropertyInfo & p_property) const { \ - return (void(Object::*)(PropertyInfo &) const) & m_class::_validate_property; \ - } \ - virtual void _validate_propertyv(PropertyInfo &p_property) const override { \ - m_inherits::_validate_propertyv(p_property); \ - if (m_class::_get_validate_property() != m_inherits::_get_validate_property()) { \ - _validate_property(p_property); \ - } \ - } \ - _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; \ - } \ - virtual bool _property_can_revertv(const StringName &p_name) const override { \ - if (m_class::_get_property_can_revert() != m_inherits::_get_property_can_revert()) { \ - if (_property_can_revert(p_name)) { \ - return true; \ - } \ - } \ - 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; \ - } \ - 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()) { \ - if (_property_get_revert(p_name, r_ret)) { \ - return true; \ - } \ - } \ - 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; \ - } \ - virtual void _notificationv(int p_notification, bool p_reversed) override { \ - if (!p_reversed) { \ - m_inherits::_notificationv(p_notification, p_reversed); \ - } \ - if (m_class::_get_notification() != m_inherits::_get_notification()) { \ - _notification(p_notification); \ - } \ - if (p_reversed) { \ - m_inherits::_notificationv(p_notification, p_reversed); \ - } \ - } \ - \ +#define GDCLASS(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 { \ + 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)); \ + } \ + 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: \ + _FORCE_INLINE_ static void (*_get_bind_methods())() { \ + return &m_class::_bind_methods; \ + } \ + _FORCE_INLINE_ static void (*_get_bind_compatibility_methods())() { \ + return &m_class::_bind_compatibility_methods; \ + } \ + \ +public: \ + static void initialize_class() { \ + static bool initialized = false; \ + if (initialized) { \ + return; \ + } \ + m_inherits::initialize_class(); \ + ::ClassDB::_add_class(); \ + if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \ + _bind_methods(); \ + } \ + if (m_class::_get_bind_compatibility_methods() != m_inherits::_get_bind_compatibility_methods()) { \ + _bind_compatibility_methods(); \ + } \ + initialized = true; \ + } \ + \ +protected: \ + virtual void _initialize_classv() override { \ + 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; \ + } \ + virtual bool _getv(const StringName &p_name, Variant &r_ret) const override { \ + if (m_class::_get_get() != m_inherits::_get_get()) { \ + if (_get(p_name, r_ret)) { \ + return true; \ + } \ + } \ + 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; \ + } \ + virtual bool _setv(const StringName &p_name, const Variant &p_property) override { \ + if (m_inherits::_setv(p_name, p_property)) { \ + return true; \ + } \ + if (m_class::_get_set() != m_inherits::_get_set()) { \ + return _set(p_name, p_property); \ + } \ + 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; \ + } \ + 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); \ + if (m_class::_get_get_property_list() != m_inherits::_get_get_property_list()) { \ + _get_property_list(p_list); \ + } \ + if (p_reversed) { \ + m_inherits::_get_property_listv(p_list, p_reversed); \ + } \ + } \ + _FORCE_INLINE_ void (Object::*_get_validate_property() const)(PropertyInfo & p_property) const { \ + return (void(Object::*)(PropertyInfo &) const) & m_class::_validate_property; \ + } \ + virtual void _validate_propertyv(PropertyInfo &p_property) const override { \ + m_inherits::_validate_propertyv(p_property); \ + if (m_class::_get_validate_property() != m_inherits::_get_validate_property()) { \ + _validate_property(p_property); \ + } \ + } \ + _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; \ + } \ + virtual bool _property_can_revertv(const StringName &p_name) const override { \ + if (m_class::_get_property_can_revert() != m_inherits::_get_property_can_revert()) { \ + if (_property_can_revert(p_name)) { \ + return true; \ + } \ + } \ + 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; \ + } \ + 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()) { \ + if (_property_get_revert(p_name, r_ret)) { \ + return true; \ + } \ + } \ + 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; \ + } \ + virtual void _notificationv(int p_notification, bool p_reversed) override { \ + if (!p_reversed) { \ + m_inherits::_notificationv(p_notification, p_reversed); \ + } \ + if (m_class::_get_notification() != m_inherits::_get_notification()) { \ + _notification(p_notification); \ + } \ + if (p_reversed) { \ + m_inherits::_notificationv(p_notification, p_reversed); \ + } \ + } \ + \ private: -#define OBJ_SAVE_TYPE(m_class) \ -public: \ - virtual String get_save_class() const override { return #m_class; } \ - \ +#define OBJ_SAVE_TYPE(m_class) \ +public: \ + virtual String get_save_class() const override { \ + return #m_class; \ + } \ + \ private: class ScriptInstance; diff --git a/core/os/memory.cpp b/core/os/memory.cpp index cdfd03b3aa70..3a496612fab8 100644 --- a/core/os/memory.cpp +++ b/core/os/memory.cpp @@ -64,7 +64,9 @@ SafeNumeric Memory::max_usage; SafeNumeric Memory::alloc_count; -inline bool is_power_of_2(size_t x) { return x && ((x & (x - 1U)) == 0U); } +inline bool is_power_of_2(size_t x) { + return x && ((x & (x - 1U)) == 0U); +} void *Memory::alloc_aligned_static(size_t p_bytes, size_t p_alignment) { DEV_ASSERT(is_power_of_2(p_alignment)); diff --git a/core/os/os.h b/core/os/os.h index c3923e08c5ea..bc8e2bcaa717 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -69,9 +69,6 @@ class OS { bool restart_on_exit = false; List restart_commandline; - // for the user interface we keep a record of the current display driver - // so we can retrieve the rendering drivers available - int _display_driver_id = -1; String _current_rendering_driver_name; String _current_rendering_method; bool _is_gles_over_gl = false; @@ -119,8 +116,6 @@ class OS { virtual void initialize() = 0; virtual void initialize_joypads() = 0; - void set_display_driver_id(int p_display_driver_id) { _display_driver_id = p_display_driver_id; } - virtual void set_main_loop(MainLoop *p_main_loop) = 0; virtual void delete_main_loop() = 0; @@ -144,8 +139,6 @@ class OS { String get_current_rendering_method() const { return _current_rendering_method; } bool get_gles_over_gl() const { return _is_gles_over_gl; } - int get_display_driver_id() const { return _display_driver_id; } - virtual Vector get_video_adapter_driver_info() const = 0; virtual bool get_user_prefers_integrated_gpu() const { return false; } diff --git a/core/os/thread.cpp b/core/os/thread.cpp index afc74364f652..3992eb31bf5f 100644 --- a/core/os/thread.cpp +++ b/core/os/thread.cpp @@ -29,13 +29,13 @@ /**************************************************************************/ #include "platform_config.h" -#ifndef PLATFORM_THREAD_OVERRIDE // See details in thread.h + +#ifndef PLATFORM_THREAD_OVERRIDE // See details in thread.h. #include "thread.h" #ifdef THREADS_ENABLED #include "core/object/script_language.h" -#include "core/templates/safe_refcount.h" SafeNumeric Thread::id_counter(1); // The first value after .increment() is 2, hence by default the main thread ID should be 1. diff --git a/core/os/thread.h b/core/os/thread.h index 066c4befa77d..9042c6c01716 100644 --- a/core/os/thread.h +++ b/core/os/thread.h @@ -29,19 +29,28 @@ /**************************************************************************/ #include "platform_config.h" + // Define PLATFORM_THREAD_OVERRIDE in your platform's `platform_config.h` -// to use a custom Thread implementation defined in `platform/[your_platform]/platform_thread.h` -// Overriding the platform implementation is required in some proprietary platforms +// to use a custom Thread implementation defined in `platform/[your_platform]/platform_thread.h`. +// Overriding the Thread implementation is required in some proprietary platforms. + #ifdef PLATFORM_THREAD_OVERRIDE + #include "platform_thread.h" + #else #ifndef THREAD_H #define THREAD_H -#include "core/templates/safe_refcount.h" #include "core/typedefs.h" +#ifdef THREADS_ENABLED + +#include "core/templates/safe_refcount.h" + +#include // IWYU pragma: keep // For hardware interference size. + #ifdef MINGW_ENABLED #define MINGW_STDTHREAD_REDUNDANCY_WARNING #include "thirdparty/mingw-std-threads/mingw.thread.h" @@ -53,8 +62,6 @@ class String; -#ifdef THREADS_ENABLED - class Thread { public: typedef void (*Callback)(void *p_userdata); @@ -143,6 +150,8 @@ class Thread { #else // No threads. +class String; + class Thread { public: typedef void (*Callback)(void *p_userdata); diff --git a/core/os/thread_safe.h b/core/os/thread_safe.h index 316b0c96876f..f49592a4ecb0 100644 --- a/core/os/thread_safe.h +++ b/core/os/thread_safe.h @@ -31,6 +31,8 @@ #ifndef THREAD_SAFE_H #define THREAD_SAFE_H +#include "core/os/mutex.h" // IWYU pragma: keep // Used in macro. + #define _THREAD_SAFE_CLASS_ mutable Mutex _thread_safe_; #define _THREAD_SAFE_METHOD_ MutexLock _thread_safe_method_(_thread_safe_); #define _THREAD_SAFE_LOCK_ _thread_safe_.lock(); diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 3e172c2b82a7..568694bdf4d0 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -304,7 +304,7 @@ void register_core_types() { void register_core_settings() { // Since in register core types, globals may not be present. GLOBAL_DEF(PropertyInfo(Variant::INT, "network/limits/tcp/connect_timeout_seconds", PROPERTY_HINT_RANGE, "1,1800,1"), (30)); - GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "network/limits/packet_peer_stream/max_buffer_po2", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), (16)); + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "network/limits/packet_peer_stream/max_buffer_po2", PROPERTY_HINT_RANGE, "8,64,1,or_greater"), (16)); GLOBAL_DEF(PropertyInfo(Variant::STRING, "network/tls/certificate_bundle_override", PROPERTY_HINT_FILE, "*.crt"), ""); GLOBAL_DEF("threading/worker_pool/max_threads", -1); diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h index 4e0baef2b132..5950834804a6 100644 --- a/core/templates/command_queue_mt.h +++ b/core/templates/command_queue_mt.h @@ -33,294 +33,74 @@ #include "core/object/worker_thread_pool.h" #include "core/os/condition_variable.h" -#include "core/os/memory.h" #include "core/os/mutex.h" #include "core/templates/local_vector.h" #include "core/templates/simple_type.h" +#include "core/templates/tuple.h" #include "core/typedefs.h" -#define COMMA(N) _COMMA_##N -#define _COMMA_0 -#define _COMMA_1 , -#define _COMMA_2 , -#define _COMMA_3 , -#define _COMMA_4 , -#define _COMMA_5 , -#define _COMMA_6 , -#define _COMMA_7 , -#define _COMMA_8 , -#define _COMMA_9 , -#define _COMMA_10 , -#define _COMMA_11 , -#define _COMMA_12 , -#define _COMMA_13 , -#define _COMMA_14 , -#define _COMMA_15 , - -// 1-based comma separated list of ITEMs -#define COMMA_SEP_LIST(ITEM, LENGTH) _COMMA_SEP_LIST_##LENGTH(ITEM) -#define _COMMA_SEP_LIST_15(ITEM) \ - _COMMA_SEP_LIST_14(ITEM) \ - , ITEM(15) -#define _COMMA_SEP_LIST_14(ITEM) \ - _COMMA_SEP_LIST_13(ITEM) \ - , ITEM(14) -#define _COMMA_SEP_LIST_13(ITEM) \ - _COMMA_SEP_LIST_12(ITEM) \ - , ITEM(13) -#define _COMMA_SEP_LIST_12(ITEM) \ - _COMMA_SEP_LIST_11(ITEM) \ - , ITEM(12) -#define _COMMA_SEP_LIST_11(ITEM) \ - _COMMA_SEP_LIST_10(ITEM) \ - , ITEM(11) -#define _COMMA_SEP_LIST_10(ITEM) \ - _COMMA_SEP_LIST_9(ITEM) \ - , ITEM(10) -#define _COMMA_SEP_LIST_9(ITEM) \ - _COMMA_SEP_LIST_8(ITEM) \ - , ITEM(9) -#define _COMMA_SEP_LIST_8(ITEM) \ - _COMMA_SEP_LIST_7(ITEM) \ - , ITEM(8) -#define _COMMA_SEP_LIST_7(ITEM) \ - _COMMA_SEP_LIST_6(ITEM) \ - , ITEM(7) -#define _COMMA_SEP_LIST_6(ITEM) \ - _COMMA_SEP_LIST_5(ITEM) \ - , ITEM(6) -#define _COMMA_SEP_LIST_5(ITEM) \ - _COMMA_SEP_LIST_4(ITEM) \ - , ITEM(5) -#define _COMMA_SEP_LIST_4(ITEM) \ - _COMMA_SEP_LIST_3(ITEM) \ - , ITEM(4) -#define _COMMA_SEP_LIST_3(ITEM) \ - _COMMA_SEP_LIST_2(ITEM) \ - , ITEM(3) -#define _COMMA_SEP_LIST_2(ITEM) \ - _COMMA_SEP_LIST_1(ITEM) \ - , ITEM(2) -#define _COMMA_SEP_LIST_1(ITEM) \ - _COMMA_SEP_LIST_0(ITEM) \ - ITEM(1) -#define _COMMA_SEP_LIST_0(ITEM) - -// 1-based semicolon separated list of ITEMs -#define SEMIC_SEP_LIST(ITEM, LENGTH) _SEMIC_SEP_LIST_##LENGTH(ITEM) -#define _SEMIC_SEP_LIST_15(ITEM) \ - _SEMIC_SEP_LIST_14(ITEM); \ - ITEM(15) -#define _SEMIC_SEP_LIST_14(ITEM) \ - _SEMIC_SEP_LIST_13(ITEM); \ - ITEM(14) -#define _SEMIC_SEP_LIST_13(ITEM) \ - _SEMIC_SEP_LIST_12(ITEM); \ - ITEM(13) -#define _SEMIC_SEP_LIST_12(ITEM) \ - _SEMIC_SEP_LIST_11(ITEM); \ - ITEM(12) -#define _SEMIC_SEP_LIST_11(ITEM) \ - _SEMIC_SEP_LIST_10(ITEM); \ - ITEM(11) -#define _SEMIC_SEP_LIST_10(ITEM) \ - _SEMIC_SEP_LIST_9(ITEM); \ - ITEM(10) -#define _SEMIC_SEP_LIST_9(ITEM) \ - _SEMIC_SEP_LIST_8(ITEM); \ - ITEM(9) -#define _SEMIC_SEP_LIST_8(ITEM) \ - _SEMIC_SEP_LIST_7(ITEM); \ - ITEM(8) -#define _SEMIC_SEP_LIST_7(ITEM) \ - _SEMIC_SEP_LIST_6(ITEM); \ - ITEM(7) -#define _SEMIC_SEP_LIST_6(ITEM) \ - _SEMIC_SEP_LIST_5(ITEM); \ - ITEM(6) -#define _SEMIC_SEP_LIST_5(ITEM) \ - _SEMIC_SEP_LIST_4(ITEM); \ - ITEM(5) -#define _SEMIC_SEP_LIST_4(ITEM) \ - _SEMIC_SEP_LIST_3(ITEM); \ - ITEM(4) -#define _SEMIC_SEP_LIST_3(ITEM) \ - _SEMIC_SEP_LIST_2(ITEM); \ - ITEM(3) -#define _SEMIC_SEP_LIST_2(ITEM) \ - _SEMIC_SEP_LIST_1(ITEM); \ - ITEM(2) -#define _SEMIC_SEP_LIST_1(ITEM) \ - _SEMIC_SEP_LIST_0(ITEM) \ - ITEM(1) -#define _SEMIC_SEP_LIST_0(ITEM) - -// 1-based space separated list of ITEMs -#define SPACE_SEP_LIST(ITEM, LENGTH) _SPACE_SEP_LIST_##LENGTH(ITEM) -#define _SPACE_SEP_LIST_15(ITEM) \ - _SPACE_SEP_LIST_14(ITEM) \ - ITEM(15) -#define _SPACE_SEP_LIST_14(ITEM) \ - _SPACE_SEP_LIST_13(ITEM) \ - ITEM(14) -#define _SPACE_SEP_LIST_13(ITEM) \ - _SPACE_SEP_LIST_12(ITEM) \ - ITEM(13) -#define _SPACE_SEP_LIST_12(ITEM) \ - _SPACE_SEP_LIST_11(ITEM) \ - ITEM(12) -#define _SPACE_SEP_LIST_11(ITEM) \ - _SPACE_SEP_LIST_10(ITEM) \ - ITEM(11) -#define _SPACE_SEP_LIST_10(ITEM) \ - _SPACE_SEP_LIST_9(ITEM) \ - ITEM(10) -#define _SPACE_SEP_LIST_9(ITEM) \ - _SPACE_SEP_LIST_8(ITEM) \ - ITEM(9) -#define _SPACE_SEP_LIST_8(ITEM) \ - _SPACE_SEP_LIST_7(ITEM) \ - ITEM(8) -#define _SPACE_SEP_LIST_7(ITEM) \ - _SPACE_SEP_LIST_6(ITEM) \ - ITEM(7) -#define _SPACE_SEP_LIST_6(ITEM) \ - _SPACE_SEP_LIST_5(ITEM) \ - ITEM(6) -#define _SPACE_SEP_LIST_5(ITEM) \ - _SPACE_SEP_LIST_4(ITEM) \ - ITEM(5) -#define _SPACE_SEP_LIST_4(ITEM) \ - _SPACE_SEP_LIST_3(ITEM) \ - ITEM(4) -#define _SPACE_SEP_LIST_3(ITEM) \ - _SPACE_SEP_LIST_2(ITEM) \ - ITEM(3) -#define _SPACE_SEP_LIST_2(ITEM) \ - _SPACE_SEP_LIST_1(ITEM) \ - ITEM(2) -#define _SPACE_SEP_LIST_1(ITEM) \ - _SPACE_SEP_LIST_0(ITEM) \ - ITEM(1) -#define _SPACE_SEP_LIST_0(ITEM) - -#define ARG(N) p##N -#define PARAM(N) P##N p##N -#define TYPE_PARAM(N) typename P##N -#define PARAM_DECL(N) GetSimpleTypeT p##N - -#define DECL_CMD(N) \ - template \ - struct Command##N : public CommandBase { \ - T *instance; \ - M method; \ - SEMIC_SEP_LIST(PARAM_DECL, N); \ - virtual void call() override { \ - (instance->*method)(COMMA_SEP_LIST(ARG, N)); \ - } \ - }; - -#define DECL_CMD_RET(N) \ - template \ - struct CommandRet##N : public SyncCommand { \ - R *ret; \ - T *instance; \ - M method; \ - SEMIC_SEP_LIST(PARAM_DECL, N); \ - virtual void call() override { \ - *ret = (instance->*method)(COMMA_SEP_LIST(ARG, N)); \ - } \ - }; - -#define DECL_CMD_SYNC(N) \ - template \ - struct CommandSync##N : public SyncCommand { \ - T *instance; \ - M method; \ - SEMIC_SEP_LIST(PARAM_DECL, N); \ - virtual void call() override { \ - (instance->*method)(COMMA_SEP_LIST(ARG, N)); \ - } \ - }; - -#define TYPE_ARG(N) P##N -#define CMD_TYPE(N) Command##N -#define CMD_ASSIGN_PARAM(N) cmd->p##N = p##N - -#define DECL_PUSH(N) \ - template \ - void push(T *p_instance, M p_method COMMA(N) COMMA_SEP_LIST(PARAM, N)) { \ - MutexLock mlock(mutex); \ - CMD_TYPE(N) *cmd = allocate(); \ - cmd->instance = p_instance; \ - cmd->method = p_method; \ - SEMIC_SEP_LIST(CMD_ASSIGN_PARAM, N); \ - if (pump_task_id != WorkerThreadPool::INVALID_TASK_ID) { \ - WorkerThreadPool::get_singleton()->notify_yield_over(pump_task_id); \ - } \ - } - -#define CMD_RET_TYPE(N) CommandRet##N - -#define DECL_PUSH_AND_RET(N) \ - template \ - void push_and_ret(T *p_instance, M p_method, COMMA_SEP_LIST(PARAM, N) COMMA(N) R *r_ret) { \ - MutexLock mlock(mutex); \ - CMD_RET_TYPE(N) *cmd = allocate(); \ - cmd->instance = p_instance; \ - cmd->method = p_method; \ - SEMIC_SEP_LIST(CMD_ASSIGN_PARAM, N); \ - cmd->ret = r_ret; \ - if (pump_task_id != WorkerThreadPool::INVALID_TASK_ID) { \ - WorkerThreadPool::get_singleton()->notify_yield_over(pump_task_id); \ - } \ - sync_tail++; \ - _wait_for_sync(mlock); \ - } - -#define CMD_SYNC_TYPE(N) CommandSync##N - -#define DECL_PUSH_AND_SYNC(N) \ - template \ - void push_and_sync(T *p_instance, M p_method COMMA(N) COMMA_SEP_LIST(PARAM, N)) { \ - MutexLock mlock(mutex); \ - CMD_SYNC_TYPE(N) *cmd = allocate(); \ - cmd->instance = p_instance; \ - cmd->method = p_method; \ - SEMIC_SEP_LIST(CMD_ASSIGN_PARAM, N); \ - if (pump_task_id != WorkerThreadPool::INVALID_TASK_ID) { \ - WorkerThreadPool::get_singleton()->notify_yield_over(pump_task_id); \ - } \ - sync_tail++; \ - _wait_for_sync(mlock); \ - } - -#define MAX_CMD_PARAMS 15 - class CommandQueueMT { struct CommandBase { bool sync = false; virtual void call() = 0; virtual ~CommandBase() = default; + + CommandBase(bool p_sync) : + sync(p_sync) {} }; - struct SyncCommand : public CommandBase { - virtual void call() override {} - SyncCommand() { - sync = true; + template + struct Command : public CommandBase { + T *instance; + M method; + Tuple...> args; + + template + _FORCE_INLINE_ Command(T *p_instance, M p_method, FwdArgs &&...p_args) : + CommandBase(NeedsSync), instance(p_instance), method(p_method), args(std::forward(p_args)...) {} + + void call() { + call_impl(BuildIndexSequence{}); + } + + private: + template + _FORCE_INLINE_ void call_impl(IndexSequence) { + // Move out of the Tuple, this will be destroyed as soon as the call is complete. + (instance->*method)(std::move(get())...); } + + // This method exists so we can call it in the parameter pack expansion in call_impl. + template + _FORCE_INLINE_ auto &get() { return ::tuple_get(args); } }; - DECL_CMD(0) - SPACE_SEP_LIST(DECL_CMD, 15) + // Separate class from Command so we can save the space of the ret pointer for commands that don't return. + template + struct CommandRet : public CommandBase { + T *instance; + M method; + R *ret; + Tuple...> args; - // Commands that return. - DECL_CMD_RET(0) - SPACE_SEP_LIST(DECL_CMD_RET, 15) + _FORCE_INLINE_ CommandRet(T *p_instance, M p_method, R *p_ret, GetSimpleTypeT... p_args) : + CommandBase(true), instance(p_instance), method(p_method), ret(p_ret), args{ p_args... } {} - /* commands that don't return but sync */ - DECL_CMD_SYNC(0) - SPACE_SEP_LIST(DECL_CMD_SYNC, 15) + void call() override { + *ret = call_impl(BuildIndexSequence{}); + } + + private: + template + _FORCE_INLINE_ R call_impl(IndexSequence) { + // Move out of the Tuple, this will be destroyed as soon as the call is complete. + return (instance->*method)(std::move(get())...); + } + + // This method exists so we can call it in the parameter pack expansion in call_impl. + template + _FORCE_INLINE_ auto &get() { return ::tuple_get(args); } + }; /***** BASE *******/ @@ -335,17 +115,32 @@ class CommandQueueMT { WorkerThreadPool::TaskID pump_task_id = WorkerThreadPool::INVALID_TASK_ID; uint64_t flush_read_ptr = 0; - template - T *allocate() { + template + _FORCE_INLINE_ void create_command(Args &&...p_args) { // alloc size is size+T+safeguard - static_assert(sizeof(T) < UINT32_MAX, "Type too large to fit in the command queue."); + constexpr uint64_t alloc_size = ((sizeof(T) + 8U - 1U) & ~(8U - 1U)); + static_assert(alloc_size < UINT32_MAX, "Type too large to fit in the command queue."); - uint32_t alloc_size = ((sizeof(T) + 8U - 1U) & ~(8U - 1U)); uint64_t size = command_mem.size(); - command_mem.resize(size + alloc_size + 8); + command_mem.resize(size + alloc_size + sizeof(uint64_t)); *(uint64_t *)&command_mem[size] = alloc_size; - T *cmd = memnew_placement(&command_mem[size + 8], T); - return cmd; + void *cmd = &command_mem[size + sizeof(uint64_t)]; + new (cmd) T(std::forward(p_args)...); + } + + template + _FORCE_INLINE_ void _push_internal(Args &&...args) { + MutexLock mlock(mutex); + create_command(std::forward(args)...); + + if (pump_task_id != WorkerThreadPool::INVALID_TASK_ID) { + WorkerThreadPool::get_singleton()->notify_yield_over(pump_task_id); + } + + if constexpr (NeedsSync) { + sync_tail++; + _wait_for_sync(mlock); + } } _FORCE_INLINE_ void _prevent_sync_wraparound() { @@ -409,17 +204,26 @@ class CommandQueueMT { void _no_op() {} public: - /* NORMAL PUSH COMMANDS */ - DECL_PUSH(0) - SPACE_SEP_LIST(DECL_PUSH, 15) + template + void push(T *p_instance, M p_method, Args &&...p_args) { + // Standard command, no sync. + using CommandType = Command; + _push_internal(p_instance, p_method, std::forward(p_args)...); + } - /* PUSH AND RET COMMANDS */ - DECL_PUSH_AND_RET(0) - SPACE_SEP_LIST(DECL_PUSH_AND_RET, 15) + template + void push_and_sync(T *p_instance, M p_method, Args... p_args) { + // Standard command, sync. + using CommandType = Command; + _push_internal(p_instance, p_method, std::forward(p_args)...); + } - /* PUSH AND RET SYNC COMMANDS*/ - DECL_PUSH_AND_SYNC(0) - SPACE_SEP_LIST(DECL_PUSH_AND_SYNC, 15) + template + void push_and_ret(T *p_instance, M p_method, R *r_ret, Args... p_args) { + // Command with return value, sync. + using CommandType = CommandRet; + _push_internal(p_instance, p_method, r_ret, std::forward(p_args)...); + } _FORCE_INLINE_ void flush_if_pending() { if (unlikely(command_mem.size() > 0)) { @@ -450,20 +254,4 @@ class CommandQueueMT { ~CommandQueueMT(); }; -#undef ARG -#undef PARAM -#undef TYPE_PARAM -#undef PARAM_DECL -#undef DECL_CMD -#undef DECL_CMD_RET -#undef DECL_CMD_SYNC -#undef TYPE_ARG -#undef CMD_TYPE -#undef CMD_ASSIGN_PARAM -#undef DECL_PUSH -#undef CMD_RET_TYPE -#undef DECL_PUSH_AND_RET -#undef CMD_SYNC_TYPE -#undef DECL_CMD_SYNC - #endif // COMMAND_QUEUE_MT_H diff --git a/core/templates/pass_func.h b/core/templates/pass_func.h index 497d3bae5d7b..3e86327f15cd 100644 --- a/core/templates/pass_func.h +++ b/core/templates/pass_func.h @@ -31,70 +31,134 @@ #ifndef PASS_FUNC_H #define PASS_FUNC_H -#define PASS0R(m_r, m_name) \ - m_r m_name() { return PASSBASE->m_name(); } -#define PASS0RC(m_r, m_name) \ - m_r m_name() const { return PASSBASE->m_name(); } -#define PASS1R(m_r, m_name, m_type1) \ - m_r m_name(m_type1 arg1) { return PASSBASE->m_name(arg1); } -#define PASS1RC(m_r, m_name, m_type1) \ - m_r m_name(m_type1 arg1) const { return PASSBASE->m_name(arg1); } +#define PASS0R(m_r, m_name) \ + m_r m_name() { \ + return PASSBASE->m_name(); \ + } +#define PASS0RC(m_r, m_name) \ + m_r m_name() const { \ + return PASSBASE->m_name(); \ + } +#define PASS1R(m_r, m_name, m_type1) \ + m_r m_name(m_type1 arg1) { \ + return PASSBASE->m_name(arg1); \ + } +#define PASS1RC(m_r, m_name, m_type1) \ + m_r m_name(m_type1 arg1) const { \ + return PASSBASE->m_name(arg1); \ + } #define PASS2R(m_r, m_name, m_type1, m_type2) \ - m_r m_name(m_type1 arg1, m_type2 arg2) { return PASSBASE->m_name(arg1, arg2); } -#define PASS2RC(m_r, m_name, m_type1, m_type2) \ - m_r m_name(m_type1 arg1, m_type2 arg2) const { return PASSBASE->m_name(arg1, arg2); } -#define PASS3R(m_r, m_name, m_type1, m_type2, m_type3) \ - m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3) { return PASSBASE->m_name(arg1, arg2, arg3); } -#define PASS3RC(m_r, m_name, m_type1, m_type2, m_type3) \ - m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3) const { return PASSBASE->m_name(arg1, arg2, arg3); } -#define PASS4R(m_r, m_name, m_type1, m_type2, m_type3, m_type4) \ - m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4) { return PASSBASE->m_name(arg1, arg2, arg3, arg4); } -#define PASS4RC(m_r, m_name, m_type1, m_type2, m_type3, m_type4) \ - m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4) const { return PASSBASE->m_name(arg1, arg2, arg3, arg4); } -#define PASS5R(m_r, m_name, m_type1, m_type2, m_type3, m_type4, m_type5) \ - m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5) { return PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5); } -#define PASS5RC(m_r, m_name, m_type1, m_type2, m_type3, m_type4, m_type5) \ - m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5) const { return PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5); } -#define PASS6R(m_r, m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \ - m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6) { return PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6); } -#define PASS6RC(m_r, m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \ - m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6) const { return PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6); } + m_r m_name(m_type1 arg1, m_type2 arg2) { \ + return PASSBASE->m_name(arg1, arg2); \ + } +#define PASS2RC(m_r, m_name, m_type1, m_type2) \ + m_r m_name(m_type1 arg1, m_type2 arg2) const { \ + return PASSBASE->m_name(arg1, arg2); \ + } +#define PASS3R(m_r, m_name, m_type1, m_type2, m_type3) \ + m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3) { \ + return PASSBASE->m_name(arg1, arg2, arg3); \ + } +#define PASS3RC(m_r, m_name, m_type1, m_type2, m_type3) \ + m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3) const { \ + return PASSBASE->m_name(arg1, arg2, arg3); \ + } +#define PASS4R(m_r, m_name, m_type1, m_type2, m_type3, m_type4) \ + m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4) { \ + return PASSBASE->m_name(arg1, arg2, arg3, arg4); \ + } +#define PASS4RC(m_r, m_name, m_type1, m_type2, m_type3, m_type4) \ + m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4) const { \ + return PASSBASE->m_name(arg1, arg2, arg3, arg4); \ + } +#define PASS5R(m_r, m_name, m_type1, m_type2, m_type3, m_type4, m_type5) \ + m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5) { \ + return PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5); \ + } +#define PASS5RC(m_r, m_name, m_type1, m_type2, m_type3, m_type4, m_type5) \ + m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5) const { \ + return PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5); \ + } +#define PASS6R(m_r, m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \ + m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6) { \ + return PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6); \ + } +#define PASS6RC(m_r, m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \ + m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6) const { \ + return PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6); \ + } -#define PASS0(m_name) \ - void m_name() { PASSBASE->m_name(); } -#define PASS1(m_name, m_type1) \ - void m_name(m_type1 arg1) { PASSBASE->m_name(arg1); } -#define PASS1C(m_name, m_type1) \ - void m_name(m_type1 arg1) const { PASSBASE->m_name(arg1); } -#define PASS2(m_name, m_type1, m_type2) \ - void m_name(m_type1 arg1, m_type2 arg2) { PASSBASE->m_name(arg1, arg2); } -#define PASS2C(m_name, m_type1, m_type2) \ - void m_name(m_type1 arg1, m_type2 arg2) const { PASSBASE->m_name(arg1, arg2); } -#define PASS3(m_name, m_type1, m_type2, m_type3) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3) { PASSBASE->m_name(arg1, arg2, arg3); } -#define PASS4(m_name, m_type1, m_type2, m_type3, m_type4) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4) { PASSBASE->m_name(arg1, arg2, arg3, arg4); } -#define PASS5(m_name, m_type1, m_type2, m_type3, m_type4, m_type5) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5) { PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5); } -#define PASS6(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6) { PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6); } -#define PASS7(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7) { PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7); } -#define PASS8(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8) { PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } -#define PASS9(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9) { PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } -#define PASS10(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10) { PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } -#define PASS11(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11) { PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); } -#define PASS12(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12) { PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); } -#define PASS13(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12, m_type13) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12, m_type13 arg13) { PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); } -#define PASS14(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12, m_type13, m_type14) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12, m_type13 arg13, m_type14 arg14) { PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); } -#define PASS15(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12, m_type13, m_type14, m_type15) \ - void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12, m_type13 arg13, m_type14 arg14, m_type15 arg15) { PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); } +#define PASS0(m_name) \ + void m_name() { \ + PASSBASE->m_name(); \ + } +#define PASS1(m_name, m_type1) \ + void m_name(m_type1 arg1) { \ + PASSBASE->m_name(arg1); \ + } +#define PASS1C(m_name, m_type1) \ + void m_name(m_type1 arg1) const { \ + PASSBASE->m_name(arg1); \ + } +#define PASS2(m_name, m_type1, m_type2) \ + void m_name(m_type1 arg1, m_type2 arg2) { \ + PASSBASE->m_name(arg1, arg2); \ + } +#define PASS2C(m_name, m_type1, m_type2) \ + void m_name(m_type1 arg1, m_type2 arg2) const { \ + PASSBASE->m_name(arg1, arg2); \ + } +#define PASS3(m_name, m_type1, m_type2, m_type3) \ + void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3) { \ + PASSBASE->m_name(arg1, arg2, arg3); \ + } +#define PASS4(m_name, m_type1, m_type2, m_type3, m_type4) \ + void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4) { \ + PASSBASE->m_name(arg1, arg2, arg3, arg4); \ + } +#define PASS5(m_name, m_type1, m_type2, m_type3, m_type4, m_type5) \ + void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5) { \ + PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5); \ + } +#define PASS6(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \ + void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6) { \ + PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6); \ + } +#define PASS7(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7) \ + void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7) { \ + PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7); \ + } +#define PASS8(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8) \ + void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8) { \ + PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); \ + } +#define PASS9(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9) \ + void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9) { \ + PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); \ + } +#define PASS10(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10) \ + void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10) { \ + PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); \ + } +#define PASS11(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11) \ + void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11) { \ + PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); \ + } +#define PASS12(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12) \ + void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12) { \ + PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); \ + } +#define PASS13(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12, m_type13) \ + void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12, m_type13 arg13) { \ + PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); \ + } +#define PASS14(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12, m_type13, m_type14) \ + void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12, m_type13 arg13, m_type14 arg14) { \ + PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); \ + } +#define PASS15(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12, m_type13, m_type14, m_type15) \ + void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12, m_type13 arg13, m_type14 arg14, m_type15 arg15) { \ + PASSBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); \ + } #endif // PASS_FUNC_H diff --git a/core/templates/tuple.h b/core/templates/tuple.h new file mode 100644 index 000000000000..2825bd46ce5b --- /dev/null +++ b/core/templates/tuple.h @@ -0,0 +1,121 @@ +/**************************************************************************/ +/* tuple.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef TUPLE_H +#define TUPLE_H + +// Simple recursive Tuple type that has no runtime overhead. +// +// The compile-time recursion works as follows: +// Assume the following: Tuple my_tuple(42, 3.14f); +// This expands to a class hierarchy that inherits from the previous step. +// So in this case this leads to: +// - struct Tuple : Tuple <--- This contains the int value. +// - struct Tuple <--- This contains the float value. +// where each of the classes has a single field of the type for that step in the +// recursion. So: float value; int value; etc. +// +// This works by splitting up the parameter pack for each step in the recursion minus the first. +// so the the first step creates the "T value" from the first template parameter. +// any further template arguments end up in "Rest", which we then use to instantiate a new +// tuple, but now minus the first argument. To write this all out: +// +// Tuple +// step 1: Tuple T = int, Rest = float. Results in a Tuple : Tuple +// step 2: Tuple T = float, no Rest. Results in a Tuple +// +// tuple_get works through a similar recursion, using the inheritance chain to walk to the right node. +// In order to tuple_get<1>(my_tuple), from the example tuple above: +// +// 1. We want tuple_get<1> to return the float, which is one level "up" from Tuple : Tuple, +// (the real type of the Tuple "root"). +// 2. Since index 1 > 0, it casts the tuple to its parent type (Tuple). This works because +// we cast to Tuple which in this case is just float. +// 3. Now we're looking for index 0 in Tuple, which directly returns its value field. Note +// how get<0> is a template specialization. +// +// At compile time, this gets fully resolved. The compiler sees get<1>(my_tuple) and: +// 1. Creates TupleGet<1, Tuple>::tuple_get which contains the cast to Tuple. +// 2. Creates TupleGet<0, Tuple>::tuple_get which directly returns the value. +// 3. The compiler will then simply optimize all of this nonsense away and return the float directly. + +#include "core/typedefs.h" + +template +struct Tuple; + +template <> +struct Tuple<> {}; + +template +struct Tuple : Tuple { + T value; + + Tuple() = default; + + template + _FORCE_INLINE_ Tuple(F &&f, R &&...rest) : + Tuple(std::forward(rest)...), + value(std::forward(f)) {} +}; + +template +struct TupleGet; + +template +struct TupleGet<0, Tuple> { + _FORCE_INLINE_ static First &tuple_get(Tuple &t) { + return t.value; + } +}; + +// Rationale for using auto here is that the alternative is writing a +// helper struct to create an otherwise useless type. we would have to write +// a second recursive template chain like: TupleGetType>::type +// just to recover the type in the most baroque way possible. + +template +struct TupleGet> { + _FORCE_INLINE_ static auto &tuple_get(Tuple &t) { + return TupleGet>::tuple_get(static_cast &>(t)); + } +}; + +template +_FORCE_INLINE_ auto &tuple_get(Tuple &t) { + return TupleGet>::tuple_get(t); +} + +template +_FORCE_INLINE_ const auto &tuple_get(const Tuple &t) { + return TupleGet>::tuple_get(t); +} + +#endif // TUPLE_H diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h index 65f64841bdef..b6810930cca1 100644 --- a/core/variant/binder_common.h +++ b/core/variant/binder_common.h @@ -82,60 +82,72 @@ struct VariantCaster { } }; -#define VARIANT_ENUM_CAST(m_enum) \ - MAKE_ENUM_TYPE_INFO(m_enum) \ - template <> \ - struct VariantCaster { \ - static _FORCE_INLINE_ m_enum cast(const Variant &p_variant) { \ - return (m_enum)p_variant.operator int64_t(); \ - } \ - }; \ - template <> \ - struct PtrToArg { \ - _FORCE_INLINE_ static m_enum convert(const void *p_ptr) { \ - return m_enum(*reinterpret_cast(p_ptr)); \ - } \ - typedef int64_t EncodeT; \ - _FORCE_INLINE_ static void encode(m_enum p_val, const void *p_ptr) { \ - *(int64_t *)p_ptr = (int64_t)p_val; \ - } \ - }; \ - template <> \ - struct ZeroInitializer { \ - static void initialize(m_enum &value) { value = (m_enum)0; } \ - }; \ - template <> \ - struct VariantInternalAccessor { \ - static _FORCE_INLINE_ m_enum get(const Variant *v) { return m_enum(*VariantInternal::get_int(v)); } \ - static _FORCE_INLINE_ void set(Variant *v, m_enum p_value) { *VariantInternal::get_int(v) = (int64_t)p_value; } \ +#define VARIANT_ENUM_CAST(m_enum) \ + MAKE_ENUM_TYPE_INFO(m_enum) \ + template <> \ + struct VariantCaster { \ + static _FORCE_INLINE_ m_enum cast(const Variant &p_variant) { \ + return (m_enum)p_variant.operator int64_t(); \ + } \ + }; \ + template <> \ + struct PtrToArg { \ + _FORCE_INLINE_ static m_enum convert(const void *p_ptr) { \ + return m_enum(*reinterpret_cast(p_ptr)); \ + } \ + typedef int64_t EncodeT; \ + _FORCE_INLINE_ static void encode(m_enum p_val, const void *p_ptr) { \ + *(int64_t *)p_ptr = (int64_t)p_val; \ + } \ + }; \ + template <> \ + struct ZeroInitializer { \ + static void initialize(m_enum &value) { \ + value = (m_enum)0; \ + } \ + }; \ + template <> \ + struct VariantInternalAccessor { \ + static _FORCE_INLINE_ m_enum get(const Variant *v) { \ + return m_enum(*VariantInternal::get_int(v)); \ + } \ + static _FORCE_INLINE_ void set(Variant *v, m_enum p_value) { \ + *VariantInternal::get_int(v) = (int64_t)p_value; \ + } \ }; -#define VARIANT_BITFIELD_CAST(m_enum) \ - MAKE_BITFIELD_TYPE_INFO(m_enum) \ - template <> \ - struct VariantCaster> { \ - static _FORCE_INLINE_ BitField cast(const Variant &p_variant) { \ - return BitField(p_variant.operator int64_t()); \ - } \ - }; \ - template <> \ - struct PtrToArg> { \ - _FORCE_INLINE_ static BitField convert(const void *p_ptr) { \ - return BitField(*reinterpret_cast(p_ptr)); \ - } \ - typedef int64_t EncodeT; \ - _FORCE_INLINE_ static void encode(BitField p_val, const void *p_ptr) { \ - *(int64_t *)p_ptr = p_val; \ - } \ - }; \ - template <> \ - struct ZeroInitializer> { \ - static void initialize(BitField &value) { value = 0; } \ - }; \ - template <> \ - struct VariantInternalAccessor> { \ - static _FORCE_INLINE_ BitField get(const Variant *v) { return BitField(*VariantInternal::get_int(v)); } \ - static _FORCE_INLINE_ void set(Variant *v, BitField p_value) { *VariantInternal::get_int(v) = p_value.operator int64_t(); } \ +#define VARIANT_BITFIELD_CAST(m_enum) \ + MAKE_BITFIELD_TYPE_INFO(m_enum) \ + template <> \ + struct VariantCaster> { \ + static _FORCE_INLINE_ BitField cast(const Variant &p_variant) { \ + return BitField(p_variant.operator int64_t()); \ + } \ + }; \ + template <> \ + struct PtrToArg> { \ + _FORCE_INLINE_ static BitField convert(const void *p_ptr) { \ + return BitField(*reinterpret_cast(p_ptr)); \ + } \ + typedef int64_t EncodeT; \ + _FORCE_INLINE_ static void encode(BitField p_val, const void *p_ptr) { \ + *(int64_t *)p_ptr = p_val; \ + } \ + }; \ + template <> \ + struct ZeroInitializer> { \ + static void initialize(BitField &value) { \ + value = 0; \ + } \ + }; \ + template <> \ + struct VariantInternalAccessor> { \ + static _FORCE_INLINE_ BitField get(const Variant *v) { \ + return BitField(*VariantInternal::get_int(v)); \ + } \ + static _FORCE_INLINE_ void set(Variant *v, BitField p_value) { \ + *VariantInternal::get_int(v) = p_value.operator int64_t(); \ + } \ }; // Object enum casts must go here diff --git a/core/variant/native_ptr.h b/core/variant/native_ptr.h index 33ba03813271..e3d45e9d5f55 100644 --- a/core/variant/native_ptr.h +++ b/core/variant/native_ptr.h @@ -53,46 +53,70 @@ struct GDExtensionPtr { operator Variant() const { return uint64_t(data); } }; -#define GDVIRTUAL_NATIVE_PTR(m_type) \ - template <> \ - struct GDExtensionConstPtr { \ - const m_type *data = nullptr; \ - GDExtensionConstPtr() {} \ - GDExtensionConstPtr(const m_type *p_assign) { data = p_assign; } \ - static const char *get_name() { return "const " #m_type; } \ - operator const m_type *() const { return data; } \ - operator Variant() const { return uint64_t(data); } \ - }; \ - template <> \ - struct VariantCaster> { \ - static _FORCE_INLINE_ GDExtensionConstPtr cast(const Variant &p_variant) { \ - return GDExtensionConstPtr((const m_type *)p_variant.operator uint64_t()); \ - } \ - }; \ - template <> \ - struct VariantInternalAccessor> { \ - static _FORCE_INLINE_ const GDExtensionConstPtr &get(const Variant *v) { return *reinterpret_cast *>(VariantInternal::get_int(v)); } \ - static _FORCE_INLINE_ void set(Variant *v, const GDExtensionConstPtr &p_value) { *VariantInternal::get_int(v) = uint64_t(p_value.data); } \ - }; \ - template <> \ - struct GDExtensionPtr { \ - m_type *data = nullptr; \ - GDExtensionPtr() {} \ - GDExtensionPtr(m_type *p_assign) { data = p_assign; } \ - static const char *get_name() { return #m_type; } \ - operator m_type *() const { return data; } \ - operator Variant() const { return uint64_t(data); } \ - }; \ - template <> \ - struct VariantCaster> { \ - static _FORCE_INLINE_ GDExtensionPtr cast(const Variant &p_variant) { \ - return GDExtensionPtr((m_type *)p_variant.operator uint64_t()); \ - } \ - }; \ - template <> \ - struct VariantInternalAccessor> { \ - static _FORCE_INLINE_ const GDExtensionPtr &get(const Variant *v) { return *reinterpret_cast *>(VariantInternal::get_int(v)); } \ - static _FORCE_INLINE_ void set(Variant *v, const GDExtensionPtr &p_value) { *VariantInternal::get_int(v) = uint64_t(p_value.data); } \ +#define GDVIRTUAL_NATIVE_PTR(m_type) \ + template <> \ + struct GDExtensionConstPtr { \ + const m_type *data = nullptr; \ + GDExtensionConstPtr() {} \ + GDExtensionConstPtr(const m_type *p_assign) { \ + data = p_assign; \ + } \ + static const char *get_name() { \ + return "const " #m_type; \ + } \ + operator const m_type *() const { \ + return data; \ + } \ + operator Variant() const { \ + return uint64_t(data); \ + } \ + }; \ + template <> \ + struct VariantCaster> { \ + static _FORCE_INLINE_ GDExtensionConstPtr cast(const Variant &p_variant) { \ + return GDExtensionConstPtr((const m_type *)p_variant.operator uint64_t()); \ + } \ + }; \ + template <> \ + struct VariantInternalAccessor> { \ + static _FORCE_INLINE_ const GDExtensionConstPtr &get(const Variant *v) { \ + return *reinterpret_cast *>(VariantInternal::get_int(v)); \ + } \ + static _FORCE_INLINE_ void set(Variant *v, const GDExtensionConstPtr &p_value) { \ + *VariantInternal::get_int(v) = uint64_t(p_value.data); \ + } \ + }; \ + template <> \ + struct GDExtensionPtr { \ + m_type *data = nullptr; \ + GDExtensionPtr() {} \ + GDExtensionPtr(m_type *p_assign) { \ + data = p_assign; \ + } \ + static const char *get_name() { \ + return #m_type; \ + } \ + operator m_type *() const { \ + return data; \ + } \ + operator Variant() const { \ + return uint64_t(data); \ + } \ + }; \ + template <> \ + struct VariantCaster> { \ + static _FORCE_INLINE_ GDExtensionPtr cast(const Variant &p_variant) { \ + return GDExtensionPtr((m_type *)p_variant.operator uint64_t()); \ + } \ + }; \ + template <> \ + struct VariantInternalAccessor> { \ + static _FORCE_INLINE_ const GDExtensionPtr &get(const Variant *v) { \ + return *reinterpret_cast *>(VariantInternal::get_int(v)); \ + } \ + static _FORCE_INLINE_ void set(Variant *v, const GDExtensionPtr &p_value) { \ + *VariantInternal::get_int(v) = uint64_t(p_value.data); \ + } \ }; template diff --git a/core/variant/type_info.h b/core/variant/type_info.h index 6bb703f2dd6e..c05f6b0be0c8 100644 --- a/core/variant/type_info.h +++ b/core/variant/type_info.h @@ -319,10 +319,12 @@ struct ZeroInitializer { static void initialize(T *&value) { value = nullptr; } }; -#define ZERO_INITIALIZER_NUMBER(m_type) \ - template <> \ - struct ZeroInitializer { \ - static void initialize(m_type &value) { value = 0; } \ +#define ZERO_INITIALIZER_NUMBER(m_type) \ + template <> \ + struct ZeroInitializer { \ + static void initialize(m_type &value) { \ + value = 0; \ + } \ }; ZERO_INITIALIZER_NUMBER(uint8_t) diff --git a/core/variant/variant.h b/core/variant/variant.h index 736e03264b29..ede1535e0c1c 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -275,53 +275,53 @@ class Variant { void _clear_internal(); - _FORCE_INLINE_ void clear() { - static const bool needs_deinit[Variant::VARIANT_MAX] = { - false, //NIL, - false, //BOOL, - false, //INT, - false, //FLOAT, - true, //STRING, - false, //VECTOR2, - false, //VECTOR2I, - false, //RECT2, - false, //RECT2I, - false, //VECTOR3, - false, //VECTOR3I, - true, //TRANSFORM2D, - false, //VECTOR4, - false, //VECTOR4I, - false, //PLANE, - false, //QUATERNION, - true, //AABB, - true, //BASIS, - true, //TRANSFORM, - true, //PROJECTION, - - // misc types - false, //COLOR, - true, //STRING_NAME, - true, //NODE_PATH, - false, //RID, - true, //OBJECT, - true, //CALLABLE, - true, //SIGNAL, - true, //DICTIONARY, - true, //ARRAY, - - // typed arrays - true, //PACKED_BYTE_ARRAY, - true, //PACKED_INT32_ARRAY, - true, //PACKED_INT64_ARRAY, - true, //PACKED_FLOAT32_ARRAY, - true, //PACKED_FLOAT64_ARRAY, - true, //PACKED_STRING_ARRAY, - true, //PACKED_VECTOR2_ARRAY, - true, //PACKED_VECTOR3_ARRAY, - true, //PACKED_COLOR_ARRAY, - true, //PACKED_VECTOR4_ARRAY, - }; + static constexpr bool needs_deinit[Variant::VARIANT_MAX] = { + false, //NIL, + false, //BOOL, + false, //INT, + false, //FLOAT, + true, //STRING, + false, //VECTOR2, + false, //VECTOR2I, + false, //RECT2, + false, //RECT2I, + false, //VECTOR3, + false, //VECTOR3I, + true, //TRANSFORM2D, + false, //VECTOR4, + false, //VECTOR4I, + false, //PLANE, + false, //QUATERNION, + true, //AABB, + true, //BASIS, + true, //TRANSFORM, + true, //PROJECTION, + + // misc types + false, //COLOR, + true, //STRING_NAME, + true, //NODE_PATH, + false, //RID, + true, //OBJECT, + true, //CALLABLE, + true, //SIGNAL, + true, //DICTIONARY, + true, //ARRAY, + + // typed arrays + true, //PACKED_BYTE_ARRAY, + true, //PACKED_INT32_ARRAY, + true, //PACKED_INT64_ARRAY, + true, //PACKED_FLOAT32_ARRAY, + true, //PACKED_FLOAT64_ARRAY, + true, //PACKED_STRING_ARRAY, + true, //PACKED_VECTOR2_ARRAY, + true, //PACKED_VECTOR3_ARRAY, + true, //PACKED_COLOR_ARRAY, + true, //PACKED_VECTOR4_ARRAY, + }; + _FORCE_INLINE_ void clear() { if (unlikely(needs_deinit[type])) { // Make it fast for types that don't need deinit. _clear_internal(); } @@ -832,7 +832,9 @@ class Variant { } _FORCE_INLINE_ Variant() {} _FORCE_INLINE_ ~Variant() { - clear(); + if (unlikely(needs_deinit[type])) { // Make it fast for types that don't need deinit. + _clear_internal(); + } } }; diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index d612cb9cead1..5f6eb8399a27 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -2104,11 +2104,12 @@ static void _register_variant_builtin_methods_math() { bind_static_method(Color, hex64, sarray("hex"), varray()); bind_static_method(Color, html, sarray("rgba"), varray()); bind_static_method(Color, html_is_valid, sarray("color"), varray()); + bind_static_method(Color, from_string, sarray("str", "default"), varray()); bind_static_method(Color, from_hsv, sarray("h", "s", "v", "alpha"), varray(1.0)); bind_static_method(Color, from_ok_hsl, sarray("h", "s", "l", "alpha"), varray(1.0)); - bind_static_method(Color, from_rgbe9995, sarray("rgbe"), varray()); + bind_static_method(Color, from_rgba8, sarray("r8", "g8", "b8", "a8"), varray(255)); } static void _register_variant_builtin_methods_misc() { diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h index 58652d26e0c2..9a40dcec84af 100644 --- a/core/variant/variant_internal.h +++ b/core/variant/variant_internal.h @@ -831,11 +831,15 @@ struct VariantInternalAccessor { static _FORCE_INLINE_ void set(Variant *v, bool p_value) { *VariantInternal::get_bool(v) = p_value; } }; -#define VARIANT_ACCESSOR_NUMBER(m_type) \ - template <> \ - struct VariantInternalAccessor { \ - static _FORCE_INLINE_ m_type get(const Variant *v) { return (m_type) * VariantInternal::get_int(v); } \ - static _FORCE_INLINE_ void set(Variant *v, m_type p_value) { *VariantInternal::get_int(v) = p_value; } \ +#define VARIANT_ACCESSOR_NUMBER(m_type) \ + template <> \ + struct VariantInternalAccessor { \ + static _FORCE_INLINE_ m_type get(const Variant *v) { \ + return (m_type) * VariantInternal::get_int(v); \ + } \ + static _FORCE_INLINE_ void set(Variant *v, m_type p_value) { \ + *VariantInternal::get_int(v) = p_value; \ + } \ }; VARIANT_ACCESSOR_NUMBER(int8_t) @@ -1130,10 +1134,12 @@ struct VariantInitializer { static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic(v); } }; -#define INITIALIZER_INT(m_type) \ - template <> \ - struct VariantInitializer { \ - static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic(v); } \ +#define INITIALIZER_INT(m_type) \ + template <> \ + struct VariantInitializer { \ + static _FORCE_INLINE_ void init(Variant *v) { \ + VariantInternal::init_generic(v); \ + } \ }; INITIALIZER_INT(uint8_t) diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp index 560067fc0889..21fd12d24643 100644 --- a/core/variant/variant_setget.cpp +++ b/core/variant/variant_setget.cpp @@ -390,9 +390,15 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const { OOB_TEST(index, v.size()); \ v.write[index] = PtrToArg::convert(member); \ } \ - static Variant::Type get_index_type() { return GetTypeInfo::VARIANT_TYPE; } \ - static uint32_t get_index_usage() { return GetTypeInfo::get_class_info().usage; } \ - static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr::get_ptr(base)->size(); } \ + static Variant::Type get_index_type() { \ + return GetTypeInfo::VARIANT_TYPE; \ + } \ + static uint32_t get_index_usage() { \ + return GetTypeInfo::get_class_info().usage; \ + } \ + static uint64_t get_indexed_size(const Variant *base) { \ + return VariantGetInternalPtr::get_ptr(base)->size(); \ + } \ }; #define INDEXED_SETGET_STRUCT_TYPED_NUMERIC(m_base_type, m_elem_type, m_assign_type) \ @@ -462,9 +468,15 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const { OOB_TEST(index, v.size()); \ v.write[index] = PtrToArg::convert(member); \ } \ - static Variant::Type get_index_type() { return GetTypeInfo::VARIANT_TYPE; } \ - static uint32_t get_index_usage() { return GetTypeInfo::get_class_info().usage; } \ - static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr::get_ptr(base)->size(); } \ + static Variant::Type get_index_type() { \ + return GetTypeInfo::VARIANT_TYPE; \ + } \ + static uint32_t get_index_usage() { \ + return GetTypeInfo::get_class_info().usage; \ + } \ + static uint64_t get_indexed_size(const Variant *base) { \ + return VariantGetInternalPtr::get_ptr(base)->size(); \ + } \ }; #define INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(m_base_type, m_elem_type, m_assign_type, m_max) \ @@ -518,9 +530,15 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const { OOB_TEST(index, m_max); \ v[index] = PtrToArg::convert(member); \ } \ - static Variant::Type get_index_type() { return GetTypeInfo::VARIANT_TYPE; } \ - static uint32_t get_index_usage() { return GetTypeInfo::get_class_info().usage; } \ - static uint64_t get_indexed_size(const Variant *base) { return m_max; } \ + static Variant::Type get_index_type() { \ + return GetTypeInfo::VARIANT_TYPE; \ + } \ + static uint32_t get_index_usage() { \ + return GetTypeInfo::get_class_info().usage; \ + } \ + static uint64_t get_indexed_size(const Variant *base) { \ + return m_max; \ + } \ }; #define INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(m_base_type, m_elem_type, m_accessor, m_max) \ @@ -568,9 +586,15 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const { OOB_TEST(index, m_max); \ v m_accessor[index] = PtrToArg::convert(member); \ } \ - static Variant::Type get_index_type() { return GetTypeInfo::VARIANT_TYPE; } \ - static uint32_t get_index_usage() { return GetTypeInfo::get_class_info().usage; } \ - static uint64_t get_indexed_size(const Variant *base) { return m_max; } \ + static Variant::Type get_index_type() { \ + return GetTypeInfo::VARIANT_TYPE; \ + } \ + static uint32_t get_index_usage() { \ + return GetTypeInfo::get_class_info().usage; \ + } \ + static uint64_t get_indexed_size(const Variant *base) { \ + return m_max; \ + } \ }; #define INDEXED_SETGET_STRUCT_BULTIN_FUNC(m_base_type, m_elem_type, m_set, m_get, m_max) \ @@ -618,9 +642,15 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const { OOB_TEST(index, m_max); \ v.m_set(index, PtrToArg::convert(member)); \ } \ - static Variant::Type get_index_type() { return GetTypeInfo::VARIANT_TYPE; } \ - static uint32_t get_index_usage() { return GetTypeInfo::get_class_info().usage; } \ - static uint64_t get_indexed_size(const Variant *base) { return m_max; } \ + static Variant::Type get_index_type() { \ + return GetTypeInfo::VARIANT_TYPE; \ + } \ + static uint32_t get_index_usage() { \ + return GetTypeInfo::get_class_info().usage; \ + } \ + static uint64_t get_indexed_size(const Variant *base) { \ + return m_max; \ + } \ }; struct VariantIndexedSetGet_Array { diff --git a/core/variant/variant_setget.h b/core/variant/variant_setget.h index 9b8c99fdaa5d..dc06c3f3747c 100644 --- a/core/variant/variant_setget.h +++ b/core/variant/variant_setget.h @@ -67,7 +67,9 @@ b.m_member = PtrToArg::convert(member); \ PtrToArg::encode(b, base); \ } \ - static Variant::Type get_type() { return GetTypeInfo::VARIANT_TYPE; } \ + static Variant::Type get_type() { \ + return GetTypeInfo::VARIANT_TYPE; \ + } \ }; #define SETGET_NUMBER_STRUCT(m_base_type, m_member_type, m_member) \ @@ -101,7 +103,9 @@ b.m_member = PtrToArg::convert(member); \ PtrToArg::encode(b, base); \ } \ - static Variant::Type get_type() { return GetTypeInfo::VARIANT_TYPE; } \ + static Variant::Type get_type() { \ + return GetTypeInfo::VARIANT_TYPE; \ + } \ }; #define SETGET_STRUCT_CUSTOM(m_base_type, m_member_type, m_member, m_custom) \ @@ -132,7 +136,9 @@ b.m_custom = PtrToArg::convert(member); \ PtrToArg::encode(b, base); \ } \ - static Variant::Type get_type() { return GetTypeInfo::VARIANT_TYPE; } \ + static Variant::Type get_type() { \ + return GetTypeInfo::VARIANT_TYPE; \ + } \ }; #define SETGET_NUMBER_STRUCT_CUSTOM(m_base_type, m_member_type, m_member, m_custom) \ @@ -166,7 +172,9 @@ b.m_custom = PtrToArg::convert(member); \ PtrToArg::encode(b, base); \ } \ - static Variant::Type get_type() { return GetTypeInfo::VARIANT_TYPE; } \ + static Variant::Type get_type() { \ + return GetTypeInfo::VARIANT_TYPE; \ + } \ }; #define SETGET_STRUCT_FUNC(m_base_type, m_member_type, m_member, m_setter, m_getter) \ @@ -197,7 +205,9 @@ b.m_setter(PtrToArg::convert(member)); \ PtrToArg::encode(b, base); \ } \ - static Variant::Type get_type() { return GetTypeInfo::VARIANT_TYPE; } \ + static Variant::Type get_type() { \ + return GetTypeInfo::VARIANT_TYPE; \ + } \ }; #define SETGET_NUMBER_STRUCT_FUNC(m_base_type, m_member_type, m_member, m_setter, m_getter) \ @@ -231,7 +241,9 @@ b.m_setter(PtrToArg::convert(member)); \ PtrToArg::encode(b, base); \ } \ - static Variant::Type get_type() { return GetTypeInfo::VARIANT_TYPE; } \ + static Variant::Type get_type() { \ + return GetTypeInfo::VARIANT_TYPE; \ + } \ }; #define SETGET_STRUCT_FUNC_INDEX(m_base_type, m_member_type, m_member, m_setter, m_getter, m_index) \ @@ -262,7 +274,9 @@ b.m_setter(m_index, PtrToArg::convert(member)); \ PtrToArg::encode(b, base); \ } \ - static Variant::Type get_type() { return GetTypeInfo::VARIANT_TYPE; } \ + static Variant::Type get_type() { \ + return GetTypeInfo::VARIANT_TYPE; \ + } \ }; SETGET_NUMBER_STRUCT(Vector2, double, x) diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp index 50932afbb672..ec9492ac5d1c 100644 --- a/core/variant/variant_utility.cpp +++ b/core/variant/variant_utility.cpp @@ -1370,8 +1370,12 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { static bool has_return_type() { \ return true; \ } \ - static bool is_vararg() { return false; } \ - static Variant::UtilityFunctionType get_type() { return m_category; } \ + static bool is_vararg() { \ + return false; \ + } \ + static Variant::UtilityFunctionType get_type() { \ + return m_category; \ + } \ }; \ register_utility_function(#m_func, m_args) @@ -1402,8 +1406,12 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { static bool has_return_type() { \ return true; \ } \ - static bool is_vararg() { return false; } \ - static Variant::UtilityFunctionType get_type() { return m_category; } \ + static bool is_vararg() { \ + return false; \ + } \ + static Variant::UtilityFunctionType get_type() { \ + return m_category; \ + } \ }; \ register_utility_function(#m_func, m_args) @@ -1436,8 +1444,12 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { static bool has_return_type() { \ return true; \ } \ - static bool is_vararg() { return false; } \ - static Variant::UtilityFunctionType get_type() { return m_category; } \ + static bool is_vararg() { \ + return false; \ + } \ + static Variant::UtilityFunctionType get_type() { \ + return m_category; \ + } \ }; \ register_utility_function(#m_func, m_args) @@ -1470,8 +1482,12 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { static bool has_return_type() { \ return true; \ } \ - static bool is_vararg() { return false; } \ - static Variant::UtilityFunctionType get_type() { return m_category; } \ + static bool is_vararg() { \ + return false; \ + } \ + static Variant::UtilityFunctionType get_type() { \ + return m_category; \ + } \ }; \ register_utility_function(#m_func, m_args) @@ -1633,8 +1649,12 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { static bool has_return_type() { \ return false; \ } \ - static bool is_vararg() { return false; } \ - static Variant::UtilityFunctionType get_type() { return m_category; } \ + static bool is_vararg() { \ + return false; \ + } \ + static Variant::UtilityFunctionType get_type() { \ + return m_category; \ + } \ }; \ register_utility_function(#m_func, m_args) diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index da1f337ef883..fb2dfa3dde55 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -388,9 +388,9 @@ Returns a human-readable name for the given [enum Error] code. [codeblock] print(OK) # Prints 0 - print(error_string(OK)) # Prints OK - print(error_string(ERR_BUSY)) # Prints Busy - print(error_string(ERR_OUT_OF_MEMORY)) # Prints Out of memory + print(error_string(OK)) # Prints "OK" + print(error_string(ERR_BUSY)) # Prints "Busy" + print(error_string(ERR_OUT_OF_MEMORY)) # Prints "Out of memory" [/codeblock] @@ -495,23 +495,23 @@ Returns the [Object] that corresponds to [param instance_id]. All Objects have a unique instance ID. See also [method Object.get_instance_id]. [codeblocks] [gdscript] - var foo = "bar" + var drink = "water" func _ready(): var id = get_instance_id() - var inst = instance_from_id(id) - print(inst.foo) # Prints bar + var instance = instance_from_id(id) + print(instance.foo) # Prints "water" [/gdscript] [csharp] public partial class MyNode : Node { - public string Foo { get; set; } = "bar"; + public string Drink { get; set; } = "water"; public override void _Ready() { ulong id = GetInstanceId(); - var inst = (MyNode)InstanceFromId(Id); - GD.Print(inst.Foo); // Prints bar + var instance = (MyNode)InstanceFromId(Id); + GD.Print(instance.Drink); // Prints "water" } } [/csharp] @@ -850,11 +850,11 @@ [codeblocks] [gdscript] var a = [1, 2, 3] - print("a", "b", a) # Prints ab[1, 2, 3] + print("a", "b", a) # Prints "ab[1, 2, 3]" [/gdscript] [csharp] Godot.Collections.Array a = [1, 2, 3]; - GD.Print("a", "b", a); // Prints ab[1, 2, 3] + GD.Print("a", "b", a); // Prints "ab[1, 2, 3]" [/csharp] [/codeblocks] [b]Note:[/b] Consider using [method push_error] and [method push_warning] to print error and warning messages instead of [method print] or [method print_rich]. This distinguishes them from print messages used for debugging purposes, while also displaying a stack trace when an error or warning is printed. See also [member Engine.print_to_stdout] and [member ProjectSettings.application/run/disable_stdout]. @@ -869,10 +869,10 @@ When printing to standard output, the supported subset of BBCode is converted to ANSI escape codes for the terminal emulator to display. Support for ANSI escape codes varies across terminal emulators, especially for italic and strikethrough. In standard output, [code]code[/code] is represented with faint text but without any font change. Unsupported tags are left as-is in standard output. [codeblocks] [gdscript skip-lint] - print_rich("[color=green][b]Hello world![/b][/color]") # Prints out "Hello world!" in green with a bold font + print_rich("[color=green][b]Hello world![/b][/color]") # Prints "Hello world!", in green with a bold font. [/gdscript] [csharp skip-lint] - GD.PrintRich("[color=green][b]Hello world![/b][/color]"); // Prints out "Hello world!" in green with a bold font + GD.PrintRich("[color=green][b]Hello world![/b][/color]"); // Prints "Hello world!", in green with a bold font. [/csharp] [/codeblocks] [b]Note:[/b] Consider using [method push_error] and [method push_warning] to print error and warning messages instead of [method print] or [method print_rich]. This distinguishes them from print messages used for debugging purposes, while also displaying a stack trace when an error or warning is printed. @@ -907,16 +907,16 @@ [b]Note:[/b] The OS terminal is [i]not[/i] the same as the editor's Output dock. The output sent to the OS terminal can be seen when running Godot from a terminal. On Windows, this requires using the [code]console.exe[/code] executable. [codeblocks] [gdscript] + # Prints "ABC" to terminal. printraw("A") printraw("B") printraw("C") - # Prints ABC to terminal [/gdscript] [csharp] + // Prints "ABC" to terminal. GD.PrintRaw("A"); GD.PrintRaw("B"); GD.PrintRaw("C"); - // Prints ABC to terminal [/csharp] [/codeblocks] @@ -927,10 +927,10 @@ Prints one or more arguments to the console with a space between each argument. [codeblocks] [gdscript] - prints("A", "B", "C") # Prints A B C + prints("A", "B", "C") # Prints "A B C" [/gdscript] [csharp] - GD.PrintS("A", "B", "C"); // Prints A B C + GD.PrintS("A", "B", "C"); // Prints "A B C" [/csharp] [/codeblocks] @@ -941,10 +941,10 @@ Prints one or more arguments to the console with a tab between each argument. [codeblocks] [gdscript] - printt("A", "B", "C") # Prints A B C + printt("A", "B", "C") # Prints "A B C" [/gdscript] [csharp] - GD.PrintT("A", "B", "C"); // Prints A B C + GD.PrintT("A", "B", "C"); // Prints "A B C" [/csharp] [/codeblocks] @@ -955,10 +955,10 @@ Pushes an error message to Godot's built-in debugger and to the OS terminal. [codeblocks] [gdscript] - push_error("test error") # Prints "test error" to debugger and terminal as error call + push_error("test error") # Prints "test error" to debugger and terminal as an error. [/gdscript] [csharp] - GD.PushError("test error"); // Prints "test error" to debugger and terminal as error call + GD.PushError("test error"); // Prints "test error" to debugger and terminal as an error. [/csharp] [/codeblocks] [b]Note:[/b] This function does not pause project execution. To print an error message and pause project execution in debug builds, use [code]assert(false, "test error")[/code] instead. @@ -970,10 +970,10 @@ Pushes a warning message to Godot's built-in debugger and to the OS terminal. [codeblocks] [gdscript] - push_warning("test warning") # Prints "test warning" to debugger and terminal as warning call + push_warning("test warning") # Prints "test warning" to debugger and terminal as a warning. [/gdscript] [csharp] - GD.PushWarning("test warning"); // Prints "test warning" to debugger and terminal as warning call + GD.PushWarning("test warning"); // Prints "test warning" to debugger and terminal as a warning. [/csharp] [/codeblocks] @@ -1413,9 +1413,9 @@ Returns a human-readable name of the given [param type], using the [enum Variant.Type] values. [codeblock] - print(TYPE_INT) # Prints 2. - print(type_string(TYPE_INT)) # Prints "int". - print(type_string(TYPE_STRING)) # Prints "String". + print(TYPE_INT) # Prints 2 + print(type_string(TYPE_INT)) # Prints "int" + print(type_string(TYPE_STRING)) # Prints "String" [/codeblock] See also [method typeof]. @@ -1429,10 +1429,10 @@ var json = JSON.new() json.parse('["a", "b", "c"]') var result = json.get_data() - if typeof(result) == TYPE_ARRAY: - print(result[0]) # Prints a + if result is Array: + print(result[0]) # Prints "a" else: - print("Unexpected result") + print("Unexpected result!") [/codeblock] See also [method type_string]. diff --git a/doc/classes/AStarGrid2D.xml b/doc/classes/AStarGrid2D.xml index ac37a18a420c..1f96eb386e61 100644 --- a/doc/classes/AStarGrid2D.xml +++ b/doc/classes/AStarGrid2D.xml @@ -20,8 +20,8 @@ astarGrid.Region = new Rect2I(0, 0, 32, 32); astarGrid.CellSize = new Vector2I(16, 16); astarGrid.Update(); - GD.Print(astarGrid.GetIdPath(Vector2I.Zero, new Vector2I(3, 4))); // prints (0, 0), (1, 1), (2, 2), (3, 3), (3, 4) - GD.Print(astarGrid.GetPointPath(Vector2I.Zero, new Vector2I(3, 4))); // prints (0, 0), (16, 16), (32, 32), (48, 48), (48, 64) + GD.Print(astarGrid.GetIdPath(Vector2I.Zero, new Vector2I(3, 4))); // Prints [(0, 0), (1, 1), (2, 2), (3, 3), (3, 4)] + GD.Print(astarGrid.GetPointPath(Vector2I.Zero, new Vector2I(3, 4))); // Prints [(0, 0), (16, 16), (32, 32), (48, 48), (48, 64)] [/csharp] [/codeblocks] To remove a point from the pathfinding grid, it must be set as "solid" with [method set_point_solid]. diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index 4cc68c518894..3ffb2c98c51e 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -410,7 +410,7 @@ return number % 2 == 0 func _ready(): - print([1, 3, 4, 7].find_custom(is_even.bind())) # prints 2 + print([1, 3, 4, 7].find_custom(is_even.bind())) # Prints 2 [/gdscript] [/codeblocks] @@ -637,10 +637,10 @@ If [method max] is not desirable, this method may also be used to implement a custom comparator: [codeblock] func _ready(): - var arr = [Vector2(5, 0), Vector2(3, 4), Vector2(1, 2)] + var arr = [Vector2i(5, 0), Vector2i(3, 4), Vector2i(1, 2)] var longest_vec = arr.reduce(func(max, vec): return vec if is_length_greater(vec, max) else max) - print(longest_vec) # Prints Vector2(3, 4). + print(longest_vec) # Prints (3, 4) func is_length_greater(a, b): return a.length() > b.length() @@ -652,11 +652,11 @@ func _ready(): var arr = [1, 2, 3, 4, 5] - # Increment count if it's even, else leaves count the same. + # If the current element is even, increment count, otherwise leave count the same. var even_count = arr.reduce(func(count, next): return count + 1 if is_even(next) else count, 0) print(even_count) # Prints 2 [/codeblock] - See also [method map], [method filter], [method any] and [method all]. + See also [method map], [method filter], [method any], and [method all]. diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml index 4f61d3843ef3..01d0d105005f 100644 --- a/doc/classes/ArrayMesh.xml +++ b/doc/classes/ArrayMesh.xml @@ -72,7 +72,7 @@ The [param arrays] argument is an array of arrays. Each of the [constant Mesh.ARRAY_MAX] elements contains an array with some of the mesh data for this surface as described by the corresponding member of [enum Mesh.ArrayType] or [code]null[/code] if it is not used by the surface. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this surface into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used. The [param blend_shapes] argument is an array of vertex data for each blend shape. Each element is an array of the same structure as [param arrays], but [constant Mesh.ARRAY_VERTEX], [constant Mesh.ARRAY_NORMAL], and [constant Mesh.ARRAY_TANGENT] are set if and only if they are set in [param arrays] and all other entries are [code]null[/code]. The [param lods] argument is a dictionary with [float] keys and [PackedInt32Array] values. Each entry in the dictionary represents an LOD level of the surface, where the value is the [constant Mesh.ARRAY_INDEX] array to use for the LOD level and the key is roughly proportional to the distance at which the LOD stats being used. I.e., increasing the key of an LOD also increases the distance that the objects has to be from the camera before the LOD is used. - The [param flags] argument is the bitwise or of, as required: One value of [enum Mesh.ArrayCustomFormat] left shifted by [code]ARRAY_FORMAT_CUSTOMn_SHIFT[/code] for each custom channel in use, [constant Mesh.ARRAY_FLAG_USE_DYNAMIC_UPDATE], [constant Mesh.ARRAY_FLAG_USE_8_BONE_WEIGHTS], or [constant Mesh.ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY]. + The [param flags] argument is the bitwise OR of, as required: One value of [enum Mesh.ArrayCustomFormat] left shifted by [code]ARRAY_FORMAT_CUSTOMn_SHIFT[/code] for each custom channel in use, [constant Mesh.ARRAY_FLAG_USE_DYNAMIC_UPDATE], [constant Mesh.ARRAY_FLAG_USE_8_BONE_WEIGHTS], or [constant Mesh.ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY]. [b]Note:[/b] When using indices, it is recommended to only use points, lines, or triangles. diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml index 81f63addd4a5..64afdff7ceb0 100644 --- a/doc/classes/Basis.xml +++ b/doc/classes/Basis.xml @@ -214,7 +214,8 @@ Creates a new [Basis] with a rotation such that the forward axis (-Z) points towards the [param target] position. By default, the -Z axis (camera forward) is treated as forward (implies +X is right). If [param use_model_front] is [code]true[/code], the +Z axis (asset front) is treated as forward (implies +X is left) and points toward the [param target] position. - The up axis (+Y) points as close to the [param up] vector as possible while staying perpendicular to the forward axis. The returned basis is orthonormalized (see [method orthonormalized]). The [param target] and [param up] vectors cannot be [constant Vector3.ZERO], and cannot be parallel to each other. + The up axis (+Y) points as close to the [param up] vector as possible while staying perpendicular to the forward axis. The returned basis is orthonormalized (see [method orthonormalized]). + The [param target] and the [param up] cannot be [constant Vector3.ZERO], and shouldn't be colinear to avoid unintended rotation around local Z axis. diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml index d5978a42f6da..6c8d26df8b9e 100644 --- a/doc/classes/Callable.xml +++ b/doc/classes/Callable.xml @@ -13,7 +13,7 @@ func test(): var callable = Callable(self, "print_args") callable.call("hello", "world") # Prints "hello world ". - callable.call(Vector2.UP, 42, callable) # Prints "(0.0, -1.0) 42 Node(node.gd)::print_args". + callable.call(Vector2.UP, 42, callable) # Prints "(0.0, -1.0) 42 Node(node.gd)::print_args" callable.call("invalid") # Invalid call, should have at least 2 arguments. [/gdscript] [csharp] @@ -28,7 +28,7 @@ // Invalid calls fail silently. Callable callable = new Callable(this, MethodName.PrintArgs); callable.Call("hello", "world"); // Default parameter values are not supported, should have 3 arguments. - callable.Call(Vector2.Up, 42, callable); // Prints "(0, -1) 42 Node(Node.cs)::PrintArgs". + callable.Call(Vector2.Up, 42, callable); // Prints "(0, -1) 42 Node(Node.cs)::PrintArgs" callable.Call("invalid"); // Invalid call, should have 3 arguments. } [/csharp] @@ -39,7 +39,7 @@ var my_lambda = func (message): print(message) - # Prints Hello everyone! + # Prints "Hello everyone!" my_lambda.call("Hello everyone!") # Prints "Attack!", when the button_pressed signal is emitted. diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml index 546d90fa3c4f..5434b5ed5915 100644 --- a/doc/classes/Color.xml +++ b/doc/classes/Color.xml @@ -177,6 +177,22 @@ [/codeblocks] + + + + + + + + Returns a [Color] constructed from red ([param r8]), green ([param g8]), blue ([param b8]), and optionally alpha ([param a8]) integer channels, each divided by [code]255.0[/code] for their final value. + [codeblock] + var red = Color.from_rgba8(255, 0, 0) # Same as Color(1, 0, 0). + var dark_blue = Color.from_rgba8(0, 0, 51) # Same as Color(0, 0, 0.2). + var my_color = Color.from_rgba8(306, 255, 0, 102) # Same as Color(1.2, 1, 0, 0.4). + [/codeblock] + [b]Note:[/b] Due to the lower precision of [method from_rgba8] compared to the standard [Color] constructor, a color created with [method from_rgba8] will generally not be equal to the same color created with the standard [Color] constructor. Use [method is_equal_approx] for comparisons to avoid issues with floating-point precision error. + + diff --git a/doc/classes/EditorContextMenuPlugin.xml b/doc/classes/EditorContextMenuPlugin.xml index fb90a2a5cd66..ee67b8f97f9a 100644 --- a/doc/classes/EditorContextMenuPlugin.xml +++ b/doc/classes/EditorContextMenuPlugin.xml @@ -61,7 +61,7 @@ popup_menu.add_item("White") popup_menu.id_pressed.connect(_on_color_submenu_option) - add_context_menu_item("Set Node Color", popup_menu) + add_context_submenu_item("Set Node Color", popup_menu) [/codeblock] diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml index b8b69586fe95..d4acb820232f 100644 --- a/doc/classes/EditorInterface.xml +++ b/doc/classes/EditorInterface.xml @@ -278,7 +278,6 @@ - Pops up an editor dialog for creating an object. The [param callback] must take a single argument of type [StringName] which will contain the type name of the selected object or be empty if no item is selected. @@ -286,17 +285,6 @@ The [param current_type] will be passed in the search box of the create dialog, and the specified type can be immediately selected when the dialog pops up. If the [param current_type] is not derived from [param base_type], there will be no result of the type in the dialog. The [param dialog_title] allows you to define a custom title for the dialog. This is useful if you want to accurately hint the usage of the dialog. If the [param dialog_title] is an empty string, the dialog will use "Create New 'Base Type'" as the default title. The [param type_blocklist] contains a list of type names, and the types in the blocklist will be hidden from the create dialog. - The [param type_suffixes] is a dictionary, with keys being [StringName]s and values being [String]s. Custom suffixes override the default suffixes which are file names of their scripts. For example, if you set a custom suffix as "Custom Suffix" for a global script type, - [codeblock lang=text] - Node - |- MyCustomNode (my_custom_node.gd) - [/codeblock] - will be - [codeblock lang=text] - Node - |- MyCustomNode (Custom Suffix) - [/codeblock] - Bear in mind that when a built-in type does not have any custom suffix, its suffix will be removed. The suffix of a type created from a script will fall back to its script file name. For global types by scripts, if you customize their suffixes to an empty string, their suffixes will be removed. [b]Note:[/b] Trying to list the base type in the [param type_blocklist] will hide all types derived from the base type from the create dialog. diff --git a/doc/classes/ImporterMesh.xml b/doc/classes/ImporterMesh.xml index 745d7a3d5d78..48584c8ac73a 100644 --- a/doc/classes/ImporterMesh.xml +++ b/doc/classes/ImporterMesh.xml @@ -32,7 +32,7 @@ The [param arrays] argument is an array of arrays. Each of the [constant Mesh.ARRAY_MAX] elements contains an array with some of the mesh data for this surface as described by the corresponding member of [enum Mesh.ArrayType] or [code]null[/code] if it is not used by the surface. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this surface into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used. The [param blend_shapes] argument is an array of vertex data for each blend shape. Each element is an array of the same structure as [param arrays], but [constant Mesh.ARRAY_VERTEX], [constant Mesh.ARRAY_NORMAL], and [constant Mesh.ARRAY_TANGENT] are set if and only if they are set in [param arrays] and all other entries are [code]null[/code]. The [param lods] argument is a dictionary with [float] keys and [PackedInt32Array] values. Each entry in the dictionary represents an LOD level of the surface, where the value is the [constant Mesh.ARRAY_INDEX] array to use for the LOD level and the key is roughly proportional to the distance at which the LOD stats being used. I.e., increasing the key of an LOD also increases the distance that the objects has to be from the camera before the LOD is used. - The [param flags] argument is the bitwise or of, as required: One value of [enum Mesh.ArrayCustomFormat] left shifted by [code]ARRAY_FORMAT_CUSTOMn_SHIFT[/code] for each custom channel in use, [constant Mesh.ARRAY_FLAG_USE_DYNAMIC_UPDATE], [constant Mesh.ARRAY_FLAG_USE_8_BONE_WEIGHTS], or [constant Mesh.ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY]. + The [param flags] argument is the bitwise OR of, as required: One value of [enum Mesh.ArrayCustomFormat] left shifted by [code]ARRAY_FORMAT_CUSTOMn_SHIFT[/code] for each custom channel in use, [constant Mesh.ARRAY_FLAG_USE_DYNAMIC_UPDATE], [constant Mesh.ARRAY_FLAG_USE_8_BONE_WEIGHTS], or [constant Mesh.ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY]. [b]Note:[/b] When using indices, it is recommended to only use points, lines, or triangles. diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml index 6cd3d2c2e49d..e74455862042 100644 --- a/doc/classes/JSON.xml +++ b/doc/classes/JSON.xml @@ -18,7 +18,7 @@ if error == OK: var data_received = json.data if typeof(data_received) == TYPE_ARRAY: - print(data_received) # Prints array + print(data_received) # Prints the array. else: print("Unexpected data") else: diff --git a/doc/classes/JavaScriptObject.xml b/doc/classes/JavaScriptObject.xml index 914fd997f483..11d09c8f0bb6 100644 --- a/doc/classes/JavaScriptObject.xml +++ b/doc/classes/JavaScriptObject.xml @@ -13,11 +13,13 @@ func _init(): var buf = JavaScriptBridge.create_object("ArrayBuffer", 10) # new ArrayBuffer(10) - print(buf) # prints [JavaScriptObject:OBJECT_ID] + print(buf) # Prints [JavaScriptObject:OBJECT_ID] var uint8arr = JavaScriptBridge.create_object("Uint8Array", buf) # new Uint8Array(buf) uint8arr[1] = 255 - prints(uint8arr[1], uint8arr.byteLength) # prints 255 10 - console.log(uint8arr) # prints in browser console "Uint8Array(10) [ 0, 255, 0, 0, 0, 0, 0, 0, 0, 0 ]" + prints(uint8arr[1], uint8arr.byteLength) # Prints "255 10" + + # Prints "Uint8Array(10) [ 0, 255, 0, 0, 0, 0, 0, 0, 0, 0 ]" in the browser's console. + console.log(uint8arr) # Equivalent of JavaScriptBridge: Array.from(uint8arr).forEach(myCallback) JavaScriptBridge.get_interface("Array").from(uint8arr).forEach(_my_js_callback) diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index 91c9072f73e9..6948d7d454d2 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -6,7 +6,7 @@ [LineEdit] provides an input field for editing a single line of text. - When the [LineEdit] control is focused using the keyboard arrow keys, it will only gain focus and not enter edit mode. - - To enter edit mode, click on the control with the mouse or press the [code]ui_text_submit[/code] action (by default [kbd]Enter[/kbd] or [kbd]Kp Enter[/kbd]). + - To enter edit mode, click on the control with the mouse, see also [member keep_editing_on_text_submit]. - To exit edit mode, press [code]ui_text_submit[/code] or [code]ui_cancel[/code] (by default [kbd]Escape[/kbd]) actions. - Check [method edit], [method unedit], [method is_editing], and [signal editing_toggled] for more information. [b]Important:[/b] @@ -80,7 +80,7 @@ Allows entering edit mode whether the [LineEdit] is focused or not. - Use [method Callable.call_deferred] if you want to enter edit mode on [signal text_submitted]. + See also [member keep_editing_on_text_submit]. @@ -283,6 +283,9 @@ If [code]true[/code], the [LineEdit] doesn't display decoration. + + If [code]true[/code], the [LineEdit] will not exit edit mode when text is submitted by pressing [code]ui_text_submit[/code] action (by default: [kbd]Enter[/kbd] or [kbd]Kp Enter[/kbd]). + Language code used for line-breaking and text shaping algorithms. If left empty, current locale is used instead. diff --git a/doc/classes/NativeMenu.xml b/doc/classes/NativeMenu.xml index 2b9e41410688..6081d7afc51e 100644 --- a/doc/classes/NativeMenu.xml +++ b/doc/classes/NativeMenu.xml @@ -366,7 +366,7 @@ Returns global menu close callback. - b]Note:[/b] This method is implemented only on macOS. + [b]Note:[/b] This method is implemented on macOS and Windows. @@ -708,7 +708,7 @@ Registers callable to emit when the menu is about to show. [b]Note:[/b] The OS can simulate menu opening to track menu item changes and global shortcuts, in which case the corresponding close callback is not triggered. Use [method is_opened] to check if the menu is currently opened. - [b]Note:[/b] This method is implemented only on macOS. + [b]Note:[/b] This method is implemented on macOS and Windows. diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml index ae13af4b8268..ba0272b02fed 100644 --- a/doc/classes/Node3D.xml +++ b/doc/classes/Node3D.xml @@ -127,7 +127,8 @@ Rotates the node so that the local forward axis (-Z, [constant Vector3.FORWARD]) points toward the [param target] position. The local up axis (+Y) points as close to the [param up] vector as possible while staying perpendicular to the local forward axis. The resulting transform is orthogonal, and the scale is preserved. Non-uniform scaling may not work correctly. - The [param target] position cannot be the same as the node's position, the [param up] vector cannot be zero, and the direction from the node's position to the [param target] vector cannot be parallel to the [param up] vector. + The [param target] position cannot be the same as the node's position, the [param up] vector cannot be zero. + The [param target] and the [param up] cannot be [constant Vector3.ZERO], and shouldn't be colinear to avoid unintended rotation around local Z axis. Operations take place in global space, which means that the node must be in the scene tree. If [param use_model_front] is [code]true[/code], the +Z axis (asset front) is treated as forward (implies +X is left) and points toward the [param target] position. By default, the -Z axis (camera forward) is treated as forward (implies +X is right). diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml index 628c7106f207..6279914e6e9e 100644 --- a/doc/classes/NodePath.xml +++ b/doc/classes/NodePath.xml @@ -100,7 +100,7 @@ // propertyPath points to the "position" in the "x" axis of this node. NodePath propertyPath = nodePath.GetAsPropertyPath(); - GD.Print(propertyPath); // Prints ":position:x". + GD.Print(propertyPath); // Prints ":position:x" [/csharp] [/codeblocks] @@ -118,11 +118,11 @@ [codeblocks] [gdscript] var node_path = ^"Sprite2D:texture:resource_name" - print(node_path.get_concatenated_subnames()) # Prints "texture:resource_name". + print(node_path.get_concatenated_subnames()) # Prints "texture:resource_name" [/gdscript] [csharp] var nodePath = new NodePath("Sprite2D:texture:resource_name"); - GD.Print(nodePath.GetConcatenatedSubnames()); // Prints "texture:resource_name". + GD.Print(nodePath.GetConcatenatedSubnames()); // Prints "texture:resource_name" [/csharp] [/codeblocks] @@ -135,15 +135,15 @@ [codeblocks] [gdscript] var sprite_path = NodePath("../RigidBody2D/Sprite2D") - print(sprite_path.get_name(0)) # Prints "..". - print(sprite_path.get_name(1)) # Prints "RigidBody2D". - print(sprite_path.get_name(2)) # Prints "Sprite". + print(sprite_path.get_name(0)) # Prints ".." + print(sprite_path.get_name(1)) # Prints "RigidBody2D" + print(sprite_path.get_name(2)) # Prints "Sprite" [/gdscript] [csharp] var spritePath = new NodePath("../RigidBody2D/Sprite2D"); - GD.Print(spritePath.GetName(0)); // Prints "..". - GD.Print(spritePath.GetName(1)); // Prints "PathFollow2D". - GD.Print(spritePath.GetName(2)); // Prints "Sprite". + GD.Print(spritePath.GetName(0)); // Prints ".." + GD.Print(spritePath.GetName(1)); // Prints "PathFollow2D" + GD.Print(spritePath.GetName(2)); // Prints "Sprite" [/csharp] [/codeblocks] @@ -163,13 +163,13 @@ [codeblocks] [gdscript] var path_to_name = NodePath("Sprite2D:texture:resource_name") - print(path_to_name.get_subname(0)) # Prints "texture". - print(path_to_name.get_subname(1)) # Prints "resource_name". + print(path_to_name.get_subname(0)) # Prints "texture" + print(path_to_name.get_subname(1)) # Prints "resource_name" [/gdscript] [csharp] var pathToName = new NodePath("Sprite2D:texture:resource_name"); - GD.Print(pathToName.GetSubname(0)); // Prints "texture". - GD.Print(pathToName.GetSubname(1)); // Prints "resource_name". + GD.Print(pathToName.GetSubname(0)); // Prints "texture" + GD.Print(pathToName.GetSubname(1)); // Prints "resource_name" [/csharp] [/codeblocks] diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 4cf24739ed46..48e18f4a3195 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -747,14 +747,19 @@ - Requests permission from the OS for the given [param name]. Returns [code]true[/code] if the permission has been successfully granted. - [b]Note:[/b] This method is currently only implemented on Android, to specifically request permission for [code]"RECORD_AUDIO"[/code] by [code]AudioDriverOpenSL[/code]. + Requests permission from the OS for the given [param name]. Returns [code]true[/code] if the permission has already been granted. See also [signal MainLoop.on_request_permissions_result]. + The [param name] must be the full permission name. For example: + - [code]OS.request_permission("android.permission.READ_EXTERNAL_STORAGE")[/code] + - [code]OS.request_permission("android.permission.POST_NOTIFICATIONS")[/code] + [b]Note:[/b] Permission must be checked during export. + [b]Note:[/b] This method is only implemented on Android. - Requests [i]dangerous[/i] permissions from the OS. Returns [code]true[/code] if permissions have been successfully granted. + Requests [i]dangerous[/i] permissions from the OS. Returns [code]true[/code] if permissions have already been granted. See also [signal MainLoop.on_request_permissions_result]. + [b]Note:[/b] Permissions must be checked during export. [b]Note:[/b] This method is only implemented on Android. Normal permissions are automatically granted at install time in Android applications. diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml index 1f37812925a1..2f8e4889a7eb 100644 --- a/doc/classes/PackedByteArray.xml +++ b/doc/classes/PackedByteArray.xml @@ -366,11 +366,11 @@ [codeblocks] [gdscript] var array = PackedByteArray([11, 46, 255]) - print(array.hex_encode()) # Prints: 0b2eff + print(array.hex_encode()) # Prints "0b2eff" [/gdscript] [csharp] byte[] array = [11, 46, 255]; - GD.Print(array.HexEncode()); // Prints: 0b2eff + GD.Print(array.HexEncode()); // Prints "0b2eff" [/csharp] [/codeblocks] diff --git a/doc/classes/PackedDataContainer.xml b/doc/classes/PackedDataContainer.xml index 048c72126a7f..cb0d45c3423c 100644 --- a/doc/classes/PackedDataContainer.xml +++ b/doc/classes/PackedDataContainer.xml @@ -16,11 +16,12 @@ var container = load("packed_data.res") for key in container: prints(key, container[key]) - - # Prints: - # key value - # lock (0, 0) - # another_key 123 + [/codeblock] + Prints: + [codeblock lang=text] + key value + lock (0, 0) + another_key 123 [/codeblock] Nested containers will be packed recursively. While iterating, they will be returned as [PackedDataContainerRef]. diff --git a/doc/classes/PackedDataContainerRef.xml b/doc/classes/PackedDataContainerRef.xml index 75222784cae0..bc79df020415 100644 --- a/doc/classes/PackedDataContainerRef.xml +++ b/doc/classes/PackedDataContainerRef.xml @@ -7,7 +7,7 @@ When packing nested containers using [PackedDataContainer], they are recursively packed into [PackedDataContainerRef] (only applies to [Array] and [Dictionary]). Their data can be retrieved the same way as from [PackedDataContainer]. [codeblock] var packed = PackedDataContainer.new() - packed.pack([1, 2, 3, ["abc", "def"], 4, 5, 6]) + packed.pack([1, 2, 3, ["nested1", "nested2"], 4, 5, 6]) for element in packed: if element is PackedDataContainerRef: @@ -15,16 +15,17 @@ print("::", subelement) else: print(element) - - # Prints: - # 1 - # 2 - # 3 - # ::abc - # ::def - # 4 - # 5 - # 6 + [/codeblock] + Prints: + [codeblock lang=text] + 1 + 2 + 3 + ::nested1 + ::nested2 + 4 + 5 + 6 [/codeblock] diff --git a/doc/classes/ParticleProcessMaterial.xml b/doc/classes/ParticleProcessMaterial.xml index 742e0cc44cf4..e1c97a74bad4 100644 --- a/doc/classes/ParticleProcessMaterial.xml +++ b/doc/classes/ParticleProcessMaterial.xml @@ -410,6 +410,13 @@ A pivot point used to calculate radial and orbital velocity of particles. + + + + Emitted when this material's emission shape is changed in any way. This includes changes to [member emission_shape], [member emission_shape_scale], or [member emission_sphere_radius], and any other property that affects the emission shape's offset, size, scale, or orientation. + + + Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set initial velocity properties. diff --git a/doc/classes/RandomNumberGenerator.xml b/doc/classes/RandomNumberGenerator.xml index 44e29d232277..e06cc1c9844d 100644 --- a/doc/classes/RandomNumberGenerator.xml +++ b/doc/classes/RandomNumberGenerator.xml @@ -100,7 +100,7 @@ var saved_state = rng.state # Store current state. print(rng.randf()) # Advance internal state. rng.state = saved_state # Restore the state. - print(rng.randf()) # Prints the same value as in previous. + print(rng.randf()) # Prints the same value as previously. [/codeblock] [b]Note:[/b] Do not set state to arbitrary values, since the random number generator requires the state to have certain qualities to behave properly. It should only be set to values that came from the state property itself. To initialize the random number generator with arbitrary input, use [member seed] instead. [b]Note:[/b] The default value of this property is pseudo-random, and changes when calling [method randomize]. The [code]0[/code] value documented here is a placeholder, and not the actual default seed. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 4adf613655c2..50d7b397b6d0 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -3795,12 +3795,11 @@ Copies the viewport to a region of the screen specified by [param rect]. If [method viewport_set_render_direct_to_screen] is [code]true[/code], then the viewport does not use a framebuffer and the contents of the viewport are rendered directly to screen. However, note that the root viewport is drawn last, therefore it will draw over the screen. Accordingly, you must set the root viewport to an area that does not cover the area that you have attached this viewport to. For example, you can set the root viewport to not render at all with the following code: - FIXME: The method seems to be non-existent. [codeblocks] [gdscript] func _ready(): - get_viewport().set_attach_to_screen_rect(Rect2()) - $Viewport.set_attach_to_screen_rect(Rect2(0, 0, 600, 600)) + RenderingServer.viewport_attach_to_screen(get_viewport().get_viewport_rid(), Rect2()) + RenderingServer.viewport_attach_to_screen($Viewport.get_viewport_rid(), Rect2(0, 0, 600, 600)) [/gdscript] [/codeblocks] Using this can result in significant optimization, especially on lower-end devices. However, it comes at the cost of having to manage your viewports manually. For further optimization, see [method viewport_set_render_direct_to_screen]. @@ -4599,27 +4598,37 @@ Flag used to mark an index array. + Mask of mesh channels permitted in blend shapes. + Shift of first custom channel. + Number of format bits per custom channel. See [enum ArrayCustomFormat]. + Amount to shift [enum ArrayCustomFormat] for custom channel index 0. + Amount to shift [enum ArrayCustomFormat] for custom channel index 1. + Amount to shift [enum ArrayCustomFormat] for custom channel index 2. + Amount to shift [enum ArrayCustomFormat] for custom channel index 3. + Mask of custom format bits per custom channel. Must be shifted by one of the SHIFT constants. See [enum ArrayCustomFormat]. + Shift of first compress flag. Compress flags should be passed to [method ArrayMesh.add_surface_from_arrays] and [method SurfaceTool.commit]. Flag used to mark that the array contains 2D vertices. + Flag indices that the mesh data will use [code]GL_DYNAMIC_DRAW[/code] on GLES. Unused on Vulkan. Flag used to mark that the array uses 8 bone weights instead of 4. diff --git a/doc/classes/ResourceLoader.xml b/doc/classes/ResourceLoader.xml index ae862dd52f1c..f8096dc7b141 100644 --- a/doc/classes/ResourceLoader.xml +++ b/doc/classes/ResourceLoader.xml @@ -47,9 +47,9 @@ Returns the dependencies for the resource at the given [param path]. [b]Note:[/b] The dependencies are returned with slices separated by [code]::[/code]. You can use [method String.get_slice] to get their components. [codeblock] - for dep in ResourceLoader.get_dependencies(path): - print(dep.get_slice("::", 0)) # Prints UID. - print(dep.get_slice("::", 2)) # Prints path. + for dependency in ResourceLoader.get_dependencies(path): + print(dependency.get_slice("::", 0)) # Prints the UID. + print(dependency.get_slice("::", 2)) # Prints the path. [/codeblock] diff --git a/doc/classes/RetargetModifier3D.xml b/doc/classes/RetargetModifier3D.xml index 522b954aba32..7f89b66a83be 100644 --- a/doc/classes/RetargetModifier3D.xml +++ b/doc/classes/RetargetModifier3D.xml @@ -10,19 +10,54 @@ + + + + + Returns [code]true[/code] if [member enable] has [constant TRANSFORM_FLAG_POSITION]. + + + + + + Returns [code]true[/code] if [member enable] has [constant TRANSFORM_FLAG_ROTATION]. + + + + + + Returns [code]true[/code] if [member enable] has [constant TRANSFORM_FLAG_SCALE]. + + + + + + + Sets [constant TRANSFORM_FLAG_POSITION] into [member enable]. + + + + + + + Sets [constant TRANSFORM_FLAG_ROTATION] into [member enable]. + + + + + + + Sets [constant TRANSFORM_FLAG_SCALE] into [member enable]. + + + - - If [code]true[/code], allows to retarget the position. + + Flags to control the process of the transform elements individually when [member use_global_pose] is disabled. [SkeletonProfile] for retargeting bones with names matching the bone list. - - If [code]true[/code], allows to retarget the rotation. - - - If [code]true[/code], allows to retarget the scale. - If [code]false[/code], in case the target skeleton has fewer bones than the source skeleton, the source bone parent's transform will be ignored. Instead, it is possible to retarget between models with different body shapes, and position, rotation, and scale can be retargeted separately. @@ -31,4 +66,18 @@ This is useful for using dummy bone with length [code]0[/code] to match postures when retargeting between models with different number of bones. + + + If set, allows to retarget the position. + + + If set, allows to retarget the rotation. + + + If set, allows to retarget the scale. + + + If set, allows to retarget the position/rotation/scale. + + diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index 47c95c97ff5e..af5dc9db3484 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -712,6 +712,7 @@ Triggered when the document is fully loaded. + [b]Note:[/b] This can happen before the text is processed for drawing. Scrolling values may not be valid until the document is drawn for the first time after this signal. diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 3f64a5c8a2ba..68a7f6733187 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -272,10 +272,10 @@ See also the [url=$DOCS_URL/tutorials/scripting/gdscript/gdscript_format_string.html]GDScript format string[/url] tutorial. [b]Note:[/b] Each replacement is done sequentially for each element of [param values], [b]not[/b] all at once. This means that if any element is inserted and it contains another placeholder, it may be changed by the next replacement. While this can be very useful, it often causes unexpected results. If not necessary, make sure [param values]'s elements do not contain placeholders. [codeblock] - print("{0} {1}".format(["{1}", "x"])) # Prints "x x". - print("{0} {1}".format(["x", "{0}"])) # Prints "x {0}". - print("{a} {b}".format({"a": "{b}", "b": "c"})) # Prints "c c". - print("{a} {b}".format({"b": "c", "a": "{b}"})) # Prints "{b} c". + print("{0} {1}".format(["{1}", "x"])) # Prints "x x" + print("{0} {1}".format(["x", "{0}"])) # Prints "x {0}" + print("{a} {b}".format({"a": "{b}", "b": "c"})) # Prints "c c" + print("{a} {b}".format({"b": "c", "a": "{b}"})) # Prints "{b} c" [/codeblock] [b]Note:[/b] In C#, it's recommended to [url=https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated]interpolate strings with "$"[/url], instead. diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml index 125bbb56cdf1..96972706e537 100644 --- a/doc/classes/StringName.xml +++ b/doc/classes/StringName.xml @@ -255,10 +255,10 @@ See also the [url=$DOCS_URL/tutorials/scripting/gdscript/gdscript_format_string.html]GDScript format string[/url] tutorial. [b]Note:[/b] Each replacement is done sequentially for each element of [param values], [b]not[/b] all at once. This means that if any element is inserted and it contains another placeholder, it may be changed by the next replacement. While this can be very useful, it often causes unexpected results. If not necessary, make sure [param values]'s elements do not contain placeholders. [codeblock] - print("{0} {1}".format(["{1}", "x"])) # Prints "x x". - print("{0} {1}".format(["x", "{0}"])) # Prints "x {0}". - print("{a} {b}".format({"a": "{b}", "b": "c"})) # Prints "c c". - print("{a} {b}".format({"b": "c", "a": "{b}"})) # Prints "{b} c". + print("{0} {1}".format(["{1}", "x"])) # Prints "x x" + print("{0} {1}".format(["x", "{0}"])) # Prints "x {0}" + print("{a} {b}".format({"a": "{b}", "b": "c"})) # Prints "c c" + print("{a} {b}".format({"b": "c", "a": "{b}"})) # Prints "{b} c" [/codeblock] [b]Note:[/b] In C#, it's recommended to [url=https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated]interpolate strings with "$"[/url], instead. diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml index 258d68752ea6..0fdc7e772367 100644 --- a/doc/classes/SurfaceTool.xml +++ b/doc/classes/SurfaceTool.xml @@ -87,7 +87,7 @@ Returns a constructed [ArrayMesh] from current information passed in. If an existing [ArrayMesh] is passed in as an argument, will add an extra surface to the existing [ArrayMesh]. - [b]FIXME:[/b] Document possible values for [param flags], it changed in 4.0. Likely some combinations of [enum Mesh.ArrayFormat]. + The [param flags] argument can be the bitwise OR of [constant Mesh.ARRAY_FLAG_USE_DYNAMIC_UPDATE], [constant Mesh.ARRAY_FLAG_USE_8_BONE_WEIGHTS], or [constant Mesh.ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY]. diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index 730b88eb5798..7fb6ec5b16c2 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -1772,9 +1772,12 @@ When [param chars_per_line] is greater than zero, line break boundaries are returned instead. [codeblock] var ts = TextServerManager.get_primary_interface() - print(ts.string_get_word_breaks("The Godot Engine, 4")) # Prints [0, 3, 4, 9, 10, 16, 18, 19], which corresponds to the following substrings: "The", "Godot", "Engine", "4" - print(ts.string_get_word_breaks("The Godot Engine, 4", "en", 5)) # Prints [0, 3, 4, 9, 10, 15, 15, 19], which corresponds to the following substrings: "The", "Godot", "Engin", "e, 4" - print(ts.string_get_word_breaks("The Godot Engine, 4", "en", 10)) # Prints [0, 9, 10, 19], which corresponds to the following substrings: "The Godot", "Engine, 4" + # Corresponds to the substrings "The", "Godot", "Engine", and "4". + print(ts.string_get_word_breaks("The Godot Engine, 4")) # Prints [0, 3, 4, 9, 10, 16, 18, 19] + # Corresponds to the substrings "The", "Godot", "Engin", and "e, 4". + print(ts.string_get_word_breaks("The Godot Engine, 4", "en", 5)) # Prints [0, 3, 4, 9, 10, 15, 15, 19] + # Corresponds to the substrings "The Godot" and "Engine, 4". + print(ts.string_get_word_breaks("The Godot Engine, 4", "en", 10)) # Prints [0, 9, 10, 19] [/codeblock] diff --git a/doc/classes/Timer.xml b/doc/classes/Timer.xml index f4fc58b9bf96..c29e67340e7e 100644 --- a/doc/classes/Timer.xml +++ b/doc/classes/Timer.xml @@ -45,7 +45,7 @@ [b]Note:[/b] After the timer enters the tree, this property is automatically set to [code]false[/code]. [b]Note:[/b] This property does nothing when the timer is running in the editor. - + If [code]true[/code], the timer will ignore [member Engine.time_scale] and update with the real, elapsed time. diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml index 1c4dcc890d96..3b5b6f7844b8 100644 --- a/doc/classes/Tween.xml +++ b/doc/classes/Tween.xml @@ -228,6 +228,13 @@ [/codeblock] + + + + + If [param ignore] is [code]true[/code], the tween will ignore [member Engine.time_scale] and update with the real, elapsed time. This affects all [Tweener]s and their delays. Default value is [code]false[/code]. + + diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml index e9ddf57355a5..75f1d511275a 100644 --- a/doc/classes/Vector2.xml +++ b/doc/classes/Vector2.xml @@ -213,9 +213,9 @@ Creates a unit [Vector2] rotated to the given [param angle] in radians. This is equivalent to doing [code]Vector2(cos(angle), sin(angle))[/code] or [code]Vector2.RIGHT.rotated(angle)[/code]. [codeblock] - print(Vector2.from_angle(0)) # Prints (1.0, 0.0). + print(Vector2.from_angle(0)) # Prints (1.0, 0.0) print(Vector2(1, 0).angle()) # Prints 0.0, which is the angle used above. - print(Vector2.from_angle(PI / 2)) # Prints (0.0, 1.0). + print(Vector2.from_angle(PI / 2)) # Prints (0.0, 1.0) [/codeblock] diff --git a/doc/classes/Vector4.xml b/doc/classes/Vector4.xml index 45780a1aedcb..bc5201baac56 100644 --- a/doc/classes/Vector4.xml +++ b/doc/classes/Vector4.xml @@ -390,7 +390,7 @@ Divides each component of the [Vector4] by the given [float]. [codeblock] - print(Vector4(10, 20, 30, 40) / 2 # Prints (5.0, 10.0, 15.0, 20.0) + print(Vector4(10, 20, 30, 40) / 2) # Prints (5.0, 10.0, 15.0, 20.0) [/codeblock] diff --git a/doc/classes/Vector4i.xml b/doc/classes/Vector4i.xml index 6c46f82a3bbb..4dd093478070 100644 --- a/doc/classes/Vector4i.xml +++ b/doc/classes/Vector4i.xml @@ -208,7 +208,7 @@ Gets the remainder of each component of the [Vector4i] with the components of the given [Vector4i]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers. [codeblock] - print(Vector4i(10, -20, 30, -40) % Vector4i(7, 8, 9, 10)) # Prints (3, -4, 3, 0) + print(Vector4i(10, -20, 30, -40) % Vector4i(7, 8, 9, 10)) # Prints (3, -4, 3, 0) [/codeblock] @@ -218,7 +218,7 @@ Gets the remainder of each component of the [Vector4i] with the given [int]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers. [codeblock] - print(Vector4i(10, -20, 30, -40) % 7) # Prints (3, -6, 2, -5) + print(Vector4i(10, -20, 30, -40) % 7) # Prints (3, -6, 2, -5) [/codeblock] @@ -287,7 +287,7 @@ Divides each component of the [Vector4i] by the given [float]. Returns a Vector4 value due to floating-point operations. [codeblock] - print(Vector4i(10, 20, 30, 40) / 2 # Prints (5.0, 10.0, 15.0, 20.0) + print(Vector4i(10, 20, 30, 40) / 2) # Prints (5.0, 10.0, 15.0, 20.0) [/codeblock] diff --git a/doc/classes/float.xml b/doc/classes/float.xml index 96ac9a804973..324a7756a2f9 100644 --- a/doc/classes/float.xml +++ b/doc/classes/float.xml @@ -70,7 +70,7 @@ Multiplies each component of the [Color], including the alpha, by the given [float]. [codeblock] - print(1.5 * Color(0.5, 0.5, 0.5)) # Prints "(0.75, 0.75, 0.75, 1.5)" + print(1.5 * Color(0.5, 0.5, 0.5)) # Prints (0.75, 0.75, 0.75, 1.5) [/codeblock] @@ -87,7 +87,7 @@ Multiplies each component of the [Vector2] by the given [float]. [codeblock] - print(2.5 * Vector2(1, 3)) # Prints "(2.5, 7.5)" + print(2.5 * Vector2(1, 3)) # Prints (2.5, 7.5) [/codeblock] diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 0cffc5274899..6ae74539eaa3 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2384,6 +2384,7 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ bool draw_sky = false; bool draw_sky_fog_only = false; bool keep_color = false; + bool draw_canvas = false; bool draw_feed = false; float sky_energy_multiplier = 1.0; int camera_feed_id = -1; @@ -2425,7 +2426,7 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ draw_sky = !render_data.transparent_bg; } break; case RS::ENV_BG_CANVAS: { - keep_color = true; + draw_canvas = true; } break; case RS::ENV_BG_KEEP: { keep_color = true; @@ -2433,6 +2434,7 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ case RS::ENV_BG_CAMERA_FEED: { camera_feed_id = environment_get_camera_feed_id(render_data.environment); draw_feed = true; + keep_color = true; } break; default: { } @@ -2544,10 +2546,14 @@ void RasterizerSceneGLES3::render_scene(const Ref &p_render_ glClear(GL_DEPTH_BUFFER_BIT); } - if (!keep_color && !draw_feed) { + // Need to clear framebuffer unless: + // a) We explicitly request not to (i.e. ENV_BG_KEEP). + // b) We are rendering to a non-intermediate framebuffer with ENV_BG_CANVAS (shared between 2D and 3D). + if (!keep_color && (!draw_canvas || fbo != rt->fbo)) { clear_color.a = render_data.transparent_bg ? 0.0f : 1.0f; glClearBufferfv(GL_COLOR, 0, clear_color.components); - } else if (fbo != rt->fbo) { + } + if ((keep_color || draw_canvas) && fbo != rt->fbo) { // Need to copy our current contents to our intermediate/MSAA buffer GLES3::CopyEffects *copy_effects = GLES3::CopyEffects::get_singleton(); diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index d16cd4d3949d..f61bb73a85a4 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1816,7 +1816,6 @@ void main() { normal = -normal; } #endif // DO_SIDE_CHECK - vec3 geo_normal = normalize(normal); #endif // NORMAL_USED #ifdef UV_USED @@ -1882,6 +1881,10 @@ void main() { #endif //USE_MULTIVIEW #endif //LIGHT_VERTEX_USED +#ifdef NORMAL_USED + vec3 geo_normal = normalize(normal); +#endif // NORMAL_USED + #ifndef USE_SHADOW_TO_OPACITY #if defined(ALPHA_SCISSOR_USED) diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp index 18a01a0bb1f3..fb45fdeaca7b 100644 --- a/drivers/gles3/storage/config.cpp +++ b/drivers/gles3/storage/config.cpp @@ -79,7 +79,7 @@ Config::Config() { bptc_supported = extensions.has("GL_ARB_texture_compression_bptc") || extensions.has("EXT_texture_compression_bptc"); astc_supported = extensions.has("GL_KHR_texture_compression_astc") || extensions.has("GL_OES_texture_compression_astc") || extensions.has("GL_KHR_texture_compression_astc_ldr") || extensions.has("GL_KHR_texture_compression_astc_hdr"); - astc_hdr_supported = extensions.has("GL_KHR_texture_compression_astc_ldr"); + astc_hdr_supported = extensions.has("GL_KHR_texture_compression_astc_hdr"); astc_layered_supported = extensions.has("GL_KHR_texture_compression_astc_sliced_3d"); if (RasterizerGLES3::is_gles_over_gl()) { diff --git a/drivers/metal/metal_objects.h b/drivers/metal/metal_objects.h index 4cb929a9081f..065998839ff7 100644 --- a/drivers/metal/metal_objects.h +++ b/drivers/metal/metal_objects.h @@ -70,12 +70,14 @@ // These types can be used in Vector and other containers that use // pointer operations not supported by ARC. namespace MTL { -#define MTL_CLASS(name) \ - class name { \ - public: \ - name(id obj = nil) : m_obj(obj) {} \ - operator id() const { return m_obj; } \ - id m_obj; \ +#define MTL_CLASS(name) \ + class name { \ + public: \ + name(id obj = nil) : m_obj(obj) {} \ + operator id() const { \ + return m_obj; \ + } \ + id m_obj; \ }; MTL_CLASS(Texture) @@ -949,8 +951,10 @@ void *owned(id p_id) { return (__bridge_retained void *)p_id; } -#define MAKE_ID(FROM, TO) \ - _FORCE_INLINE_ TO make(FROM p_obj) { return TO(owned(p_obj)); } +#define MAKE_ID(FROM, TO) \ + _FORCE_INLINE_ TO make(FROM p_obj) { \ + return TO(owned(p_obj)); \ + } MAKE_ID(id, RDD::TextureID) MAKE_ID(id, RDD::BufferID) diff --git a/drivers/metal/metal_objects.mm b/drivers/metal/metal_objects.mm index b44c496e4f6f..04900a0e5162 100644 --- a/drivers/metal/metal_objects.mm +++ b/drivers/metal/metal_objects.mm @@ -56,6 +56,10 @@ #import +// We have to undefine these macros because they are defined in NSObjCRuntime.h. +#undef MIN +#undef MAX + void MDCommandBuffer::begin() { DEV_ASSERT(commandBuffer == nil); commandBuffer = queue.commandBufferWithUnretainedReferences; @@ -764,6 +768,7 @@ [render.encoder setVertexBuffers:render.vertex_buffers.ptr() offsets:render.vertex_offsets.ptr() withRange:NSMakeRange(first, p_binding_count)]; + render.dirty.clear_flag(RenderState::DIRTY_VERTEX); } else { render.dirty.set_flag(RenderState::DIRTY_VERTEX); } @@ -1082,7 +1087,7 @@ UniformSet const &set = p_shader->sets[index]; - for (uint32_t i = 0; i < uniforms.size(); i++) { + for (uint32_t i = 0; i < MIN(uniforms.size(), set.uniforms.size()); i++) { RDD::BoundUniform const &uniform = uniforms[i]; UniformInfo ui = set.uniforms[i]; diff --git a/drivers/metal/metal_utils.h b/drivers/metal/metal_utils.h index f3ee395d04ae..6bb2e2dd1584 100644 --- a/drivers/metal/metal_utils.h +++ b/drivers/metal/metal_utils.h @@ -53,11 +53,15 @@ void clear(Tv &p_value, Tm p_mask) { /*! Returns whether the specified value has any of the bits specified in mask set to 1. */ template -static constexpr bool any(Tv p_value, const Tm p_mask) { return ((p_value & p_mask) != 0); } +static constexpr bool any(Tv p_value, const Tm p_mask) { + return ((p_value & p_mask) != 0); +} /*! Returns whether the specified value has all of the bits specified in mask set to 1. */ template -static constexpr bool all(Tv p_value, const Tm p_mask) { return ((p_value & p_mask) == p_mask); } +static constexpr bool all(Tv p_value, const Tm p_mask) { + return ((p_value & p_mask) == p_mask); +} } //namespace flags diff --git a/drivers/png/SCsub b/drivers/png/SCsub index 4268a664750c..c07424ff6cdf 100644 --- a/drivers/png/SCsub +++ b/drivers/png/SCsub @@ -48,7 +48,6 @@ if env["builtin_libpng"]: neon_sources = [] neon_sources.append(env_neon.Object(thirdparty_dir + "arm/arm_init.c")) neon_sources.append(env_neon.Object(thirdparty_dir + "arm/filter_neon_intrinsics.c")) - neon_sources.append(env_neon.Object(thirdparty_dir + "arm/filter_neon.S")) neon_sources.append(env_neon.Object(thirdparty_dir + "arm/palette_neon_intrinsics.c")) thirdparty_obj += neon_sources elif env["arch"].startswith("x86"): diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index 816ffd7a322f..6d3e4c7dbf19 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -438,11 +438,19 @@ Error DirAccessUnix::remove(String p_path) { return FAILED; } + int err; if (S_ISDIR(flags.st_mode) && !is_link(p_path)) { - return ::rmdir(p_path.utf8().get_data()) == 0 ? OK : FAILED; + err = ::rmdir(p_path.utf8().get_data()); } else { - return ::unlink(p_path.utf8().get_data()) == 0 ? OK : FAILED; + err = ::unlink(p_path.utf8().get_data()); } + if (err != 0) { + return FAILED; + } + if (remove_notification_func != nullptr) { + remove_notification_func(p_path); + } + return OK; } bool DirAccessUnix::is_link(String p_file) { @@ -552,6 +560,8 @@ DirAccessUnix::DirAccessUnix() { change_dir(current_dir); } +DirAccessUnix::RemoveNotificationFunc DirAccessUnix::remove_notification_func = nullptr; + DirAccessUnix::~DirAccessUnix() { list_dir_end(); } diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h index 8d13ff1fa88d..adf1fa80e7be 100644 --- a/drivers/unix/dir_access_unix.h +++ b/drivers/unix/dir_access_unix.h @@ -52,6 +52,9 @@ class DirAccessUnix : public DirAccess { virtual bool is_hidden(const String &p_name); public: + typedef void (*RemoveNotificationFunc)(const String &p_file); + static RemoveNotificationFunc remove_notification_func; + virtual Error list_dir_begin() override; ///< This starts dir listing virtual String get_next() override; virtual bool current_is_dir() const override; diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index f2e4b3966be8..048d42529029 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -443,7 +443,7 @@ void FileAccessUnix::close() { _close(); } -CloseNotificationFunc FileAccessUnix::close_notification_func = nullptr; +FileAccessUnix::CloseNotificationFunc FileAccessUnix::close_notification_func = nullptr; FileAccessUnix::~FileAccessUnix() { _close(); diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index 66e4bccc2525..fb9d684714c3 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -38,8 +38,6 @@ #if defined(UNIX_ENABLED) -typedef void (*CloseNotificationFunc)(const String &p_file, int p_flags); - class FileAccessUnix : public FileAccess { FILE *f = nullptr; int flags = 0; @@ -56,6 +54,7 @@ class FileAccessUnix : public FileAccess { #endif public: + typedef void (*CloseNotificationFunc)(const String &p_file, int p_flags); static CloseNotificationFunc close_notification_func; virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index 43c6285d2827..2c8fa257869e 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -689,7 +689,7 @@ void AnimationBezierTrackEdit::set_editor(AnimationTrackEditor *p_editor) { } void AnimationBezierTrackEdit::_play_position_draw() { - if (!animation.is_valid() || play_position_pos < 0) { + if (animation.is_null() || play_position_pos < 0) { return; } diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 6ae74aef4285..f93029a3c5cc 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -8066,7 +8066,7 @@ void AnimationTrackKeyEditEditor::_time_edit_exited() { } AnimationTrackKeyEditEditor::AnimationTrackKeyEditEditor(Ref p_animation, int p_track, real_t p_key_ofs, bool p_use_fps) { - if (!p_animation.is_valid()) { + if (p_animation.is_null()) { return; } diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp index da3112fc79c7..9c30f156267e 100644 --- a/editor/animation_track_editor_plugins.cpp +++ b/editor/animation_track_editor_plugins.cpp @@ -220,7 +220,7 @@ Rect2 AnimationTrackEditAudio::get_key_rect(int p_index, float p_pixels_sec) { Ref stream = object->call("get_stream"); - if (!stream.is_valid()) { + if (stream.is_null()) { return AnimationTrackEdit::get_key_rect(p_index, p_pixels_sec); } @@ -260,7 +260,7 @@ void AnimationTrackEditAudio::draw_key(int p_index, float p_pixels_sec, int p_x, Ref stream = object->call("get_stream"); - if (!stream.is_valid()) { + if (stream.is_null()) { AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right); return; } @@ -379,7 +379,7 @@ Rect2 AnimationTrackEditSpriteFrame::get_key_rect(int p_index, float p_pixels_se if (Object::cast_to(object) || Object::cast_to(object)) { Ref texture = object->call("get_texture"); - if (!texture.is_valid()) { + if (texture.is_null()) { return AnimationTrackEdit::get_key_rect(p_index, p_pixels_sec); } @@ -422,7 +422,7 @@ Rect2 AnimationTrackEditSpriteFrame::get_key_rect(int p_index, float p_pixels_se } Ref texture = sf->get_frame_texture(animation_name, frame); - if (!texture.is_valid()) { + if (texture.is_null()) { return AnimationTrackEdit::get_key_rect(p_index, p_pixels_sec); } @@ -456,7 +456,7 @@ void AnimationTrackEditSpriteFrame::draw_key(int p_index, float p_pixels_sec, in if (Object::cast_to(object) || Object::cast_to(object)) { texture = object->call("get_texture"); - if (!texture.is_valid()) { + if (texture.is_null()) { AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right); return; } @@ -514,7 +514,7 @@ void AnimationTrackEditSpriteFrame::draw_key(int p_index, float p_pixels_sec, in } texture = sf->get_frame_texture(animation_name, frame); - if (!texture.is_valid()) { + if (texture.is_null()) { AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right); return; } @@ -808,7 +808,7 @@ int AnimationTrackEditTypeAudio::get_key_height() const { Rect2 AnimationTrackEditTypeAudio::get_key_rect(int p_index, float p_pixels_sec) { Ref stream = get_animation()->audio_track_get_key_stream(get_track(), p_index); - if (!stream.is_valid()) { + if (stream.is_null()) { return AnimationTrackEdit::get_key_rect(p_index, p_pixels_sec); } @@ -841,7 +841,7 @@ bool AnimationTrackEditTypeAudio::is_key_selectable_by_distance() const { void AnimationTrackEditTypeAudio::draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) { Ref stream = get_animation()->audio_track_get_key_stream(get_track(), p_index); - if (!stream.is_valid()) { + if (stream.is_null()) { AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right); // Draw diamond. return; } @@ -1025,7 +1025,7 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref &p_event) { for (int i = 0; i < get_animation()->track_get_key_count(get_track()); i++) { Ref stream = get_animation()->audio_track_get_key_stream(get_track(), i); - if (!stream.is_valid()) { + if (stream.is_null()) { continue; } diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 5ccf2d413d0a..753ed209336f 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -675,8 +675,6 @@ void FindReplaceBar::_search_text_submitted(const String &p_text) { } else { search_next(); } - - callable_mp(search_text, &LineEdit::edit).call_deferred(); } void FindReplaceBar::_replace_text_submitted(const String &p_text) { @@ -784,6 +782,7 @@ FindReplaceBar::FindReplaceBar() { // Search toolbar search_text = memnew(LineEdit); + search_text->set_keep_editing_on_text_submit(true); vbc_lineedit->add_child(search_text); search_text->set_placeholder(TTR("Find")); search_text->set_tooltip_text(TTR("Find")); @@ -866,7 +865,7 @@ void CodeTextEditor::input(const Ref &event) { const Ref key_event = event; - if (!key_event.is_valid()) { + if (key_event.is_null()) { return; } if (!key_event->is_pressed()) { @@ -1053,7 +1052,7 @@ Ref CodeTextEditor::_get_completion_icon(const ScriptLanguage::CodeCo tex = get_editor_theme_icon(p_option.display); } else { tex = EditorNode::get_singleton()->get_class_icon(p_option.display); - if (!tex.is_valid()) { + if (tex.is_null()) { tex = get_editor_theme_icon(SNAME("Object")); } } diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index a383ebbc3c21..7f1670bcb648 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -111,10 +111,28 @@ bool CreateDialog::_is_type_preferred(const String &p_type) const { return EditorNode::get_editor_data().script_class_is_parent(p_type, preferred_search_result_type); } +void CreateDialog::_script_button_clicked(TreeItem *p_item, int p_column, int p_button_id, MouseButton p_mouse_button_index) { + if (p_mouse_button_index != MouseButton::LEFT) { + return; + } + // The id of opening-script button is 1. + if (p_button_id != 1) { + return; + } + + String scr_path = ScriptServer::get_global_class_path(p_item->get_text(0)); + Ref