diff --git a/.clang-format b/.clang-format index 46923aae03..dd0e5447d5 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 1eb974f3f8..04c48cf892 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 0000000000..95a1e90766 --- /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 523ff71307..91784612cf 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 d028a2e60c..b6d2d53ee7 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -69,3 +69,6 @@ e8542b06acca3c1bdeee4b528411771f0819f084 # 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 ebc301dd0f..2405cc22be 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 2803ff4b5e..025c4b2a94 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 ae2fc9388c..e4013f0493 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 270204ebe5..b1b96e56eb 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 2f130e2c97..c3f2a7fe86 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 95ff09a114..8ad705cd70 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 fd5e74b914..937f0e895d 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 e832faaca4..27580f7c7f 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 dac6270b2b..2f253fb82f 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 56c57624e5..0562d5168d 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 f7a61457ad..d04bc5d49e 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] - id: codespell @@ -152,10 +134,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 @@ -173,7 +155,7 @@ repos: - platform/web/js/engine/config.js - platform/web/js/engine/features.js - --destination - - '' + - "" - -d - dry-run pass_filenames: false @@ -194,14 +176,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 @@ -217,17 +197,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 c287db8c16..2c9c11f5e9 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1580,7 +1580,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 06eb2f72ba..199ae01080 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -42,11 +42,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 61e21ba783..023fc96709 100644 --- a/core/io/resource_uid.cpp +++ b/core/io/resource_uid.cpp @@ -231,7 +231,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); @@ -259,7 +259,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; } @@ -284,6 +284,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 761a53cc67..903478be07 100644 --- a/core/io/resource_uid.h +++ b/core/io/resource_uid.h @@ -37,6 +37,8 @@ #include "core/string/string_name.h" #include "core/templates/hash_map.h" +class FileAccess; + class ResourceUID : public Object { GDCLASS(ResourceUID, Object) public: @@ -80,6 +82,7 @@ public: 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 fcc5f8d0e8..abd16f5519 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -1051,9 +1051,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 c09477d3af..db2134ff54 100644 --- a/core/math/color.cpp +++ b/core/math/color.cpp @@ -484,6 +484,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 f9137ca296..2a0f9e36d5 100644 --- a/core/math/color.h +++ b/core/math/color.h @@ -215,6 +215,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 da2a960eca..3f6410fef2 100644 --- a/core/math/quaternion.h +++ b/core/math/quaternion.h @@ -144,14 +144,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 35a69d3860..266b7f9e27 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -132,6 +132,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; @@ -328,6 +329,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 9654553e27..239c44f516 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -391,177 +391,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 44f42c6721..5028c67cd9 100644 --- a/core/os/memory.cpp +++ b/core/os/memory.cpp @@ -66,7 +66,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 c406754945..ec639dd94c 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -71,9 +71,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; @@ -121,8 +118,6 @@ protected: 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; @@ -146,8 +141,6 @@ public: 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 4426f8aed5..6f92f45a28 100644 --- a/core/os/thread.cpp +++ b/core/os/thread.cpp @@ -31,13 +31,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 68d63e4e40..9e1ed3bbe9 100644 --- a/core/os/thread.h +++ b/core/os/thread.h @@ -31,19 +31,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" @@ -55,8 +64,6 @@ class String; -#ifdef THREADS_ENABLED - class Thread { public: typedef void (*Callback)(void *p_userdata); @@ -145,6 +152,8 @@ public: #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 e4743b292b..1fb363e792 100644 --- a/core/os/thread_safe.h +++ b/core/os/thread_safe.h @@ -33,6 +33,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 5a22346f47..b439aebdcf 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -306,7 +306,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 0631b2eba3..af2b0da2c8 100644 --- a/core/templates/command_queue_mt.h +++ b/core/templates/command_queue_mt.h @@ -35,294 +35,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 *******/ @@ -337,17 +117,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() { @@ -411,17 +206,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)) { @@ -452,20 +256,4 @@ public: ~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 7e2a206fda..10a2503819 100644 --- a/core/templates/pass_func.h +++ b/core/templates/pass_func.h @@ -33,70 +33,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 0000000000..00850113b4 --- /dev/null +++ b/core/templates/tuple.h @@ -0,0 +1,123 @@ +/**************************************************************************/ +/* tuple.h */ +/**************************************************************************/ +/* This file is part of: */ +/* REDOT ENGINE */ +/* https://redotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2024-present Redot Engine contributors */ +/* (see REDOT_AUTHORS.md) */ +/* 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 007a42a97b..fc3f66ae28 100644 --- a/core/variant/binder_common.h +++ b/core/variant/binder_common.h @@ -84,60 +84,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 a10ed68156..1261afd9c8 100644 --- a/core/variant/native_ptr.h +++ b/core/variant/native_ptr.h @@ -55,46 +55,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 3a4b15b597..33cefb3a5c 100644 --- a/core/variant/type_info.h +++ b/core/variant/type_info.h @@ -321,10 +321,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 433feb94b3..d69dea4f49 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -277,53 +277,53 @@ private: void _clear_internal(); + 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() { - 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, - }; - if (unlikely(needs_deinit[type])) { // Make it fast for types that don't need deinit. _clear_internal(); } @@ -834,7 +834,9 @@ public: } _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 89ab7e20d6..b14fd95f0e 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -2106,11 +2106,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 bee7461fa7..bf019935c6 100644 --- a/core/variant/variant_internal.h +++ b/core/variant/variant_internal.h @@ -833,11 +833,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) @@ -1132,10 +1136,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 aa2e36b7f0..91cfe6dfdc 100644 --- a/core/variant/variant_setget.cpp +++ b/core/variant/variant_setget.cpp @@ -392,9 +392,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) \ @@ -464,9 +470,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) \ @@ -520,9 +532,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) \ @@ -570,9 +588,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) \ @@ -620,9 +644,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 6a25b3da01..faaffcd86a 100644 --- a/core/variant/variant_setget.h +++ b/core/variant/variant_setget.h @@ -69,7 +69,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) \ @@ -103,7 +105,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) \ @@ -134,7 +138,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) \ @@ -168,7 +174,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) \ @@ -199,7 +207,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) \ @@ -233,7 +243,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) \ @@ -264,7 +276,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 8e4231c90e..ac2d82159b 100644 --- a/core/variant/variant_utility.cpp +++ b/core/variant/variant_utility.cpp @@ -1372,8 +1372,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) @@ -1404,8 +1408,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) @@ -1438,8 +1446,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) @@ -1472,8 +1484,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) @@ -1635,8 +1651,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 ebb444b1f3..d64b988555 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 Redot 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 Redot'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 Redot'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 67fa25e940..bb90a15ba2 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 4cc68c5188..3ffb2c98c5 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 ccee1d4a08..ae6a38d4ee 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 c6e4290a28..150c9d6be6 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 d5978a42f6..6c8d26df8b 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 dd9c36a27a..cb3a5f4da5 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 fb90a2a5cd..ee67b8f97f 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 6b29f762e5..35aa812298 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 745d7a3d5d..48584c8ac7 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 267429ed88..868d4ae196 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 914fd997f4..11d09c8f0b 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 91c9072f73..6948d7d454 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 2b9e414106..6081d7afc5 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 a129ce2400..e85adea485 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 628c7106f2..6279914e6e 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 9f5eec6ace..a883a8bf5a 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 2c29646c77..4b97d3f6ad 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 048c72126a..cb0d45c342 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 75222784ca..bc79df0204 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 742e0cc44c..e1c97a74ba 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 5135b23d65..4de31aaa36 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 5e73dfda6d..fe52a04b6c 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 ae862dd52f..f8096dc7b1 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 522b954aba..7f89b66a83 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 47c95c97ff..af5dc9db34 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 4179e50fe5..c1fed2a281 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 db8f786446..107e24d65c 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 8e44146d95..7c141ec1da 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 21f032d462..b92e2e4036 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 Redot Engine, 4")) # Prints [0, 3, 4, 9, 10, 16, 18, 19], which corresponds to the following substrings: "The", "Redot", "Engine", "4" - print(ts.string_get_word_breaks("The Redot Engine, 4", "en", 5)) # Prints [0, 3, 4, 9, 10, 15, 15, 19], which corresponds to the following substrings: "The", "Redot", "Engin", "e, 4" - print(ts.string_get_word_breaks("The Redot Engine, 4", "en", 10)) # Prints [0, 9, 10, 19], which corresponds to the following substrings: "The Redot", "Engine, 4" + # Corresponds to the substrings "The", "Redot", "Engine", and "4". + print(ts.string_get_word_breaks("The Redot Engine, 4")) # Prints [0, 3, 4, 9, 10, 16, 18, 19] + # Corresponds to the substrings "The", "Redot", "Engin", and "e, 4". + print(ts.string_get_word_breaks("The Redot Engine, 4", "en", 5)) # Prints [0, 3, 4, 9, 10, 15, 15, 19] + # Corresponds to the substrings "The Redot" and "Engine, 4". + print(ts.string_get_word_breaks("The Redot Engine, 4", "en", 10)) # Prints [0, 9, 10, 19] [/codeblock] diff --git a/doc/classes/Timer.xml b/doc/classes/Timer.xml index f4fc58b9bf..c29e67340e 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 c760e5a6e4..45f489d57e 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 947df08f87..2932d90fa4 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 45780a1aed..bc5201baac 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 6c46f82a3b..4dd0934780 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 11681be793..10f4f7c2f1 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 cb107cdf17..0a4ebea3ad 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2386,6 +2386,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; @@ -2427,7 +2428,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; @@ -2435,6 +2436,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: { } @@ -2546,10 +2548,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 d16cd4d394..f61bb73a85 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 c60d370217..6530c4d8b9 100644 --- a/drivers/gles3/storage/config.cpp +++ b/drivers/gles3/storage/config.cpp @@ -81,7 +81,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 899b93456b..0e4fb1fcc9 100644 --- a/drivers/metal/metal_objects.h +++ b/drivers/metal/metal_objects.h @@ -72,12 +72,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) @@ -951,8 +953,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 b305380abc..859a3821c8 100644 --- a/drivers/metal/metal_objects.mm +++ b/drivers/metal/metal_objects.mm @@ -58,6 +58,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; @@ -766,6 +770,7 @@ void MDCommandBuffer::render_bind_vertex_buffers(uint32_t p_binding_count, const [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); } @@ -1084,7 +1089,7 @@ void MDUniformSet::bind_uniforms_direct(MDShader *p_shader, MDCommandBuffer::Ren 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 fd16254914..7445ffd24d 100644 --- a/drivers/metal/metal_utils.h +++ b/drivers/metal/metal_utils.h @@ -55,11 +55,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 e029ea9b49..84819b4858 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 a703fdedf3..4ba4fe4ebe 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -440,11 +440,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) { @@ -554,6 +562,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 378ce6d80d..d404049103 100644 --- a/drivers/unix/dir_access_unix.h +++ b/drivers/unix/dir_access_unix.h @@ -54,6 +54,9 @@ protected: 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 79e510500c..1cb9a4e14f 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -445,7 +445,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 f50a2ab58e..0c38f6e93c 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -40,8 +40,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; @@ -58,6 +56,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 3a40c4be78..23b1456b56 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -691,7 +691,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 9870859691..cf6bfbd323 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -8068,7 +8068,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 ef24a79b52..44fcdd9e5c 100644 --- a/editor/animation_track_editor_plugins.cpp +++ b/editor/animation_track_editor_plugins.cpp @@ -222,7 +222,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); } @@ -262,7 +262,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; } @@ -381,7 +381,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); } @@ -424,7 +424,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); } @@ -458,7 +458,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; } @@ -516,7 +516,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; } @@ -810,7 +810,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); } @@ -843,7 +843,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; } @@ -1027,7 +1027,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 ed6447a74a..8ea5b713ae 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -677,8 +677,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) { @@ -786,6 +784,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")); @@ -868,7 +867,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()) { @@ -1055,7 +1054,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 5fb78276c3..4da400a149 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -113,10 +113,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