diff options
682 files changed, 11152 insertions, 31904 deletions
diff --git a/.github/actions/godot-deps/action.yml b/.github/actions/godot-deps/action.yml index ee4d7d3751..e99167ff2b 100644 --- a/.github/actions/godot-deps/action.yml +++ b/.github/actions/godot-deps/action.yml @@ -12,7 +12,7 @@ runs: steps: # Use python 3.x release (works cross platform) - name: Set up Python 3.x - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: # Semantic version range syntax or exact version of a Python version python-version: ${{ inputs.python-version }} diff --git a/.github/actions/upload-artifact/action.yml b/.github/actions/upload-artifact/action.yml index bc1871b914..ae0e634cbf 100644 --- a/.github/actions/upload-artifact/action.yml +++ b/.github/actions/upload-artifact/action.yml @@ -12,7 +12,7 @@ runs: using: "composite" steps: - name: Upload Godot Artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: ${{ inputs.name }} path: ${{ inputs.path }} diff --git a/.github/workflows/android_builds.yml b/.github/workflows/android_builds.yml index a9a580247b..4f54f6629e 100644 --- a/.github/workflows/android_builds.yml +++ b/.github/workflows/android_builds.yml @@ -17,7 +17,7 @@ jobs: name: Template (target=release, tools=no) steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # Azure repositories are not reliable, we need to prevent azure giving us packages. - name: Make apt sources.list use the default Ubuntu repositories @@ -27,8 +27,9 @@ jobs: sudo apt-get update - name: Set up Java 11 - uses: actions/setup-java@v1 + uses: actions/setup-java@v3 with: + distribution: temurin java-version: 11 - name: Setup Godot build cache @@ -38,19 +39,19 @@ jobs: - name: Setup python and scons uses: ./.github/actions/godot-deps - - name: Compilation (armv7) + - name: Compilation (arm32) uses: ./.github/actions/godot-build with: - sconsflags: ${{ env.SCONSFLAGS }} android_arch=armv7 + sconsflags: ${{ env.SCONSFLAGS }} arch=arm32 platform: android target: release tools: false tests: false - - name: Compilation (arm64v8) + - name: Compilation (arm64) uses: ./.github/actions/godot-build with: - sconsflags: ${{ env.SCONSFLAGS }} android_arch=arm64v8 + sconsflags: ${{ env.SCONSFLAGS }} arch=arm64 platform: android target: release tools: false diff --git a/.github/workflows/ios_builds.yml b/.github/workflows/ios_builds.yml index 03277edc1d..bc00fad569 100644 --- a/.github/workflows/ios_builds.yml +++ b/.github/workflows/ios_builds.yml @@ -17,7 +17,7 @@ jobs: name: Template (target=release, tools=no) steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Godot build cache uses: ./.github/actions/godot-cache @@ -26,7 +26,7 @@ jobs: - name: Setup python and scons uses: ./.github/actions/godot-deps - - name: Compilation (arm64v8) + - name: Compilation (arm64) uses: ./.github/actions/godot-build with: sconsflags: ${{ env.SCONSFLAGS }} diff --git a/.github/workflows/javascript_builds.yml b/.github/workflows/javascript_builds.yml index 00c79e8ba0..54bde92b16 100644 --- a/.github/workflows/javascript_builds.yml +++ b/.github/workflows/javascript_builds.yml @@ -19,18 +19,10 @@ jobs: name: Template (target=release, tools=no) steps: - - uses: actions/checkout@v2 - - # Additional cache for Emscripten generated system libraries - - name: Load Emscripten cache - id: javascript-template-emscripten-cache - uses: actions/cache@v2 - with: - path: ${{env.EM_CACHE_FOLDER}} - key: ${{env.EM_VERSION}}-${{github.job}} + - uses: actions/checkout@v3 - name: Set up Emscripten latest - uses: mymindstorm/setup-emsdk@v10 + uses: mymindstorm/setup-emsdk@v11 with: version: ${{env.EM_VERSION}} actions-cache-folder: ${{env.EM_CACHE_FOLDER}} diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml index 2999154fd3..2e8bd101e5 100644 --- a/.github/workflows/linux_builds.yml +++ b/.github/workflows/linux_builds.yml @@ -4,7 +4,7 @@ on: [push, pull_request] # Global Settings env: # Only used for the cache key. Increment version to force clean build. - GODOT_BASE_BRANCH: master-v2 + GODOT_BASE_BRANCH: master SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes DOTNET_NOLOGO: true DOTNET_CLI_TELEMETRY_OPTOUT: false @@ -26,9 +26,9 @@ jobs: target: release_debug tools: true tests: false # Disabled due freeze caused by mix Mono build and CI - sconsflags: module_mono_enabled=yes mono_static=yes mono_glue=no + sconsflags: module_mono_enabled=yes doc-test: true - bin: "./bin/godot.linuxbsd.opt.tools.64.mono" + bin: "./bin/godot.linuxbsd.opt.tools.x86_64.mono" build-mono: true proj-conv: true artifact: true @@ -43,7 +43,7 @@ jobs: # Can be turned off for PRs that intentionally break compat with godot-cpp, # until both the upstream PR and the matching godot-cpp changes are merged. godot-cpp-test: true - bin: "./bin/godot.linuxbsd.double.tools.64.san" + bin: "./bin/godot.linuxbsd.double.tools.x86_64.san" build-mono: false # Skip 2GiB artifact speeding up action. artifact: false @@ -54,7 +54,7 @@ jobs: tools: true tests: true sconsflags: use_asan=yes use_ubsan=yes use_llvm=yes linker=lld - bin: "./bin/godot.linuxbsd.tools.64.llvm.san" + bin: "./bin/godot.linuxbsd.tools.x86_64.llvm.san" build-mono: false # Skip 2GiB artifact speeding up action. artifact: false @@ -64,7 +64,7 @@ jobs: target: release tools: false tests: false - sconsflags: module_mono_enabled=yes mono_static=yes mono_glue=no debug_symbols=no + sconsflags: module_mono_enabled=yes debug_symbols=no build-mono: false artifact: true @@ -77,7 +77,7 @@ jobs: artifact: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Linux dependencies shell: bash @@ -102,7 +102,7 @@ jobs: uses: ./.github/actions/godot-deps - name: Set up .NET Sdk - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v2 if: ${{ matrix.build-mono }} with: dotnet-version: '6.0.x' @@ -126,16 +126,6 @@ jobs: run: | ./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --godot-platform=linuxbsd - # Rebuild with mono - - name: Compilation (mono_glue=yes) - uses: ./.github/actions/godot-build - if: ${{ matrix.build-mono }} - with: - sconsflags: ${{ env.SCONSFLAGS }} ${{ matrix.sconsflags }} mono_glue=yes - platform: linuxbsd - target: ${{ matrix.target }} - tools: ${{ matrix.tools }} - # Execute unit tests for the editor - name: Unit tests if: ${{ matrix.tests }} @@ -205,7 +195,7 @@ jobs: # Checkout godot-cpp - name: Checkout godot-cpp if: ${{ matrix.godot-cpp-test }} - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: godotengine/godot-cpp submodules: 'recursive' diff --git a/.github/workflows/macos_builds.yml b/.github/workflows/macos_builds.yml index 0ad0995bb7..be1fb8de85 100644 --- a/.github/workflows/macos_builds.yml +++ b/.github/workflows/macos_builds.yml @@ -4,7 +4,7 @@ on: [push, pull_request] # Global Settings env: # Only used for the cache key. Increment version to force clean build. - GODOT_BASE_BRANCH: master-v3 + GODOT_BASE_BRANCH: master SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes concurrency: @@ -24,7 +24,7 @@ jobs: target: release_debug tools: true tests: true - bin: "./bin/godot.macos.opt.tools.64" + bin: "./bin/godot.macos.opt.tools.x86_64" - name: Template (target=release, tools=no) cache-name: macos-template @@ -34,7 +34,7 @@ jobs: sconsflags: debug_symbols=no steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Godot build cache uses: ./.github/actions/godot-cache diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml index fea82791ed..557b67c970 100644 --- a/.github/workflows/static_checks.yml +++ b/.github/workflows/static_checks.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Azure repositories are not reliable, we need to prevent Azure giving us packages. - name: Make apt sources.list use the default Ubuntu repositories diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml index e04d49adde..9033e1ab1d 100644 --- a/.github/workflows/windows_builds.yml +++ b/.github/workflows/windows_builds.yml @@ -5,7 +5,7 @@ on: [push, pull_request] # SCONS_CACHE for windows must be set in the build environment env: # Only used for the cache key. Increment version to force clean build. - GODOT_BASE_BRANCH: master-v2 + GODOT_BASE_BRANCH: master SCONSFLAGS: verbose=yes warnings=all werror=yes module_text_server_fb_enabled=yes SCONS_CACHE_MSVC_CONFIG: true @@ -29,7 +29,7 @@ jobs: tests: true # Skip debug symbols, they're way too big with MSVC. sconsflags: debug_symbols=no - bin: "./bin/godot.windows.opt.tools.64.exe" + bin: "./bin/godot.windows.opt.tools.x86_64.exe" - name: Template (target=release, tools=no) cache-name: windows-template @@ -39,7 +39,7 @@ jobs: sconsflags: debug_symbols=no steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Godot build cache uses: ./.github/actions/godot-cache diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 49355d2782..a1e8d3a59d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,7 +37,7 @@ Godot runs on a large variety of platforms and operating systems and devices. For bugs that are likely OS-specific and/or graphics-related, please also specify: -- Device (CPU model including architecture, e.g. x86, x86_64, ARM, etc.) +- Device (CPU model including architecture, e.g. x86_64, arm64, etc.) - GPU model (and the driver version in use if you know it) **Bug reports not including the required information may be closed at the @@ -74,10 +74,10 @@ if your ZIP file isn't accepted by GitHub because it's too large. We recommend always attaching a minimal reproduction project, even if the issue may seem simple to reproduce manually. -**Note for C# users:** If your issue is not Mono-specific, please upload a -minimal reproduction project written in GDScript or VisualScript. +**Note for C# users:** If your issue is not .NET-specific, please upload a +minimal reproduction project written in GDScript. This will make it easier for contributors to reproduce the issue -locally as not everyone has a Mono setup available. +locally as not everyone has a .NET setup available. **If you've been asked by a maintainer to upload a minimal reproduction project, you *must* do so within 7 days.** Otherwise, your bug report will be closed as diff --git a/SConstruct b/SConstruct index d0d03bd8dc..55ed3771ac 100644 --- a/SConstruct +++ b/SConstruct @@ -55,6 +55,7 @@ _helper_module("modules.modules_builders", "modules/modules_builders.py") import methods import glsl_builders import gles3_builders +from platform_methods import architectures, architecture_aliases if methods.get_cmdline_bool("tools", True): _helper_module("editor.editor_builders", "editor/editor_builders.py") @@ -161,12 +162,11 @@ if profile: opts = Variables(customs, ARGUMENTS) # Target build options -opts.Add("p", "Platform (alias for 'platform')", "") opts.Add("platform", "Target platform (%s)" % ("|".join(platform_list),), "") +opts.Add("p", "Platform (alias for 'platform')", "") opts.Add(BoolVariable("tools", "Build the tools (a.k.a. the Godot editor)", True)) opts.Add(EnumVariable("target", "Compilation target", "debug", ("debug", "release_debug", "release"))) -opts.Add("arch", "Platform-dependent architecture (arm/arm64/x86/x64/mips/...)", "") -opts.Add(EnumVariable("bits", "Target platform bits", "default", ("default", "32", "64"))) +opts.Add(EnumVariable("arch", "CPU architecture", "auto", ["auto"] + architectures, architecture_aliases)) opts.Add(EnumVariable("float", "Floating-point precision", "default", ("default", "32", "64"))) opts.Add(EnumVariable("optimize", "Optimization type", "speed", ("speed", "size", "none"))) opts.Add(BoolVariable("production", "Set defaults to build Godot for use in production", False)) @@ -502,12 +502,17 @@ if selected_platform in platform_list: # Platform specific flags flag_list = platform_flags[selected_platform] for f in flag_list: - if not (f[0] in ARGUMENTS): # allow command line to override platform flags + if not (f[0] in ARGUMENTS) or ARGUMENTS[f[0]] == "auto": # Allow command line to override platform flags env[f[0]] = f[1] # Must happen after the flags' definition, so that they can be used by platform detect detect.configure(env) + print( + 'Building for platform "%s", architecture "%s", %s, target "%s".' + % (selected_platform, env["arch"], "editor" if env["tools"] else "template", env["target"]) + ) + # Set our C and C++ standard requirements. # C++17 is required as we need guaranteed copy elision as per GH-36436. # Prepending to make it possible to override. @@ -693,13 +698,7 @@ if selected_platform in platform_list: ) suffix += ".debug" - if env["arch"] != "": - suffix += "." + env["arch"] - elif env["bits"] == "32": - suffix += ".32" - elif env["bits"] == "64": - suffix += ".64" - + suffix += "." + env["arch"] suffix += env.extra_suffix sys.path.remove(tmppath) diff --git a/core/config/engine.cpp b/core/config/engine.cpp index 6606557fce..3efc0e822a 100644 --- a/core/config/engine.cpp +++ b/core/config/engine.cpp @@ -36,6 +36,7 @@ #include "core/io/json.h" #include "core/license.gen.h" #include "core/os/os.h" +#include "core/variant/typed_array.h" #include "core/version.h" void Engine::set_physics_ticks_per_second(int p_ips) { @@ -136,8 +137,8 @@ Dictionary Engine::get_author_info() const { return dict; } -Array Engine::get_copyright_info() const { - Array components; +TypedArray<Dictionary> Engine::get_copyright_info() const { + TypedArray<Dictionary> components; for (int component_index = 0; component_index < COPYRIGHT_INFO_COUNT; component_index++) { const ComponentCopyright &cp_info = COPYRIGHT_INFO[component_index]; Dictionary component_dict; diff --git a/core/config/engine.h b/core/config/engine.h index b4364dbda4..121fd4d541 100644 --- a/core/config/engine.h +++ b/core/config/engine.h @@ -36,6 +36,9 @@ #include "core/templates/list.h" #include "core/templates/vector.h" +template <typename T> +class TypedArray; + class Engine { public: struct Singleton { @@ -139,7 +142,7 @@ public: Dictionary get_version_info() const; Dictionary get_author_info() const; - Array get_copyright_info() const; + TypedArray<Dictionary> get_copyright_info() const; Dictionary get_donor_info() const; Dictionary get_license_info() const; String get_license_text() const; diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 630bd68e65..bcc87d78c4 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -39,6 +39,7 @@ #include "core/math/geometry_2d.h" #include "core/math/geometry_3d.h" #include "core/os/keyboard.h" +#include "core/variant/typed_array.h" namespace core_bind { @@ -436,10 +437,6 @@ bool OS::is_stdout_verbose() const { return ::OS::get_singleton()->is_stdout_verbose(); } -void OS::dump_memory_to_file(const String &p_file) { - ::OS::get_singleton()->dump_memory_to_file(p_file.utf8().get_data()); -} - struct OSCoreBindImg { String path; Size2 size; @@ -666,7 +663,6 @@ void OS::_bind_methods() { ClassDB::bind_method(D_METHOD("is_debug_build"), &OS::is_debug_build); - ClassDB::bind_method(D_METHOD("dump_memory_to_file", "file"), &OS::dump_memory_to_file); ClassDB::bind_method(D_METHOD("dump_resources_to_file", "file"), &OS::dump_resources_to_file); ClassDB::bind_method(D_METHOD("print_resources_in_use", "short"), &OS::print_resources_in_use, DEFVAL(false)); ClassDB::bind_method(D_METHOD("print_all_resources", "tofile"), &OS::print_all_resources, DEFVAL("")); @@ -818,7 +814,7 @@ Vector<Point2> Geometry2D::convex_hull(const Vector<Point2> &p_points) { return ::Geometry2D::convex_hull(p_points); } -Array Geometry2D::merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { +TypedArray<PackedVector2Array> Geometry2D::merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { Vector<Vector<Point2>> polys = ::Geometry2D::merge_polygons(p_polygon_a, p_polygon_b); Array ret; @@ -829,10 +825,10 @@ Array Geometry2D::merge_polygons(const Vector<Vector2> &p_polygon_a, const Vecto return ret; } -Array Geometry2D::clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { +TypedArray<PackedVector2Array> Geometry2D::clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { Vector<Vector<Point2>> polys = ::Geometry2D::clip_polygons(p_polygon_a, p_polygon_b); - Array ret; + TypedArray<PackedVector2Array> ret; for (int i = 0; i < polys.size(); ++i) { ret.push_back(polys[i]); @@ -840,7 +836,7 @@ Array Geometry2D::clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector return ret; } -Array Geometry2D::intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { +TypedArray<PackedVector2Array> Geometry2D::intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { Vector<Vector<Point2>> polys = ::Geometry2D::intersect_polygons(p_polygon_a, p_polygon_b); Array ret; @@ -851,7 +847,7 @@ Array Geometry2D::intersect_polygons(const Vector<Vector2> &p_polygon_a, const V return ret; } -Array Geometry2D::exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { +TypedArray<PackedVector2Array> Geometry2D::exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) { Vector<Vector<Point2>> polys = ::Geometry2D::exclude_polygons(p_polygon_a, p_polygon_b); Array ret; @@ -862,7 +858,7 @@ Array Geometry2D::exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vec return ret; } -Array Geometry2D::clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) { +TypedArray<PackedVector2Array> Geometry2D::clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) { Vector<Vector<Point2>> polys = ::Geometry2D::clip_polyline_with_polygon(p_polyline, p_polygon); Array ret; @@ -873,7 +869,7 @@ Array Geometry2D::clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, return ret; } -Array Geometry2D::intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) { +TypedArray<PackedVector2Array> Geometry2D::intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) { Vector<Vector<Point2>> polys = ::Geometry2D::intersect_polyline_with_polygon(p_polyline, p_polygon); Array ret; @@ -884,7 +880,7 @@ Array Geometry2D::intersect_polyline_with_polygon(const Vector<Vector2> &p_polyl return ret; } -Array Geometry2D::offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) { +TypedArray<PackedVector2Array> Geometry2D::offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) { Vector<Vector<Point2>> polys = ::Geometry2D::offset_polygon(p_polygon, p_delta, ::Geometry2D::PolyJoinType(p_join_type)); Array ret; @@ -895,7 +891,7 @@ Array Geometry2D::offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delt return ret; } -Array Geometry2D::offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { +TypedArray<PackedVector2Array> Geometry2D::offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { Vector<Vector<Point2>> polys = ::Geometry2D::offset_polyline(p_polygon, p_delta, ::Geometry2D::PolyJoinType(p_join_type), ::Geometry2D::PolyEndType(p_end_type)); Array ret; @@ -988,16 +984,19 @@ Geometry3D *Geometry3D::get_singleton() { return singleton; } -Vector<Plane> Geometry3D::build_box_planes(const Vector3 &p_extents) { - return ::Geometry3D::build_box_planes(p_extents); +TypedArray<Plane> Geometry3D::build_box_planes(const Vector3 &p_extents) { + Variant ret = ::Geometry3D::build_box_planes(p_extents); + return ret; } -Vector<Plane> Geometry3D::build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis) { - return ::Geometry3D::build_cylinder_planes(p_radius, p_height, p_sides, p_axis); +TypedArray<Plane> Geometry3D::build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis) { + Variant ret = ::Geometry3D::build_cylinder_planes(p_radius, p_height, p_sides, p_axis); + return ret; } -Vector<Plane> Geometry3D::build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis) { - return ::Geometry3D::build_capsule_planes(p_radius, p_height, p_sides, p_lats, p_axis); +TypedArray<Plane> Geometry3D::build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis) { + Variant ret = ::Geometry3D::build_capsule_planes(p_radius, p_height, p_sides, p_lats, p_axis); + return ret; } Vector<Vector3> Geometry3D::get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2) { @@ -2022,10 +2021,10 @@ Dictionary ClassDB::get_signal(StringName p_class, StringName p_signal) const { } } -Array ClassDB::get_signal_list(StringName p_class, bool p_no_inheritance) const { +TypedArray<Dictionary> ClassDB::get_signal_list(StringName p_class, bool p_no_inheritance) const { List<MethodInfo> signals; ::ClassDB::get_signal_list(p_class, &signals, p_no_inheritance); - Array ret; + TypedArray<Dictionary> ret; for (const MethodInfo &E : signals) { ret.push_back(E.operator Dictionary()); @@ -2034,10 +2033,10 @@ Array ClassDB::get_signal_list(StringName p_class, bool p_no_inheritance) const return ret; } -Array ClassDB::get_property_list(StringName p_class, bool p_no_inheritance) const { +TypedArray<Dictionary> ClassDB::get_property_list(StringName p_class, bool p_no_inheritance) const { List<PropertyInfo> plist; ::ClassDB::get_property_list(p_class, &plist, p_no_inheritance); - Array ret; + TypedArray<Dictionary> ret; for (const PropertyInfo &E : plist) { ret.push_back(E.operator Dictionary()); } @@ -2066,10 +2065,10 @@ bool ClassDB::has_method(StringName p_class, StringName p_method, bool p_no_inhe return ::ClassDB::has_method(p_class, p_method, p_no_inheritance); } -Array ClassDB::get_method_list(StringName p_class, bool p_no_inheritance) const { +TypedArray<Dictionary> ClassDB::get_method_list(StringName p_class, bool p_no_inheritance) const { List<MethodInfo> methods; ::ClassDB::get_method_list(p_class, &methods, p_no_inheritance); - Array ret; + TypedArray<Dictionary> ret; for (const MethodInfo &E : methods) { #ifdef DEBUG_METHODS_ENABLED @@ -2254,7 +2253,7 @@ Dictionary Engine::get_author_info() const { return ::Engine::get_singleton()->get_author_info(); } -Array Engine::get_copyright_info() const { +TypedArray<Dictionary> Engine::get_copyright_info() const { return ::Engine::get_singleton()->get_copyright_info(); } diff --git a/core/core_bind.h b/core/core_bind.h index 79230bd685..642a0c00c7 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -45,6 +45,8 @@ #include "core/templates/safe_refcount.h" class MainLoop; +template <typename T> +class TypedArray; namespace core_bind { @@ -199,7 +201,6 @@ public: String get_model_name() const; - void dump_memory_to_file(const String &p_file); void dump_resources_to_file(const String &p_file); void print_resources_in_use(bool p_short = false); @@ -301,14 +302,14 @@ public: OPERATION_XOR }; // 2D polygon boolean operations. - Array merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Union (add). - Array clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Difference (subtract). - Array intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Common area (multiply). - Array exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // All but common area (xor). + TypedArray<PackedVector2Array> merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Union (add). + TypedArray<PackedVector2Array> clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Difference (subtract). + TypedArray<PackedVector2Array> intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Common area (multiply). + TypedArray<PackedVector2Array> exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // All but common area (xor). // 2D polyline vs polygon operations. - Array clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Cut. - Array intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Chop. + TypedArray<PackedVector2Array> clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Cut. + TypedArray<PackedVector2Array> intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Chop. // 2D offset polygons/polylines. enum PolyJoinType { @@ -323,8 +324,8 @@ public: END_SQUARE, END_ROUND }; - Array offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE); - Array offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE, PolyEndType p_end_type = END_SQUARE); + TypedArray<PackedVector2Array> offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE); + TypedArray<PackedVector2Array> offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE, PolyEndType p_end_type = END_SQUARE); Dictionary make_atlas(const Vector<Size2> &p_rects); @@ -341,9 +342,9 @@ protected: public: static Geometry3D *get_singleton(); - Vector<Plane> build_box_planes(const Vector3 &p_extents); - Vector<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis = Vector3::AXIS_Z); - Vector<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z); + TypedArray<Plane> build_box_planes(const Vector3 &p_extents); + TypedArray<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis = Vector3::AXIS_Z); + TypedArray<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z); Vector<Vector3> get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2); Vector3 get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b); Vector3 get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b); @@ -602,15 +603,15 @@ public: bool has_signal(StringName p_class, StringName p_signal) const; Dictionary get_signal(StringName p_class, StringName p_signal) const; - Array get_signal_list(StringName p_class, bool p_no_inheritance = false) const; + TypedArray<Dictionary> get_signal_list(StringName p_class, bool p_no_inheritance = false) const; - Array get_property_list(StringName p_class, bool p_no_inheritance = false) const; + TypedArray<Dictionary> get_property_list(StringName p_class, bool p_no_inheritance = false) const; Variant get_property(Object *p_object, const StringName &p_property) const; Error set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const; bool has_method(StringName p_class, StringName p_method, bool p_no_inheritance = false) const; - Array get_method_list(StringName p_class, bool p_no_inheritance = false) const; + TypedArray<Dictionary> get_method_list(StringName p_class, bool p_no_inheritance = false) const; PackedStringArray get_integer_constant_list(const StringName &p_class, bool p_no_inheritance = false) const; bool has_integer_constant(const StringName &p_class, const StringName &p_name) const; @@ -661,7 +662,7 @@ public: Dictionary get_version_info() const; Dictionary get_author_info() const; - Array get_copyright_info() const; + TypedArray<Dictionary> get_copyright_info() const; Dictionary get_donor_info() const; Dictionary get_license_info() const; String get_license_text() const; diff --git a/core/core_constants.cpp b/core/core_constants.cpp index dc0ab72a86..299b60872d 100644 --- a/core/core_constants.cpp +++ b/core/core_constants.cpp @@ -612,6 +612,7 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALE_ID); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALIZABLE_STRING); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_TYPE); + BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_HIDE_QUATERNION_EDIT); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX); BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NONE); diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp index 867b1fc637..5cf951a93c 100644 --- a/core/extension/extension_api_dump.cpp +++ b/core/extension/extension_api_dump.cpp @@ -52,6 +52,9 @@ static String get_type_name(const PropertyInfo &p_info) { if (p_info.type == Variant::INT && (p_info.usage & (PROPERTY_USAGE_CLASS_IS_BITFIELD))) { return String("bitfield::") + String(p_info.class_name); } + if (p_info.type == Variant::INT && (p_info.usage & PROPERTY_USAGE_ARRAY)) { + return "int"; + } if (p_info.class_name != StringName()) { return p_info.class_name; } @@ -88,6 +91,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() { } const uint32_t vec3_elems = 3; + const uint32_t vec4_elems = 4; const uint32_t ptrsize_32 = 4; const uint32_t ptrsize_64 = 8; static const char *build_config_name[4] = { "float_32", "float_64", "double_32", "double_64" }; @@ -138,7 +142,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() { { Variant::AABB, (vec3_elems * 2) * sizeof(float), (vec3_elems * 2) * sizeof(float), (vec3_elems * 2) * sizeof(double), (vec3_elems * 2) * sizeof(double) }, { Variant::BASIS, (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(double), (vec3_elems * 3) * sizeof(double) }, { Variant::TRANSFORM3D, (vec3_elems * 4) * sizeof(float), (vec3_elems * 4) * sizeof(float), (vec3_elems * 4) * sizeof(double), (vec3_elems * 4) * sizeof(double) }, - { Variant::PROJECTION, 4 * 4 * sizeof(float), 4 * 4 * sizeof(float), 4 * 4 * sizeof(double), 4 * 4 * sizeof(double) }, + { Variant::PROJECTION, (vec4_elems * 4) * sizeof(float), (vec4_elems * 4) * sizeof(float), (vec4_elems * 4) * sizeof(double), (vec4_elems * 4) * sizeof(double) }, { Variant::COLOR, 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(float) }, { Variant::STRING_NAME, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, { Variant::NODE_PATH, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, @@ -284,6 +288,10 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() { { Variant::BASIS, "z", vec3_elems * 2 * sizeof(float), vec3_elems * 2 * sizeof(float), vec3_elems * 2 * sizeof(double), vec3_elems * 2 * sizeof(double) }, { Variant::TRANSFORM3D, "basis", 0, 0, 0, 0 }, { Variant::TRANSFORM3D, "origin", (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(double), (vec3_elems * 3) * sizeof(double) }, + { Variant::PROJECTION, "x", 0, 0, 0, 0 }, + { Variant::PROJECTION, "y", vec4_elems * sizeof(float), vec4_elems * sizeof(float), vec4_elems * sizeof(double), vec4_elems * sizeof(double) }, + { Variant::PROJECTION, "z", vec4_elems * 2 * sizeof(float), vec4_elems * 2 * sizeof(float), vec4_elems * 2 * sizeof(double), vec4_elems * 2 * sizeof(double) }, + { Variant::PROJECTION, "w", vec4_elems * 3 * sizeof(float), vec4_elems * 3 * sizeof(float), vec4_elems * 3 * sizeof(double), vec4_elems * 3 * sizeof(double) }, { Variant::COLOR, "r", 0, 0, 0, 0 }, { Variant::COLOR, "g", sizeof(float), sizeof(float), sizeof(float), sizeof(float) }, { Variant::COLOR, "b", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float) }, @@ -840,12 +848,16 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() { List<PropertyInfo> property_list; ClassDB::get_property_list(class_name, &property_list, true); for (const PropertyInfo &F : property_list) { - if (F.usage & PROPERTY_USAGE_CATEGORY || F.usage & PROPERTY_USAGE_GROUP || F.usage & PROPERTY_USAGE_SUBGROUP) { + if (F.usage & PROPERTY_USAGE_CATEGORY || F.usage & PROPERTY_USAGE_GROUP || F.usage & PROPERTY_USAGE_SUBGROUP || (F.type == Variant::NIL && F.usage & PROPERTY_USAGE_ARRAY)) { continue; //not real properties } if (F.name.begins_with("_")) { continue; //hidden property } + if (F.name.find("/") >= 0) { + // Ignore properties with '/' (slash) in the name. These are only meant for use in the inspector. + continue; + } StringName property_name = F.name; Dictionary d2; d2["type"] = get_type_name(F); diff --git a/core/input/input.cpp b/core/input/input.cpp index e08647f5ea..4e538a85ae 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -767,9 +767,6 @@ Point2i Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, con return rel_warped; } -void Input::iteration(float p_step) { -} - void Input::action_press(const StringName &p_action, float p_strength) { Action action; @@ -974,11 +971,9 @@ void Input::joy_axis(int p_device, JoyAxis p_axis, float p_value) { if (map.type == TYPE_BUTTON) { bool pressed = map.value > 0.5; - if (pressed == joy_buttons_pressed.has(_combine_device((JoyButton)map.index, p_device))) { - // Button already pressed or released; so ignore. - return; + if (pressed != joy_buttons_pressed.has(_combine_device((JoyButton)map.index, p_device))) { + _button_event(p_device, (JoyButton)map.index, pressed); } - _button_event(p_device, (JoyButton)map.index, pressed); // Ensure opposite D-Pad button is also released. switch ((JoyButton)map.index) { @@ -1129,7 +1124,7 @@ Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, J value = -value; } if (binding.input.axis.range == FULL_AXIS || - (binding.input.axis.range == POSITIVE_HALF_AXIS && value > 0) || + (binding.input.axis.range == POSITIVE_HALF_AXIS && value >= 0) || (binding.input.axis.range == NEGATIVE_HALF_AXIS && value < 0)) { event.type = binding.outputType; float shifted_positive_value = 0; diff --git a/core/input/input.h b/core/input/input.h index 3ad8c91ddf..a07174b887 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -114,6 +114,15 @@ private: int mouse_from_touch_index = -1; + struct VibrationInfo { + float weak_magnitude; + float strong_magnitude; + float duration; // Duration in seconds + uint64_t timestamp; + }; + + HashMap<int, VibrationInfo> joy_vibration; + struct VelocityTrack { uint64_t last_tick = 0; Vector2 velocity; @@ -226,15 +235,6 @@ private: EventDispatchFunc event_dispatch_function = nullptr; protected: - struct VibrationInfo { - float weak_magnitude; - float strong_magnitude; - float duration; // Duration in seconds - uint64_t timestamp; - }; - - HashMap<int, VibrationInfo> joy_vibration; - static void _bind_methods(); public: @@ -295,8 +295,6 @@ public: void action_press(const StringName &p_action, float p_strength = 1.f); void action_release(const StringName &p_action); - void iteration(float p_step); - void set_emulate_touch_from_mouse(bool p_emulate); bool is_emulating_touch_from_mouse() const; void ensure_touch_mouse_raised(); diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 942c5248df..702e257fb4 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -34,6 +34,7 @@ #include "core/input/input.h" #include "core/os/keyboard.h" #include "core/os/os.h" +#include "core/variant/typed_array.h" InputMap *InputMap::singleton = nullptr; @@ -99,8 +100,8 @@ void InputMap::erase_action(const StringName &p_action) { input_map.erase(p_action); } -Array InputMap::_get_actions() { - Array ret; +TypedArray<StringName> InputMap::_get_actions() { + TypedArray<StringName> ret; List<StringName> actions = get_actions(); if (actions.is_empty()) { return ret; @@ -190,8 +191,8 @@ void InputMap::action_erase_events(const StringName &p_action) { input_map[p_action].inputs.clear(); } -Array InputMap::_action_get_events(const StringName &p_action) { - Array ret; +TypedArray<InputEvent> InputMap::_action_get_events(const StringName &p_action) { + TypedArray<InputEvent> ret; const List<Ref<InputEvent>> *al = action_get_events(p_action); if (al) { for (const List<Ref<InputEvent>>::Element *E = al->front(); E; E = E->next()) { diff --git a/core/input/input_map.h b/core/input/input_map.h index 2400a4a3f7..414a06b2f1 100644 --- a/core/input/input_map.h +++ b/core/input/input_map.h @@ -36,6 +36,9 @@ #include "core/object/object.h" #include "core/templates/hash_map.h" +template <typename T> +class TypedArray; + class InputMap : public Object { GDCLASS(InputMap, Object); @@ -60,8 +63,8 @@ private: List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr) const; - Array _action_get_events(const StringName &p_action); - Array _get_actions(); + TypedArray<InputEvent> _action_get_events(const StringName &p_action); + TypedArray<StringName> _get_actions(); protected: static void _bind_methods(); diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index 8ed3d40c22..72c00bd678 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -115,6 +115,10 @@ FileAccess::CreateFunc FileAccess::get_create_func(AccessType p_access) { return create_func[p_access]; } +FileAccess::AccessType FileAccess::get_access_type() const { + return _access_type; +} + String FileAccess::fix_path(const String &p_path) const { //helper used by file accesses that use a single filesystem diff --git a/core/io/file_access.h b/core/io/file_access.h index 3386800686..fc0eb95d44 100644 --- a/core/io/file_access.h +++ b/core/io/file_access.h @@ -60,6 +60,7 @@ public: virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) = 0; protected: + AccessType get_access_type() const; String fix_path(const String &p_path) const; virtual Error _open(const String &p_path, int p_mode_flags) = 0; ///< open a file virtual uint64_t _get_modified_time(const String &p_file) = 0; diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp index 9cf7c9caba..d09697b951 100644 --- a/core/io/image_loader.cpp +++ b/core/io/image_loader.cpp @@ -44,7 +44,7 @@ bool ImageFormatLoader::recognize(const String &p_extension) const { return false; } -Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, bool p_force_linear, float p_scale) { +Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, uint32_t p_flags, float p_scale) { ERR_FAIL_COND_V_MSG(p_image.is_null(), ERR_INVALID_PARAMETER, "It's not a reference to a valid Image object."); Ref<FileAccess> f = p_custom; @@ -60,7 +60,7 @@ Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> if (!loader[i]->recognize(extension)) { continue; } - Error err = loader[i]->load_image(p_image, f, p_force_linear, p_scale); + Error err = loader[i]->load_image(p_image, f, p_flags, p_scale); if (err != OK) { ERR_PRINT("Error loading image: " + p_file); } @@ -152,7 +152,7 @@ Ref<Resource> ResourceFormatLoaderImage::load(const String &p_path, const String Ref<Image> image; image.instantiate(); - Error err = ImageLoader::loader[idx]->load_image(image, f, false, 1.0); + Error err = ImageLoader::loader[idx]->load_image(image, f); if (err != OK) { if (r_error) { diff --git a/core/io/image_loader.h b/core/io/image_loader.h index c91d382c25..cb64d2310e 100644 --- a/core/io/image_loader.h +++ b/core/io/image_loader.h @@ -44,11 +44,16 @@ class ImageFormatLoader { friend class ResourceFormatLoaderImage; protected: - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) = 0; + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags = (uint32_t)FLAG_NONE, float p_scale = 1.0) = 0; virtual void get_recognized_extensions(List<String> *p_extensions) const = 0; bool recognize(const String &p_extension) const; public: + enum LoaderFlags { + FLAG_NONE = 0, + FLAG_FORCE_LINEAR = 1, + }; + virtual ~ImageFormatLoader() {} }; @@ -58,7 +63,7 @@ class ImageLoader { protected: public: - static Error load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom = Ref<FileAccess>(), bool p_force_linear = false, float p_scale = 1.0); + static Error load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom = Ref<FileAccess>(), uint32_t p_flags = (uint32_t)ImageFormatLoader::FLAG_NONE, float p_scale = 1.0); static void get_recognized_extensions(List<String> *p_extensions); static ImageFormatLoader *recognize(const String &p_extension); diff --git a/core/io/ip.cpp b/core/io/ip.cpp index 25e3bef5fc..a4d8dc3d5b 100644 --- a/core/io/ip.cpp +++ b/core/io/ip.cpp @@ -33,6 +33,7 @@ #include "core/os/semaphore.h" #include "core/os/thread.h" #include "core/templates/hash_map.h" +#include "core/variant/typed_array.h" VARIANT_ENUM_CAST(IP::ResolverStatus); @@ -124,11 +125,11 @@ struct _IP_ResolverPrivate { }; IPAddress IP::resolve_hostname(const String &p_hostname, IP::Type p_type) { - const Array addresses = resolve_hostname_addresses(p_hostname, p_type); - return addresses.size() ? addresses[0].operator IPAddress() : IPAddress(); + const PackedStringArray addresses = resolve_hostname_addresses(p_hostname, p_type); + return addresses.size() ? (IPAddress)addresses[0] : IPAddress(); } -Array IP::resolve_hostname_addresses(const String &p_hostname, Type p_type) { +PackedStringArray IP::resolve_hostname_addresses(const String &p_hostname, Type p_type) { List<IPAddress> res; String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type); @@ -148,7 +149,7 @@ Array IP::resolve_hostname_addresses(const String &p_hostname, Type p_type) { } resolver->mutex.unlock(); - Array result; + PackedStringArray result; for (int i = 0; i < res.size(); ++i) { result.push_back(String(res[i])); } @@ -254,8 +255,8 @@ void IP::clear_cache(const String &p_hostname) { } } -Array IP::_get_local_addresses() const { - Array addresses; +PackedStringArray IP::_get_local_addresses() const { + PackedStringArray addresses; List<IPAddress> ip_addresses; get_local_addresses(&ip_addresses); for (const IPAddress &E : ip_addresses) { @@ -265,8 +266,8 @@ Array IP::_get_local_addresses() const { return addresses; } -Array IP::_get_local_interfaces() const { - Array results; +TypedArray<Dictionary> IP::_get_local_interfaces() const { + TypedArray<Dictionary> results; HashMap<String, Interface_Info> interfaces; get_local_interfaces(&interfaces); for (KeyValue<String, Interface_Info> &E : interfaces) { diff --git a/core/io/ip.h b/core/io/ip.h index 4d83515e2b..f2d93a454d 100644 --- a/core/io/ip.h +++ b/core/io/ip.h @@ -34,6 +34,9 @@ #include "core/io/ip_address.h" #include "core/os/os.h" +template <typename T> +class TypedArray; + struct _IP_ResolverPrivate; class IP : public Object { @@ -68,8 +71,8 @@ protected: static IP *singleton; static void _bind_methods(); - Array _get_local_addresses() const; - Array _get_local_interfaces() const; + PackedStringArray _get_local_addresses() const; + TypedArray<Dictionary> _get_local_interfaces() const; static IP *(*_create)(); @@ -82,7 +85,7 @@ public: }; IPAddress resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY); - Array resolve_hostname_addresses(const String &p_hostname, Type p_type = TYPE_ANY); + PackedStringArray resolve_hostname_addresses(const String &p_hostname, Type p_type = TYPE_ANY); // async resolver hostname ResolverID resolve_hostname_queue_item(const String &p_hostname, Type p_type = TYPE_ANY); ResolverStatus get_resolve_item_status(ResolverID p_id) const; diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 274316f058..386ccb78e9 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -70,7 +70,7 @@ void ResourceFormatSaver::get_recognized_extensions(const Ref<Resource> &p_resou } void ResourceFormatSaver::_bind_methods() { - GDVIRTUAL_BIND(_save, "path", "resource", "flags"); + GDVIRTUAL_BIND(_save, "resource", "path", "flags"); GDVIRTUAL_BIND(_recognize, "resource"); GDVIRTUAL_BIND(_get_recognized_extensions, "resource"); } diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index 41a0848d01..b4281820e2 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -209,8 +209,8 @@ bool AStar3D::has_point(int64_t p_id) const { return points.has(p_id); } -Array AStar3D::get_point_ids() { - Array point_list; +PackedInt64Array AStar3D::get_point_ids() { + PackedInt64Array point_list; for (OAHashMap<int64_t, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) { point_list.push_back(*(it.key)); @@ -605,7 +605,7 @@ Vector<int64_t> AStar2D::get_point_connections(int64_t p_id) { return astar.get_point_connections(p_id); } -Array AStar2D::get_point_ids() { +PackedInt64Array AStar2D::get_point_ids() { return astar.get_point_ids(); } diff --git a/core/math/a_star.h b/core/math/a_star.h index c1497d133f..a9e2a62bb2 100644 --- a/core/math/a_star.h +++ b/core/math/a_star.h @@ -133,7 +133,7 @@ public: void remove_point(int64_t p_id); bool has_point(int64_t p_id) const; Vector<int64_t> get_point_connections(int64_t p_id); - Array get_point_ids(); + PackedInt64Array get_point_ids(); void set_point_disabled(int64_t p_id, bool p_disabled = true); bool is_point_disabled(int64_t p_id) const; @@ -183,7 +183,7 @@ public: void remove_point(int64_t p_id); bool has_point(int64_t p_id) const; Vector<int64_t> get_point_connections(int64_t p_id); - Array get_point_ids(); + PackedInt64Array get_point_ids(); void set_point_disabled(int64_t p_id, bool p_disabled = true); bool is_point_disabled(int64_t p_id) const; diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp index 36358f6feb..c836a82e37 100644 --- a/core/math/quaternion.cpp +++ b/core/math/quaternion.cpp @@ -112,10 +112,11 @@ Quaternion Quaternion::exp() const { Quaternion src = *this; Vector3 src_v = Vector3(src.x, src.y, src.z); real_t theta = src_v.length(); - if (theta < CMP_EPSILON) { + src_v = src_v.normalized(); + if (theta < CMP_EPSILON || !src_v.is_normalized()) { return Quaternion(0, 0, 0, 1); } - return Quaternion(src_v.normalized(), theta); + return Quaternion(src_v, theta); } Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) const { diff --git a/core/object/object.cpp b/core/object/object.cpp index 5203685c7f..4f7f55c8b6 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -38,6 +38,7 @@ #include "core/os/os.h" #include "core/string/print_string.h" #include "core/string/translation.h" +#include "core/variant/typed_array.h" #ifdef DEBUG_ENABLED @@ -102,8 +103,8 @@ PropertyInfo PropertyInfo::from_dict(const Dictionary &p_dict) { return pi; } -Array convert_property_list(const List<PropertyInfo> *p_list) { - Array va; +TypedArray<Dictionary> convert_property_list(const List<PropertyInfo> *p_list) { + TypedArray<Dictionary> va; for (const List<PropertyInfo>::Element *E = p_list->front(); E; E = E->next()) { va.push_back(Dictionary(E->get())); } @@ -519,7 +520,7 @@ void Object::validate_property(PropertyInfo &p_property) const { _validate_propertyv(p_property); } -bool Object::property_can_revert(const String &p_name) const { +bool Object::property_can_revert(const StringName &p_name) const { if (script_instance) { if (script_instance->property_can_revert(p_name)) { return true; @@ -543,7 +544,7 @@ bool Object::property_can_revert(const String &p_name) const { return _property_can_revertv(p_name); } -Variant Object::property_get_revert(const String &p_name) const { +Variant Object::property_get_revert(const StringName &p_name) const { Variant ret; if (script_instance) { @@ -912,16 +913,16 @@ void Object::remove_meta(const StringName &p_name) { set_meta(p_name, Variant()); } -Array Object::_get_property_list_bind() const { +TypedArray<Dictionary> Object::_get_property_list_bind() const { List<PropertyInfo> lpi; get_property_list(&lpi); return convert_property_list(&lpi); } -Array Object::_get_method_list_bind() const { +TypedArray<Dictionary> Object::_get_method_list_bind() const { List<MethodInfo> ml; get_method_list(&ml); - Array ret; + TypedArray<Dictionary> ret; for (List<MethodInfo>::Element *E = ml.front(); E; E = E->next()) { Dictionary d = E->get(); @@ -1109,11 +1110,11 @@ void Object::_add_user_signal(const String &p_name, const Array &p_args) { add_user_signal(mi); } -Array Object::_get_signal_list() const { +TypedArray<Dictionary> Object::_get_signal_list() const { List<MethodInfo> signal_list; get_signal_list(&signal_list); - Array ret; + TypedArray<Dictionary> ret; for (const MethodInfo &E : signal_list) { ret.push_back(Dictionary(E)); } @@ -1121,11 +1122,11 @@ Array Object::_get_signal_list() const { return ret; } -Array Object::_get_signal_connection_list(const StringName &p_signal) const { +TypedArray<Dictionary> Object::_get_signal_connection_list(const StringName &p_signal) const { List<Connection> conns; get_all_signal_connections(&conns); - Array ret; + TypedArray<Dictionary> ret; for (const Connection &c : conns) { if (c.signal.get_name() == p_signal) { @@ -1136,8 +1137,8 @@ Array Object::_get_signal_connection_list(const StringName &p_signal) const { return ret; } -Array Object::_get_incoming_connections() const { - Array ret; +TypedArray<Dictionary> Object::_get_incoming_connections() const { + TypedArray<Dictionary> ret; int connections_amount = connections.size(); for (int idx_conn = 0; idx_conn < connections_amount; idx_conn++) { ret.push_back(connections[idx_conn]); @@ -1553,7 +1554,12 @@ void Object::_bind_methods() { miget.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; BIND_OBJ_CORE_METHOD(miget); - BIND_OBJ_CORE_METHOD(MethodInfo(Variant::ARRAY, "_get_property_list")); + MethodInfo plget("_get_property_list"); + plget.return_val.type = Variant::ARRAY; + plget.return_val.hint = PROPERTY_HINT_ARRAY_TYPE; + plget.return_val.hint_string = "Dictionary"; + BIND_OBJ_CORE_METHOD(plget); + BIND_OBJ_CORE_METHOD(MethodInfo(Variant::BOOL, "_property_can_revert", PropertyInfo(Variant::STRING_NAME, "property"))); MethodInfo mipgr("_property_get_revert", PropertyInfo(Variant::STRING_NAME, "property")); mipgr.return_val.name = "Variant"; diff --git a/core/object/object.h b/core/object/object.h index 093b104664..13a40191e6 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -45,6 +45,9 @@ #include "core/variant/callable_bind.h" #include "core/variant/variant.h" +template <typename T> +class TypedArray; + enum PropertyHint { PROPERTY_HINT_NONE, ///< no hint provided. PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,no_slider][,radians][,degrees][,exp][,suffix:<keyword>] range. @@ -91,6 +94,7 @@ enum PropertyHint { PROPERTY_HINT_LOCALE_ID, PROPERTY_HINT_LOCALIZABLE_STRING, PROPERTY_HINT_NODE_TYPE, ///< a node object type + PROPERTY_HINT_HIDE_QUATERNION_EDIT, /// Only Node3D::transform should hide the quaternion editor. PROPERTY_HINT_MAX, // When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit }; @@ -207,7 +211,7 @@ struct PropertyInfo { } }; -Array convert_property_list(const List<PropertyInfo> *p_list); +TypedArray<Dictionary> convert_property_list(const List<PropertyInfo> *p_list); enum MethodFlags { METHOD_FLAG_NORMAL = 1, @@ -597,9 +601,9 @@ private: void _add_user_signal(const String &p_name, const Array &p_args = Array()); bool _has_user_signal(const StringName &p_name) const; Error _emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error); - Array _get_signal_list() const; - Array _get_signal_connection_list(const StringName &p_signal) const; - Array _get_incoming_connections() const; + TypedArray<Dictionary> _get_signal_list() const; + TypedArray<Dictionary> _get_signal_connection_list(const StringName &p_signal) const; + TypedArray<Dictionary> _get_incoming_connections() const; void _set_bind(const StringName &p_set, const Variant &p_value); Variant _get_bind(const StringName &p_name) const; void _set_indexed_bind(const NodePath &p_name, const Variant &p_value); @@ -698,8 +702,8 @@ protected: } Vector<StringName> _get_meta_list_bind() const; - Array _get_property_list_bind() const; - Array _get_method_list_bind() const; + TypedArray<Dictionary> _get_property_list_bind() const; + TypedArray<Dictionary> _get_method_list_bind() const; void _clear_internal_resource_paths(const Variant &p_var); @@ -805,8 +809,8 @@ public: void get_property_list(List<PropertyInfo> *p_list, bool p_reversed = false) const; void validate_property(PropertyInfo &p_property) const; - bool property_can_revert(const String &p_name) const; - Variant property_get_revert(const String &p_name) const; + bool property_can_revert(const StringName &p_name) const; + Variant property_get_revert(const StringName &p_name) const; bool has_method(const StringName &p_method) const; void get_method_list(List<MethodInfo> *p_list) const; diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index b06c2e8896..e56d2e80b9 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -34,6 +34,7 @@ #include "core/core_string_names.h" #include "core/debugger/engine_debugger.h" #include "core/debugger/script_debugger.h" +#include "core/variant/typed_array.h" #include <stdint.h> @@ -61,8 +62,8 @@ Variant Script::_get_property_default_value(const StringName &p_property) { return ret; } -Array Script::_get_script_property_list() { - Array ret; +TypedArray<Dictionary> Script::_get_script_property_list() { + TypedArray<Dictionary> ret; List<PropertyInfo> list; get_script_property_list(&list); for (const PropertyInfo &E : list) { @@ -71,8 +72,8 @@ Array Script::_get_script_property_list() { return ret; } -Array Script::_get_script_method_list() { - Array ret; +TypedArray<Dictionary> Script::_get_script_method_list() { + TypedArray<Dictionary> ret; List<MethodInfo> list; get_script_method_list(&list); for (const MethodInfo &E : list) { @@ -81,8 +82,8 @@ Array Script::_get_script_method_list() { return ret; } -Array Script::_get_script_signal_list() { - Array ret; +TypedArray<Dictionary> Script::_get_script_signal_list() { + TypedArray<Dictionary> ret; List<MethodInfo> list; get_script_signal_list(&list); for (const MethodInfo &E : list) { diff --git a/core/object/script_language.h b/core/object/script_language.h index bfdedbe4a5..12a21150bc 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -37,6 +37,8 @@ #include "core/templates/rb_map.h" class ScriptLanguage; +template <typename T> +class TypedArray; typedef void (*ScriptEditRequestFunction)(const String &p_path); @@ -108,9 +110,9 @@ protected: virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {} Variant _get_property_default_value(const StringName &p_property); - Array _get_script_property_list(); - Array _get_script_method_list(); - Array _get_script_signal_list(); + TypedArray<Dictionary> _get_script_property_list(); + TypedArray<Dictionary> _get_script_method_list(); + TypedArray<Dictionary> _get_script_signal_list(); Dictionary _get_script_constant_map(); public: diff --git a/core/object/script_language_extension.cpp b/core/object/script_language_extension.cpp index 9de784ea7f..78e9038b66 100644 --- a/core/object/script_language_extension.cpp +++ b/core/object/script_language_extension.cpp @@ -62,6 +62,7 @@ void ScriptExtension::_bind_methods() { GDVIRTUAL_BIND(_has_script_signal, "signal"); GDVIRTUAL_BIND(_get_script_signal_list); + GDVIRTUAL_BIND(_has_property_default_value, "property"); GDVIRTUAL_BIND(_get_property_default_value, "property"); GDVIRTUAL_BIND(_update_exports); diff --git a/core/os/keyboard.h b/core/os/keyboard.h index 517a53e505..29418049cb 100644 --- a/core/os/keyboard.h +++ b/core/os/keyboard.h @@ -329,67 +329,71 @@ enum class KeyModifierMask { // To avoid having unnecessary operators, only define the ones that are needed. -inline Key operator-(uint32_t a, Key b) { +constexpr Key operator-(uint32_t a, Key b) { return (Key)(a - (uint32_t)b); } -inline Key &operator-=(Key &a, int b) { - return (Key &)((int &)a -= b); +constexpr Key &operator-=(Key &a, int b) { + a = static_cast<Key>(static_cast<int>(a) - static_cast<int>(b)); + return a; } -inline Key operator+(Key a, int b) { +constexpr Key operator+(Key a, int b) { return (Key)((int)a + (int)b); } -inline Key operator+(Key a, Key b) { +constexpr Key operator+(Key a, Key b) { return (Key)((int)a + (int)b); } -inline Key operator-(Key a, Key b) { +constexpr Key operator-(Key a, Key b) { return (Key)((int)a - (int)b); } -inline Key operator&(Key a, Key b) { +constexpr Key operator&(Key a, Key b) { return (Key)((int)a & (int)b); } -inline Key operator|(Key a, Key b) { +constexpr Key operator|(Key a, Key b) { return (Key)((int)a | (int)b); } -inline Key &operator|=(Key &a, Key b) { - return (Key &)((int &)a |= (int)b); +constexpr Key &operator|=(Key &a, Key b) { + a = static_cast<Key>(static_cast<int>(a) | static_cast<int>(b)); + return a; } -inline Key &operator|=(Key &a, KeyModifierMask b) { - return (Key &)((int &)a |= (int)b); +constexpr Key &operator|=(Key &a, KeyModifierMask b) { + a = static_cast<Key>(static_cast<int>(a) | static_cast<int>(b)); + return a; } -inline Key &operator&=(Key &a, KeyModifierMask b) { - return (Key &)((int &)a &= (int)b); +constexpr Key &operator&=(Key &a, KeyModifierMask b) { + a = static_cast<Key>(static_cast<int>(a) & static_cast<int>(b)); + return a; } -inline Key operator|(Key a, KeyModifierMask b) { +constexpr Key operator|(Key a, KeyModifierMask b) { return (Key)((int)a | (int)b); } -inline Key operator&(Key a, KeyModifierMask b) { +constexpr Key operator&(Key a, KeyModifierMask b) { return (Key)((int)a & (int)b); } -inline Key operator+(KeyModifierMask a, Key b) { +constexpr Key operator+(KeyModifierMask a, Key b) { return (Key)((int)a + (int)b); } -inline Key operator|(KeyModifierMask a, Key b) { +constexpr Key operator|(KeyModifierMask a, Key b) { return (Key)((int)a | (int)b); } -inline KeyModifierMask operator+(KeyModifierMask a, KeyModifierMask b) { +constexpr KeyModifierMask operator+(KeyModifierMask a, KeyModifierMask b) { return (KeyModifierMask)((int)a + (int)b); } -inline KeyModifierMask operator|(KeyModifierMask a, KeyModifierMask b) { +constexpr KeyModifierMask operator|(KeyModifierMask a, KeyModifierMask b) { return (KeyModifierMask)((int)a | (int)b); } diff --git a/core/os/os.cpp b/core/os/os.cpp index 6091079241..45cd7109e2 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -186,10 +186,6 @@ void OS::set_stderr_enabled(bool p_enabled) { _stderr_enabled = p_enabled; } -void OS::dump_memory_to_file(const char *p_file) { - //Memory::dump_static_mem_to_file(p_file); -} - static Ref<FileAccess> _OSPRF; static void _OS_printres(Object *p_obj) { diff --git a/core/os/os.h b/core/os/os.h index be9d73c22d..ff769cc4f1 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -246,7 +246,6 @@ public: virtual bool is_disable_crash_handler() const { return false; } virtual void initialize_debugging() {} - virtual void dump_memory_to_file(const char *p_file); virtual void dump_resources_to_file(const char *p_file); virtual void print_resources_in_use(bool p_short = false); virtual void print_all_resources(String p_to_file = ""); diff --git a/core/string/translation.cpp b/core/string/translation.cpp index b83b7c786f..4748f1a0cb 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -70,7 +70,7 @@ void Translation::_set_messages(const Dictionary &p_messages) { void Translation::set_locale(const String &p_locale) { locale = TranslationServer::get_singleton()->standardize_locale(p_locale); - if (OS::get_singleton()->get_main_loop() && TranslationServer::get_singleton()->get_loaded_locales().has(this)) { + if (OS::get_singleton()->get_main_loop() && TranslationServer::get_singleton()->get_loaded_locales().has(get_locale())) { OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED); } } @@ -505,11 +505,11 @@ String TranslationServer::get_locale() const { return locale; } -Array TranslationServer::get_loaded_locales() const { - Array locales; +PackedStringArray TranslationServer::get_loaded_locales() const { + PackedStringArray locales; for (const Ref<Translation> &E : translations) { const Ref<Translation> &t = E; - ERR_FAIL_COND_V(t.is_null(), Array()); + ERR_FAIL_COND_V(t.is_null(), PackedStringArray()); String l = t->get_locale(); locales.push_back(l); diff --git a/core/string/translation.h b/core/string/translation.h index 20c6ebd5a5..3f97a8d4fc 100644 --- a/core/string/translation.h +++ b/core/string/translation.h @@ -145,7 +145,7 @@ public: String get_locale_name(const String &p_locale) const; - Array get_loaded_locales() const; + PackedStringArray get_loaded_locales() const; void add_translation(const Ref<Translation> &p_translation); void remove_translation(const Ref<Translation> &p_translation); diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index 13be7516d5..0c43ba9ccc 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -3451,18 +3451,19 @@ String String::replacen(const String &p_key, const String &p_with) const { String String::repeat(int p_count) const { ERR_FAIL_COND_V_MSG(p_count < 0, "", "Parameter count should be a positive number."); - String new_string; - const char32_t *src = this->get_data(); - - new_string.resize(length() * p_count + 1); - new_string[length() * p_count] = 0; - - for (int i = 0; i < p_count; i++) { - for (int j = 0; j < length(); j++) { - new_string[i * length() + j] = src[j]; - } - } - + int len = length(); + String new_string = *this; + new_string.resize(p_count * len + 1); + + char32_t *dst = new_string.ptrw(); + int offset = 1; + int stride = 1; + while (offset < p_count) { + memcpy(dst + offset * len, dst, stride * len * sizeof(char32_t)); + offset += stride; + stride = MIN(stride * 2, p_count - offset); + } + dst[p_count * len] = _null; return new_string; } @@ -4666,6 +4667,71 @@ String String::sprintf(const Array &values, bool *error) const { in_format = false; break; } + case 'v': { // Vector2/3/4/2i/3i/4i + if (value_index >= values.size()) { + return "not enough arguments for format string"; + } + + int count; + switch (values[value_index].get_type()) { + case Variant::VECTOR2: + case Variant::VECTOR2I: { + count = 2; + } break; + case Variant::VECTOR3: + case Variant::VECTOR3I: { + count = 3; + } break; + case Variant::VECTOR4: + case Variant::VECTOR4I: { + count = 4; + } break; + default: { + return "%v requires a vector type (Vector2/3/4/2i/3i/4i)"; + } + } + + Vector4 vec = values[value_index]; + String str = "("; + for (int i = 0; i < count; i++) { + double val = vec[i]; + // Pad decimals out. + String number_str = String::num(ABS(val), min_decimals).pad_decimals(min_decimals); + + int initial_len = number_str.length(); + + // Padding. Leave room for sign later if required. + int pad_chars_count = val < 0 ? min_chars - 1 : min_chars; + String pad_char = pad_with_zeros ? String("0") : String(" "); + if (left_justified) { + number_str = number_str.rpad(pad_chars_count, pad_char); + } else { + number_str = number_str.lpad(pad_chars_count, pad_char); + } + + // Add sign if needed. + if (val < 0) { + if (left_justified) { + number_str = number_str.insert(0, "-"); + } else { + number_str = number_str.insert(pad_with_zeros ? 0 : number_str.length() - initial_len, "-"); + } + } + + // Add number to combined string + str += number_str; + + if (i < count - 1) { + str += ", "; + } + } + str += ")"; + + formatted += str; + ++value_index; + in_format = false; + break; + } case 's': { // String if (value_index >= values.size()) { return "not enough arguments for format string"; @@ -4758,7 +4824,7 @@ String String::sprintf(const Array &values, bool *error) const { } break; } - case '.': { // Float separator. + case '.': { // Float/Vector separator. if (in_decimals) { return "too many decimal points in format"; } @@ -4772,8 +4838,12 @@ String String::sprintf(const Array &values, bool *error) const { return "not enough arguments for format string"; } - if (!values[value_index].is_num()) { - return "* wants number"; + Variant::Type value_type = values[value_index].get_type(); + if (!values[value_index].is_num() && + value_type != Variant::VECTOR2 && value_type != Variant::VECTOR2I && + value_type != Variant::VECTOR3 && value_type != Variant::VECTOR3I && + value_type != Variant::VECTOR4 && value_type != Variant::VECTOR4I) { + return "* wants number or vector"; } int size = values[value_index]; diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp index 3a0b6c1bb9..d048f45737 100644 --- a/core/variant/variant_construct.cpp +++ b/core/variant/variant_construct.cpp @@ -162,6 +162,7 @@ void Variant::_register_variant_constructors() { add_constructor<VariantConstructNoArgs<Projection>>(sarray()); add_constructor<VariantConstructor<Projection, Projection>>(sarray("from")); add_constructor<VariantConstructor<Projection, Transform3D>>(sarray("from")); + add_constructor<VariantConstructor<Projection, Vector4, Vector4, Vector4, Vector4>>(sarray("x_axis", "y_axis", "z_axis", "w_axis")); add_constructor<VariantConstructNoArgs<Color>>(sarray()); add_constructor<VariantConstructor<Color, Color>>(sarray("from")); diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 722177c9e8..bd500f6b35 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -1303,10 +1303,8 @@ <member name="TranslationServer" type="TranslationServer" setter="" getter=""> The [TranslationServer] singleton. </member> - <member name="VisualScriptCustomNodes" type="VisualScriptCustomNodes" setter="" getter=""> - The [VisualScriptCustomNodes] singleton. - </member> <member name="WorkerThreadPool" type="WorkerThreadPool" setter="" getter=""> + The [WorkerThreadPool] singleton. </member> <member name="XRServer" type="XRServer" setter="" getter=""> The [XRServer] singleton. @@ -2710,7 +2708,10 @@ </constant> <constant name="PROPERTY_HINT_NODE_TYPE" value="44" enum="PropertyHint"> </constant> - <constant name="PROPERTY_HINT_MAX" value="45" enum="PropertyHint"> + <constant name="PROPERTY_HINT_HIDE_QUATERNION_EDIT" value="45" enum="PropertyHint"> + Hints that a quaternion property should disable the temporary euler editor. + </constant> + <constant name="PROPERTY_HINT_MAX" value="46" enum="PropertyHint"> </constant> <constant name="PROPERTY_USAGE_NONE" value="0" enum="PropertyUsageFlags"> </constant> diff --git a/doc/classes/AStar2D.xml b/doc/classes/AStar2D.xml index 977e73e7ca..6e76df647e 100644 --- a/doc/classes/AStar2D.xml +++ b/doc/classes/AStar2D.xml @@ -218,7 +218,7 @@ </description> </method> <method name="get_point_ids"> - <return type="Array" /> + <return type="PackedInt64Array" /> <description> Returns an array of all point IDs. </description> diff --git a/doc/classes/AStar3D.xml b/doc/classes/AStar3D.xml index efce94e25d..45b1019bab 100644 --- a/doc/classes/AStar3D.xml +++ b/doc/classes/AStar3D.xml @@ -245,7 +245,7 @@ </description> </method> <method name="get_point_ids"> - <return type="Array" /> + <return type="PackedInt64Array" /> <description> Returns an array of all point IDs. </description> diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml index fef65181ae..8b97fda4d3 100644 --- a/doc/classes/Animation.xml +++ b/doc/classes/Animation.xml @@ -130,14 +130,6 @@ Sets the stream of the key identified by [param key_idx] to value [param stream]. The [param track_idx] must be the index of an Audio Track. </description> </method> - <method name="bezier_track_get_key_handle_mode" qualifiers="const"> - <return type="int" /> - <param index="0" name="track_idx" type="int" /> - <param index="1" name="key_idx" type="int" /> - <description> - Returns the handle mode of the key identified by [param key_idx]. See [enum HandleMode] for possible values. The [param track_idx] must be the index of a Bezier Track. - </description> - </method> <method name="bezier_track_get_key_in_handle" qualifiers="const"> <return type="Vector2" /> <param index="0" name="track_idx" type="int" /> @@ -169,7 +161,6 @@ <param index="2" name="value" type="float" /> <param index="3" name="in_handle" type="Vector2" default="Vector2(0, 0)" /> <param index="4" name="out_handle" type="Vector2" default="Vector2(0, 0)" /> - <param index="5" name="handle_mode" type="int" enum="Animation.HandleMode" default="1" /> <description> Inserts a Bezier Track key at the given [param time] in seconds. The [param track_idx] must be the index of a Bezier Track. [param in_handle] is the left-side weight of the added Bezier curve point, [param out_handle] is the right-side one, while [param value] is the actual value at this point. @@ -183,16 +174,6 @@ Returns the interpolated value at the given [param time] (in seconds). The [param track_idx] must be the index of a Bezier Track. </description> </method> - <method name="bezier_track_set_key_handle_mode"> - <return type="void" /> - <param index="0" name="track_idx" type="int" /> - <param index="1" name="key_idx" type="int" /> - <param index="2" name="key_handle_mode" type="int" enum="Animation.HandleMode" /> - <param index="3" name="balanced_value_time_ratio" type="float" default="1.0" /> - <description> - Changes the handle mode of the keyframe at the given [param key_idx]. See [enum HandleMode] for possible values. The [param track_idx] must be the index of a Bezier Track. - </description> - </method> <method name="bezier_track_set_key_in_handle"> <return type="void" /> <param index="0" name="track_idx" type="int" /> @@ -619,9 +600,6 @@ <constant name="INTERPOLATION_CUBIC" value="2" enum="InterpolationType"> Cubic interpolation. </constant> - <constant name="INTERPOLATION_CUBIC_IN_TIME" value="3" enum="InterpolationType"> - Cubic interpolation with uniformed time. - </constant> <constant name="UPDATE_CONTINUOUS" value="0" enum="UpdateMode"> Update between keyframes. </constant> @@ -643,11 +621,5 @@ <constant name="LOOP_PINGPONG" value="2" enum="LoopMode"> Repeats playback and reverse playback at both ends of the animation. </constant> - <constant name="HANDLE_MODE_FREE" value="0" enum="HandleMode"> - Assigning the free handle mode to a Bezier Track's keyframe allows you to edit the keyframe's left and right handles independently from one another. - </constant> - <constant name="HANDLE_MODE_BALANCED" value="1" enum="HandleMode"> - Assigning the balanced handle mode to a Bezier Track's keyframe makes it so the two handles of the keyframe always stay aligned when changing either the keyframe's left or right handle. - </constant> </constants> </class> diff --git a/doc/classes/AnimationLibrary.xml b/doc/classes/AnimationLibrary.xml index 015d306b41..fbbf9a3be4 100644 --- a/doc/classes/AnimationLibrary.xml +++ b/doc/classes/AnimationLibrary.xml @@ -1,10 +1,13 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="AnimationLibrary" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> + Container for [Animation] resources. </brief_description> <description> + An animation library stores a set of animations accessible through [StringName] keys, for use with [AnimationPlayer] nodes. </description> <tutorials> + <link title="Animation tutorial index">$DOCS_URL/tutorials/animation/index.html</link> </tutorials> <methods> <method name="add_animation"> @@ -12,29 +15,34 @@ <param index="0" name="name" type="StringName" /> <param index="1" name="animation" type="Animation" /> <description> + Adds the [param animation] to the library, accesible by the key [param name]. </description> </method> <method name="get_animation" qualifiers="const"> <return type="Animation" /> <param index="0" name="name" type="StringName" /> <description> + Returns the [Animation] with the key [param name], or [code]null[/code] if none is found. </description> </method> <method name="get_animation_list" qualifiers="const"> <return type="StringName[]" /> <description> + Returns the keys for the [Animation]s stored in the library. </description> </method> <method name="has_animation" qualifiers="const"> <return type="bool" /> <param index="0" name="name" type="StringName" /> <description> + Returns [code]true[/code] if the library stores an [Animation] with [param name] as the key. </description> </method> <method name="remove_animation"> <return type="void" /> <param index="0" name="name" type="StringName" /> <description> + Removes the [Animation] with the key [param name]. </description> </method> <method name="rename_animation"> @@ -42,6 +50,7 @@ <param index="0" name="name" type="StringName" /> <param index="1" name="newname" type="StringName" /> <description> + Changes the key of the [Animation] associated with the key [param name] to [param newname]. </description> </method> </methods> @@ -53,17 +62,20 @@ <signal name="animation_added"> <param index="0" name="name" type="StringName" /> <description> + Emitted when an [Animation] is added, under the key [param name]. </description> </signal> <signal name="animation_removed"> <param index="0" name="name" type="StringName" /> <description> + Emitted when an [Animation] stored with the key [param name] is removed. </description> </signal> <signal name="animation_renamed"> <param index="0" name="name" type="StringName" /> <param index="1" name="to_name" type="StringName" /> <description> + Emitted when the key for an [Animation] is changed, from [param name] to [param to_name]. </description> </signal> </signals> diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml index beb259b12b..1b5a795b3c 100644 --- a/doc/classes/AnimationNodeStateMachineTransition.xml +++ b/doc/classes/AnimationNodeStateMachineTransition.xml @@ -9,7 +9,7 @@ </tutorials> <members> <member name="advance_condition" type="StringName" setter="set_advance_condition" getter="get_advance_condition" default="&"""> - Turn on auto advance when this condition is set. The provided name will become a boolean parameter on the [AnimationTree] that can be controlled from code (see [url=$DOCS_URL/tutorials/animation/animation_tree.html#controlling-from-code][/url]). For example, if [member AnimationTree.tree_root] is an [AnimationNodeStateMachine] and [member advance_condition] is set to [code]"idle"[/code]: + Turn on auto advance when this condition is set. The provided name will become a boolean parameter on the [AnimationTree] that can be controlled from code (see [url=$DOCS_URL/tutorials/animation/animation_tree.html#controlling-from-code]Using AnimationTree[/url]). For example, if [member AnimationTree.tree_root] is an [AnimationNodeStateMachine] and [member advance_condition] is set to [code]"idle"[/code]: [codeblocks] [gdscript] $animation_tree.set("parameters/conditions/idle", is_on_floor and (linear_velocity.x == 0)) diff --git a/doc/classes/Area2D.xml b/doc/classes/Area2D.xml index c61705505e..f1e40d4979 100644 --- a/doc/classes/Area2D.xml +++ b/doc/classes/Area2D.xml @@ -4,7 +4,9 @@ 2D area for detection and physics and audio influence. </brief_description> <description> - 2D area that detects [CollisionObject2D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping) and route audio to a custom audio bus. + 2D area that detects [CollisionObject2D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping) and route audio to custom audio buses. + To give the area its shape, add a [CollisionShape2D] or a [CollisionPolygon2D] node as a [i]direct[/i] child (or add multiple such nodes as direct children) of the area. + [b]Warning:[/b] See [ConcavePolygonShape2D] for a warning about possibly unexpected behavior when using that shape for an area. </description> <tutorials> <link title="Using Area2D">$DOCS_URL/tutorials/physics/using_area_2d.html</link> diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml index 3c50a1ac05..14081918cf 100644 --- a/doc/classes/Area3D.xml +++ b/doc/classes/Area3D.xml @@ -5,6 +5,8 @@ </brief_description> <description> 3D area that detects [CollisionObject3D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping) and route audio to custom audio buses. + To give the area its shape, add a [CollisionShape3D] or a [CollisionPolygon3D] node as a [i]direct[/i] child (or add multiple such nodes as direct children) of the area. + [b]Warning:[/b] See [ConcavePolygonShape3D] (also called "trimesh") for a warning about possibly unexpected behavior when using that shape for an area. </description> <tutorials> <link title="3D Platformer Demo">https://godotengine.org/asset-library/asset/125</link> diff --git a/doc/classes/AudioEffectDelay.xml b/doc/classes/AudioEffectDelay.xml index 8223ccd6bd..b9ae12204e 100644 --- a/doc/classes/AudioEffectDelay.xml +++ b/doc/classes/AudioEffectDelay.xml @@ -14,40 +14,40 @@ <member name="dry" type="float" setter="set_dry" getter="get_dry" default="1.0"> Output percent of original sound. At 0, only delayed sounds are output. Value can range from 0 to 1. </member> - <member name="feedback/active" type="bool" setter="set_feedback_active" getter="is_feedback_active" default="false"> + <member name="feedback_active" type="bool" setter="set_feedback_active" getter="is_feedback_active" default="false"> If [code]true[/code], feedback is enabled. </member> - <member name="feedback/delay_ms" type="float" setter="set_feedback_delay_ms" getter="get_feedback_delay_ms" default="340.0"> + <member name="feedback_delay_ms" type="float" setter="set_feedback_delay_ms" getter="get_feedback_delay_ms" default="340.0"> Feedback delay time in milliseconds. </member> - <member name="feedback/level_db" type="float" setter="set_feedback_level_db" getter="get_feedback_level_db" default="-6.0"> + <member name="feedback_level_db" type="float" setter="set_feedback_level_db" getter="get_feedback_level_db" default="-6.0"> Sound level for [code]tap1[/code]. </member> - <member name="feedback/lowpass" type="float" setter="set_feedback_lowpass" getter="get_feedback_lowpass" default="16000.0"> + <member name="feedback_lowpass" type="float" setter="set_feedback_lowpass" getter="get_feedback_lowpass" default="16000.0"> Low-pass filter for feedback, in Hz. Frequencies below this value are filtered out of the source signal. </member> - <member name="tap1/active" type="bool" setter="set_tap1_active" getter="is_tap1_active" default="true"> + <member name="tap1_active" type="bool" setter="set_tap1_active" getter="is_tap1_active" default="true"> If [code]true[/code], [code]tap1[/code] will be enabled. </member> - <member name="tap1/delay_ms" type="float" setter="set_tap1_delay_ms" getter="get_tap1_delay_ms" default="250.0"> + <member name="tap1_delay_ms" type="float" setter="set_tap1_delay_ms" getter="get_tap1_delay_ms" default="250.0"> [code]tap1[/code] delay time in milliseconds. </member> - <member name="tap1/level_db" type="float" setter="set_tap1_level_db" getter="get_tap1_level_db" default="-6.0"> + <member name="tap1_level_db" type="float" setter="set_tap1_level_db" getter="get_tap1_level_db" default="-6.0"> Sound level for [code]tap1[/code]. </member> - <member name="tap1/pan" type="float" setter="set_tap1_pan" getter="get_tap1_pan" default="0.2"> + <member name="tap1_pan" type="float" setter="set_tap1_pan" getter="get_tap1_pan" default="0.2"> Pan position for [code]tap1[/code]. Value can range from -1 (fully left) to 1 (fully right). </member> - <member name="tap2/active" type="bool" setter="set_tap2_active" getter="is_tap2_active" default="true"> + <member name="tap2_active" type="bool" setter="set_tap2_active" getter="is_tap2_active" default="true"> If [code]true[/code], [code]tap2[/code] will be enabled. </member> - <member name="tap2/delay_ms" type="float" setter="set_tap2_delay_ms" getter="get_tap2_delay_ms" default="500.0"> + <member name="tap2_delay_ms" type="float" setter="set_tap2_delay_ms" getter="get_tap2_delay_ms" default="500.0"> [b]Tap2[/b] delay time in milliseconds. </member> - <member name="tap2/level_db" type="float" setter="set_tap2_level_db" getter="get_tap2_level_db" default="-12.0"> + <member name="tap2_level_db" type="float" setter="set_tap2_level_db" getter="get_tap2_level_db" default="-12.0"> Sound level for [code]tap2[/code]. </member> - <member name="tap2/pan" type="float" setter="set_tap2_pan" getter="get_tap2_pan" default="-0.4"> + <member name="tap2_pan" type="float" setter="set_tap2_pan" getter="get_tap2_pan" default="-0.4"> Pan position for [code]tap2[/code]. Value can range from -1 (fully left) to 1 (fully right). </member> </members> diff --git a/doc/classes/AudioServer.xml b/doc/classes/AudioServer.xml index 5bd1c82641..8dc80e3bdc 100644 --- a/doc/classes/AudioServer.xml +++ b/doc/classes/AudioServer.xml @@ -30,7 +30,7 @@ </description> </method> <method name="capture_get_device_list"> - <return type="Array" /> + <return type="PackedStringArray" /> <description> Returns the names of all audio input devices detected on the system. </description> @@ -117,7 +117,7 @@ </description> </method> <method name="get_device_list"> - <return type="Array" /> + <return type="PackedStringArray" /> <description> Returns the names of all audio devices detected on the system. </description> diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index fcdf59e36e..33a129a48e 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -718,7 +718,7 @@ </constant> <constant name="BILLBOARD_PARTICLES" value="3" enum="BillboardMode"> Used for particle systems when assigned to [GPUParticles3D] and [CPUParticles3D] nodes. Enables [code]particles_anim_*[/code] properties. - The [member ParticlesMaterial.anim_speed_min] or [member CPUParticles3D.anim_speed_min] should also be set to a value bigger than zero for the animation to play. + The [member ParticleProcessMaterial.anim_speed_min] or [member CPUParticles3D.anim_speed_min] should also be set to a value bigger than zero for the animation to play. </constant> <constant name="TEXTURE_CHANNEL_RED" value="0" enum="TextureChannel"> Used to read from the red channel of a texture. diff --git a/doc/classes/BitMap.xml b/doc/classes/BitMap.xml index 53fd9a7b67..9323642274 100644 --- a/doc/classes/BitMap.xml +++ b/doc/classes/BitMap.xml @@ -58,7 +58,7 @@ </description> </method> <method name="opaque_to_polygons" qualifiers="const"> - <return type="Array" /> + <return type="PackedVector2Array[]" /> <param index="0" name="rect" type="Rect2" /> <param index="1" name="epsilon" type="float" default="2.0" /> <description> diff --git a/doc/classes/ButtonGroup.xml b/doc/classes/ButtonGroup.xml index 8bedb5a1ac..277bda2836 100644 --- a/doc/classes/ButtonGroup.xml +++ b/doc/classes/ButtonGroup.xml @@ -11,7 +11,7 @@ </tutorials> <methods> <method name="get_buttons"> - <return type="Array" /> + <return type="BaseButton[]" /> <description> Returns an [Array] of [Button]s who have this as their [ButtonGroup] (see [member BaseButton.button_group]). </description> diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml index 64e9310181..906789d09f 100644 --- a/doc/classes/CPUParticles2D.xml +++ b/doc/classes/CPUParticles2D.xml @@ -15,7 +15,7 @@ <return type="void" /> <param index="0" name="particles" type="Node" /> <description> - Sets this node's properties to match a given [GPUParticles2D] node with an assigned [ParticlesMaterial]. + Sets this node's properties to match a given [GPUParticles2D] node with an assigned [ParticleProcessMaterial]. </description> </method> <method name="get_param_curve" qualifiers="const"> diff --git a/doc/classes/CPUParticles3D.xml b/doc/classes/CPUParticles3D.xml index bb1dcd322f..99fd0501fc 100644 --- a/doc/classes/CPUParticles3D.xml +++ b/doc/classes/CPUParticles3D.xml @@ -14,7 +14,7 @@ <return type="void" /> <param index="0" name="particles" type="Node" /> <description> - Sets this node's properties to match a given [GPUParticles3D] node with an assigned [ParticlesMaterial]. + Sets this node's properties to match a given [GPUParticles3D] node with an assigned [ParticleProcessMaterial]. </description> </method> <method name="get_param_curve" qualifiers="const"> diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml index 6b379e0509..65fdecc3c6 100644 --- a/doc/classes/Camera3D.xml +++ b/doc/classes/Camera3D.xml @@ -37,7 +37,7 @@ </description> </method> <method name="get_frustum" qualifiers="const"> - <return type="Array" /> + <return type="Plane[]" /> <description> Returns the camera's frustum planes in world space units as an array of [Plane]s in the following order: near, far, left, top, right, bottom. Not to be confused with [member frustum_offset]. </description> diff --git a/doc/classes/CameraServer.xml b/doc/classes/CameraServer.xml index d7a9888fac..d346fbde4f 100644 --- a/doc/classes/CameraServer.xml +++ b/doc/classes/CameraServer.xml @@ -19,7 +19,7 @@ </description> </method> <method name="feeds"> - <return type="Array" /> + <return type="CameraFeed[]" /> <description> Returns an array of [CameraFeed]s. </description> diff --git a/doc/classes/CanvasItemMaterial.xml b/doc/classes/CanvasItemMaterial.xml index 22daf79074..59226840bc 100644 --- a/doc/classes/CanvasItemMaterial.xml +++ b/doc/classes/CanvasItemMaterial.xml @@ -28,7 +28,7 @@ [b]Note:[/b] This property is only used and visible in the editor if [member particles_animation] is [code]true[/code]. </member> <member name="particles_animation" type="bool" setter="set_particles_animation" getter="get_particles_animation" default="false"> - If [code]true[/code], enable spritesheet-based animation features when assigned to [GPUParticles2D] and [CPUParticles2D] nodes. The [member ParticlesMaterial.anim_speed_max] or [member CPUParticles2D.anim_speed_max] should also be set to a positive value for the animation to play. + If [code]true[/code], enable spritesheet-based animation features when assigned to [GPUParticles2D] and [CPUParticles2D] nodes. The [member ParticleProcessMaterial.anim_speed_max] or [member CPUParticles2D.anim_speed_max] should also be set to a positive value for the animation to play. This property (and other [code]particles_anim_*[/code] properties that depend on it) has no effect on other types of nodes. </member> </members> diff --git a/doc/classes/CanvasLayer.xml b/doc/classes/CanvasLayer.xml index ff2c3a8855..555137ac45 100644 --- a/doc/classes/CanvasLayer.xml +++ b/doc/classes/CanvasLayer.xml @@ -35,11 +35,11 @@ <member name="custom_viewport" type="Node" setter="set_custom_viewport" getter="get_custom_viewport"> The custom [Viewport] node assigned to the [CanvasLayer]. If [code]null[/code], uses the default viewport instead. </member> - <member name="follow_viewport_enable" type="bool" setter="set_follow_viewport" getter="is_following_viewport" default="false"> + <member name="follow_viewport_enabled" type="bool" setter="set_follow_viewport" getter="is_following_viewport" default="false"> Sets the layer to follow the viewport in order to simulate a pseudo 3D effect. </member> <member name="follow_viewport_scale" type="float" setter="set_follow_viewport_scale" getter="get_follow_viewport_scale" default="1.0"> - Scales the layer when using [member follow_viewport_enable]. Layers moving into the foreground should have increasing scales, while layers moving into the background should have decreasing scales. + Scales the layer when using [member follow_viewport_enabled]. Layers moving into the foreground should have increasing scales, while layers moving into the background should have decreasing scales. </member> <member name="layer" type="int" setter="set_layer" getter="get_layer" default="1"> Layer index for draw order. Lower values are drawn first. diff --git a/doc/classes/CharacterBody2D.xml b/doc/classes/CharacterBody2D.xml index 95612de284..2d169904f7 100644 --- a/doc/classes/CharacterBody2D.xml +++ b/doc/classes/CharacterBody2D.xml @@ -140,12 +140,6 @@ </method> </methods> <members> - <member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.08"> - Extra margin used for collision recovery when calling [method move_and_slide]. - If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion. - A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors. - A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies. - </member> <member name="floor_block_on_wall" type="bool" setter="set_floor_block_on_wall_enabled" getter="is_floor_block_on_wall_enabled" default="true"> If [code]true[/code], the body will be able to move on the floor only. This option avoids to be able to walk on walls, it will however allow to slide down along them. </member> @@ -170,15 +164,21 @@ <member name="motion_mode" type="int" setter="set_motion_mode" getter="get_motion_mode" enum="CharacterBody2D.MotionMode" default="0"> Sets the motion mode which defines the behavior of [method move_and_slide]. See [enum MotionMode] constants for available modes. </member> - <member name="moving_platform_apply_velocity_on_leave" type="int" setter="set_moving_platform_apply_velocity_on_leave" getter="get_moving_platform_apply_velocity_on_leave" enum="CharacterBody2D.MovingPlatformApplyVelocityOnLeave" default="0"> - Sets the behavior to apply when you leave a moving platform. By default, to be physically accurate, when you leave the last platform velocity is applied. See [enum MovingPlatformApplyVelocityOnLeave] constants for available behavior. - </member> - <member name="moving_platform_floor_layers" type="int" setter="set_moving_platform_floor_layers" getter="get_moving_platform_floor_layers" default="4294967295"> + <member name="platform_floor_layers" type="int" setter="set_platform_floor_layers" getter="get_platform_floor_layers" default="4294967295"> Collision layers that will be included for detecting floor bodies that will act as moving platforms to be followed by the [CharacterBody2D]. By default, all floor bodies are detected and propagate their velocity. </member> - <member name="moving_platform_wall_layers" type="int" setter="set_moving_platform_wall_layers" getter="get_moving_platform_wall_layers" default="0"> + <member name="platform_on_leave" type="int" setter="set_platform_on_leave" getter="get_platform_on_leave" enum="CharacterBody2D.PlatformOnLeave" default="0"> + Sets the behavior to apply when you leave a moving platform. By default, to be physically accurate, when you leave the last platform velocity is applied. See [enum PlatformOnLeave] constants for available behavior. + </member> + <member name="platform_wall_layers" type="int" setter="set_platform_wall_layers" getter="get_platform_wall_layers" default="0"> Collision layers that will be included for detecting wall bodies that will act as moving platforms to be followed by the [CharacterBody2D]. By default, all wall bodies are ignored. </member> + <member name="safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.08"> + Extra margin used for collision recovery when calling [method move_and_slide]. + If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion. + A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors. + A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies. + </member> <member name="slide_on_ceiling" type="bool" setter="set_slide_on_ceiling_enabled" getter="is_slide_on_ceiling_enabled" default="true"> If [code]true[/code], during a jump against the ceiling, the body will slide, if [code]false[/code] it will be stopped and will fall vertically. </member> @@ -199,13 +199,13 @@ <constant name="MOTION_MODE_FLOATING" value="1" enum="MotionMode"> Apply when there is no notion of floor or ceiling. All collisions will be reported as [code]on_wall[/code]. In this mode, when you slide, the speed will always be constant. This mode is suitable for top-down games. </constant> - <constant name="PLATFORM_VEL_ON_LEAVE_ALWAYS" value="0" enum="MovingPlatformApplyVelocityOnLeave"> + <constant name="PLATFORM_ON_LEAVE_ADD_VELOCITY" value="0" enum="PlatformOnLeave"> Add the last platform velocity to the [member velocity] when you leave a moving platform. </constant> - <constant name="PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY" value="1" enum="MovingPlatformApplyVelocityOnLeave"> + <constant name="PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY" value="1" enum="PlatformOnLeave"> Add the last platform velocity to the [member velocity] when you leave a moving platform, but any downward motion is ignored. It's useful to keep full jump height even when the platform is moving down. </constant> - <constant name="PLATFORM_VEL_ON_LEAVE_NEVER" value="2" enum="MovingPlatformApplyVelocityOnLeave"> + <constant name="PLATFORM_ON_LEAVE_DO_NOTHING" value="2" enum="PlatformOnLeave"> Do nothing when leaving a platform. </constant> </constants> diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml index deb93253ea..cbcd6b3af7 100644 --- a/doc/classes/CharacterBody3D.xml +++ b/doc/classes/CharacterBody3D.xml @@ -125,12 +125,6 @@ </method> </methods> <members> - <member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.001"> - Extra margin used for collision recovery when calling [method move_and_slide]. - If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion. - A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors. - A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies. - </member> <member name="floor_block_on_wall" type="bool" setter="set_floor_block_on_wall_enabled" getter="is_floor_block_on_wall_enabled" default="true"> If [code]true[/code], the body will be able to move on the floor only. This option avoids to be able to walk on walls, it will however allow to slide down along them. </member> @@ -155,15 +149,21 @@ <member name="motion_mode" type="int" setter="set_motion_mode" getter="get_motion_mode" enum="CharacterBody3D.MotionMode" default="0"> Sets the motion mode which defines the behavior of [method move_and_slide]. See [enum MotionMode] constants for available modes. </member> - <member name="moving_platform_apply_velocity_on_leave" type="int" setter="set_moving_platform_apply_velocity_on_leave" getter="get_moving_platform_apply_velocity_on_leave" enum="CharacterBody3D.MovingPlatformApplyVelocityOnLeave" default="0"> - Sets the behavior to apply when you leave a moving platform. By default, to be physically accurate, when you leave the last platform velocity is applied. See [enum MovingPlatformApplyVelocityOnLeave] constants for available behavior. - </member> - <member name="moving_platform_floor_layers" type="int" setter="set_moving_platform_floor_layers" getter="get_moving_platform_floor_layers" default="4294967295"> + <member name="platform_floor_layers" type="int" setter="set_platform_floor_layers" getter="get_platform_floor_layers" default="4294967295"> Collision layers that will be included for detecting floor bodies that will act as moving platforms to be followed by the [CharacterBody3D]. By default, all floor bodies are detected and propagate their velocity. </member> - <member name="moving_platform_wall_layers" type="int" setter="set_moving_platform_wall_layers" getter="get_moving_platform_wall_layers" default="0"> + <member name="platform_on_leave" type="int" setter="set_platform_on_leave" getter="get_platform_on_leave" enum="CharacterBody3D.PlatformOnLeave" default="0"> + Sets the behavior to apply when you leave a moving platform. By default, to be physically accurate, when you leave the last platform velocity is applied. See [enum PlatformOnLeave] constants for available behavior. + </member> + <member name="platform_wall_layers" type="int" setter="set_platform_wall_layers" getter="get_platform_wall_layers" default="0"> Collision layers that will be included for detecting wall bodies that will act as moving platforms to be followed by the [CharacterBody3D]. By default, all wall bodies are ignored. </member> + <member name="safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.001"> + Extra margin used for collision recovery when calling [method move_and_slide]. + If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion. + A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors. + A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies. + </member> <member name="slide_on_ceiling" type="bool" setter="set_slide_on_ceiling_enabled" getter="is_slide_on_ceiling_enabled" default="true"> If [code]true[/code], during a jump against the ceiling, the body will slide, if [code]false[/code] it will be stopped and will fall vertically. </member> @@ -184,13 +184,13 @@ <constant name="MOTION_MODE_FLOATING" value="1" enum="MotionMode"> Apply when there is no notion of floor or ceiling. All collisions will be reported as [code]on_wall[/code]. In this mode, when you slide, the speed will always be constant. This mode is suitable for games without ground like space games. </constant> - <constant name="PLATFORM_VEL_ON_LEAVE_ALWAYS" value="0" enum="MovingPlatformApplyVelocityOnLeave"> + <constant name="PLATFORM_ON_LEAVE_ADD_VELOCITY" value="0" enum="PlatformOnLeave"> Add the last platform velocity to the [member velocity] when you leave a moving platform. </constant> - <constant name="PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY" value="1" enum="MovingPlatformApplyVelocityOnLeave"> + <constant name="PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY" value="1" enum="PlatformOnLeave"> Add the last platform velocity to the [member velocity] when you leave a moving platform, but any downward motion is ignored. It's useful to keep full jump height even when the platform is moving down. </constant> - <constant name="PLATFORM_VEL_ON_LEAVE_NEVER" value="2" enum="MovingPlatformApplyVelocityOnLeave"> + <constant name="PLATFORM_ON_LEAVE_DO_NOTHING" value="2" enum="PlatformOnLeave"> Do nothing when leaving a platform. </constant> </constants> diff --git a/doc/classes/ClassDB.xml b/doc/classes/ClassDB.xml index 90ce52fdb0..58a536406f 100644 --- a/doc/classes/ClassDB.xml +++ b/doc/classes/ClassDB.xml @@ -66,7 +66,7 @@ </description> </method> <method name="class_get_method_list" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <param index="0" name="class" type="StringName" /> <param index="1" name="no_inheritance" type="bool" default="false" /> <description> @@ -83,7 +83,7 @@ </description> </method> <method name="class_get_property_list" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <param index="0" name="class" type="StringName" /> <param index="1" name="no_inheritance" type="bool" default="false" /> <description> @@ -99,7 +99,7 @@ </description> </method> <method name="class_get_signal_list" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <param index="0" name="class" type="StringName" /> <param index="1" name="no_inheritance" type="bool" default="false" /> <description> diff --git a/doc/classes/CodeEdit.xml b/doc/classes/CodeEdit.xml index 6513b1ee13..ca482a39e0 100644 --- a/doc/classes/CodeEdit.xml +++ b/doc/classes/CodeEdit.xml @@ -18,7 +18,7 @@ </description> </method> <method name="_filter_code_completion_candidates" qualifiers="virtual const"> - <return type="Array" /> + <return type="Dictionary[]" /> <param index="0" name="candidates" type="Dictionary[]" /> <description> Override this method to define what items in [param candidates] should be displayed. @@ -159,13 +159,13 @@ </description> </method> <method name="get_bookmarked_lines" qualifiers="const"> - <return type="Array" /> + <return type="PackedInt32Array" /> <description> Gets all bookmarked lines. </description> </method> <method name="get_breakpointed_lines" qualifiers="const"> - <return type="Array" /> + <return type="PackedInt32Array" /> <description> Gets all breakpointed lines. </description> @@ -226,7 +226,7 @@ </description> </method> <method name="get_executing_lines" qualifiers="const"> - <return type="Array" /> + <return type="PackedInt32Array" /> <description> Gets all executing lines. </description> diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml index 832f47e2bb..67d5a667e8 100644 --- a/doc/classes/CollisionObject2D.xml +++ b/doc/classes/CollisionObject2D.xml @@ -55,7 +55,7 @@ </description> </method> <method name="get_shape_owners"> - <return type="Array" /> + <return type="PackedInt32Array" /> <description> Returns an [Array] of [code]owner_id[/code] identifiers. You can use these ids in other methods that take [code]owner_id[/code] as an argument. </description> diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml index 04ccf3fc62..4d10a33032 100644 --- a/doc/classes/CollisionObject3D.xml +++ b/doc/classes/CollisionObject3D.xml @@ -49,7 +49,7 @@ </description> </method> <method name="get_shape_owners"> - <return type="Array" /> + <return type="PackedInt32Array" /> <description> Returns an [Array] of [code]owner_id[/code] identifiers. You can use these ids in other methods that take [code]owner_id[/code] as an argument. </description> diff --git a/doc/classes/CollisionShape2D.xml b/doc/classes/CollisionShape2D.xml index 246e0e8663..fa8fbd0d3e 100644 --- a/doc/classes/CollisionShape2D.xml +++ b/doc/classes/CollisionShape2D.xml @@ -4,7 +4,8 @@ Node that represents collision shape data in 2D space. </brief_description> <description> - Editor facility for creating and editing collision shapes in 2D space. You can use this node to represent all sorts of collision shapes, for example, add this to an [Area2D] to give it a detection shape, or add it to a [PhysicsBody2D] to create a solid object. [b]IMPORTANT[/b]: this is an Editor-only helper to create shapes, use [method CollisionObject2D.shape_owner_get_shape] to get the actual shape. + Editor facility for creating and editing collision shapes in 2D space. Set the [member shape] property to configure the shape. [b]IMPORTANT[/b]: this is an Editor-only helper to create shapes, use [method CollisionObject2D.shape_owner_get_shape] to get the actual shape. + You can use this node to represent all sorts of collision shapes, for example, add this to an [Area2D] to give it a detection shape, or add it to a [PhysicsBody2D] to create a solid object. </description> <tutorials> <link title="Physics introduction">$DOCS_URL/tutorials/physics/physics_introduction.html</link> diff --git a/doc/classes/CollisionShape3D.xml b/doc/classes/CollisionShape3D.xml index c8423dac9e..304b46ba27 100644 --- a/doc/classes/CollisionShape3D.xml +++ b/doc/classes/CollisionShape3D.xml @@ -4,7 +4,8 @@ Node that represents collision shape data in 3D space. </brief_description> <description> - Editor facility for creating and editing collision shapes in 3D space. You can use this node to represent all sorts of collision shapes, for example, add this to an [Area3D] to give it a detection shape, or add it to a [PhysicsBody3D] to create a solid object. [b]IMPORTANT[/b]: this is an Editor-only helper to create shapes, use [method CollisionObject3D.shape_owner_get_shape] to get the actual shape. + Editor facility for creating and editing collision shapes in 3D space. Set the [member shape] property to configure the shape. [b]IMPORTANT[/b]: this is an Editor-only helper to create shapes, use [method CollisionObject3D.shape_owner_get_shape] to get the actual shape. + You can use this node to represent all sorts of collision shapes, for example, add this to an [Area3D] to give it a detection shape, or add it to a [PhysicsBody3D] to create a solid object. </description> <tutorials> <link title="Physics introduction">$DOCS_URL/tutorials/physics/physics_introduction.html</link> diff --git a/doc/classes/ConcavePolygonShape2D.xml b/doc/classes/ConcavePolygonShape2D.xml index f3c245c229..902993e439 100644 --- a/doc/classes/ConcavePolygonShape2D.xml +++ b/doc/classes/ConcavePolygonShape2D.xml @@ -7,6 +7,7 @@ 2D concave polygon shape to be added as a [i]direct[/i] child of a [PhysicsBody2D] or [Area2D] using a [CollisionShape2D] node. It is made out of segments and is optimal for complex polygonal concave collisions. However, it is not advised to use for [RigidDynamicBody2D] nodes. A CollisionPolygon2D in convex decomposition mode (solids) or several convex objects are advised for that instead. Otherwise, a concave polygon 2D shape is better for static collisions. The main difference between a [ConvexPolygonShape2D] and a [ConcavePolygonShape2D] is that a concave polygon assumes it is concave and uses a more complex method of collision detection, and a convex one forces itself to be convex to speed up collision detection. [b]Performance:[/b] Due to its complexity, [ConcavePolygonShape2D] is the slowest collision shape to check collisions against. Its use should generally be limited to level geometry. For convex geometry, using [ConvexPolygonShape2D] will perform better. For dynamic physics bodies that need concave collision, several [ConvexPolygonShape2D]s can be used to represent its collision by using convex decomposition; see [ConvexPolygonShape2D]'s documentation for instructions. However, consider using primitive collision shapes such as [CircleShape2D] or [RectangleShape2D] first. + [b]Warning:[/b] Using this shape for an [Area2D] (via a [CollisionShape2D] node) may give unexpected results: the area will only detect collisions with the segments in the [ConcavePolygonShape2D] (and not with any "inside" of the shape, for example). </description> <tutorials> </tutorials> diff --git a/doc/classes/ConcavePolygonShape3D.xml b/doc/classes/ConcavePolygonShape3D.xml index 6a54b4bda7..d22793e52c 100644 --- a/doc/classes/ConcavePolygonShape3D.xml +++ b/doc/classes/ConcavePolygonShape3D.xml @@ -7,6 +7,7 @@ 3D concave polygon shape resource (also called "trimesh") to be added as a [i]direct[/i] child of a [PhysicsBody3D] or [Area3D] using a [CollisionShape3D] node. This shape is created by feeding a list of triangles. Despite its name, [ConcavePolygonShape3D] can also store convex polygon shapes. However, unlike [ConvexPolygonShape3D], [ConcavePolygonShape3D] is [i]not[/i] limited to storing convex shapes exclusively. [b]Note:[/b] When used for collision, [ConcavePolygonShape3D] is intended to work with static [PhysicsBody3D] nodes like [StaticBody3D] and will not work with [CharacterBody3D] or [RigidDynamicBody3D] with a mode other than Static. [b]Performance:[/b] Due to its complexity, [ConcavePolygonShape3D] is the slowest collision shape to check collisions against. Its use should generally be limited to level geometry. For convex geometry, using [ConvexPolygonShape3D] will perform better. For dynamic physics bodies that need concave collision, several [ConvexPolygonShape3D]s can be used to represent its collision by using convex decomposition; see [ConvexPolygonShape3D]'s documentation for instructions. However, consider using primitive collision shapes such as [SphereShape3D] or [BoxShape3D] first. + [b]Warning:[/b] Using this shape for an [Area3D] (via a [CollisionShape3D] node, created e.g. by using the [i]Create Trimesh Collision Sibling[/i] option in the [i]Mesh[/i] menu that appears when selecting a [MeshInstance3D] node) may give unexpected results: the area will only detect collisions with the triangle faces in the [ConcavePolygonShape3D] (and not with any "inside" of the shape, for example); moreover it will only detect all such collisions if [member backface_collision] is [code]true[/code]. </description> <tutorials> <link title="3D Physics Tests Demo">https://godotengine.org/asset-library/asset/675</link> diff --git a/doc/classes/ConeTwistJoint3D.xml b/doc/classes/ConeTwistJoint3D.xml index 5f2ad109f2..1cfe9d197d 100644 --- a/doc/classes/ConeTwistJoint3D.xml +++ b/doc/classes/ConeTwistJoint3D.xml @@ -36,13 +36,13 @@ <member name="softness" type="float" setter="set_param" getter="get_param" default="0.8"> The ease with which the joint starts to twist. If it's too low, it takes more force to start twisting the joint. </member> - <member name="swing_span" type="float" setter="_set_swing_span" getter="_get_swing_span" default="45.0"> + <member name="swing_span" type="float" setter="set_param" getter="get_param" default="0.785398"> Swing is rotation from side to side, around the axis perpendicular to the twist axis. The swing span defines, how much rotation will not get corrected along the swing axis. Could be defined as looseness in the [ConeTwistJoint3D]. If below 0.05, this behavior is locked. </member> - <member name="twist_span" type="float" setter="_set_twist_span" getter="_get_twist_span" default="180.0"> + <member name="twist_span" type="float" setter="set_param" getter="get_param" default="3.14159"> Twist is the rotation around the twist axis, this value defined how far the joint can twist. Twist is locked if below 0.05. </member> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 30d34e4f4d..a3cd4d0752 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -196,7 +196,7 @@ </description> </method> <method name="_structured_text_parser" qualifiers="virtual const"> - <return type="Array" /> + <return type="Vector2i[]" /> <param index="0" name="args" type="Array" /> <param index="1" name="text" type="String" /> <description> @@ -1145,6 +1145,7 @@ </signal> <signal name="theme_changed"> <description> + Emitted when the [constant NOTIFICATION_THEME_CHANGED] notification is sent. </description> </signal> </signals> @@ -1174,7 +1175,12 @@ Sent when the node loses focus. </constant> <constant name="NOTIFICATION_THEME_CHANGED" value="45"> - Sent when the node's [member theme] changes, right before Godot redraws the control. Happens when you call one of the [code]add_theme_*_override[/code] methods. + Sent when the node needs to refresh its theme items. This happens in one of the following cases: + - The [member theme] property is changed on this node or any of its ancestors. + - The [member theme_type_variation] property is changed on this node. + - One of the node's theme property overrides is changed. + - The node enters the scene tree. + [b]Note:[/b] As an optimization, this notification won't be sent from changes that occur while this node is outside of the scene tree. Instead, all of the theme item updates can be applied at once when the node enters the scene tree. </constant> <constant name="NOTIFICATION_SCROLL_BEGIN" value="47"> Sent when this node is inside a [ScrollContainer] which has begun being scrolled. diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 989d0cdb55..bcad75215a 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -105,7 +105,7 @@ </description> </method> <method name="get_display_cutouts" qualifiers="const"> - <return type="Array" /> + <return type="Rect2[]" /> <description> Returns an [Array] of [Rect2], each of which is the bounding rectangle for a display cutout or notch. These are non-functional areas on edge-to-edge screens used by cameras and sensors. Returns an empty array if the device does not have cutouts. See also [method get_display_safe_area]. [b]Note:[/b] Currently only implemented on Android. Other platforms will return an empty array even if they do have display cutouts or notches. @@ -857,7 +857,7 @@ </description> </method> <method name="tts_get_voices" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <description> Returns an [Array] of voice information dictionaries. Each [Dictionary] contains two [String] entries: diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml index 3555d2fd48..f7f1d456d0 100644 --- a/doc/classes/EditorImportPlugin.xml +++ b/doc/classes/EditorImportPlugin.xml @@ -115,7 +115,7 @@ </tutorials> <methods> <method name="_get_import_options" qualifiers="virtual const"> - <return type="Array" /> + <return type="Dictionary[]" /> <param index="0" name="path" type="String" /> <param index="1" name="preset_index" type="int" /> <description> diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml index beed364974..49cd715f5e 100644 --- a/doc/classes/EditorInterface.xml +++ b/doc/classes/EditorInterface.xml @@ -101,7 +101,7 @@ </description> </method> <method name="get_open_scenes" qualifiers="const"> - <return type="Array" /> + <return type="PackedStringArray" /> <description> Returns an [Array] with the file paths of the currently opened scenes. </description> @@ -166,7 +166,7 @@ </description> </method> <method name="make_mesh_previews"> - <return type="Array" /> + <return type="Texture2D[]" /> <param index="0" name="meshes" type="Array" /> <param index="1" name="preview_size" type="int" /> <description> diff --git a/doc/classes/EditorResourcePicker.xml b/doc/classes/EditorResourcePicker.xml index c88a7b75b0..4182ab3c16 100644 --- a/doc/classes/EditorResourcePicker.xml +++ b/doc/classes/EditorResourcePicker.xml @@ -62,9 +62,9 @@ </signal> <signal name="resource_selected"> <param index="0" name="resource" type="Resource" /> - <param index="1" name="edit" type="bool" /> + <param index="1" name="inspect" type="bool" /> <description> - Emitted when the resource value was set and user clicked to edit it. When [param edit] is [code]true[/code], the signal was caused by the context menu "Edit" option. + Emitted when the resource value was set and user clicked to edit it. When [param inspect] is [code]true[/code], the signal was caused by the context menu "Edit" or "Inspect" option. </description> </signal> </signals> diff --git a/doc/classes/EditorSelection.xml b/doc/classes/EditorSelection.xml index 9c3e87ddb0..54029c2ccf 100644 --- a/doc/classes/EditorSelection.xml +++ b/doc/classes/EditorSelection.xml @@ -31,7 +31,7 @@ </description> </method> <method name="get_transformable_selected_nodes"> - <return type="Array" /> + <return type="Node[]" /> <description> Gets the list of selected nodes, optimized for transform operations (i.e. moving them, rotating, etc). This list avoids situations where a node is selected and also child/grandchild. </description> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index 5c27a9c645..d538a0af2a 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -85,7 +85,7 @@ </description> </method> <method name="get_changed_settings" qualifiers="const"> - <return type="Array" /> + <return type="PackedStringArray" /> <description> Gets an array of the settings which have been changed since the last save. Note that internally [code]changed_settings[/code] is cleared after a successful save, so generally the most appropriate place to use this method is when processing [constant NOTIFICATION_EDITOR_SETTINGS_CHANGED] </description> @@ -465,15 +465,15 @@ </member> <member name="interface/editor/code_font_contextual_ligatures" type="int" setter="" getter=""> The font ligatures to enable for the currently configured code font. Not all fonts include support for ligatures. - [b]Note:[/b] The default editor code font (Hack) does not have contextual ligatures in its font file. + [b]Note:[/b] The default editor code font ([url=https://www.jetbrains.com/lp/mono/]JetBrains Mono[/url]) has contextual ligatures in its font file. </member> <member name="interface/editor/code_font_custom_opentype_features" type="String" setter="" getter=""> List of custom OpenType features to use, if supported by the currently configured code font. Not all fonts include support for custom OpenType features. The string should follow the OpenType specification. - [b]Note:[/b] The default editor code font (Hack) does not have custom OpenType features in its font file. + [b]Note:[/b] The default editor code font ([url=https://www.jetbrains.com/lp/mono/]JetBrains Mono[/url]) has custom OpenType features in its font file, but there is no documented list yet. </member> <member name="interface/editor/code_font_custom_variations" type="String" setter="" getter=""> List of alternative characters to use, if supported by the currently configured code font. Not all fonts include support for custom variations. The string should follow the OpenType specification. - [b]Note:[/b] The default editor code font (Hack) does not have alternate characters in its font file. + [b]Note:[/b] The default editor code font ([url=https://www.jetbrains.com/lp/mono/]JetBrains Mono[/url]) has alternate characters in its font file, but there is no documented list yet. </member> <member name="interface/editor/code_font_size" type="int" setter="" getter=""> The size of the font in the script editor. This setting does not impact the font size of the Output panel (see [member run/output/font_size]). diff --git a/doc/classes/EditorSyntaxHighlighter.xml b/doc/classes/EditorSyntaxHighlighter.xml index 15b730acb4..51f4474fe7 100644 --- a/doc/classes/EditorSyntaxHighlighter.xml +++ b/doc/classes/EditorSyntaxHighlighter.xml @@ -17,7 +17,7 @@ </description> </method> <method name="_get_supported_languages" qualifiers="virtual const"> - <return type="Array" /> + <return type="PackedStringArray" /> <description> Virtual method which can be overridden to return the supported language names. </description> diff --git a/doc/classes/EditorVCSInterface.xml b/doc/classes/EditorVCSInterface.xml index cc75861130..89ba79f7d9 100644 --- a/doc/classes/EditorVCSInterface.xml +++ b/doc/classes/EditorVCSInterface.xml @@ -17,7 +17,7 @@ </description> </method> <method name="get_file_diff"> - <return type="Array" /> + <return type="Dictionary[]" /> <param index="0" name="file_path" type="String" /> <description> Returns an [Array] of [Dictionary] objects containing the diff output from the VCS in use, if a VCS addon is initialized, else returns an empty [Array] object. The diff contents also consist of some contextual lines which provide context to the observed line change in the file. diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml index 2350a1f51b..301a3e55fb 100644 --- a/doc/classes/Engine.xml +++ b/doc/classes/Engine.xml @@ -34,7 +34,7 @@ </description> </method> <method name="get_copyright_info" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <description> Returns an Array of copyright information Dictionaries. [code]name[/code] - String, component name diff --git a/doc/classes/FontFile.xml b/doc/classes/FontFile.xml index 4c82ead1de..df378d9d2f 100644 --- a/doc/classes/FontFile.xml +++ b/doc/classes/FontFile.xml @@ -146,7 +146,7 @@ </description> </method> <method name="get_glyph_list" qualifiers="const"> - <return type="Array" /> + <return type="PackedInt32Array" /> <param index="0" name="cache_index" type="int" /> <param index="1" name="size" type="Vector2i" /> <description> @@ -199,7 +199,7 @@ </description> </method> <method name="get_kerning_list" qualifiers="const"> - <return type="Array" /> + <return type="Vector2i[]" /> <param index="0" name="cache_index" type="int" /> <param index="1" name="size" type="int" /> <description> @@ -233,7 +233,7 @@ </description> </method> <method name="get_size_cache_list" qualifiers="const"> - <return type="Array" /> + <return type="Vector2i[]" /> <param index="0" name="cache_index" type="int" /> <description> Returns list of the font sizes in the cache. Each size is [code]Vector2i[/code] with font size and outline size. diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml index 606d2456c5..f41e34c43a 100644 --- a/doc/classes/GPUParticles2D.xml +++ b/doc/classes/GPUParticles2D.xml @@ -5,7 +5,7 @@ </brief_description> <description> 2D particle node used to create a variety of particle systems and effects. [GPUParticles2D] features an emitter that generates some number of particles at a given rate. - Use the [code]process_material[/code] property to add a [ParticlesMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles. + Use the [code]process_material[/code] property to add a [ParticleProcessMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles. </description> <tutorials> <link title="Particle systems (2D)">$DOCS_URL/tutorials/2d/particle_systems_2d.html</link> @@ -73,7 +73,7 @@ Particle system starts as if it had already run for this many seconds. </member> <member name="process_material" type="Material" setter="set_process_material" getter="get_process_material"> - [Material] for processing particles. Can be a [ParticlesMaterial] or a [ShaderMaterial]. + [Material] for processing particles. Can be a [ParticleProcessMaterial] or a [ShaderMaterial]. </member> <member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio" default="0.0"> Emission lifetime randomness ratio. diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml index fc7b12e64f..e7b436010e 100644 --- a/doc/classes/GPUParticles3D.xml +++ b/doc/classes/GPUParticles3D.xml @@ -5,7 +5,7 @@ </brief_description> <description> 3D particle node used to create a variety of particle systems and effects. [GPUParticles3D] features an emitter that generates some number of particles at a given rate. - Use the [code]process_material[/code] property to add a [ParticlesMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles. + Use the [code]process_material[/code] property to add a [ParticleProcessMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles. </description> <tutorials> <link title="Controlling thousands of fish with Particles">$DOCS_URL/tutorials/performance/vertex_animation/controlling_thousands_of_fish.html</link> @@ -105,7 +105,7 @@ Amount of time to preprocess the particles before animation starts. Lets you start the animation some time after particles have started emitting. </member> <member name="process_material" type="Material" setter="set_process_material" getter="get_process_material"> - [Material] for processing particles. Can be a [ParticlesMaterial] or a [ShaderMaterial]. + [Material] for processing particles. Can be a [ParticleProcessMaterial] or a [ShaderMaterial]. </member> <member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio" default="0.0"> Emission randomness ratio. diff --git a/doc/classes/GPUParticlesAttractor3D.xml b/doc/classes/GPUParticlesAttractor3D.xml index e69255cc31..a1c49afcca 100644 --- a/doc/classes/GPUParticlesAttractor3D.xml +++ b/doc/classes/GPUParticlesAttractor3D.xml @@ -18,7 +18,7 @@ <member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="4294967295"> The particle rendering layers ([member VisualInstance3D.layers]) that will be affected by the attractor. By default, all particles are affected by an attractor. After configuring particle nodes accordingly, specific layers can be unchecked to prevent certain particles from being affected by attractors. For example, this can be used if you're using an attractor as part of a spell effect but don't want the attractor to affect unrelated weather particles at the same position. - Particle attraction can also be disabled on a per-process material basis by setting [member ParticlesMaterial.attractor_interaction_enabled] on the [GPUParticles3D] node. + Particle attraction can also be disabled on a per-process material basis by setting [member ParticleProcessMaterial.attractor_interaction_enabled] on the [GPUParticles3D] node. </member> <member name="directionality" type="float" setter="set_directionality" getter="get_directionality" default="0.0"> Adjusts how directional the attractor is. At [code]0.0[/code], the attractor is not directional at all: it will attract particles towards its center. At [code]1.0[/code], the attractor is fully directional: particles will always be pushed towards local -Z (or +Z if [member strength] is negative). diff --git a/doc/classes/GPUParticlesCollision3D.xml b/doc/classes/GPUParticlesCollision3D.xml index 435f9781f0..1b744f7ed6 100644 --- a/doc/classes/GPUParticlesCollision3D.xml +++ b/doc/classes/GPUParticlesCollision3D.xml @@ -7,7 +7,7 @@ Particle collision shapes can be used to make particles stop or bounce against them. Particle collision shapes in real-time and can be moved, rotated and scaled during gameplay. Unlike attractors, non-uniform scaling of collision shapes is [i]not[/i] supported. Particle collision shapes can be temporarily disabled by hiding them. - [b]Note:[/b] [member ParticlesMaterial.collision_enabled] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work. + [b]Note:[/b] [member ParticleProcessMaterial.collision_mode] must be [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.COLLISION_HIDE_ON_CONTACT] on the [GPUParticles3D]'s process material for collision to work. [b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D]. [b]Note:[/b] Particles pushed by a collider that is being moved will not be interpolated, which can result in visible stuttering. This can be alleviated by setting [member GPUParticles3D.fixed_fps] to [code]0[/code] or a value that matches or exceeds the target framerate. </description> @@ -15,9 +15,9 @@ </tutorials> <members> <member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="4294967295"> - The particle rendering layers ([member VisualInstance3D.layers]) that will be affected by the collision shape. By default, all particles that have [member ParticlesMaterial.collision_enabled] set to [code]true[/code] will be affected by a collision shape. + The particle rendering layers ([member VisualInstance3D.layers]) that will be affected by the collision shape. By default, all particles that have [member ParticleProcessMaterial.collision_mode] set to [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.COLLISION_HIDE_ON_CONTACT] will be affected by a collision shape. After configuring particle nodes accordingly, specific layers can be unchecked to prevent certain particles from being affected by attractors. For example, this can be used if you're using an attractor as part of a spell effect but don't want the attractor to affect unrelated weather particles at the same position. - Particle attraction can also be disabled on a per-process material basis by setting [member ParticlesMaterial.attractor_interaction_enabled] on the [GPUParticles3D] node. + Particle attraction can also be disabled on a per-process material basis by setting [member ParticleProcessMaterial.attractor_interaction_enabled] on the [GPUParticles3D] node. </member> </members> </class> diff --git a/doc/classes/GPUParticlesCollisionBox3D.xml b/doc/classes/GPUParticlesCollisionBox3D.xml index 60d66ca682..103be18bfd 100644 --- a/doc/classes/GPUParticlesCollisionBox3D.xml +++ b/doc/classes/GPUParticlesCollisionBox3D.xml @@ -5,7 +5,7 @@ </brief_description> <description> Box-shaped 3D particle collision shape affecting [GPUParticles3D] nodes. - [b]Note:[/b] [member ParticlesMaterial.collision_enabled] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work. + [b]Note:[/b] [member ParticleProcessMaterial.collision_mode] must be [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.COLLISION_HIDE_ON_CONTACT] on the [GPUParticles3D]'s process material for collision to work. [b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D]. </description> <tutorials> diff --git a/doc/classes/GPUParticlesCollisionHeightField3D.xml b/doc/classes/GPUParticlesCollisionHeightField3D.xml index 3fcad43efb..6e996d5fbd 100644 --- a/doc/classes/GPUParticlesCollisionHeightField3D.xml +++ b/doc/classes/GPUParticlesCollisionHeightField3D.xml @@ -7,7 +7,7 @@ Real-time heightmap-shaped 3D particle attractor affecting [GPUParticles3D] nodes. Heightmap shapes allow for efficiently representing collisions for convex and concave objects with a single "floor" (such as terrain). This is less flexible than [GPUParticlesCollisionSDF3D], but it doesn't require a baking step. [GPUParticlesCollisionHeightField3D] can also be regenerated in real-time when it is moved, when the camera moves, or even continuously. This makes [GPUParticlesCollisionHeightField3D] a good choice for weather effects such as rain and snow and games with highly dynamic geometry. However, since heightmaps cannot represent overhangs, [GPUParticlesCollisionHeightField3D] is not suited for indoor particle collision. - [b]Note:[/b] [member ParticlesMaterial.collision_enabled] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work. + [b]Note:[/b] [member ParticleProcessMaterial.collision_mode] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work. [b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D]. </description> <tutorials> diff --git a/doc/classes/GPUParticlesCollisionSDF3D.xml b/doc/classes/GPUParticlesCollisionSDF3D.xml index 29adf4fbc1..8467cfdda1 100644 --- a/doc/classes/GPUParticlesCollisionSDF3D.xml +++ b/doc/classes/GPUParticlesCollisionSDF3D.xml @@ -8,7 +8,7 @@ Signed distance fields (SDF) allow for efficiently representing approximate collision shapes for convex and concave objects of any shape. This is more flexible than [GPUParticlesCollisionHeightField3D], but it requires a baking step. [b]Baking:[/b] The signed distance field texture can be baked by selecting the [GPUParticlesCollisionSDF3D] node in the editor, then clicking [b]Bake SDF[/b] at the top of the 3D viewport. Any [i]visible[/i] [MeshInstance3D]s touching the [member extents] will be taken into account for baking, regardless of their [member GeometryInstance3D.gi_mode]. [b]Note:[/b] Baking a [GPUParticlesCollisionSDF3D]'s [member texture] is only possible within the editor, as there is no bake method exposed for use in exported projects. However, it's still possible to load pre-baked [Texture3D]s into its [member texture] property in an exported project. - [b]Note:[/b] [member ParticlesMaterial.collision_enabled] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work. + [b]Note:[/b] [member ParticleProcessMaterial.collision_mode] must be [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.COLLISION_HIDE_ON_CONTACT] on the [GPUParticles3D]'s process material for collision to work. [b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D]. </description> <tutorials> diff --git a/doc/classes/GPUParticlesCollisionSphere3D.xml b/doc/classes/GPUParticlesCollisionSphere3D.xml index 6651a732da..ee582108dd 100644 --- a/doc/classes/GPUParticlesCollisionSphere3D.xml +++ b/doc/classes/GPUParticlesCollisionSphere3D.xml @@ -5,7 +5,7 @@ </brief_description> <description> Sphere-shaped 3D particle collision shape affecting [GPUParticles3D] nodes. - [b]Note:[/b] [member ParticlesMaterial.collision_enabled] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work. + [b]Note:[/b] [member ParticleProcessMaterial.collision_mode] must be [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.COLLISION_HIDE_ON_CONTACT] on the [GPUParticles3D]'s process material for collision to work. [b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D]. </description> <tutorials> diff --git a/doc/classes/Generic6DOFJoint3D.xml b/doc/classes/Generic6DOFJoint3D.xml index 5eec089a6f..e6058b1bf9 100644 --- a/doc/classes/Generic6DOFJoint3D.xml +++ b/doc/classes/Generic6DOFJoint3D.xml @@ -102,7 +102,7 @@ <member name="angular_limit_x/force_limit" type="float" setter="set_param_x" getter="get_param_x" default="0.0"> The maximum amount of force that can occur, when rotating around the X axis. </member> - <member name="angular_limit_x/lower_angle" type="float" setter="_set_angular_lo_limit_x" getter="_get_angular_lo_limit_x" default="0.0"> + <member name="angular_limit_x/lower_angle" type="float" setter="set_param_x" getter="get_param_x" default="0.0"> The minimum rotation in negative direction to break loose and rotate around the X axis. </member> <member name="angular_limit_x/restitution" type="float" setter="set_param_x" getter="get_param_x" default="0.0"> @@ -111,7 +111,7 @@ <member name="angular_limit_x/softness" type="float" setter="set_param_x" getter="get_param_x" default="0.5"> The speed of all rotations across the X axis. </member> - <member name="angular_limit_x/upper_angle" type="float" setter="_set_angular_hi_limit_x" getter="_get_angular_hi_limit_x" default="0.0"> + <member name="angular_limit_x/upper_angle" type="float" setter="set_param_x" getter="get_param_x" default="0.0"> The minimum rotation in positive direction to break loose and rotate around the X axis. </member> <member name="angular_limit_y/damping" type="float" setter="set_param_y" getter="get_param_y" default="1.0"> @@ -126,7 +126,7 @@ <member name="angular_limit_y/force_limit" type="float" setter="set_param_y" getter="get_param_y" default="0.0"> The maximum amount of force that can occur, when rotating around the Y axis. </member> - <member name="angular_limit_y/lower_angle" type="float" setter="_set_angular_lo_limit_y" getter="_get_angular_lo_limit_y" default="0.0"> + <member name="angular_limit_y/lower_angle" type="float" setter="set_param_y" getter="get_param_y" default="0.0"> The minimum rotation in negative direction to break loose and rotate around the Y axis. </member> <member name="angular_limit_y/restitution" type="float" setter="set_param_y" getter="get_param_y" default="0.0"> @@ -135,7 +135,7 @@ <member name="angular_limit_y/softness" type="float" setter="set_param_y" getter="get_param_y" default="0.5"> The speed of all rotations across the Y axis. </member> - <member name="angular_limit_y/upper_angle" type="float" setter="_set_angular_hi_limit_y" getter="_get_angular_hi_limit_y" default="0.0"> + <member name="angular_limit_y/upper_angle" type="float" setter="set_param_y" getter="get_param_y" default="0.0"> The minimum rotation in positive direction to break loose and rotate around the Y axis. </member> <member name="angular_limit_z/damping" type="float" setter="set_param_z" getter="get_param_z" default="1.0"> @@ -150,7 +150,7 @@ <member name="angular_limit_z/force_limit" type="float" setter="set_param_z" getter="get_param_z" default="0.0"> The maximum amount of force that can occur, when rotating around the Z axis. </member> - <member name="angular_limit_z/lower_angle" type="float" setter="_set_angular_lo_limit_z" getter="_get_angular_lo_limit_z" default="0.0"> + <member name="angular_limit_z/lower_angle" type="float" setter="set_param_z" getter="get_param_z" default="0.0"> The minimum rotation in negative direction to break loose and rotate around the Z axis. </member> <member name="angular_limit_z/restitution" type="float" setter="set_param_z" getter="get_param_z" default="0.0"> @@ -159,7 +159,7 @@ <member name="angular_limit_z/softness" type="float" setter="set_param_z" getter="get_param_z" default="0.5"> The speed of all rotations across the Z axis. </member> - <member name="angular_limit_z/upper_angle" type="float" setter="_set_angular_hi_limit_z" getter="_get_angular_hi_limit_z" default="0.0"> + <member name="angular_limit_z/upper_angle" type="float" setter="set_param_z" getter="get_param_z" default="0.0"> The minimum rotation in positive direction to break loose and rotate around the Z axis. </member> <member name="angular_motor_x/enabled" type="bool" setter="set_flag_x" getter="get_flag_x" default="false"> diff --git a/doc/classes/Geometry2D.xml b/doc/classes/Geometry2D.xml index 80d19e22c5..392ca2cabb 100644 --- a/doc/classes/Geometry2D.xml +++ b/doc/classes/Geometry2D.xml @@ -10,7 +10,7 @@ </tutorials> <methods> <method name="clip_polygons"> - <return type="Array" /> + <return type="PackedVector2Array[]" /> <param index="0" name="polygon_a" type="PackedVector2Array" /> <param index="1" name="polygon_b" type="PackedVector2Array" /> <description> @@ -19,7 +19,7 @@ </description> </method> <method name="clip_polyline_with_polygon"> - <return type="Array" /> + <return type="PackedVector2Array[]" /> <param index="0" name="polyline" type="PackedVector2Array" /> <param index="1" name="polygon" type="PackedVector2Array" /> <description> @@ -34,7 +34,7 @@ </description> </method> <method name="exclude_polygons"> - <return type="Array" /> + <return type="PackedVector2Array[]" /> <param index="0" name="polygon_a" type="PackedVector2Array" /> <param index="1" name="polygon_b" type="PackedVector2Array" /> <description> @@ -71,7 +71,7 @@ </description> </method> <method name="intersect_polygons"> - <return type="Array" /> + <return type="PackedVector2Array[]" /> <param index="0" name="polygon_a" type="PackedVector2Array" /> <param index="1" name="polygon_b" type="PackedVector2Array" /> <description> @@ -80,7 +80,7 @@ </description> </method> <method name="intersect_polyline_with_polygon"> - <return type="Array" /> + <return type="PackedVector2Array[]" /> <param index="0" name="polyline" type="PackedVector2Array" /> <param index="1" name="polygon" type="PackedVector2Array" /> <description> @@ -130,7 +130,7 @@ </description> </method> <method name="merge_polygons"> - <return type="Array" /> + <return type="PackedVector2Array[]" /> <param index="0" name="polygon_a" type="PackedVector2Array" /> <param index="1" name="polygon_b" type="PackedVector2Array" /> <description> @@ -139,7 +139,7 @@ </description> </method> <method name="offset_polygon"> - <return type="Array" /> + <return type="PackedVector2Array[]" /> <param index="0" name="polygon" type="PackedVector2Array" /> <param index="1" name="delta" type="float" /> <param index="2" name="join_type" type="int" enum="Geometry2D.PolyJoinType" default="0" /> @@ -166,7 +166,7 @@ </description> </method> <method name="offset_polyline"> - <return type="Array" /> + <return type="PackedVector2Array[]" /> <param index="0" name="polyline" type="PackedVector2Array" /> <param index="1" name="delta" type="float" /> <param index="2" name="join_type" type="int" enum="Geometry2D.PolyJoinType" default="0" /> diff --git a/doc/classes/Geometry3D.xml b/doc/classes/Geometry3D.xml index c841842d14..d37b0b7b81 100644 --- a/doc/classes/Geometry3D.xml +++ b/doc/classes/Geometry3D.xml @@ -10,14 +10,14 @@ </tutorials> <methods> <method name="build_box_planes"> - <return type="Array" /> + <return type="Plane[]" /> <param index="0" name="extents" type="Vector3" /> <description> Returns an array with 6 [Plane]s that describe the sides of a box centered at the origin. The box size is defined by [param extents], which represents one (positive) corner of the box (i.e. half its actual size). </description> </method> <method name="build_capsule_planes"> - <return type="Array" /> + <return type="Plane[]" /> <param index="0" name="radius" type="float" /> <param index="1" name="height" type="float" /> <param index="2" name="sides" type="int" /> @@ -28,7 +28,7 @@ </description> </method> <method name="build_cylinder_planes"> - <return type="Array" /> + <return type="Plane[]" /> <param index="0" name="radius" type="float" /> <param index="1" name="height" type="float" /> <param index="2" name="sides" type="int" /> diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml index 9f9d1a7ed6..e5aa78971e 100644 --- a/doc/classes/GraphEdit.xml +++ b/doc/classes/GraphEdit.xml @@ -149,7 +149,7 @@ </description> </method> <method name="get_connection_list" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <description> Returns an Array containing the list of connections. A connection consists in a structure of the form [code]{ from_port: 0, from: "GraphNode name 0", to_port: 1, to: "GraphNode name 1" }[/code]. </description> diff --git a/doc/classes/HingeJoint3D.xml b/doc/classes/HingeJoint3D.xml index d2547434e7..99524795f9 100644 --- a/doc/classes/HingeJoint3D.xml +++ b/doc/classes/HingeJoint3D.xml @@ -47,7 +47,7 @@ <member name="angular_limit/enable" type="bool" setter="set_flag" getter="get_flag" default="false"> If [code]true[/code], the hinges maximum and minimum rotation, defined by [member angular_limit/lower] and [member angular_limit/upper] has effects. </member> - <member name="angular_limit/lower" type="float" setter="_set_lower_limit" getter="_get_lower_limit" default="-90.0"> + <member name="angular_limit/lower" type="float" setter="set_param" getter="get_param" default="-1.5708"> The minimum rotation. Only active if [member angular_limit/enable] is [code]true[/code]. </member> <member name="angular_limit/relaxation" type="float" setter="set_param" getter="get_param" default="1.0"> @@ -55,7 +55,7 @@ </member> <member name="angular_limit/softness" type="float" setter="set_param" getter="get_param" default="0.9"> </member> - <member name="angular_limit/upper" type="float" setter="_set_upper_limit" getter="_get_upper_limit" default="90.0"> + <member name="angular_limit/upper" type="float" setter="set_param" getter="get_param" default="1.5708"> The maximum rotation. Only active if [member angular_limit/enable] is [code]true[/code]. </member> <member name="motor/enable" type="bool" setter="set_flag" getter="get_flag" default="false"> diff --git a/doc/classes/IP.xml b/doc/classes/IP.xml index e476a86a49..1e5e6da513 100644 --- a/doc/classes/IP.xml +++ b/doc/classes/IP.xml @@ -24,13 +24,13 @@ </description> </method> <method name="get_local_addresses" qualifiers="const"> - <return type="Array" /> + <return type="PackedStringArray" /> <description> Returns all the user's current IPv4 and IPv6 addresses as an array. </description> </method> <method name="get_local_interfaces" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <description> Returns all network adapters as an array. Each adapter is a dictionary of the form: @@ -74,7 +74,7 @@ </description> </method> <method name="resolve_hostname_addresses"> - <return type="Array" /> + <return type="PackedStringArray" /> <param index="0" name="host" type="String" /> <param index="1" name="ip_type" type="int" enum="IP.Type" default="3" /> <description> diff --git a/doc/classes/ImageTexture.xml b/doc/classes/ImageTexture.xml index c750b540a4..45cbd7ac87 100644 --- a/doc/classes/ImageTexture.xml +++ b/doc/classes/ImageTexture.xml @@ -6,20 +6,20 @@ <description> A [Texture2D] based on an [Image]. For an image to be displayed, an [ImageTexture] has to be created from it using the [method create_from_image] method: [codeblock] - var image = Image.load_from_file("res://icon.png") + var image = Image.load_from_file("res://icon.svg") var texture = ImageTexture.create_from_image(image) $Sprite2D.texture = texture [/codeblock] This way, textures can be created at run-time by loading images both from within the editor and externally. [b]Warning:[/b] Prefer to load imported textures with [method @GDScript.load] over loading them from within the filesystem dynamically with [method Image.load], as it may not work in exported projects: [codeblock] - var texture = load("res://icon.png") + var texture = load("res://icon.svg") $Sprite2D.texture = texture [/codeblock] This is because images have to be imported as a [CompressedTexture2D] first to be loaded with [method @GDScript.load]. If you'd still like to load an image file just like any other [Resource], import it as an [Image] resource instead, and then load it normally using the [method @GDScript.load] method. [b]Note:[/b] The image can be retrieved from an imported texture using the [method Texture2D.get_image] method, which returns a copy of the image: [codeblock] - var texture = load("res://icon.png") + var texture = load("res://icon.svg") var image : Image = texture.get_image() [/codeblock] An [ImageTexture] is not meant to be operated from within the editor interface directly, and is mostly useful for rendering images on screen dynamically via code. If you need to generate images procedurally from within the editor, consider saving and importing images as custom texture resources implementing a new [EditorImportPlugin]. diff --git a/doc/classes/InputMap.xml b/doc/classes/InputMap.xml index d60abd7975..1d7d54f681 100644 --- a/doc/classes/InputMap.xml +++ b/doc/classes/InputMap.xml @@ -41,7 +41,7 @@ </description> </method> <method name="action_get_events"> - <return type="Array" /> + <return type="InputEvent[]" /> <param index="0" name="action" type="StringName" /> <description> Returns an array of [InputEvent]s associated with a given action. @@ -91,7 +91,7 @@ </description> </method> <method name="get_actions"> - <return type="Array" /> + <return type="StringName[]" /> <description> Returns an array of all actions in the [InputMap]. </description> diff --git a/doc/classes/Joint3D.xml b/doc/classes/Joint3D.xml index fef8fdf965..a9ca86d269 100644 --- a/doc/classes/Joint3D.xml +++ b/doc/classes/Joint3D.xml @@ -10,16 +10,16 @@ <link title="3D Truck Town Demo">https://godotengine.org/asset-library/asset/524</link> </tutorials> <members> - <member name="collision/exclude_nodes" type="bool" setter="set_exclude_nodes_from_collision" getter="get_exclude_nodes_from_collision" default="true"> + <member name="exclude_nodes_from_collision" type="bool" setter="set_exclude_nodes_from_collision" getter="get_exclude_nodes_from_collision" default="true"> If [code]true[/code], the two bodies of the nodes are not able to collide with each other. </member> - <member name="nodes/node_a" type="NodePath" setter="set_node_a" getter="get_node_a" default="NodePath("")"> + <member name="node_a" type="NodePath" setter="set_node_a" getter="get_node_a" default="NodePath("")"> The node attached to the first side (A) of the joint. </member> - <member name="nodes/node_b" type="NodePath" setter="set_node_b" getter="get_node_b" default="NodePath("")"> + <member name="node_b" type="NodePath" setter="set_node_b" getter="get_node_b" default="NodePath("")"> The node attached to the second side (B) of the joint. </member> - <member name="solver/priority" type="int" setter="set_solver_priority" getter="get_solver_priority" default="1"> + <member name="solver_priority" type="int" setter="set_solver_priority" getter="get_solver_priority" default="1"> The priority used to define which solver is executed first for multiple joints. The lower the value, the higher the priority. </member> </members> diff --git a/doc/classes/Label.xml b/doc/classes/Label.xml index 239eea099b..52b2e9a729 100644 --- a/doc/classes/Label.xml +++ b/doc/classes/Label.xml @@ -62,8 +62,8 @@ </member> <member name="mouse_filter" type="int" setter="set_mouse_filter" getter="get_mouse_filter" overrides="Control" enum="Control.MouseFilter" default="2" /> <member name="percent_visible" type="float" setter="set_percent_visible" getter="get_percent_visible" default="1.0"> - Limits the number of visible characters. If you set [code]percent_visible[/code] to 0.5, only up to half of the text's characters will display on screen. Useful to animate the text in a dialog box. - [b]Note:[/b] Setting this property updates [member visible_characters] based on current [method get_total_character_count]. + The fraction of characters to display, relative to the total number of characters (see [method get_total_character_count]). If set to [code]1.0[/code], all characters are displayed. If set to [code]0.5[/code], only half of the characters will be displayed. This can be useful when animating the text appearing in a dialog box. + [b]Note:[/b] Setting this property updates [member visible_characters] accordingly. </member> <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" default="4" /> <member name="structured_text_bidi_override" type="int" setter="set_structured_text_bidi_override" getter="get_structured_text_bidi_override" enum="TextServer.StructuredTextParser" default="0"> @@ -88,8 +88,8 @@ Controls the text's vertical alignment. Supports top, center, bottom, and fill. Set it to one of the [enum VerticalAlignment] constants. </member> <member name="visible_characters" type="int" setter="set_visible_characters" getter="get_visible_characters" default="-1"> - Restricts the number of characters to display. Set to -1 to disable. - [b]Note:[/b] Setting this property updates [member percent_visible] based on current [method get_total_character_count]. + The number of characters to display. If set to [code]-1[/code], all characters are displayed. This can be useful when animating the text appearing in a dialog box. + [b]Note:[/b] Setting this property updates [member percent_visible] accordingly. </member> <member name="visible_characters_behavior" type="int" setter="set_visible_characters_behavior" getter="get_visible_characters_behavior" enum="TextServer.VisibleCharactersBehavior" default="0"> Sets the clipping behavior when [member visible_characters] or [member percent_visible] is set. See [enum TextServer.VisibleCharactersBehavior] for more info. diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index 20703f680c..5ca2a22749 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -65,7 +65,7 @@ </description> </method> <method name="get_scroll_offset" qualifiers="const"> - <return type="int" /> + <return type="float" /> <description> Returns the scroll offset due to [member caret_column], as a number of characters. </description> diff --git a/doc/classes/Position2D.xml b/doc/classes/Marker2D.xml index 754fd1fdf1..bf90438bf0 100644 --- a/doc/classes/Position2D.xml +++ b/doc/classes/Marker2D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Position2D" inherits="Node2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="Marker2D" inherits="Node2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Generic 2D position hint for editing. </brief_description> diff --git a/doc/classes/Position3D.xml b/doc/classes/Marker3D.xml index d91e0fbfdf..5ad1cdf513 100644 --- a/doc/classes/Position3D.xml +++ b/doc/classes/Marker3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Position3D" inherits="Node3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="Marker3D" inherits="Node3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Generic 3D position hint for editing. </brief_description> diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml index 8e98efa6fc..d3d5a7bfaa 100644 --- a/doc/classes/Mesh.xml +++ b/doc/classes/Mesh.xml @@ -60,7 +60,7 @@ </description> </method> <method name="_surface_get_blend_shape_arrays" qualifiers="virtual const"> - <return type="Array" /> + <return type="Array[]" /> <param index="0" name="index" type="int" /> <description> </description> @@ -153,7 +153,7 @@ </description> </method> <method name="surface_get_blend_shape_arrays" qualifiers="const"> - <return type="Array" /> + <return type="Array[]" /> <param index="0" name="surf_idx" type="int" /> <description> Returns the blend shape arrays for the requested surface. diff --git a/doc/classes/NavigationAgent2D.xml b/doc/classes/NavigationAgent2D.xml index 30ad13ec93..bf3aff2c58 100644 --- a/doc/classes/NavigationAgent2D.xml +++ b/doc/classes/NavigationAgent2D.xml @@ -126,7 +126,7 @@ <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1"> A bitfield determining what navigation layers of navigation regions this agent will use to calculate path. Changing it runtime will clear current navigation path and generate new one, according to new navigation layers. </member> - <member name="neighbor_dist" type="float" setter="set_neighbor_dist" getter="get_neighbor_dist" default="500.0"> + <member name="neighbor_distance" type="float" setter="set_neighbor_distance" getter="get_neighbor_distance" default="500.0"> The distance to search for other agents. </member> <member name="path_desired_distance" type="float" setter="set_path_desired_distance" getter="get_path_desired_distance" default="1.0"> @@ -136,7 +136,7 @@ The maximum distance the agent is allowed away from the ideal path to the final location. This can happen due to trying to avoid collisions. When the maximum distance is exceeded, it recalculates the ideal path. </member> <member name="radius" type="float" setter="set_radius" getter="get_radius" default="10.0"> - The radius of the avoidance agent. This is the "body" of the avoidance agent and not the avoidance maneuver starting radius (which is controlled by [member neighbor_dist]). + The radius of the avoidance agent. This is the "body" of the avoidance agent and not the avoidance maneuver starting radius (which is controlled by [member neighbor_distance]). Does not affect normal pathfinding. To change an actor's pathfinding radius bake [NavigationMesh] resources with a different [member NavigationMesh.agent_radius] property and use different navigation maps for each actor size. </member> <member name="target_desired_distance" type="float" setter="set_target_desired_distance" getter="get_target_desired_distance" default="1.0"> diff --git a/doc/classes/NavigationAgent3D.xml b/doc/classes/NavigationAgent3D.xml index 22c468cb6b..7c48f0b52b 100644 --- a/doc/classes/NavigationAgent3D.xml +++ b/doc/classes/NavigationAgent3D.xml @@ -132,7 +132,7 @@ <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1"> A bitfield determining what navigation layers of navigation regions this NavigationAgent will use to calculate path. Changing it runtime will clear current navigation path and generate new one, according to new navigation layers. </member> - <member name="neighbor_dist" type="float" setter="set_neighbor_dist" getter="get_neighbor_dist" default="50.0"> + <member name="neighbor_distance" type="float" setter="set_neighbor_distance" getter="get_neighbor_distance" default="50.0"> The distance to search for other agents. </member> <member name="path_desired_distance" type="float" setter="set_path_desired_distance" getter="get_path_desired_distance" default="1.0"> @@ -142,7 +142,7 @@ The maximum distance the agent is allowed away from the ideal path to the final location. This can happen due to trying to avoid collisions. When the maximum distance is exceeded, it recalculates the ideal path. </member> <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0"> - The radius of the avoidance agent. This is the "body" of the avoidance agent and not the avoidance maneuver starting radius (which is controlled by [member neighbor_dist]). + The radius of the avoidance agent. This is the "body" of the avoidance agent and not the avoidance maneuver starting radius (which is controlled by [member neighbor_distance]). Does not affect normal pathfinding. To change an actor's pathfinding radius bake [NavigationMesh] resources with a different [member NavigationMesh.agent_radius] property and use different navigation maps for each actor size. </member> <member name="target_desired_distance" type="float" setter="set_target_desired_distance" getter="get_target_desired_distance" default="1.0"> diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml index e4e9a7fea9..b85c1c6649 100644 --- a/doc/classes/NavigationServer2D.xml +++ b/doc/classes/NavigationServer2D.xml @@ -72,10 +72,10 @@ Sets the maximum speed of the agent. Must be positive. </description> </method> - <method name="agent_set_neighbor_dist" qualifiers="const"> + <method name="agent_set_neighbor_distance" qualifiers="const"> <return type="void" /> <param index="0" name="agent" type="RID" /> - <param index="1" name="dist" type="float" /> + <param index="1" name="distance" type="float" /> <description> Sets the maximum distance to other agents this agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe. </description> @@ -128,7 +128,7 @@ </description> </method> <method name="get_maps" qualifiers="const"> - <return type="Array" /> + <return type="RID[]" /> <description> Returns all created navigation map [RID]s on the NavigationServer. This returns both 2D and 3D created navigation maps as there is technically no distinction between them. </description> @@ -150,7 +150,7 @@ </description> </method> <method name="map_get_agents" qualifiers="const"> - <return type="Array" /> + <return type="RID[]" /> <param index="0" name="map" type="RID" /> <description> Returns all navigation agents [RID]s that are currently assigned to the requested navigation [param map]. @@ -198,7 +198,7 @@ </description> </method> <method name="map_get_regions" qualifiers="const"> - <return type="Array" /> + <return type="RID[]" /> <param index="0" name="map" type="RID" /> <description> Returns all navigation regions [RID]s that are currently assigned to the requested navigation [param map]. diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml index 7c6b828aa9..5b2a8fc08b 100644 --- a/doc/classes/NavigationServer3D.xml +++ b/doc/classes/NavigationServer3D.xml @@ -72,10 +72,10 @@ Sets the maximum speed of the agent. Must be positive. </description> </method> - <method name="agent_set_neighbor_dist" qualifiers="const"> + <method name="agent_set_neighbor_distance" qualifiers="const"> <return type="void" /> <param index="0" name="agent" type="RID" /> - <param index="1" name="dist" type="float" /> + <param index="1" name="distance" type="float" /> <description> Sets the maximum distance to other agents this agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe. </description> @@ -128,7 +128,7 @@ </description> </method> <method name="get_maps" qualifiers="const"> - <return type="Array" /> + <return type="RID[]" /> <description> Returns all created navigation map [RID]s on the NavigationServer. This returns both 2D and 3D created navigation maps as there is technically no distinction between them. </description> @@ -150,7 +150,7 @@ </description> </method> <method name="map_get_agents" qualifiers="const"> - <return type="Array" /> + <return type="RID[]" /> <param index="0" name="map" type="RID" /> <description> Returns all navigation agents [RID]s that are currently assigned to the requested navigation [param map]. @@ -216,7 +216,7 @@ </description> </method> <method name="map_get_regions" qualifiers="const"> - <return type="Array" /> + <return type="RID[]" /> <param index="0" name="map" type="RID" /> <description> Returns all navigation regions [RID]s that are currently assigned to the requested navigation [param map]. diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index d38a724d39..b882425960 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -241,7 +241,7 @@ <description> Returns a child node by its index (see [method get_child_count]). This method is often used for iterating all children of a node. Negative indices access the children from the last one. - If [param include_internal] is [code]true[/code], internal children are skipped (see [code]internal[/code] parameter in [method add_child]). + If [param include_internal] is [code]false[/code], internal children are skipped (see [code]internal[/code] parameter in [method add_child]). To access a child node via its name, use [method get_node]. </description> </method> @@ -262,7 +262,7 @@ </description> </method> <method name="get_groups" qualifiers="const"> - <return type="Array" /> + <return type="StringName[]" /> <description> Returns an array listing the groups that the node is a member of. [b]Note:[/b] For performance reasons, the order of node groups is [i]not[/i] guaranteed. The order of node groups should not be relied upon as it can vary across project runs. diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml index e9f1f995a5..53b93beb40 100644 --- a/doc/classes/Node3D.xml +++ b/doc/classes/Node3D.xml @@ -39,7 +39,7 @@ </description> </method> <method name="get_gizmos" qualifiers="const"> - <return type="Array" /> + <return type="Node3DGizmo[]" /> <description> Returns all the gizmos attached to this [code]Node3D[/code]. </description> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index e4b5404c2c..e180c73733 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -88,14 +88,6 @@ [b]Note:[/b] When [method delay_usec] is called on the main thread, it will freeze the project and will prevent it from redrawing and registering input until the delay has passed. When using [method delay_usec] as part of an [EditorPlugin] or [EditorScript], it will freeze the editor but won't freeze the project if it is currently running (since the project is an independent child process). </description> </method> - <method name="dump_memory_to_file"> - <return type="void" /> - <param index="0" name="file" type="String" /> - <description> - Dumps the memory allocation ringlist to a file (only works in debug). - Entry format per line: "Address - Size - Description". - </description> - </method> <method name="dump_resources_to_file"> <return type="void" /> <param index="0" name="file" type="String" /> diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml index 2e03ac5291..3c71a02a21 100644 --- a/doc/classes/Object.xml +++ b/doc/classes/Object.xml @@ -5,7 +5,7 @@ </brief_description> <description> Every class which is not a built-in type inherits from this class. - You can construct Objects from scripting languages, using [code]Object.new()[/code] in GDScript, [code]new Object[/code] in C#, or the "Construct Object" node in VisualScript. + You can construct Objects from scripting languages, using [code]Object.new()[/code] in GDScript, or [code]new Object[/code] in C#. Objects do not manage memory. If a class inherits from Object, you will have to delete instances of it manually. To do so, call the [method free] method from your script or delete the instance from C++. Some classes that extend Object add memory management. This is the case of [RefCounted], which counts references and deletes itself automatically when no longer referenced. [Node], another fundamental type, deletes all its children when freed from memory. Objects export properties, which are mainly useful for storage and editing, but not really so much in programming. Properties are exported in [method _get_property_list] and handled in [method _get] and [method _set]. However, scripting languages and C++ have simpler means to export them. @@ -43,7 +43,7 @@ </description> </method> <method name="_get_property_list" qualifiers="virtual"> - <return type="Array" /> + <return type="Dictionary[]" /> <description> Virtual method which can be overridden to customize the return value of [method get_property_list]. Returns the object's property list as an [Array] of dictionaries. @@ -353,7 +353,7 @@ </description> </method> <method name="get_incoming_connections" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <description> Returns an [Array] of dictionaries with information about signals that are connected to the object. Each [Dictionary] contains three String entries: @@ -394,13 +394,13 @@ </description> </method> <method name="get_method_list" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <description> Returns the object's methods and their signatures as an [Array]. </description> </method> <method name="get_property_list" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <description> Returns the object's property list as an [Array] of dictionaries. Each property's [Dictionary] contain at least [code]name: String[/code] and [code]type: int[/code] (see [enum Variant.Type]) entries. Optionally, it can also include [code]hint: int[/code] (see [enum PropertyHint]), [code]hint_string: String[/code], and [code]usage: int[/code] (see [enum PropertyUsageFlags]). @@ -413,14 +413,14 @@ </description> </method> <method name="get_signal_connection_list" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <param index="0" name="signal" type="StringName" /> <description> Returns an [Array] of connections for the given [param signal]. </description> </method> <method name="get_signal_list" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <description> Returns the list of signals as an [Array] of dictionaries. </description> diff --git a/doc/classes/ParticlesMaterial.xml b/doc/classes/ParticleProcessMaterial.xml index fe4caaa10c..b2dca5a2df 100644 --- a/doc/classes/ParticlesMaterial.xml +++ b/doc/classes/ParticleProcessMaterial.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="ParticlesMaterial" inherits="Material" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="ParticleProcessMaterial" inherits="Material" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Particle properties for [GPUParticles3D] and [GPUParticles2D] nodes. </brief_description> <description> - ParticlesMaterial defines particle properties and behavior. It is used in the [code]process_material[/code] of [GPUParticles3D] and [GPUParticles2D] emitter nodes. + ParticleProcessMaterial defines particle properties and behavior. It is used in the [code]process_material[/code] of [GPUParticles3D] and [GPUParticles2D] emitter nodes. Some of this material's properties are applied to each particle when emitted, while others can have a [CurveTexture] applied to vary values over the lifetime of the particle. Particle animation is available only in [GPUParticles2D]. To use it, attach a [CanvasItemMaterial], with [member CanvasItemMaterial.particles_animation] enabled, to the particles node. </description> @@ -13,35 +13,35 @@ <methods> <method name="get_param_max" qualifiers="const"> <return type="float" /> - <param index="0" name="param" type="int" enum="ParticlesMaterial.Parameter" /> + <param index="0" name="param" type="int" enum="ParticleProcessMaterial.Parameter" /> <description> Returns the maximum value range for the given parameter. </description> </method> <method name="get_param_min" qualifiers="const"> <return type="float" /> - <param index="0" name="param" type="int" enum="ParticlesMaterial.Parameter" /> + <param index="0" name="param" type="int" enum="ParticleProcessMaterial.Parameter" /> <description> Returns the minimum value range for the given parameter. </description> </method> <method name="get_param_texture" qualifiers="const"> <return type="Texture2D" /> - <param index="0" name="param" type="int" enum="ParticlesMaterial.Parameter" /> + <param index="0" name="param" type="int" enum="ParticleProcessMaterial.Parameter" /> <description> Returns the [Texture2D] used by the specified parameter. </description> </method> <method name="get_particle_flag" qualifiers="const"> <return type="bool" /> - <param index="0" name="particle_flag" type="int" enum="ParticlesMaterial.ParticleFlags" /> + <param index="0" name="particle_flag" type="int" enum="ParticleProcessMaterial.ParticleFlags" /> <description> Returns [code]true[/code] if the specified particle flag is enabled. See [enum ParticleFlags] for options. </description> </method> <method name="set_param_max"> <return type="void" /> - <param index="0" name="param" type="int" enum="ParticlesMaterial.Parameter" /> + <param index="0" name="param" type="int" enum="ParticleProcessMaterial.Parameter" /> <param index="1" name="value" type="float" /> <description> Sets the maximum value range for the given parameter. @@ -49,7 +49,7 @@ </method> <method name="set_param_min"> <return type="void" /> - <param index="0" name="param" type="int" enum="ParticlesMaterial.Parameter" /> + <param index="0" name="param" type="int" enum="ParticleProcessMaterial.Parameter" /> <param index="1" name="value" type="float" /> <description> Sets the minimum value range for the given parameter. @@ -57,7 +57,7 @@ </method> <method name="set_param_texture"> <return type="void" /> - <param index="0" name="param" type="int" enum="ParticlesMaterial.Parameter" /> + <param index="0" name="param" type="int" enum="ParticleProcessMaterial.Parameter" /> <param index="1" name="texture" type="Texture2D" /> <description> Sets the [Texture2D] for the specified [enum Parameter]. @@ -65,7 +65,7 @@ </method> <method name="set_particle_flag"> <return type="void" /> - <param index="0" name="particle_flag" type="int" enum="ParticlesMaterial.ParticleFlags" /> + <param index="0" name="particle_flag" type="int" enum="ParticleProcessMaterial.ParticleFlags" /> <param index="1" name="enable" type="bool" /> <description> If [code]true[/code], enables the specified particle flag. See [enum ParticleFlags] for options. @@ -115,14 +115,15 @@ <member name="attractor_interaction_enabled" type="bool" setter="set_attractor_interaction_enabled" getter="is_attractor_interaction_enabled" default="true"> True if the interaction with particle attractors is enabled. </member> - <member name="collision_bounce" type="float" setter="set_collision_bounce" getter="get_collision_bounce" default="0.0"> - Collision bounciness. + <member name="collision_bounce" type="float" setter="set_collision_bounce" getter="get_collision_bounce"> + The particles' bounciness. Values range from [code]0[/code] (no bounce) to [code]1[/code] (full bounciness). Only effective if [member collision_mode] is [constant COLLISION_RIGID]. </member> - <member name="collision_enabled" type="bool" setter="set_collision_enabled" getter="is_collision_enabled" default="false"> - True if collisions are enabled for this particle system. + <member name="collision_friction" type="float" setter="set_collision_friction" getter="get_collision_friction"> + The particles' friction. Values range from [code]0[/code] (frictionless) to [code]1[/code] (maximum friction). Only effective if [member collision_mode] is [constant COLLISION_RIGID]. </member> - <member name="collision_friction" type="float" setter="set_collision_friction" getter="get_collision_friction" default="0.0"> - Collision friction. + <member name="collision_mode" type="int" setter="set_collision_mode" getter="get_collision_mode" enum="ParticleProcessMaterial.CollisionMode" default="0"> + The particles' collision mode. + [b]Note:[/b] Particles can only collide with [GPUParticlesCollision3D] nodes, not [PhysicsBody3D] nodes. To make particles collide with various objects, you can add [GPUParticlesCollision3D] nodes as children of [PhysicsBody3D] nodes. </member> <member name="collision_use_scale" type="bool" setter="set_collision_use_scale" getter="is_collision_using_scale" default="false"> Should collision take scale into account. @@ -175,7 +176,7 @@ <member name="emission_ring_radius" type="float" setter="set_emission_ring_radius" getter="get_emission_ring_radius"> The radius of the ring when using the emitter [constant EMISSION_SHAPE_RING]. </member> - <member name="emission_shape" type="int" setter="set_emission_shape" getter="get_emission_shape" enum="ParticlesMaterial.EmissionShape" default="0"> + <member name="emission_shape" type="int" setter="set_emission_shape" getter="get_emission_shape" enum="ParticleProcessMaterial.EmissionShape" default="0"> Particles will be emitted inside this region. Use [enum EmissionShape] constants for values. </member> <member name="emission_sphere_radius" type="float" setter="set_emission_sphere_radius" getter="get_emission_sphere_radius"> @@ -260,7 +261,7 @@ </member> <member name="sub_emitter_keep_velocity" type="bool" setter="set_sub_emitter_keep_velocity" getter="get_sub_emitter_keep_velocity" default="false"> </member> - <member name="sub_emitter_mode" type="int" setter="set_sub_emitter_mode" getter="get_sub_emitter_mode" enum="ParticlesMaterial.SubEmitterMode" default="0"> + <member name="sub_emitter_mode" type="int" setter="set_sub_emitter_mode" getter="get_sub_emitter_mode" enum="ParticleProcessMaterial.SubEmitterMode" default="0"> </member> <member name="tangential_accel_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture"> Each particle's tangential acceleration will vary along this [CurveTexture]. @@ -404,5 +405,17 @@ <constant name="SUB_EMITTER_MAX" value="4" enum="SubEmitterMode"> Represents the size of the [enum SubEmitterMode] enum. </constant> + <constant name="COLLISION_DISABLED" value="0" enum="CollisionMode"> + No collision for particles. Particles will go through [GPUParticlesCollision3D] nodes. + </constant> + <constant name="COLLISION_RIGID" value="1" enum="CollisionMode"> + [RigidDynamicBody3D]-style collision for particles using [GPUParticlesCollision3D] nodes. + </constant> + <constant name="COLLISION_HIDE_ON_CONTACT" value="2" enum="CollisionMode"> + Hide particles instantly when colliding with a [GPUParticlesCollision3D] node. This can be combined with a subemitter that uses the [constant COLLISION_RIGID] collision mode to "replace" the parent particle with the subemitter on impact. + </constant> + <constant name="COLLISION_MAX" value="3" enum="CollisionMode"> + Represents the size of the [enum CollisionMode] enum. + </constant> </constants> </class> diff --git a/doc/classes/PathFollow2D.xml b/doc/classes/PathFollow2D.xml index ae4a4b2886..09d6872e10 100644 --- a/doc/classes/PathFollow2D.xml +++ b/doc/classes/PathFollow2D.xml @@ -5,7 +5,7 @@ </brief_description> <description> This node takes its parent [Path2D], and returns the coordinates of a point within it, given a distance from the first vertex. - It is useful for making other nodes follow a path, without coding the movement pattern. For that, the nodes must be children of this node. The descendant nodes will then move accordingly when setting an offset in this node. + It is useful for making other nodes follow a path, without coding the movement pattern. For that, the nodes must be children of this node. The descendant nodes will then move accordingly when setting the [member progress] in this node. </description> <tutorials> </tutorials> @@ -24,15 +24,15 @@ <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="true"> If [code]true[/code], any offset outside the path's length will wrap around, instead of stopping at the ends. Use it for cyclic paths. </member> - <member name="offset" type="float" setter="set_offset" getter="get_offset" default="0.0"> - The distance along the path in pixels. + <member name="progress" type="float" setter="set_progress" getter="get_progress" default="0.0"> + The distance along the path, in pixels. Changing this value sets this node's position to a point within the path. + </member> + <member name="progress_ratio" type="float" setter="set_progress_ratio" getter="get_progress_ratio" default="0.0"> + The distance along the path as a number in the range 0.0 (for the first vertex) to 1.0 (for the last). This is just another way of expressing the progress within the path, as the offset supplied is multiplied internally by the path's length. </member> <member name="rotates" type="bool" setter="set_rotates" getter="is_rotating" default="true"> If [code]true[/code], this node rotates to follow the path, with the +X direction facing forward on the path. </member> - <member name="unit_offset" type="float" setter="set_unit_offset" getter="get_unit_offset" default="0.0"> - The distance along the path as a number in the range 0.0 (for the first vertex) to 1.0 (for the last). This is just another way of expressing the offset within the path, as the offset supplied is multiplied internally by the path's length. - </member> <member name="v_offset" type="float" setter="set_v_offset" getter="get_v_offset" default="0.0"> The node's offset perpendicular to the curve. </member> diff --git a/doc/classes/PathFollow3D.xml b/doc/classes/PathFollow3D.xml index f9fab07be5..ba7207be8f 100644 --- a/doc/classes/PathFollow3D.xml +++ b/doc/classes/PathFollow3D.xml @@ -5,7 +5,7 @@ </brief_description> <description> This node takes its parent [Path3D], and returns the coordinates of a point within it, given a distance from the first vertex. - It is useful for making other nodes follow a path, without coding the movement pattern. For that, the nodes must be children of this node. The descendant nodes will then move accordingly when setting an offset in this node. + It is useful for making other nodes follow a path, without coding the movement pattern. For that, the nodes must be children of this node. The descendant nodes will then move accordingly when setting the [member progress] in this node. </description> <tutorials> </tutorials> @@ -21,15 +21,15 @@ <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="true"> If [code]true[/code], any offset outside the path's length will wrap around, instead of stopping at the ends. Use it for cyclic paths. </member> - <member name="offset" type="float" setter="set_offset" getter="get_offset" default="0.0"> - The distance from the first vertex, measured in 3D units along the path. This sets this node's position to a point within the path. + <member name="progress" type="float" setter="set_progress" getter="get_progress" default="0.0"> + The distance from the first vertex, measured in 3D units along the path. Changing this value sets this node's position to a point within the path. + </member> + <member name="progress_ratio" type="float" setter="set_progress_ratio" getter="get_progress_ratio" default="0.0"> + The distance from the first vertex, considering 0.0 as the first vertex and 1.0 as the last. This is just another way of expressing the progress within the path, as the progress supplied is multiplied internally by the path's length. </member> <member name="rotation_mode" type="int" setter="set_rotation_mode" getter="get_rotation_mode" enum="PathFollow3D.RotationMode" default="3"> Allows or forbids rotation on one or more axes, depending on the [enum RotationMode] constants being used. </member> - <member name="unit_offset" type="float" setter="set_unit_offset" getter="get_unit_offset" default="0.0"> - The distance from the first vertex, considering 0.0 as the first vertex and 1.0 as the last. This is just another way of expressing the offset within the path, as the offset supplied is multiplied internally by the path's length. - </member> <member name="v_offset" type="float" setter="set_v_offset" getter="get_v_offset" default="0.0"> The node's offset perpendicular to the curve. </member> diff --git a/doc/classes/Performance.xml b/doc/classes/Performance.xml index ddb290f007..92fa1040af 100644 --- a/doc/classes/Performance.xml +++ b/doc/classes/Performance.xml @@ -79,7 +79,7 @@ </description> </method> <method name="get_custom_monitor_names"> - <return type="Array" /> + <return type="StringName[]" /> <description> Returns the names of active custom monitors in an [Array]. </description> diff --git a/doc/classes/PhysicsBody2D.xml b/doc/classes/PhysicsBody2D.xml index 2350fd4458..e8d7ac9920 100644 --- a/doc/classes/PhysicsBody2D.xml +++ b/doc/classes/PhysicsBody2D.xml @@ -32,7 +32,7 @@ Moves the body along the vector [param distance]. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code]. Returns a [KinematicCollision2D], which contains information about the collision when stopped, or when touching another body along the motion. If [param test_only] is [code]true[/code], the body does not move but the would-be collision information is given. - [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody2D.collision/safe_margin] for more details). + [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody2D.safe_margin] for more details). </description> </method> <method name="remove_collision_exception_with"> @@ -52,7 +52,7 @@ Checks for collisions without moving the body. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code]. Virtually sets the node's position, scale and rotation to that of the given [Transform2D], then tries to move the body along the vector [param distance]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path. [param collision] is an optional object of type [KinematicCollision2D], which contains additional information about the collision when stopped, or when touching another body along the motion. - [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody2D.collision/safe_margin] for more details). + [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody2D.safe_margin] for more details). </description> </method> </methods> diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml index 3ef7fc9030..310671274f 100644 --- a/doc/classes/PhysicsBody3D.xml +++ b/doc/classes/PhysicsBody3D.xml @@ -40,7 +40,7 @@ Moves the body along the vector [param distance]. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code]. The body will stop if it collides. Returns a [KinematicCollision3D], which contains information about the collision when stopped, or when touching another body along the motion. If [param test_only] is [code]true[/code], the body does not move but the would-be collision information is given. - [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody3D.collision/safe_margin] for more details). + [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody3D.safe_margin] for more details). [param max_collisions] allows to retrieve more than one collision result. </description> </method> @@ -70,7 +70,7 @@ Checks for collisions without moving the body. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code]. Virtually sets the node's position, scale and rotation to that of the given [Transform3D], then tries to move the body along the vector [param distance]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path. [param collision] is an optional object of type [KinematicCollision3D], which contains additional information about the collision when stopped, or when touching another body along the motion. - [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody3D.collision/safe_margin] for more details). + [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody3D.safe_margin] for more details). [param max_collisions] allows to retrieve more than one collision result. </description> </method> diff --git a/doc/classes/PhysicsDirectSpaceState2D.xml b/doc/classes/PhysicsDirectSpaceState2D.xml index 6290ea315f..d4cb073d15 100644 --- a/doc/classes/PhysicsDirectSpaceState2D.xml +++ b/doc/classes/PhysicsDirectSpaceState2D.xml @@ -12,7 +12,7 @@ </tutorials> <methods> <method name="cast_motion"> - <return type="Array" /> + <return type="PackedFloat32Array" /> <param index="0" name="parameters" type="PhysicsShapeQueryParameters2D" /> <description> Checks how far a [Shape2D] can move without colliding. All the parameters for the query, including the shape and the motion, are supplied through a [PhysicsShapeQueryParameters2D] object. @@ -21,7 +21,7 @@ </description> </method> <method name="collide_shape"> - <return type="Array" /> + <return type="PackedVector2Array[]" /> <param index="0" name="parameters" type="PhysicsShapeQueryParameters2D" /> <param index="1" name="max_results" type="int" default="32" /> <description> @@ -44,7 +44,7 @@ </description> </method> <method name="intersect_point"> - <return type="Array" /> + <return type="Dictionary[]" /> <param index="0" name="parameters" type="PhysicsPointQueryParameters2D" /> <param index="1" name="max_results" type="int" default="32" /> <description> @@ -72,7 +72,7 @@ </description> </method> <method name="intersect_shape"> - <return type="Array" /> + <return type="Dictionary[]" /> <param index="0" name="parameters" type="PhysicsShapeQueryParameters2D" /> <param index="1" name="max_results" type="int" default="32" /> <description> diff --git a/doc/classes/PhysicsDirectSpaceState3D.xml b/doc/classes/PhysicsDirectSpaceState3D.xml index 619891df90..cc1cf8a323 100644 --- a/doc/classes/PhysicsDirectSpaceState3D.xml +++ b/doc/classes/PhysicsDirectSpaceState3D.xml @@ -12,7 +12,7 @@ </tutorials> <methods> <method name="cast_motion"> - <return type="Array" /> + <return type="PackedFloat32Array" /> <param index="0" name="parameters" type="PhysicsShapeQueryParameters3D" /> <description> Checks how far a [Shape3D] can move without colliding. All the parameters for the query, including the shape, are supplied through a [PhysicsShapeQueryParameters3D] object. @@ -21,7 +21,7 @@ </description> </method> <method name="collide_shape"> - <return type="Array" /> + <return type="PackedVector2Array[]" /> <param index="0" name="parameters" type="PhysicsShapeQueryParameters3D" /> <param index="1" name="max_results" type="int" default="32" /> <description> @@ -46,7 +46,7 @@ </description> </method> <method name="intersect_point"> - <return type="Array" /> + <return type="Dictionary[]" /> <param index="0" name="parameters" type="PhysicsPointQueryParameters3D" /> <param index="1" name="max_results" type="int" default="32" /> <description> @@ -73,7 +73,7 @@ </description> </method> <method name="intersect_shape"> - <return type="Array" /> + <return type="Dictionary[]" /> <param index="0" name="parameters" type="PhysicsShapeQueryParameters3D" /> <param index="1" name="max_results" type="int" default="32" /> <description> diff --git a/doc/classes/PlaneMesh.xml b/doc/classes/PlaneMesh.xml index 6b3a7ed548..564b6fe743 100644 --- a/doc/classes/PlaneMesh.xml +++ b/doc/classes/PlaneMesh.xml @@ -4,7 +4,7 @@ Class representing a planar [PrimitiveMesh]. </brief_description> <description> - Class representing a planar [PrimitiveMesh]. This flat mesh does not have a thickness. By default, this mesh is aligned on the X and Z axes; this default rotation isn't suited for use with billboarded materials. For billboarded materials, use [QuadMesh] instead. + Class representing a planar [PrimitiveMesh]. This flat mesh does not have a thickness. By default, this mesh is aligned on the X and Z axes; this default rotation isn't suited for use with billboarded materials. For billboarded materials, change [member orientation] to [constant FACE_Z]. [b]Note:[/b] When using a large textured [PlaneMesh] (e.g. as a floor), you may stumble upon UV jittering issues depending on the camera angle. To solve this, increase [member subdivide_depth] and [member subdivide_width] until you no longer notice UV jittering. </description> <tutorials> @@ -13,6 +13,9 @@ <member name="center_offset" type="Vector3" setter="set_center_offset" getter="get_center_offset" default="Vector3(0, 0, 0)"> Offset of the generated plane. Useful for particles. </member> + <member name="orientation" type="int" setter="set_orientation" getter="get_orientation" enum="PlaneMesh.Orientation" default="1"> + Direction that the [PlaneMesh] is facing. See [enum Orientation] for options. + </member> <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2(2, 2)"> Size of the generated plane. </member> @@ -23,4 +26,15 @@ Number of subdivision along the X axis. </member> </members> + <constants> + <constant name="FACE_X" value="0" enum="Orientation"> + [PlaneMesh] will face the positive X-axis. + </constant> + <constant name="FACE_Y" value="1" enum="Orientation"> + [PlaneMesh] will face the positive Y-axis. This matches the behaviour of the [PlaneMesh] in Godot 3.x. + </constant> + <constant name="FACE_Z" value="2" enum="Orientation"> + [PlaneMesh] will face the positive Z-axis. This matches the behvaiour of the QuadMesh in Godot 3.x. + </constant> + </constants> </class> diff --git a/doc/classes/Polygon2D.xml b/doc/classes/Polygon2D.xml index 5d5c69aadd..12f8055180 100644 --- a/doc/classes/Polygon2D.xml +++ b/doc/classes/Polygon2D.xml @@ -79,10 +79,10 @@ <member name="internal_vertex_count" type="int" setter="set_internal_vertex_count" getter="get_internal_vertex_count" default="0"> </member> <member name="invert_border" type="float" setter="set_invert_border" getter="get_invert_border" default="100.0"> - Added padding applied to the bounding box when using [code]invert[/code]. Setting this value too small may result in a "Bad Polygon" error. + Added padding applied to the bounding box when [member invert_enabled] is set to [code]true[/code]. Setting this value too small may result in a "Bad Polygon" error. </member> - <member name="invert_enable" type="bool" setter="set_invert" getter="get_invert" default="false"> - If [code]true[/code], polygon will be inverted, containing the area outside the defined points and extending to the [code]invert_border[/code]. + <member name="invert_enabled" type="bool" setter="set_invert_enabled" getter="get_invert_enabled" default="false"> + If [code]true[/code], the polygon will be inverted, containing the area outside the defined points and extending to the [member invert_border]. </member> <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)"> The offset applied to each vertex. diff --git a/doc/classes/PrimitiveMesh.xml b/doc/classes/PrimitiveMesh.xml index 7046a21f68..1b9ecdbfa0 100644 --- a/doc/classes/PrimitiveMesh.xml +++ b/doc/classes/PrimitiveMesh.xml @@ -4,7 +4,7 @@ Base class for all primitive meshes. Handles applying a [Material] to a primitive mesh. </brief_description> <description> - Base class for all primitive meshes. Handles applying a [Material] to a primitive mesh. Examples include [BoxMesh], [CapsuleMesh], [CylinderMesh], [PlaneMesh], [PrismMesh], [QuadMesh], and [SphereMesh]. + Base class for all primitive meshes. Handles applying a [Material] to a primitive mesh. Examples include [BoxMesh], [CapsuleMesh], [CylinderMesh], [PlaneMesh], [PrismMesh], and [SphereMesh]. </description> <tutorials> </tutorials> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 45b56622d2..29e96c3a9a 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -464,9 +464,6 @@ <member name="debug/settings/stdout/verbose_stdout" type="bool" setter="" getter="" default="false"> Print more information to standard output when running. It displays information such as memory leaks, which scenes and resources are being loaded, etc. This can also be enabled using the [code]--verbose[/code] or [code]-v[/code] command line argument, even on an exported project. See also [method OS.is_stdout_verbose] and [method @GlobalScope.print_verbose]. </member> - <member name="debug/settings/visual_script/max_call_stack" type="int" setter="" getter="" default="1024"> - Maximum call stack in visual scripting, to avoid infinite recursion. - </member> <member name="debug/shapes/collision/contact_color" type="Color" setter="" getter="" default="Color(1, 0.2, 0.1, 0.8)"> Color of the contact points between collision shapes, visible when "Visible Collision Shapes" is enabled in the Debug menu. </member> diff --git a/doc/classes/Projection.xml b/doc/classes/Projection.xml index b8f6e54d87..5690ea5e95 100644 --- a/doc/classes/Projection.xml +++ b/doc/classes/Projection.xml @@ -24,6 +24,16 @@ <description> </description> </constructor> + <constructor name="Projection"> + <return type="Projection" /> + <param index="0" name="x_axis" type="Vector4" /> + <param index="1" name="y_axis" type="Vector4" /> + <param index="2" name="z_axis" type="Vector4" /> + <param index="3" name="w_axis" type="Vector4" /> + <description> + Constructs a Projection from four [Vector4] values (matrix columns). + </description> + </constructor> </constructors> <methods> <method name="create_depth_correction" qualifiers="static"> diff --git a/doc/classes/QuadMesh.xml b/doc/classes/QuadMesh.xml deleted file mode 100644 index d641ebaa1f..0000000000 --- a/doc/classes/QuadMesh.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="QuadMesh" inherits="PrimitiveMesh" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> - <brief_description> - Class representing a square mesh. - </brief_description> - <description> - Class representing a square [PrimitiveMesh]. This flat mesh does not have a thickness. By default, this mesh is aligned on the X and Y axes; this default rotation is more suited for use with billboarded materials. Unlike [PlaneMesh], this mesh doesn't provide subdivision options. - </description> - <tutorials> - <link title="GUI in 3D Demo">https://godotengine.org/asset-library/asset/127</link> - <link title="2D in 3D Demo">https://godotengine.org/asset-library/asset/129</link> - </tutorials> - <members> - <member name="center_offset" type="Vector3" setter="set_center_offset" getter="get_center_offset" default="Vector3(0, 0, 0)"> - Offset of the generated Quad. Useful for particles. - </member> - <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2(1, 1)"> - Size on the X and Y axes. - </member> - </members> -</class> diff --git a/doc/classes/RDUniform.xml b/doc/classes/RDUniform.xml index d144024000..e4b7883f02 100644 --- a/doc/classes/RDUniform.xml +++ b/doc/classes/RDUniform.xml @@ -19,7 +19,7 @@ </description> </method> <method name="get_ids" qualifiers="const"> - <return type="Array" /> + <return type="RID[]" /> <description> </description> </method> diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 855a55b4e2..639db6b3b5 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -1416,7 +1416,7 @@ </description> </method> <method name="instance_geometry_get_shader_uniform_list" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <param index="0" name="instance" type="RID" /> <description> </description> @@ -1591,7 +1591,7 @@ </description> </method> <method name="instances_cull_aabb" qualifiers="const"> - <return type="Array" /> + <return type="PackedInt64Array" /> <param index="0" name="aabb" type="AABB" /> <param index="1" name="scenario" type="RID" /> <description> @@ -1600,7 +1600,7 @@ </description> </method> <method name="instances_cull_convex" qualifiers="const"> - <return type="Array" /> + <return type="PackedInt64Array" /> <param index="0" name="convex" type="Array" /> <param index="1" name="scenario" type="RID" /> <description> @@ -1609,7 +1609,7 @@ </description> </method> <method name="instances_cull_ray" qualifiers="const"> - <return type="Array" /> + <return type="PackedInt64Array" /> <param index="0" name="from" type="Vector3" /> <param index="1" name="to" type="Vector3" /> <param index="2" name="scenario" type="RID" /> @@ -1969,7 +1969,7 @@ </description> </method> <method name="mesh_surface_get_blend_shape_arrays" qualifiers="const"> - <return type="Array" /> + <return type="Array[]" /> <param index="0" name="mesh" type="RID" /> <param index="1" name="surface" type="int" /> <description> diff --git a/doc/classes/ResourceFormatSaver.xml b/doc/classes/ResourceFormatSaver.xml index a84c2165f5..05bfcf3446 100644 --- a/doc/classes/ResourceFormatSaver.xml +++ b/doc/classes/ResourceFormatSaver.xml @@ -26,8 +26,8 @@ </method> <method name="_save" qualifiers="virtual"> <return type="int" /> - <param index="0" name="path" type="Resource" /> - <param index="1" name="resource" type="String" /> + <param index="0" name="resource" type="Resource" /> + <param index="1" name="path" type="String" /> <param index="2" name="flags" type="int" /> <description> Saves the given resource object to a file at the target [param path]. [param flags] is a bitmask composed with [enum ResourceSaver.SaverFlags] constants. diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index 1d4304bd99..f96e136a57 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -481,8 +481,8 @@ If [code]true[/code], the label uses the custom font color. </member> <member name="percent_visible" type="float" setter="set_percent_visible" getter="get_percent_visible" default="1.0"> - The range of characters to display, as a [float] between 0.0 and 1.0. - [b]Note:[/b] Setting this property updates [member visible_characters] based on current [method get_total_character_count]. + The fraction of characters to display, relative to the total number of characters (see [method get_total_character_count]). If set to [code]1.0[/code], all characters are displayed. If set to [code]0.5[/code], only half of the characters will be displayed. This can be useful when animating the text appearing in a dialog box. + [b]Note:[/b] Setting this property updates [member visible_characters] accordingly. </member> <member name="progress_bar_delay" type="int" setter="set_progress_bar_delay" getter="get_progress_bar_delay" default="1000"> The delay after which the loading progress bar is displayed, in milliseconds. Set to [code]-1[/code] to disable progress bar entirely. @@ -520,8 +520,8 @@ If [code]true[/code], text processing is done in a background thread. </member> <member name="visible_characters" type="int" setter="set_visible_characters" getter="get_visible_characters" default="-1"> - The restricted number of characters to display in the label. If [code]-1[/code], all characters will be displayed. - [b]Note:[/b] Setting this property updates [member percent_visible] based on current [method get_total_character_count]. + The number of characters to display. If set to [code]-1[/code], all characters are displayed. This can be useful when animating the text appearing in a dialog box. + [b]Note:[/b] Setting this property updates [member percent_visible] accordingly. </member> <member name="visible_characters_behavior" type="int" setter="set_visible_characters_behavior" getter="get_visible_characters_behavior" enum="TextServer.VisibleCharactersBehavior" default="0"> Sets the clipping behavior when [member visible_characters] or [member percent_visible] is set. See [enum TextServer.VisibleCharactersBehavior] for more info. diff --git a/doc/classes/RigidDynamicBody2D.xml b/doc/classes/RigidDynamicBody2D.xml index 445e6d94ea..1434affee1 100644 --- a/doc/classes/RigidDynamicBody2D.xml +++ b/doc/classes/RigidDynamicBody2D.xml @@ -100,10 +100,17 @@ <method name="get_colliding_bodies" qualifiers="const"> <return type="Node2D[]" /> <description> - Returns a list of the bodies colliding with this one. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. + Returns a list of the bodies colliding with this one. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [b]Note:[/b] The result of this test is not immediate after moving objects. For performance, list of collisions is updated once per frame and before the physics step. Consider using signals instead. </description> </method> + <method name="get_contact_count" qualifiers="const"> + <return type="int" /> + <description> + Returns the number of contacts this body has with other bodies. By default, this returns 0 unless bodies are configured to monitor contacts (see [member contact_monitor]). + [b]Note:[/b] To retrieve the colliding bodies, use [method get_colliding_bodies]. + </description> + </method> <method name="set_axis_velocity"> <return type="void" /> <param index="0" name="axis_velocity" type="Vector2" /> @@ -142,11 +149,8 @@ See [method add_constant_torque]. </member> <member name="contact_monitor" type="bool" setter="set_contact_monitor" getter="is_contact_monitor_enabled" default="false"> - If [code]true[/code], the body will emit signals when it collides with another RigidDynamicBody2D. See also [member contacts_reported]. - </member> - <member name="contacts_reported" type="int" setter="set_max_contacts_reported" getter="get_max_contacts_reported" default="0"> - The maximum number of contacts that will be recorded. Requires [member contact_monitor] to be set to [code]true[/code]. - [b]Note:[/b] The number of contacts is different from the number of collisions. Collisions between parallel edges will result in two contacts (one at each end). + If [code]true[/code], the RigidDynamicBody2D will emit signals when it collides with another RigidDynamicBody2D. + [b]Note:[/b] By default the maximum contacts reported is set to 0, meaning nothing will be recorded, see [member max_contacts_reported]. </member> <member name="continuous_cd" type="int" setter="set_continuous_collision_detection_mode" getter="get_continuous_collision_detection_mode" enum="RigidDynamicBody2D.CCDMode" default="0"> Continuous collision detection mode. @@ -187,6 +191,10 @@ <member name="mass" type="float" setter="set_mass" getter="get_mass" default="1.0"> The body's mass. </member> + <member name="max_contacts_reported" type="int" setter="set_max_contacts_reported" getter="get_max_contacts_reported" default="0"> + The maximum number of contacts that will be recorded. Requires a value greater than 0 and [member contact_monitor] to be set to [code]true[/code] to start to register contacts. Use [method get_contact_count] to retrieve the count or [method get_colliding_bodies] to retrieve bodies that have been collided with. + [b]Note:[/b] The number of contacts is different from the number of collisions. Collisions between parallel edges will result in two contacts (one at each end), and collisions between parallel faces will result in four contacts (one at each corner). + </member> <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> The physics material override for the body. If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one. @@ -199,14 +207,14 @@ <signal name="body_entered"> <param index="0" name="body" type="Node" /> <description> - Emitted when a collision with another [PhysicsBody2D] or [TileMap] occurs. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s. + Emitted when a collision with another [PhysicsBody2D] or [TileMap] occurs. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s. [param body] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap]. </description> </signal> <signal name="body_exited"> <param index="0" name="body" type="Node" /> <description> - Emitted when the collision with another [PhysicsBody2D] or [TileMap] ends. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s. + Emitted when the collision with another [PhysicsBody2D] or [TileMap] ends. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s. [param body] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap]. </description> </signal> @@ -216,7 +224,7 @@ <param index="2" name="body_shape_index" type="int" /> <param index="3" name="local_shape_index" type="int" /> <description> - Emitted when one of this RigidDynamicBody2D's [Shape2D]s collides with another [PhysicsBody2D] or [TileMap]'s [Shape2D]s. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s. + Emitted when one of this RigidDynamicBody2D's [Shape2D]s collides with another [PhysicsBody2D] or [TileMap]'s [Shape2D]s. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s. [param body_rid] the [RID] of the other [PhysicsBody2D] or [TileSet]'s [CollisionObject2D] used by the [PhysicsServer2D]. [param body] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap]. [param body_shape_index] the index of the [Shape2D] of the other [PhysicsBody2D] or [TileMap] used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code]. @@ -229,7 +237,7 @@ <param index="2" name="body_shape_index" type="int" /> <param index="3" name="local_shape_index" type="int" /> <description> - Emitted when the collision between one of this RigidDynamicBody2D's [Shape2D]s and another [PhysicsBody2D] or [TileMap]'s [Shape2D]s ends. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s. + Emitted when the collision between one of this RigidDynamicBody2D's [Shape2D]s and another [PhysicsBody2D] or [TileMap]'s [Shape2D]s ends. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s. [param body_rid] the [RID] of the other [PhysicsBody2D] or [TileSet]'s [CollisionObject2D] used by the [PhysicsServer2D]. [param body] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap]. [param body_shape_index] the index of the [Shape2D] of the other [PhysicsBody2D] or [TileMap] used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code]. diff --git a/doc/classes/RigidDynamicBody3D.xml b/doc/classes/RigidDynamicBody3D.xml index 83f24be418..fb747177ae 100644 --- a/doc/classes/RigidDynamicBody3D.xml +++ b/doc/classes/RigidDynamicBody3D.xml @@ -98,12 +98,19 @@ </description> </method> <method name="get_colliding_bodies" qualifiers="const"> - <return type="Array" /> + <return type="Node3D[]" /> <description> - Returns a list of the bodies colliding with this one. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. + Returns a list of the bodies colliding with this one. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [b]Note:[/b] The result of this test is not immediate after moving objects. For performance, list of collisions is updated once per frame and before the physics step. Consider using signals instead. </description> </method> + <method name="get_contact_count" qualifiers="const"> + <return type="int" /> + <description> + Returns the number of contacts this body has with other bodies. By default, this returns 0 unless bodies are configured to monitor contacts (see [member contact_monitor]). + [b]Note:[/b] To retrieve the colliding bodies, use [method get_colliding_bodies]. + </description> + </method> <method name="get_inverse_inertia_tensor" qualifiers="const"> <return type="Basis" /> <description> @@ -148,11 +155,8 @@ See [method add_constant_torque]. </member> <member name="contact_monitor" type="bool" setter="set_contact_monitor" getter="is_contact_monitor_enabled" default="false"> - If [code]true[/code], the RigidDynamicBody3D will emit signals when it collides with another RigidDynamicBody3D. See also [member contacts_reported]. - </member> - <member name="contacts_reported" type="int" setter="set_max_contacts_reported" getter="get_max_contacts_reported" default="0"> - The maximum number of contacts that will be recorded. Requires [member contact_monitor] to be set to [code]true[/code]. - [b]Note:[/b] The number of contacts is different from the number of collisions. Collisions between parallel edges will result in two contacts (one at each end), and collisions between parallel faces will result in four contacts (one at each corner). + If [code]true[/code], the RigidDynamicBody3D will emit signals when it collides with another RigidDynamicBody3D. + [b]Note:[/b] By default the maximum contacts reported is set to 0, meaning nothing will be recorded, see [member max_contacts_reported]. </member> <member name="continuous_cd" type="bool" setter="set_use_continuous_collision_detection" getter="is_using_continuous_collision_detection" default="false"> If [code]true[/code], continuous collision detection is used. @@ -193,6 +197,10 @@ <member name="mass" type="float" setter="set_mass" getter="get_mass" default="1.0"> The body's mass. </member> + <member name="max_contacts_reported" type="int" setter="set_max_contacts_reported" getter="get_max_contacts_reported" default="0"> + The maximum number of contacts that will be recorded. Requires a value greater than 0 and [member contact_monitor] to be set to [code]true[/code] to start to register contacts. Use [method get_contact_count] to retrieve the count or [method get_colliding_bodies] to retrieve bodies that have been collided with. + [b]Note:[/b] The number of contacts is different from the number of collisions. Collisions between parallel edges will result in two contacts (one at each end), and collisions between parallel faces will result in four contacts (one at each corner). + </member> <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> The physics material override for the body. If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one. @@ -205,14 +213,14 @@ <signal name="body_entered"> <param index="0" name="body" type="Node" /> <description> - Emitted when a collision with another [PhysicsBody3D] or [GridMap] occurs. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s. + Emitted when a collision with another [PhysicsBody3D] or [GridMap] occurs. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s. [param body] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap]. </description> </signal> <signal name="body_exited"> <param index="0" name="body" type="Node" /> <description> - Emitted when the collision with another [PhysicsBody3D] or [GridMap] ends. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s. + Emitted when the collision with another [PhysicsBody3D] or [GridMap] ends. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s. [param body] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap]. </description> </signal> @@ -222,7 +230,7 @@ <param index="2" name="body_shape_index" type="int" /> <param index="3" name="local_shape_index" type="int" /> <description> - Emitted when one of this RigidDynamicBody3D's [Shape3D]s collides with another [PhysicsBody3D] or [GridMap]'s [Shape3D]s. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s. + Emitted when one of this RigidDynamicBody3D's [Shape3D]s collides with another [PhysicsBody3D] or [GridMap]'s [Shape3D]s. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s. [param body_rid] the [RID] of the other [PhysicsBody3D] or [MeshLibrary]'s [CollisionObject3D] used by the [PhysicsServer3D]. [param body] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap]. [param body_shape_index] the index of the [Shape3D] of the other [PhysicsBody3D] or [GridMap] used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code]. @@ -235,7 +243,7 @@ <param index="2" name="body_shape_index" type="int" /> <param index="3" name="local_shape_index" type="int" /> <description> - Emitted when the collision between one of this RigidDynamicBody3D's [Shape3D]s and another [PhysicsBody3D] or [GridMap]'s [Shape3D]s ends. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s. + Emitted when the collision between one of this RigidDynamicBody3D's [Shape3D]s and another [PhysicsBody3D] or [GridMap]'s [Shape3D]s ends. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s. [param body_rid] the [RID] of the other [PhysicsBody3D] or [MeshLibrary]'s [CollisionObject3D] used by the [PhysicsServer3D]. [GridMap]s are detected if the Meshes have [Shape3D]s. [param body] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap]. [param body_shape_index] the index of the [Shape3D] of the other [PhysicsBody3D] or [GridMap] used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code]. diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml index 0b358bd06f..417703ff01 100644 --- a/doc/classes/SceneTree.xml +++ b/doc/classes/SceneTree.xml @@ -113,14 +113,14 @@ </description> </method> <method name="get_nodes_in_group"> - <return type="Array" /> + <return type="Node[]" /> <param index="0" name="group" type="StringName" /> <description> Returns a list of all nodes assigned to the given group. </description> </method> <method name="get_processed_tweens"> - <return type="Array" /> + <return type="Tween[]" /> <description> Returns an array of currently existing [Tween]s in the [SceneTree] (both running and paused). </description> diff --git a/doc/classes/Script.xml b/doc/classes/Script.xml index 8202f9f536..40ec8ed429 100644 --- a/doc/classes/Script.xml +++ b/doc/classes/Script.xml @@ -44,19 +44,19 @@ </description> </method> <method name="get_script_method_list"> - <return type="Array" /> + <return type="Dictionary[]" /> <description> Returns the list of methods in this [Script]. </description> </method> <method name="get_script_property_list"> - <return type="Array" /> + <return type="Dictionary[]" /> <description> Returns the list of properties in this [Script]. </description> </method> <method name="get_script_signal_list"> - <return type="Array" /> + <return type="Dictionary[]" /> <description> Returns the list of user signals defined in this [Script]. </description> diff --git a/doc/classes/ScriptEditor.xml b/doc/classes/ScriptEditor.xml index 9118f38a3e..becaff975e 100644 --- a/doc/classes/ScriptEditor.xml +++ b/doc/classes/ScriptEditor.xml @@ -22,13 +22,13 @@ </description> </method> <method name="get_open_script_editors" qualifiers="const"> - <return type="Array" /> + <return type="ScriptEditorBase[]" /> <description> Returns an array with all [ScriptEditorBase] objects which are currently open in editor. </description> </method> <method name="get_open_scripts" qualifiers="const"> - <return type="Array" /> + <return type="Script[]" /> <description> Returns an array with all [Script] objects which are currently open in editor. </description> diff --git a/doc/classes/ScriptExtension.xml b/doc/classes/ScriptExtension.xml index b59c49d785..045eadda41 100644 --- a/doc/classes/ScriptExtension.xml +++ b/doc/classes/ScriptExtension.xml @@ -96,6 +96,12 @@ <description> </description> </method> + <method name="_has_property_default_value" qualifiers="virtual const"> + <return type="bool" /> + <param index="0" name="property" type="StringName" /> + <description> + </description> + </method> <method name="_has_script_signal" qualifiers="virtual const"> <return type="bool" /> <param index="0" name="signal" type="StringName" /> diff --git a/doc/classes/Shape2D.xml b/doc/classes/Shape2D.xml index 4d7031ab86..34ca228795 100644 --- a/doc/classes/Shape2D.xml +++ b/doc/classes/Shape2D.xml @@ -21,7 +21,7 @@ </description> </method> <method name="collide_and_get_contacts"> - <return type="Array" /> + <return type="PackedVector2Array" /> <param index="0" name="local_xform" type="Transform2D" /> <param index="1" name="with_shape" type="Shape2D" /> <param index="2" name="shape_xform" type="Transform2D" /> @@ -45,7 +45,7 @@ </description> </method> <method name="collide_with_motion_and_get_contacts"> - <return type="Array" /> + <return type="PackedVector2Array" /> <param index="0" name="local_xform" type="Transform2D" /> <param index="1" name="local_motion" type="Vector2" /> <param index="2" name="with_shape" type="Shape2D" /> diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml index 69b9988641..75f7a37752 100644 --- a/doc/classes/Skeleton3D.xml +++ b/doc/classes/Skeleton3D.xml @@ -20,15 +20,6 @@ Adds a bone, with name [param name]. [method get_bone_count] will become the bone index. </description> </method> - <method name="add_bone_child"> - <return type="void" /> - <param index="0" name="bone_idx" type="int" /> - <param index="1" name="child_bone_idx" type="int" /> - <description> - Takes the given bone pose/transform and converts it to a world transform, relative to the [Skeleton3D] node. - This is useful for using the bone transform in calculations with transforms from [Node3D]-based nodes. - </description> - </method> <method name="clear_bones"> <return type="void" /> <description> @@ -272,15 +263,6 @@ Binds the given Skin to the Skeleton. </description> </method> - <method name="remove_bone_child"> - <return type="void" /> - <param index="0" name="bone_idx" type="int" /> - <param index="1" name="child_bone_idx" type="int" /> - <description> - Removes the passed in child bone index, [param child_bone_idx], from the passed-in bone, [param bone_idx], if it exists. - [b]Note:[/b] This does not remove the child bone, but instead it removes the connection it has to the parent bone. - </description> - </method> <method name="reset_bone_pose"> <return type="void" /> <param index="0" name="bone_idx" type="int" /> @@ -294,14 +276,6 @@ Sets all bone poses to rests. </description> </method> - <method name="set_bone_children"> - <return type="void" /> - <param index="0" name="bone_idx" type="int" /> - <param index="1" name="bone_children" type="PackedInt32Array" /> - <description> - Sets the children for the passed in bone, [param bone_idx], to the passed-in array of bone indexes, [param bone_children]. - </description> - </method> <method name="set_bone_enabled"> <return type="void" /> <param index="0" name="bone_idx" type="int" /> diff --git a/doc/classes/SliderJoint3D.xml b/doc/classes/SliderJoint3D.xml index 7470f89979..a67c38b12d 100644 --- a/doc/classes/SliderJoint3D.xml +++ b/doc/classes/SliderJoint3D.xml @@ -28,7 +28,7 @@ The amount of damping of the rotation when the limit is surpassed. A lower damping value allows a rotation initiated by body A to travel to body B slower. </member> - <member name="angular_limit/lower_angle" type="float" setter="_set_lower_limit_angular" getter="_get_lower_limit_angular" default="0.0"> + <member name="angular_limit/lower_angle" type="float" setter="set_param" getter="get_param" default="0.0"> The lower limit of rotation in the slider. </member> <member name="angular_limit/restitution" type="float" setter="set_param" getter="get_param" default="0.7"> @@ -39,7 +39,7 @@ A factor applied to the all rotation once the limit is surpassed. Makes all rotation slower when between 0 and 1. </member> - <member name="angular_limit/upper_angle" type="float" setter="_set_upper_limit_angular" getter="_get_upper_limit_angular" default="0.0"> + <member name="angular_limit/upper_angle" type="float" setter="set_param" getter="get_param" default="0.0"> The upper limit of rotation in the slider. </member> <member name="angular_motion/damping" type="float" setter="set_param" getter="get_param" default="1.0"> diff --git a/doc/classes/SoftDynamicBody3D.xml b/doc/classes/SoftDynamicBody3D.xml index 87492704d7..7f0a1d94d0 100644 --- a/doc/classes/SoftDynamicBody3D.xml +++ b/doc/classes/SoftDynamicBody3D.xml @@ -19,7 +19,7 @@ </description> </method> <method name="get_collision_exceptions"> - <return type="Array" /> + <return type="PhysicsBody3D[]" /> <description> Returns an array of nodes that were added as collision exceptions for this body. </description> diff --git a/doc/classes/SubViewport.xml b/doc/classes/SubViewport.xml index b62c294f2c..7020cae1de 100644 --- a/doc/classes/SubViewport.xml +++ b/doc/classes/SubViewport.xml @@ -25,7 +25,7 @@ The update mode when the sub-viewport is used as a render target. </member> <member name="size" type="Vector2i" setter="set_size" getter="get_size" default="Vector2i(512, 512)"> - The width and height of the sub-viewport. + The width and height of the sub-viewport. Must be set to a value greater than or equal to 2 pixels on both dimensions. Otherwise, nothing will be displayed. </member> <member name="size_2d_override" type="Vector2i" setter="set_size_2d_override" getter="get_size_2d_override" default="Vector2i(0, 0)"> The 2D size override of the sub-viewport. If either the width or height is [code]0[/code], the override is disabled. diff --git a/doc/classes/TextMesh.xml b/doc/classes/TextMesh.xml index 17a0ca32e4..678b95cc72 100644 --- a/doc/classes/TextMesh.xml +++ b/doc/classes/TextMesh.xml @@ -11,6 +11,9 @@ <tutorials> </tutorials> <members> + <member name="autowrap_mode" type="int" setter="set_autowrap_mode" getter="get_autowrap_mode" enum="TextServer.AutowrapMode" default="0"> + If set to something other than [constant TextServer.AUTOWRAP_OFF], the text gets wrapped inside the node's bounding rectangle. If you resize the node, it will change its height automatically to show all the text. To see how each mode behaves, see [enum TextServer.AutowrapMode]. + </member> <member name="curve_step" type="float" setter="set_curve_step" getter="get_curve_step" default="0.5"> Step (in pixels) used to approximate Bézier curves. </member> @@ -29,6 +32,12 @@ <member name="language" type="String" setter="set_language" getter="get_language" default=""""> Language code used for text shaping algorithms, if left empty current locale is used instead. </member> + <member name="line_spacing" type="float" setter="set_line_spacing" getter="get_line_spacing" default="0.0"> + Vertical space between lines in multiline [TextMesh]. + </member> + <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)"> + The text drawing offset (in pixels). + </member> <member name="pixel_size" type="float" setter="set_pixel_size" getter="get_pixel_size" default="0.01"> The size of one pixel's width on the text to scale it in 3D. </member> @@ -47,6 +56,9 @@ <member name="uppercase" type="bool" setter="set_uppercase" getter="is_uppercase" default="false"> If [code]true[/code], all the text displays as UPPERCASE. </member> + <member name="vertical_alignment" type="int" setter="set_vertical_alignment" getter="get_vertical_alignment" enum="VerticalAlignment" default="1"> + Controls the text's vertical alignment. Supports top, center, bottom. Set it to one of the [enum VerticalAlignment] constants. + </member> <member name="width" type="float" setter="set_width" getter="get_width" default="500.0"> Text width (in pixels), used for fill alignment. </member> diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index 55d7e8ff2b..9b77d0f58c 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -195,7 +195,7 @@ </description> </method> <method name="font_get_glyph_list" qualifiers="const"> - <return type="Array" /> + <return type="PackedInt32Array" /> <param index="0" name="font_rid" type="RID" /> <param index="1" name="size" type="Vector2i" /> <description> @@ -275,7 +275,7 @@ </description> </method> <method name="font_get_kerning_list" qualifiers="const"> - <return type="Array" /> + <return type="Vector2i[]" /> <param index="0" name="font_rid" type="RID" /> <param index="1" name="size" type="int" /> <description> @@ -356,7 +356,7 @@ </description> </method> <method name="font_get_size_cache_list" qualifiers="const"> - <return type="Array" /> + <return type="Vector2i[]" /> <param index="0" name="font_rid" type="RID" /> <description> Returns list of the font sizes in the cache. Each size is [code]Vector2i[/code] with font size and outline size. @@ -993,7 +993,7 @@ </description> </method> <method name="parse_structured_text" qualifiers="const"> - <return type="Array" /> + <return type="Vector2i[]" /> <param index="0" name="parser_type" type="int" enum="TextServer.StructuredTextParser" /> <param index="1" name="args" type="Array" /> <param index="2" name="text" type="String" /> @@ -1162,7 +1162,7 @@ </description> </method> <method name="shaped_text_get_ellipsis_glyphs" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <param index="0" name="shaped" type="RID" /> <description> Returns array of the glyphs in the ellipsis. @@ -1183,7 +1183,7 @@ </description> </method> <method name="shaped_text_get_glyphs" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <param index="0" name="shaped" type="RID" /> <description> Returns an array of glyphs in the visual order. @@ -1463,7 +1463,7 @@ </description> </method> <method name="shaped_text_sort_logical"> - <return type="Array" /> + <return type="Dictionary[]" /> <param index="0" name="shaped" type="RID" /> <description> Returns text glyphs in the logical order. diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml index cfac266ad2..23eb25dc10 100644 --- a/doc/classes/TextServerExtension.xml +++ b/doc/classes/TextServerExtension.xml @@ -187,7 +187,7 @@ </description> </method> <method name="font_get_glyph_list" qualifiers="virtual const"> - <return type="Array" /> + <return type="PackedInt32Array" /> <param index="0" name="font_rid" type="RID" /> <param index="1" name="size" type="Vector2i" /> <description> @@ -265,7 +265,7 @@ </description> </method> <method name="font_get_kerning_list" qualifiers="virtual const"> - <return type="Array" /> + <return type="Vector2i[]" /> <param index="0" name="font_rid" type="RID" /> <param index="1" name="size" type="int" /> <description> @@ -346,7 +346,7 @@ </description> </method> <method name="font_get_size_cache_list" qualifiers="virtual const"> - <return type="Array" /> + <return type="Vector2i[]" /> <param index="0" name="font_rid" type="RID" /> <description> Returns list of the font sizes in the cache. Each size is [code]Vector2i[/code] with font size and outline size. @@ -979,7 +979,7 @@ </description> </method> <method name="parse_structured_text" qualifiers="virtual const"> - <return type="Array" /> + <return type="Vector2i[]" /> <param index="0" name="parser_type" type="int" enum="TextServer.StructuredTextParser" /> <param index="1" name="args" type="Array" /> <param index="2" name="text" type="String" /> diff --git a/doc/classes/TextServerManager.xml b/doc/classes/TextServerManager.xml index 19b0e9e6f2..9477e5ec54 100644 --- a/doc/classes/TextServerManager.xml +++ b/doc/classes/TextServerManager.xml @@ -38,7 +38,7 @@ </description> </method> <method name="get_interfaces" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <description> Returns a list of available interfaces the index and name of each interface. </description> diff --git a/doc/classes/TranslationServer.xml b/doc/classes/TranslationServer.xml index 3da9096555..7b18d8ddb6 100644 --- a/doc/classes/TranslationServer.xml +++ b/doc/classes/TranslationServer.xml @@ -65,7 +65,7 @@ </description> </method> <method name="get_loaded_locales" qualifiers="const"> - <return type="Array" /> + <return type="PackedStringArray" /> <description> Returns an array of all loaded locales of the project. </description> diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml index efa0e4e393..bf66d9f12a 100644 --- a/doc/classes/Tree.xml +++ b/doc/classes/Tree.xml @@ -351,10 +351,11 @@ Emitted when [method TreeItem.propagate_check] is called. Connect to this signal to process the items that are affected when [method TreeItem.propagate_check] is invoked. The order that the items affected will be processed is as follows: the item that invoked the method, children of that item, and finally parents of that item. </description> </signal> - <signal name="column_title_pressed"> + <signal name="column_title_clicked"> <param index="0" name="column" type="int" /> + <param index="1" name="mouse_button_index" type="int" /> <description> - Emitted when a column's title is pressed. + Emitted when a column's title is clicked with either [constant MOUSE_BUTTON_LEFT] or [constant MOUSE_BUTTON_RIGHT]. </description> </signal> <signal name="custom_item_clicked"> diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml index 6207477441..6d4408cf61 100644 --- a/doc/classes/TreeItem.xml +++ b/doc/classes/TreeItem.xml @@ -126,7 +126,7 @@ </description> </method> <method name="get_children"> - <return type="Array" /> + <return type="TreeItem[]" /> <description> Returns an array of references to the item's children. </description> diff --git a/doc/classes/Variant.xml b/doc/classes/Variant.xml index 0d6fcd0ef5..6b384d6a77 100644 --- a/doc/classes/Variant.xml +++ b/doc/classes/Variant.xml @@ -23,7 +23,6 @@ [/codeblocks] Godot tracks all scripting API variables within Variants. Without even realizing it, you use Variants all the time. When a particular language enforces its own rules for keeping data typed, then that language is applying its own custom logic over the base Variant scripting API. - GDScript automatically wrap values in them. It keeps all data in plain Variants by default and then optionally enforces custom static typing rules on variable types. - - VisualScript tracks properties inside Variants as well, but it also uses static typing. The GUI interface enforces that properties have a particular type that doesn't change over time. - C# is statically typed, but uses the Mono [code]object[/code] type in place of Godot's Variant class when it needs to represent a dynamic value. [code]object[/code] is the Mono runtime's equivalent of the same concept. The global [method @GlobalScope.typeof] function returns the enumerated value of the Variant type stored in the current variable (see [enum Variant.Type]). [codeblocks] diff --git a/doc/classes/VisualShader.xml b/doc/classes/VisualShader.xml index 558b1086b7..a2089ae2b8 100644 --- a/doc/classes/VisualShader.xml +++ b/doc/classes/VisualShader.xml @@ -81,7 +81,7 @@ </description> </method> <method name="get_node_connections" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <param index="0" name="type" type="int" enum="VisualShader.Type" /> <description> Returns the list of connected nodes with the specified type. @@ -206,17 +206,19 @@ </constant> <constant name="VARYING_TYPE_FLOAT" value="0" enum="VaryingType"> </constant> - <constant name="VARYING_TYPE_VECTOR_2D" value="1" enum="VaryingType"> + <constant name="VARYING_TYPE_INT" value="1" enum="VaryingType"> </constant> - <constant name="VARYING_TYPE_VECTOR_3D" value="2" enum="VaryingType"> + <constant name="VARYING_TYPE_VECTOR_2D" value="2" enum="VaryingType"> </constant> - <constant name="VARYING_TYPE_VECTOR_4D" value="3" enum="VaryingType"> + <constant name="VARYING_TYPE_VECTOR_3D" value="3" enum="VaryingType"> </constant> - <constant name="VARYING_TYPE_COLOR" value="4" enum="VaryingType"> + <constant name="VARYING_TYPE_VECTOR_4D" value="4" enum="VaryingType"> </constant> - <constant name="VARYING_TYPE_TRANSFORM" value="5" enum="VaryingType"> + <constant name="VARYING_TYPE_BOOLEAN" value="5" enum="VaryingType"> </constant> - <constant name="VARYING_TYPE_MAX" value="6" enum="VaryingType"> + <constant name="VARYING_TYPE_TRANSFORM" value="6" enum="VaryingType"> + </constant> + <constant name="VARYING_TYPE_MAX" value="7" enum="VaryingType"> </constant> <constant name="NODE_ID_INVALID" value="-1"> </constant> diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index ce7ad1e64e..c3002a8a9f 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -448,7 +448,7 @@ </signal> <signal name="theme_changed"> <description> - Emitted when the [member theme] is modified or changed to another [Theme]. + Emitted when the [constant NOTIFICATION_THEME_CHANGED] notification is sent. </description> </signal> <signal name="visibility_changed"> @@ -467,6 +467,13 @@ <constant name="NOTIFICATION_VISIBILITY_CHANGED" value="30"> Emitted when [Window]'s visibility changes, right before [signal visibility_changed]. </constant> + <constant name="NOTIFICATION_THEME_CHANGED" value="32"> + Sent when the node needs to refresh its theme items. This happens in one of the following cases: + - The [member theme] property is changed on this node or any of its ancestors. + - The [member theme_type_variation] property is changed on this node. + - The node enters the scene tree. + [b]Note:[/b] As an optimization, this notification won't be sent from changes that occur while this node is outside of the scene tree. Instead, all of the theme item updates can be applied at once when the node enters the scene tree. + </constant> <constant name="MODE_WINDOWED" value="0" enum="Mode"> Windowed mode, i.e. [Window] doesn't occupy whole screen (unless set to the size of the screen). </constant> diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml index 7e96b33edd..48b00323d3 100644 --- a/doc/classes/XRServer.xml +++ b/doc/classes/XRServer.xml @@ -64,7 +64,7 @@ </description> </method> <method name="get_interfaces" qualifiers="const"> - <return type="Array" /> + <return type="Dictionary[]" /> <description> Returns a list of available interfaces the ID and name of each interface. </description> diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp index f86c4d82ef..f4c87da9e9 100644 --- a/drivers/alsa/audio_driver_alsa.cpp +++ b/drivers/alsa/audio_driver_alsa.cpp @@ -50,7 +50,7 @@ Error AudioDriverALSA::init_device() { // If there is a specified device check that it is really present if (device_name != "Default") { - Array list = get_device_list(); + PackedStringArray list = get_device_list(); if (list.find(device_name) == -1) { device_name = "Default"; new_device = "Default"; @@ -168,9 +168,8 @@ Error AudioDriverALSA::init() { return ERR_CANT_OPEN; } - active = false; - thread_exited = false; - exit_thread = false; + active.clear(); + exit_thread.clear(); Error err = init_device(); if (err == OK) { @@ -183,11 +182,11 @@ Error AudioDriverALSA::init() { void AudioDriverALSA::thread_func(void *p_udata) { AudioDriverALSA *ad = static_cast<AudioDriverALSA *>(p_udata); - while (!ad->exit_thread) { + while (!ad->exit_thread.is_set()) { ad->lock(); ad->start_counting_ticks(); - if (!ad->active) { + if (!ad->active.is_set()) { for (uint64_t i = 0; i < ad->period_size * ad->channels; i++) { ad->samples_out.write[i] = 0; } @@ -203,7 +202,7 @@ void AudioDriverALSA::thread_func(void *p_udata) { int todo = ad->period_size; int total = 0; - while (todo && !ad->exit_thread) { + while (todo && !ad->exit_thread.is_set()) { int16_t *src = (int16_t *)ad->samples_out.ptr(); int wrote = snd_pcm_writei(ad->pcm_handle, (void *)(src + (total * ad->channels)), todo); @@ -222,8 +221,8 @@ void AudioDriverALSA::thread_func(void *p_udata) { wrote = snd_pcm_recover(ad->pcm_handle, wrote, 0); if (wrote < 0) { ERR_PRINT("ALSA: Failed and can't recover: " + String(snd_strerror(wrote))); - ad->active = false; - ad->exit_thread = true; + ad->active.clear(); + ad->exit_thread.set(); } } } @@ -241,8 +240,8 @@ void AudioDriverALSA::thread_func(void *p_udata) { err = ad->init_device(); if (err != OK) { - ad->active = false; - ad->exit_thread = true; + ad->active.clear(); + ad->exit_thread.set(); } } } @@ -250,12 +249,10 @@ void AudioDriverALSA::thread_func(void *p_udata) { ad->stop_counting_ticks(); ad->unlock(); } - - ad->thread_exited = true; } void AudioDriverALSA::start() { - active = true; + active.set(); } int AudioDriverALSA::get_mix_rate() const { @@ -266,8 +263,8 @@ AudioDriver::SpeakerMode AudioDriverALSA::get_speaker_mode() const { return speaker_mode; } -Array AudioDriverALSA::get_device_list() { - Array list; +PackedStringArray AudioDriverALSA::get_device_list() { + PackedStringArray list; list.push_back("Default"); @@ -327,7 +324,7 @@ void AudioDriverALSA::finish_device() { } void AudioDriverALSA::finish() { - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); finish_device(); diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h index dbb40fa088..fa1dba38ed 100644 --- a/drivers/alsa/audio_driver_alsa.h +++ b/drivers/alsa/audio_driver_alsa.h @@ -35,6 +35,7 @@ #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/templates/safe_refcount.h" #include "servers/audio_server.h" #include "asound-so_wrap.h" @@ -64,9 +65,8 @@ class AudioDriverALSA : public AudioDriver { snd_pcm_uframes_t period_size; int channels = 0; - bool active = false; - bool thread_exited = false; - mutable bool exit_thread = false; + SafeFlag active; + SafeFlag exit_thread; public: const char *get_name() const { @@ -77,7 +77,7 @@ public: virtual void start(); virtual int get_mix_rate() const; virtual SpeakerMode get_speaker_mode() const; - virtual Array get_device_list(); + virtual PackedStringArray get_device_list(); virtual String get_device(); virtual void set_device(String device); virtual void lock(); diff --git a/drivers/alsamidi/midi_driver_alsamidi.cpp b/drivers/alsamidi/midi_driver_alsamidi.cpp index c334146dd2..d2a0076023 100644 --- a/drivers/alsamidi/midi_driver_alsamidi.cpp +++ b/drivers/alsamidi/midi_driver_alsamidi.cpp @@ -79,7 +79,7 @@ void MIDIDriverALSAMidi::thread_func(void *p_udata) { int expected_size = 255; int bytes = 0; - while (!md->exit_thread) { + while (!md->exit_thread.is_set()) { int ret; md->lock(); @@ -149,14 +149,14 @@ Error MIDIDriverALSAMidi::open() { } snd_device_name_free_hint(hints); - exit_thread = false; + exit_thread.clear(); thread.start(MIDIDriverALSAMidi::thread_func, this); return OK; } void MIDIDriverALSAMidi::close() { - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); for (int i = 0; i < connected_inputs.size(); i++) { @@ -193,7 +193,7 @@ PackedStringArray MIDIDriverALSAMidi::get_connected_inputs() { } MIDIDriverALSAMidi::MIDIDriverALSAMidi() { - exit_thread = false; + exit_thread.clear(); } MIDIDriverALSAMidi::~MIDIDriverALSAMidi() { diff --git a/drivers/alsamidi/midi_driver_alsamidi.h b/drivers/alsamidi/midi_driver_alsamidi.h index b0fa8c297a..ac3530b1b2 100644 --- a/drivers/alsamidi/midi_driver_alsamidi.h +++ b/drivers/alsamidi/midi_driver_alsamidi.h @@ -36,6 +36,7 @@ #include "core/os/midi_driver.h" #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/templates/safe_refcount.h" #include "core/templates/vector.h" #include "../alsa/asound-so_wrap.h" @@ -47,7 +48,7 @@ class MIDIDriverALSAMidi : public MIDIDriver { Vector<snd_rawmidi_t *> connected_inputs; - bool exit_thread; + SafeFlag exit_thread; static void thread_func(void *p_udata); diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp index cc38c2352f..1db85e2a60 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.cpp +++ b/drivers/coreaudio/audio_driver_coreaudio.cpp @@ -215,6 +215,7 @@ OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon, } ad->lock(); + ad->start_counting_ticks(); AudioBufferList bufferList; bufferList.mNumberBuffers = 1; @@ -237,6 +238,7 @@ OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon, ERR_PRINT("AudioUnitRender failed, code: " + itos(result)); } + ad->stop_counting_ticks(); ad->unlock(); return result; @@ -493,8 +495,8 @@ Error AudioDriverCoreAudio::capture_stop() { #ifdef MACOS_ENABLED -Array AudioDriverCoreAudio::_get_device_list(bool capture) { - Array list; +PackedStringArray AudioDriverCoreAudio::_get_device_list(bool capture) { + PackedStringArray list; list.push_back("Default"); @@ -637,7 +639,7 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) { } } -Array AudioDriverCoreAudio::get_device_list() { +PackedStringArray AudioDriverCoreAudio::get_device_list() { return _get_device_list(); } @@ -659,7 +661,7 @@ void AudioDriverCoreAudio::capture_set_device(const String &p_name) { } } -Array AudioDriverCoreAudio::capture_get_device_list() { +PackedStringArray AudioDriverCoreAudio::capture_get_device_list() { return _get_device_list(true); } diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h index 7fac8a99ed..aac5077bb1 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.h +++ b/drivers/coreaudio/audio_driver_coreaudio.h @@ -59,7 +59,7 @@ class AudioDriverCoreAudio : public AudioDriver { Vector<int16_t> input_buf; #ifdef MACOS_ENABLED - Array _get_device_list(bool capture = false); + PackedStringArray _get_device_list(bool capture = false); void _set_device(const String &device, bool capture = false); static OSStatus input_device_address_cb(AudioObjectID inObjectID, @@ -107,11 +107,11 @@ public: void stop(); #ifdef MACOS_ENABLED - virtual Array get_device_list(); + virtual PackedStringArray get_device_list(); virtual String get_device(); virtual void set_device(String device); - virtual Array capture_get_device_list(); + virtual PackedStringArray capture_get_device_list(); virtual void capture_set_device(const String &p_name); virtual String capture_get_device(); #endif diff --git a/drivers/png/SCsub b/drivers/png/SCsub index 39d296e7cf..ad7aaf1ee8 100644 --- a/drivers/png/SCsub +++ b/drivers/png/SCsub @@ -37,7 +37,7 @@ if env["builtin_libpng"]: import os # Enable ARM NEON instructions on 32-bit Android to compile more optimized code. - use_neon = "android_arch" in env and env["android_arch"] == "armv7" and os.name != "nt" + use_neon = env["platform"] == "android" and env["arch"] == "arm32" and os.name != "nt" if use_neon: env_png.Append(CPPDEFINES=[("PNG_ARM_NEON_OPT", 2)]) else: diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp index 917bfec574..8d2f8a7ed6 100644 --- a/drivers/png/image_loader_png.cpp +++ b/drivers/png/image_loader_png.cpp @@ -36,7 +36,7 @@ #include <string.h> -Error ImageLoaderPNG::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { +Error ImageLoaderPNG::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) { const uint64_t buffer_size = f->get_length(); Vector<uint8_t> file_buffer; Error err = file_buffer.resize(buffer_size); @@ -48,7 +48,7 @@ Error ImageLoaderPNG::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_f f->get_buffer(writer, buffer_size); } const uint8_t *reader = file_buffer.ptr(); - return PNGDriverCommon::png_to_image(reader, buffer_size, p_force_linear, p_image); + return PNGDriverCommon::png_to_image(reader, buffer_size, p_flags & FLAG_FORCE_LINEAR, p_image); } void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const { diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h index 9bcfb720d3..91c3c8925f 100644 --- a/drivers/png/image_loader_png.h +++ b/drivers/png/image_loader_png.h @@ -40,7 +40,7 @@ private: static Ref<Image> load_mem_png(const uint8_t *p_png, int p_size); public: - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderPNG(); }; diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index a6c35b6837..b25cf1d5b4 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -178,7 +178,7 @@ Error AudioDriverPulseAudio::detect_channels(bool capture) { Error AudioDriverPulseAudio::init_device() { // If there is a specified device check that it is really present if (device_name != "Default") { - Array list = get_device_list(); + PackedStringArray list = get_device_list(); if (list.find(device_name) == -1) { device_name = "Default"; new_device = "Default"; @@ -285,9 +285,8 @@ Error AudioDriverPulseAudio::init() { return ERR_CANT_OPEN; } - active = false; - thread_exited = false; - exit_thread = false; + active.clear(); + exit_thread.clear(); mix_rate = GLOBAL_GET("audio/driver/mix_rate"); @@ -384,7 +383,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { size_t avail_bytes = 0; uint64_t default_device_msec = OS::get_singleton()->get_ticks_msec(); - while (!ad->exit_thread) { + while (!ad->exit_thread.is_set()) { size_t read_bytes = 0; size_t written_bytes = 0; @@ -392,7 +391,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { ad->lock(); ad->start_counting_ticks(); - if (!ad->active) { + if (!ad->active.is_set()) { ad->samples_out.fill(0); } else { ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw()); @@ -462,8 +461,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { err = ad->init_device(); if (err != OK) { - ad->active = false; - ad->exit_thread = true; + ad->active.clear(); + ad->exit_thread.set(); break; } } @@ -501,8 +500,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { Error err = ad->init_device(); if (err != OK) { ERR_PRINT("PulseAudio: init_device error"); - ad->active = false; - ad->exit_thread = true; + ad->active.clear(); + ad->exit_thread.set(); break; } @@ -555,8 +554,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { err = ad->capture_init_device(); if (err != OK) { - ad->active = false; - ad->exit_thread = true; + ad->active.clear(); + ad->exit_thread.set(); break; } } @@ -571,12 +570,10 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { OS::get_singleton()->delay_usec(1000); } } - - ad->thread_exited = true; } void AudioDriverPulseAudio::start() { - active = true; + active.set(); } int AudioDriverPulseAudio::get_mix_rate() const { @@ -599,7 +596,7 @@ void AudioDriverPulseAudio::pa_sinklist_cb(pa_context *c, const pa_sink_info *l, ad->pa_status++; } -Array AudioDriverPulseAudio::get_device_list() { +PackedStringArray AudioDriverPulseAudio::get_device_list() { pa_devices.clear(); pa_devices.push_back("Default"); @@ -661,7 +658,7 @@ void AudioDriverPulseAudio::finish() { return; } - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); finish_device(); @@ -681,7 +678,7 @@ void AudioDriverPulseAudio::finish() { Error AudioDriverPulseAudio::capture_init_device() { // If there is a specified device check that it is really present if (capture_device_name != "Default") { - Array list = capture_get_device_list(); + PackedStringArray list = capture_get_device_list(); if (list.find(capture_device_name) == -1) { capture_device_name = "Default"; capture_new_device = "Default"; @@ -785,7 +782,7 @@ void AudioDriverPulseAudio::pa_sourcelist_cb(pa_context *c, const pa_source_info ad->pa_status++; } -Array AudioDriverPulseAudio::capture_get_device_list() { +PackedStringArray AudioDriverPulseAudio::capture_get_device_list() { pa_rec_devices.clear(); pa_rec_devices.push_back("Default"); diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h index af96489972..85e328b49f 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.h +++ b/drivers/pulseaudio/audio_driver_pulseaudio.h @@ -35,6 +35,7 @@ #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/templates/safe_refcount.h" #include "servers/audio_server.h" #include "pulse-so_wrap.h" @@ -67,12 +68,11 @@ class AudioDriverPulseAudio : public AudioDriver { int channels = 0; int pa_ready = 0; int pa_status = 0; - Array pa_devices; - Array pa_rec_devices; + PackedStringArray pa_devices; + PackedStringArray pa_rec_devices; - bool active = false; - bool thread_exited = false; - mutable bool exit_thread = false; + SafeFlag active; + SafeFlag exit_thread; float latency = 0; @@ -103,11 +103,11 @@ public: virtual int get_mix_rate() const; virtual SpeakerMode get_speaker_mode() const; - virtual Array get_device_list(); + virtual PackedStringArray get_device_list(); virtual String get_device(); virtual void set_device(String device); - virtual Array capture_get_device_list(); + virtual PackedStringArray capture_get_device_list(); virtual void capture_set_device(const String &p_name); virtual String capture_get_device(); diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index 3a62850339..fb90b776cf 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -501,11 +501,11 @@ Error AudioDriverWASAPI::init_capture_device(bool reinit) { } Error AudioDriverWASAPI::audio_device_finish(AudioDeviceWASAPI *p_device) { - if (p_device->active) { + if (p_device->active.is_set()) { if (p_device->audio_client) { p_device->audio_client->Stop(); } - p_device->active = false; + p_device->active.clear(); } SAFE_RELEASE(p_device->audio_client) @@ -533,8 +533,7 @@ Error AudioDriverWASAPI::init() { ERR_PRINT("WASAPI: init_render_device error"); } - exit_thread = false; - thread_exited = false; + exit_thread.clear(); thread.start(thread_func, this); @@ -553,8 +552,8 @@ AudioDriver::SpeakerMode AudioDriverWASAPI::get_speaker_mode() const { return get_speaker_mode_by_total_channels(channels); } -Array AudioDriverWASAPI::audio_device_get_list(bool p_capture) { - Array list; +PackedStringArray AudioDriverWASAPI::audio_device_get_list(bool p_capture) { + PackedStringArray list; IMMDeviceCollection *devices = nullptr; IMMDeviceEnumerator *enumerator = nullptr; @@ -563,14 +562,14 @@ Array AudioDriverWASAPI::audio_device_get_list(bool p_capture) { CoInitialize(nullptr); HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator); - ERR_FAIL_COND_V(hr != S_OK, Array()); + ERR_FAIL_COND_V(hr != S_OK, PackedStringArray()); hr = enumerator->EnumAudioEndpoints(p_capture ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices); - ERR_FAIL_COND_V(hr != S_OK, Array()); + ERR_FAIL_COND_V(hr != S_OK, PackedStringArray()); UINT count = 0; hr = devices->GetCount(&count); - ERR_FAIL_COND_V(hr != S_OK, Array()); + ERR_FAIL_COND_V(hr != S_OK, PackedStringArray()); for (ULONG i = 0; i < count; i++) { IMMDevice *device = nullptr; @@ -600,7 +599,7 @@ Array AudioDriverWASAPI::audio_device_get_list(bool p_capture) { return list; } -Array AudioDriverWASAPI::get_device_list() { +PackedStringArray AudioDriverWASAPI::get_device_list() { return audio_device_get_list(false); } @@ -684,7 +683,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { uint32_t avail_frames = 0; uint32_t write_ofs = 0; - while (!ad->exit_thread) { + while (!ad->exit_thread.is_set()) { uint32_t read_frames = 0; uint32_t written_frames = 0; @@ -692,7 +691,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { ad->lock(); ad->start_counting_ticks(); - if (ad->audio_output.active) { + if (ad->audio_output.active.is_set()) { ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw()); } else { for (int i = 0; i < ad->samples_in.size(); i++) { @@ -758,7 +757,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { } } else { ERR_PRINT("WASAPI: Get buffer error"); - ad->exit_thread = true; + ad->exit_thread.set(); } } } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) { @@ -807,7 +806,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { write_ofs = 0; } - if (ad->audio_input.active) { + if (ad->audio_input.active.is_set()) { UINT32 packet_length = 0; BYTE *data; UINT32 num_frames_available; @@ -886,8 +885,6 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { OS::get_singleton()->delay_usec(1000); } } - - ad->thread_exited = true; } void AudioDriverWASAPI::start() { @@ -896,7 +893,7 @@ void AudioDriverWASAPI::start() { if (hr != S_OK) { ERR_PRINT("WASAPI: Start failed"); } else { - audio_output.active = true; + audio_output.active.set(); } } } @@ -910,7 +907,7 @@ void AudioDriverWASAPI::unlock() { } void AudioDriverWASAPI::finish() { - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); finish_capture_device(); @@ -924,19 +921,19 @@ Error AudioDriverWASAPI::capture_start() { return err; } - if (audio_input.active) { + if (audio_input.active.is_set()) { return FAILED; } audio_input.audio_client->Start(); - audio_input.active = true; + audio_input.active.set(); return OK; } Error AudioDriverWASAPI::capture_stop() { - if (audio_input.active) { + if (audio_input.active.is_set()) { audio_input.audio_client->Stop(); - audio_input.active = false; + audio_input.active.clear(); return OK; } @@ -950,7 +947,7 @@ void AudioDriverWASAPI::capture_set_device(const String &p_name) { unlock(); } -Array AudioDriverWASAPI::capture_get_device_list() { +PackedStringArray AudioDriverWASAPI::capture_get_device_list() { return audio_device_get_list(true); } diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h index 9058077a1f..c30a54c042 100644 --- a/drivers/wasapi/audio_driver_wasapi.h +++ b/drivers/wasapi/audio_driver_wasapi.h @@ -35,6 +35,7 @@ #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/templates/safe_refcount.h" #include "servers/audio_server.h" #include <audioclient.h> @@ -48,7 +49,7 @@ class AudioDriverWASAPI : public AudioDriver { IAudioClient *audio_client = nullptr; IAudioRenderClient *render_client = nullptr; IAudioCaptureClient *capture_client = nullptr; - bool active = false; + SafeFlag active; WORD format_tag = 0; WORD bits_per_sample = 0; @@ -76,8 +77,7 @@ class AudioDriverWASAPI : public AudioDriver { float real_latency = 0.0; bool using_audio_client_3 = false; - bool thread_exited = false; - mutable bool exit_thread = false; + SafeFlag exit_thread; static _FORCE_INLINE_ void write_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i, int32_t sample); static _FORCE_INLINE_ int32_t read_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i); @@ -91,7 +91,7 @@ class AudioDriverWASAPI : public AudioDriver { Error audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool reinit); Error audio_device_finish(AudioDeviceWASAPI *p_device); - Array audio_device_get_list(bool p_capture); + PackedStringArray audio_device_get_list(bool p_capture); public: virtual const char *get_name() const { @@ -103,7 +103,7 @@ public: virtual int get_mix_rate() const; virtual float get_latency(); virtual SpeakerMode get_speaker_mode() const; - virtual Array get_device_list(); + virtual PackedStringArray get_device_list(); virtual String get_device(); virtual void set_device(String device); virtual void lock(); @@ -112,7 +112,7 @@ public: virtual Error capture_start(); virtual Error capture_stop(); - virtual Array capture_get_device_list(); + virtual PackedStringArray capture_get_device_list(); virtual void capture_set_device(const String &p_name); virtual String capture_get_device(); diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp index c32c7cf1e5..6c48c1a844 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.cpp +++ b/drivers/xaudio2/audio_driver_xaudio2.cpp @@ -38,9 +38,8 @@ const char *AudioDriverXAudio2::get_name() const { } Error AudioDriverXAudio2::init() { - active = false; - thread_exited = false; - exit_thread = false; + active.clear(); + exit_thread.clear(); pcm_open = false; samples_in = nullptr; @@ -86,17 +85,19 @@ Error AudioDriverXAudio2::init() { void AudioDriverXAudio2::thread_func(void *p_udata) { AudioDriverXAudio2 *ad = static_cast<AudioDriverXAudio2 *>(p_udata); - while (!ad->exit_thread) { - if (!ad->active) { + while (!ad->exit_thread.is_set()) { + if (!ad->active.is_set()) { for (int i = 0; i < AUDIO_BUFFERS; i++) { ad->xaudio_buffer[i].Flags = XAUDIO2_END_OF_STREAM; } } else { ad->lock(); + ad->start_counting_ticks(); ad->audio_server_process(ad->buffer_size, ad->samples_in); + ad->stop_counting_ticks(); ad->unlock(); for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) { @@ -117,12 +118,10 @@ void AudioDriverXAudio2::thread_func(void *p_udata) { } } } - - ad->thread_exited = true; } void AudioDriverXAudio2::start() { - active = true; + active.set(); HRESULT hr = source_voice->Start(0); ERR_FAIL_COND_MSG(hr != S_OK, "Error starting XAudio2 driver. Error code: " + itos(hr) + "."); } @@ -154,7 +153,7 @@ void AudioDriverXAudio2::unlock() { } void AudioDriverXAudio2::finish() { - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); if (source_voice) { diff --git a/drivers/xaudio2/audio_driver_xaudio2.h b/drivers/xaudio2/audio_driver_xaudio2.h index 81432ceb8e..0f64d54a1f 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.h +++ b/drivers/xaudio2/audio_driver_xaudio2.h @@ -33,6 +33,7 @@ #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/templates/safe_refcount.h" #include "servers/audio_server.h" #include <mmsystem.h> @@ -77,9 +78,8 @@ class AudioDriverXAudio2 : public AudioDriver { int channels = 0; - bool active = false; - bool thread_exited = false; - mutable bool exit_thread = false; + SafeFlag active; + SafeFlag exit_thread; bool pcm_open = false; WAVEFORMATEX wave_format = { 0 }; diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp index 462f314471..648e950fd4 100644 --- a/editor/action_map_editor.cpp +++ b/editor/action_map_editor.cpp @@ -1061,6 +1061,9 @@ void ActionMapEditor::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { action_list_search->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); + if (!actions_cache.is_empty()) { + update_action_list(); + } } break; } } diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index 11e46152ef..9af8b907c4 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -41,7 +41,7 @@ float AnimationBezierTrackEdit::_bezier_h_to_pixel(float p_h) { float h = p_h; h = (h - v_scroll) / v_zoom; - h = (get_size().height / 2) - h; + h = (get_size().height / 2.0) - h; return h; } @@ -52,10 +52,10 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) { int right_limit = get_size().width; //selection may have altered the order of keys - RBMap<float, int> key_order; + RBMap<real_t, int> key_order; for (int i = 0; i < animation->track_get_key_count(p_track); i++) { - float ofs = animation->track_get_key_time(p_track, i); + real_t ofs = animation->track_get_key_time(p_track, i); if (moving_selection && selection.has(IntPair(p_track, i))) { ofs += moving_selection_offset.x; } @@ -63,7 +63,7 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) { key_order[ofs] = i; } - for (RBMap<float, int>::Element *E = key_order.front(); E; E = E->next()) { + for (RBMap<real_t, int>::Element *E = key_order.front(); E; E = E->next()) { int i = E->get(); if (!E->next()) { @@ -75,7 +75,7 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) { float offset = animation->track_get_key_time(p_track, i); float height = animation->bezier_track_get_key_value(p_track, i); Vector2 out_handle = animation->bezier_track_get_key_out_handle(p_track, i); - if (p_track == moving_handle_track && moving_handle != 0 && moving_handle_key == i) { + if (p_track == moving_handle_track && (moving_handle == -1 || moving_handle == 1) && moving_handle_key == i) { out_handle = moving_handle_right; } @@ -89,7 +89,7 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) { float offset_n = animation->track_get_key_time(p_track, i_n); float height_n = animation->bezier_track_get_key_value(p_track, i_n); Vector2 in_handle = animation->bezier_track_get_key_in_handle(p_track, i_n); - if (p_track == moving_handle_track && moving_handle != 0 && moving_handle_key == i_n) { + if (p_track == moving_handle_track && (moving_handle == -1 || moving_handle == 1) && moving_handle_key == i_n) { in_handle = moving_handle_left; } @@ -139,7 +139,7 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) { //narrow high and low as much as possible for (int k = 0; k < iterations; k++) { - float middle = (low + high) / 2; + float middle = (low + high) / 2.0; Vector2 interp = start.bezier_interpolate(out_handle, in_handle, end, middle); @@ -316,7 +316,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) { int h = MAX(text_buf.get_size().y, icon->get_height()); - draw_texture(icon, Point2(ofs, vofs + int(h - icon->get_height()) / 2)); + draw_texture(icon, Point2(ofs, vofs + int(h - icon->get_height()) / 2.0)); ofs += icon->get_width(); margin = icon->get_width(); @@ -403,29 +403,29 @@ void AnimationBezierTrackEdit::_notification(int p_what) { Vector2 string_pos = Point2(margin, vofs); text_buf.draw(get_canvas_item(), string_pos, cc); - float icon_start_height = vofs + rect.size.y / 2; - Rect2 remove_rect = Rect2(remove_hpos, icon_start_height - remove->get_height() / 2, remove->get_width(), remove->get_height()); + float icon_start_height = vofs + rect.size.y / 2.0; + Rect2 remove_rect = Rect2(remove_hpos, icon_start_height - remove->get_height() / 2.0, remove->get_width(), remove->get_height()); if (read_only) { draw_texture(remove, remove_rect.position, dc); } else { draw_texture(remove, remove_rect.position); } - Rect2 lock_rect = Rect2(lock_hpos, icon_start_height - lock->get_height() / 2, lock->get_width(), lock->get_height()); + Rect2 lock_rect = Rect2(lock_hpos, icon_start_height - lock->get_height() / 2.0, lock->get_width(), lock->get_height()); if (locked_tracks.has(current_track)) { draw_texture(lock, lock_rect.position); } else { draw_texture(unlock, lock_rect.position); } - Rect2 visible_rect = Rect2(visibility_hpos, icon_start_height - visible->get_height() / 2, visible->get_width(), visible->get_height()); + Rect2 visible_rect = Rect2(visibility_hpos, icon_start_height - visible->get_height() / 2.0, visible->get_width(), visible->get_height()); if (hidden_tracks.has(current_track)) { draw_texture(hidden, visible_rect.position); } else { draw_texture(visible, visible_rect.position); } - Rect2 solo_rect = Rect2(solo_hpos, icon_start_height - solo->get_height() / 2, solo->get_width(), solo->get_height()); + Rect2 solo_rect = Rect2(solo_hpos, icon_start_height - solo->get_height() / 2.0, solo->get_width(), solo->get_height()); draw_texture(solo, solo_rect.position); RBMap<int, Rect2> track_icons; @@ -456,7 +456,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) { bool first = true; int prev_iv = 0; for (int i = font->get_height(font_size); i < get_size().height; i++) { - float ofs = get_size().height / 2 - i; + float ofs = get_size().height / 2.0 - i; ofs *= v_zoom; ofs += v_scroll; @@ -495,7 +495,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) { Vector2 pos((offset - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value)); if (pos.x >= limit && pos.x <= right_limit) { - draw_texture(point, pos - point->get_size() / 2, E.value); + draw_texture(point, pos - point->get_size() / 2.0, E.value); } } } @@ -547,14 +547,15 @@ void AnimationBezierTrackEdit::_notification(int p_what) { Vector2 pos((offset - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value)); Vector2 in_vec = animation->bezier_track_get_key_in_handle(i, j); - if (moving_handle != 0 && moving_handle_track == i && moving_handle_key == j) { + + if ((moving_handle == 1 || moving_handle == -1) && moving_handle_track == i && moving_handle_key == j) { in_vec = moving_handle_left; } Vector2 pos_in(((offset + in_vec.x) - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value + in_vec.y)); Vector2 out_vec = animation->bezier_track_get_key_out_handle(i, j); - if (moving_handle != 0 && moving_handle_track == i && moving_handle_key == j) { + if ((moving_handle == 1 || moving_handle == -1) && moving_handle_track == i && moving_handle_key == j) { out_vec = moving_handle_right; } @@ -569,7 +570,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) { ep.track = i; ep.key = j; if (pos.x >= limit && pos.x <= right_limit) { - ep.point_rect.position = (pos - bezier_icon->get_size() / 2).floor(); + ep.point_rect.position = (pos - bezier_icon->get_size() / 2.0).floor(); ep.point_rect.size = bezier_icon->get_size(); if (selection.has(IntPair(i, j))) { draw_texture(selected_icon, ep.point_rect.position); @@ -584,18 +585,22 @@ void AnimationBezierTrackEdit::_notification(int p_what) { } ep.point_rect = ep.point_rect.grow(ep.point_rect.size.width * 0.5); } + ep.point_rect = ep.point_rect.grow(ep.point_rect.size.width * 0.5); + if (i == selected_track || selection.has(IntPair(i, j))) { - if (pos_in.x >= limit && pos_in.x <= right_limit) { - ep.in_rect.position = (pos_in - bezier_handle_icon->get_size() / 2).floor(); - ep.in_rect.size = bezier_handle_icon->get_size(); - draw_texture(bezier_handle_icon, ep.in_rect.position); - ep.in_rect = ep.in_rect.grow(ep.in_rect.size.width * 0.5); - } - if (pos_out.x >= limit && pos_out.x <= right_limit) { - ep.out_rect.position = (pos_out - bezier_handle_icon->get_size() / 2).floor(); - ep.out_rect.size = bezier_handle_icon->get_size(); - draw_texture(bezier_handle_icon, ep.out_rect.position); - ep.out_rect = ep.out_rect.grow(ep.out_rect.size.width * 0.5); + if (animation->bezier_track_get_key_handle_mode(i, j) != Animation::HANDLE_MODE_LINEAR) { + if (pos_in.x >= limit && pos_in.x <= right_limit) { + ep.in_rect.position = (pos_in - bezier_handle_icon->get_size() / 2.0).floor(); + ep.in_rect.size = bezier_handle_icon->get_size(); + draw_texture(bezier_handle_icon, ep.in_rect.position); + ep.in_rect = ep.in_rect.grow(ep.in_rect.size.width * 0.5); + } + if (pos_out.x >= limit && pos_out.x <= right_limit) { + ep.out_rect.position = (pos_out - bezier_handle_icon->get_size() / 2.0).floor(); + ep.out_rect.size = bezier_handle_icon->get_size(); + draw_texture(bezier_handle_icon, ep.out_rect.position); + ep.out_rect = ep.out_rect.grow(ep.out_rect.size.width * 0.5); + } } } if (!locked_tracks.has(i)) { @@ -664,7 +669,6 @@ void AnimationBezierTrackEdit::set_editor(AnimationTrackEditor *p_editor) { editor = p_editor; connect("clear_selection", Callable(editor, "_clear_selection").bind(false)); connect("select_key", Callable(editor, "_key_selected"), CONNECT_DEFERRED); - connect("deselect_key", Callable(editor, "_key_deselected"), CONNECT_DEFERRED); } void AnimationBezierTrackEdit::_play_position_draw() { @@ -685,7 +689,7 @@ void AnimationBezierTrackEdit::_play_position_draw() { } } -void AnimationBezierTrackEdit::set_play_position(float p_pos) { +void AnimationBezierTrackEdit::set_play_position(real_t p_pos) { play_position_pos = p_pos; play_position->update(); } @@ -786,13 +790,14 @@ void AnimationBezierTrackEdit::_clear_selection() { update(); } -void AnimationBezierTrackEdit::_change_selected_keys_handle_mode(Animation::HandleMode p_mode) { +void AnimationBezierTrackEdit::_change_selected_keys_handle_mode(Animation::HandleMode p_mode, bool p_auto) { undo_redo->create_action(TTR("Update Selected Key Handles")); - double ratio = timeline->get_zoom_scale() * v_zoom; - for (const IntPair &E : selection) { - const IntPair track_key_pair = E; - undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_handle_mode", track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_handle_mode(track_key_pair.first, track_key_pair.second), ratio); - undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_handle_mode", track_key_pair.first, track_key_pair.second, p_mode, ratio); + for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { + const IntPair track_key_pair = E->get(); + undo_redo->add_undo_method(editor, "_bezier_track_set_key_handle_mode", animation.ptr(), track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_handle_mode(track_key_pair.first, track_key_pair.second), Animation::HANDLE_SET_MODE_NONE); + undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_in_handle(track_key_pair.first, track_key_pair.second)); + undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_out_handle(track_key_pair.first, track_key_pair.second)); + undo_redo->add_do_method(editor, "_bezier_track_set_key_handle_mode", animation.ptr(), track_key_pair.first, track_key_pair.second, p_mode, p_auto ? Animation::HANDLE_SET_MODE_AUTO : Animation::HANDLE_SET_MODE_RESET); } undo_redo->commit_action(); } @@ -804,7 +809,7 @@ void AnimationBezierTrackEdit::_clear_selection_for_anim(const Ref<Animation> &p _clear_selection(); } -void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int p_track, float p_pos) { +void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int p_track, real_t p_pos) { if (!(animation == p_anim)) { return; } @@ -813,7 +818,7 @@ void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int ERR_FAIL_COND(idx < 0); selection.insert(IntPair(p_track, idx)); - emit_signal(SNAME("select_key"), p_track, idx, true); + emit_signal(SNAME("select_key"), idx, true, p_track); update(); } @@ -869,16 +874,16 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { return; } - float minimum_time = INFINITY; - float maximum_time = -INFINITY; - float minimum_value = INFINITY; - float maximum_value = -INFINITY; + real_t minimum_time = INFINITY; + real_t maximum_time = -INFINITY; + real_t minimum_value = INFINITY; + real_t maximum_value = -INFINITY; for (const IntPair &E : selection) { IntPair key_pair = E; - float time = animation->track_get_key_time(key_pair.first, key_pair.second); - float value = animation->bezier_track_get_key_value(key_pair.first, key_pair.second); + real_t time = animation->track_get_key_time(key_pair.first, key_pair.second); + real_t value = animation->bezier_track_get_key_value(key_pair.first, key_pair.second); minimum_time = MIN(time, minimum_time); maximum_time = MAX(time, maximum_time); @@ -888,8 +893,8 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { float width = get_size().width - timeline->get_name_limit() - timeline->get_buttons_width(); float padding = width * 0.1; - float desired_scale = (width - padding / 2) / (maximum_time - minimum_time); - minimum_time = MAX(0, minimum_time - (padding / 2) / desired_scale); + float desired_scale = (width - padding / 2.0) / (maximum_time - minimum_time); + minimum_time = MAX(0, minimum_time - (padding / 2.0) / desired_scale); float zv = Math::pow(100 / desired_scale, 0.125f); if (zv < 1) { @@ -943,7 +948,12 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Selected Key(s)"), MENU_KEY_DELETE); menu->add_separator(); menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesFree"), SNAME("EditorIcons")), TTR("Make Handles Free"), MENU_KEY_SET_HANDLE_FREE); + menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesLinear"), SNAME("EditorIcons")), TTR("Make Handles Linear"), MENU_KEY_SET_HANDLE_LINEAR); menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Make Handles Balanced"), MENU_KEY_SET_HANDLE_BALANCED); + menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesMirror"), SNAME("EditorIcons")), TTR("Make Handles Mirrored"), MENU_KEY_SET_HANDLE_MIRRORED); + menu->add_separator(); + menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Make Handles Balanced (Auto Tangent)"), MENU_KEY_SET_HANDLE_AUTO_BALANCED); + menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesMirror"), SNAME("EditorIcons")), TTR("Make Handles Mirrored (Auto Tangent)"), MENU_KEY_SET_HANDLE_AUTO_MIRRORED); } if (menu->get_item_count()) { @@ -985,9 +995,10 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { for (int i = 0; i < animation->track_get_key_count(track); ++i) { undo_redo->add_undo_method( - animation.ptr(), - "bezier_track_insert_key", - track, animation->track_get_key_time(track, i), + this, + "_bezier_track_insert_key", + track, + animation->track_get_key_time(track, i), animation->bezier_track_get_key_value(track, i), animation->bezier_track_get_key_in_handle(track, i), animation->bezier_track_get_key_out_handle(track, i), @@ -1094,6 +1105,9 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { moving_selection = false; moving_selection_from_key = pair.second; moving_selection_from_track = pair.first; + moving_handle_track = pair.first; + moving_handle_left = animation->bezier_track_get_key_in_handle(pair.first, pair.second); + moving_handle_right = animation->bezier_track_get_key_out_handle(pair.first, pair.second); moving_selection_offset = Vector2(); select_single_attempt = pair; update(); @@ -1103,10 +1117,12 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { moving_selection_from_key = pair.second; moving_selection_from_track = pair.first; moving_selection_offset = Vector2(); - set_animation_and_track(animation, pair.first, read_only); + moving_handle_track = pair.first; + moving_handle_left = animation->bezier_track_get_key_in_handle(pair.first, pair.second); + moving_handle_right = animation->bezier_track_get_key_out_handle(pair.first, pair.second); selection.clear(); selection.insert(pair); - update(); + set_animation_and_track(animation, pair.first, read_only); } return; } @@ -1138,24 +1154,23 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { //insert new point if (mb->get_position().x >= limit && mb->get_position().x < get_size().width && mb->is_command_pressed()) { Array new_point; - new_point.resize(6); + new_point.resize(5); - float h = (get_size().height / 2 - mb->get_position().y) * v_zoom + v_scroll; + float h = (get_size().height / 2.0 - mb->get_position().y) * v_zoom + v_scroll; new_point[0] = h; new_point[1] = -0.25; new_point[2] = 0; new_point[3] = 0.25; new_point[4] = 0; - new_point[5] = 0; - float time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value(); + real_t time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value(); while (animation->track_find_key(selected_track, time, true) != -1) { time += 0.001; } undo_redo->create_action(TTR("Add Bezier Point")); - undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point); + undo_redo->add_do_method(animation.ptr(), "bezier_track_insert_key", selected_track, time, new_point); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time); undo_redo->commit_action(); @@ -1219,10 +1234,10 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { //select by clicking on curve int track_count = animation->get_track_count(); - float animation_length = animation->get_length(); + real_t animation_length = animation->get_length(); animation->set_length(real_t(INT_MAX)); //bezier_track_interpolate doesn't find keys if they exist beyond anim length - float time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value(); + real_t time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value(); for (int i = 0; i < track_count; ++i) { if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER || hidden_tracks.has(i) || locked_tracks.has(i)) { @@ -1246,20 +1261,6 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { update(); } - if (moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { - if (!read_only) { - undo_redo->create_action(TTR("Move Bezier Points")); - undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", selected_track, moving_handle_key, moving_handle_left); - undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", selected_track, moving_handle_key, moving_handle_right); - undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", selected_track, moving_handle_key, animation->bezier_track_get_key_in_handle(selected_track, moving_handle_key)); - undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", selected_track, moving_handle_key, animation->bezier_track_get_key_out_handle(selected_track, moving_handle_key)); - undo_redo->commit_action(); - - moving_handle = 0; - update(); - } - } - if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { if (!read_only) { if (moving_selection) { @@ -1268,13 +1269,14 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { undo_redo->create_action(TTR("Move Bezier Points")); List<AnimMoveRestore> to_restore; + List<Animation::HandleMode> to_restore_handle_modes; // 1-remove the keys for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->get().first, E->get().second); } // 2- remove overlapped keys for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { - float newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); + real_t newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); int idx = animation->track_find_key(E->get().first, newtime, true); if (idx == -1) { @@ -1293,33 +1295,62 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { amr.time = newtime; to_restore.push_back(amr); + to_restore_handle_modes.push_back(animation->bezier_track_get_key_handle_mode(E->get().first, idx)); } // 3-move the keys (re insert them) for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { - float newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); + real_t newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); Array key = animation->track_get_key_value(E->get().first, E->get().second); - float h = key[0]; + real_t h = key[0]; h += moving_selection_offset.y; key[0] = h; - undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->get().first, newpos, key, 1); + undo_redo->add_do_method( + this, + "_bezier_track_insert_key", + E->get().first, + newpos, + key[0], + Vector2(key[1], key[2]), + Vector2(key[3], key[4]), + animation->bezier_track_get_key_handle_mode(E->get().first, E->get().second)); } // 4-(undo) remove inserted keys for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { - float newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); + real_t newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newpos); } // 5-(undo) reinsert keys for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { - float oldpos = animation->track_get_key_time(E->get().first, E->get().second); - undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->get().first, oldpos, animation->track_get_key_value(E->get().first, E->get().second), 1); + real_t oldpos = animation->track_get_key_time(E->get().first, E->get().second); + Array key = animation->track_get_key_value(E->get().first, E->get().second); + undo_redo->add_undo_method( + this, + "_bezier_track_insert_key", + E->get().first, + oldpos, + key[0], + Vector2(key[1], key[2]), + Vector2(key[3], key[4]), + animation->bezier_track_get_key_handle_mode(E->get().first, E->get().second)); } // 6-(undo) reinsert overlapped keys - for (const AnimMoveRestore &amr : to_restore) { + for (int i = 0; i < to_restore.size(); i++) { + const AnimMoveRestore &amr = to_restore[i]; + Array key = amr.key; undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, 1); + undo_redo->add_undo_method( + this, + "_bezier_track_insert_key", + amr.track, + amr.time, + key[0], + Vector2(key[1], key[2]), + Vector2(key[3], key[4]), + to_restore_handle_modes[i]); } undo_redo->add_do_method(this, "_clear_selection_for_anim", animation); @@ -1328,8 +1359,8 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { // 7-reselect for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { - float oldpos = animation->track_get_key_time(E->get().first, E->get().second); - float newpos = editor->snap_time(oldpos + moving_selection_offset.x); + real_t oldpos = animation->track_get_key_time(E->get().first, E->get().second); + real_t newpos = editor->snap_time(oldpos + moving_selection_offset.x); undo_redo->add_do_method(this, "_select_at_anim", animation, E->get().first, newpos); undo_redo->add_undo_method(this, "_select_at_anim", animation, E->get().first, oldpos); @@ -1356,12 +1387,16 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { select_single_attempt = IntPair(-1, -1); } - float y = (get_size().height / 2 - mm->get_position().y) * v_zoom + v_scroll; + float y = (get_size().height / 2.0 - mm->get_position().y) * v_zoom + v_scroll; float x = editor->snap_time(((mm->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value()); if (!read_only) { moving_selection_offset = Vector2(x - animation->track_get_key_time(moving_selection_from_track, moving_selection_from_key), y - animation->bezier_track_get_key_value(moving_selection_from_track, moving_selection_from_key)); } + + additional_moving_handle_lefts.clear(); + additional_moving_handle_rights.clear(); + update(); } @@ -1380,8 +1415,8 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { update(); } - if (moving_handle != 0 && mm.is_valid()) { - float y = (get_size().height / 2 - mm->get_position().y) * v_zoom + v_scroll; + if ((moving_handle == 1 || moving_handle == -1) && mm.is_valid()) { + float y = (get_size().height / 2.0 - mm->get_position().y) * v_zoom + v_scroll; float x = editor->snap_time((mm->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value(); Vector2 key_pos = Vector2(animation->track_get_key_time(selected_track, moving_handle_key), animation->bezier_track_get_key_value(selected_track, moving_handle_key)); @@ -1394,8 +1429,10 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { if (moving_handle == -1) { moving_handle_left = moving_handle_value; - if (animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key) == Animation::HANDLE_MODE_BALANCED) { - double ratio = timeline->get_zoom_scale() * v_zoom; + Animation::HandleMode handle_mode = animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key); + + if (handle_mode == Animation::HANDLE_MODE_BALANCED) { + real_t ratio = timeline->get_zoom_scale() * v_zoom; Transform2D xform; xform.set_scale(Vector2(1.0, 1.0 / ratio)); @@ -1403,12 +1440,16 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { Vector2 vec_in = xform.xform(moving_handle_left); moving_handle_right = xform.affine_inverse().xform(-vec_in.normalized() * vec_out.length()); + } else if (handle_mode == Animation::HANDLE_MODE_MIRRORED) { + moving_handle_right = -moving_handle_left; } } else if (moving_handle == 1) { moving_handle_right = moving_handle_value; - if (animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key) == Animation::HANDLE_MODE_BALANCED) { - double ratio = timeline->get_zoom_scale() * v_zoom; + Animation::HandleMode handle_mode = animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key); + + if (handle_mode == Animation::HANDLE_MODE_BALANCED) { + real_t ratio = timeline->get_zoom_scale() * v_zoom; Transform2D xform; xform.set_scale(Vector2(1.0, 1.0 / ratio)); @@ -1416,26 +1457,26 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { Vector2 vec_out = xform.xform(moving_handle_right); moving_handle_left = xform.affine_inverse().xform(-vec_out.normalized() * vec_in.length()); + } else if (handle_mode == Animation::HANDLE_MODE_MIRRORED) { + moving_handle_left = -moving_handle_right; } } update(); } - bool is_finishing_key_handle_drag = moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT; - if (is_finishing_key_handle_drag) { + if ((moving_handle == -1 || moving_handle == 1) && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { if (!read_only) { undo_redo->create_action(TTR("Move Bezier Points")); if (moving_handle == -1) { - double ratio = timeline->get_zoom_scale() * v_zoom; + real_t ratio = timeline->get_zoom_scale() * v_zoom; undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, moving_handle_left, ratio); undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_in_handle(moving_handle_track, moving_handle_key), ratio); } else if (moving_handle == 1) { - double ratio = timeline->get_zoom_scale() * v_zoom; + real_t ratio = timeline->get_zoom_scale() * v_zoom; undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, moving_handle_right, ratio); undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_out_handle(moving_handle_track, moving_handle_key), ratio); } undo_redo->commit_action(); - moving_handle = 0; update(); } @@ -1469,7 +1510,7 @@ void AnimationBezierTrackEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_or timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() * 1.05); } } - v_scroll = v_scroll + (p_origin.y - get_size().y / 2) * (v_zoom - v_zoom_orig); + v_scroll = v_scroll + (p_origin.y - get_size().y / 2.0) * (v_zoom - v_zoom_orig); update(); } @@ -1478,20 +1519,19 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) { case MENU_KEY_INSERT: { if (animation->get_track_count() > 0) { Array new_point; - new_point.resize(6); + new_point.resize(5); - float h = (get_size().height / 2 - menu_insert_key.y) * v_zoom + v_scroll; + float h = (get_size().height / 2.0 - menu_insert_key.y) * v_zoom + v_scroll; new_point[0] = h; new_point[1] = -0.25; new_point[2] = 0; new_point[3] = 0.25; new_point[4] = 0; - new_point[5] = Animation::HANDLE_MODE_BALANCED; int limit = timeline->get_name_limit(); - float time = ((menu_insert_key.x - limit) / timeline->get_zoom_scale()) + timeline->get_value(); + real_t time = ((menu_insert_key.x - limit) / timeline->get_zoom_scale()) + timeline->get_value(); while (animation->track_find_key(selected_track, time, true) != -1) { time += 0.001; @@ -1501,8 +1541,8 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) { undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time); undo_redo->commit_action(); + update(); } - } break; case MENU_KEY_DUPLICATE: { duplicate_selection(); @@ -1513,9 +1553,21 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) { case MENU_KEY_SET_HANDLE_FREE: { _change_selected_keys_handle_mode(Animation::HANDLE_MODE_FREE); } break; + case MENU_KEY_SET_HANDLE_LINEAR: { + _change_selected_keys_handle_mode(Animation::HANDLE_MODE_LINEAR); + } break; case MENU_KEY_SET_HANDLE_BALANCED: { _change_selected_keys_handle_mode(Animation::HANDLE_MODE_BALANCED); } break; + case MENU_KEY_SET_HANDLE_MIRRORED: { + _change_selected_keys_handle_mode(Animation::HANDLE_MODE_MIRRORED); + } break; + case MENU_KEY_SET_HANDLE_AUTO_BALANCED: { + _change_selected_keys_handle_mode(Animation::HANDLE_MODE_BALANCED, true); + } break; + case MENU_KEY_SET_HANDLE_AUTO_MIRRORED: { + _change_selected_keys_handle_mode(Animation::HANDLE_MODE_MIRRORED, true); + } break; } } @@ -1524,9 +1576,9 @@ void AnimationBezierTrackEdit::duplicate_selection() { return; } - float top_time = 1e10; + real_t top_time = 1e10; for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { - float t = animation->track_get_key_time(E->get().first, E->get().second); + real_t t = animation->track_get_key_time(E->get().first, E->get().second); if (t < top_time) { top_time = t; } @@ -1534,17 +1586,17 @@ void AnimationBezierTrackEdit::duplicate_selection() { undo_redo->create_action(TTR("Anim Duplicate Keys")); - List<Pair<int, float>> new_selection_values; + List<Pair<int, real_t>> new_selection_values; for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { - float t = animation->track_get_key_time(E->get().first, E->get().second); - float dst_time = t + (timeline->get_play_position() - top_time); + real_t t = animation->track_get_key_time(E->get().first, E->get().second); + real_t dst_time = t + (timeline->get_play_position() - top_time); int existing_idx = animation->track_find_key(E->get().first, dst_time, true); undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->get().first, dst_time, animation->track_get_key_value(E->get().first, E->get().second), animation->track_get_key_transition(E->get().first, E->get().second)); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, dst_time); - Pair<int, float> p; + Pair<int, real_t> p; p.first = E->get().first; p.second = dst_time; new_selection_values.push_back(p); @@ -1559,9 +1611,9 @@ void AnimationBezierTrackEdit::duplicate_selection() { //reselect duplicated selection.clear(); - for (const Pair<int, float> &E : new_selection_values) { + for (const Pair<int, real_t> &E : new_selection_values) { int track = E.first; - float time = E.second; + real_t time = E.second; int existing_idx = animation->track_find_key(track, time, true); @@ -1591,18 +1643,24 @@ void AnimationBezierTrackEdit::delete_selection() { } } +void AnimationBezierTrackEdit::_bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const Animation::HandleMode p_handle_mode) { + ERR_FAIL_COND(animation.is_null()); + int idx = animation->bezier_track_insert_key(p_track, p_time, p_value, p_in_handle, p_out_handle); + animation->bezier_track_set_key_handle_mode(p_track, idx, p_handle_mode); +} + void AnimationBezierTrackEdit::_bind_methods() { - ClassDB::bind_method("_clear_selection", &AnimationBezierTrackEdit::_clear_selection); - ClassDB::bind_method("_clear_selection_for_anim", &AnimationBezierTrackEdit::_clear_selection_for_anim); - ClassDB::bind_method("_select_at_anim", &AnimationBezierTrackEdit::_select_at_anim); - ClassDB::bind_method("_update_hidden_tracks_after", &AnimationBezierTrackEdit::_update_hidden_tracks_after); - ClassDB::bind_method("_update_locked_tracks_after", &AnimationBezierTrackEdit::_update_locked_tracks_after); + ClassDB::bind_method(D_METHOD("_clear_selection"), &AnimationBezierTrackEdit::_clear_selection); + ClassDB::bind_method(D_METHOD("_clear_selection_for_anim"), &AnimationBezierTrackEdit::_clear_selection_for_anim); + ClassDB::bind_method(D_METHOD("_select_at_anim"), &AnimationBezierTrackEdit::_select_at_anim); + ClassDB::bind_method(D_METHOD("_update_hidden_tracks_after"), &AnimationBezierTrackEdit::_update_hidden_tracks_after); + ClassDB::bind_method(D_METHOD("_update_locked_tracks_after"), &AnimationBezierTrackEdit::_update_locked_tracks_after); + ClassDB::bind_method(D_METHOD("_bezier_track_insert_key"), &AnimationBezierTrackEdit::_bezier_track_insert_key); ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::FLOAT, "position"), PropertyInfo(Variant::BOOL, "drag"))); ADD_SIGNAL(MethodInfo("remove_request", PropertyInfo(Variant::INT, "track"))); ADD_SIGNAL(MethodInfo("insert_key", PropertyInfo(Variant::FLOAT, "offset"))); - ADD_SIGNAL(MethodInfo("select_key", PropertyInfo(Variant::INT, "track"), PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "single"))); - ADD_SIGNAL(MethodInfo("deselect_key", PropertyInfo(Variant::INT, "track"), PropertyInfo(Variant::INT, "index"))); + ADD_SIGNAL(MethodInfo("select_key", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "single"), PropertyInfo(Variant::INT, "track"))); ADD_SIGNAL(MethodInfo("clear_selection")); ADD_SIGNAL(MethodInfo("close_request")); diff --git a/editor/animation_bezier_editor.h b/editor/animation_bezier_editor.h index 3e94b4fa84..beb7a5e9c6 100644 --- a/editor/animation_bezier_editor.h +++ b/editor/animation_bezier_editor.h @@ -32,7 +32,7 @@ #define ANIMATION_BEZIER_EDITOR_H #include "animation_track_editor.h" -#include "core/templates/rb_set.h" +#include "core/templates/hashfuncs.h" class EditorUndoRedoManager; class ViewPanner; @@ -45,14 +45,18 @@ class AnimationBezierTrackEdit : public Control { MENU_KEY_DUPLICATE, MENU_KEY_DELETE, MENU_KEY_SET_HANDLE_FREE, + MENU_KEY_SET_HANDLE_LINEAR, MENU_KEY_SET_HANDLE_BALANCED, + MENU_KEY_SET_HANDLE_MIRRORED, + MENU_KEY_SET_HANDLE_AUTO_BALANCED, + MENU_KEY_SET_HANDLE_AUTO_MIRRORED, }; AnimationTimelineEdit *timeline = nullptr; Ref<EditorUndoRedoManager> undo_redo; Node *root = nullptr; Control *play_position = nullptr; //separate control used to draw so updates for only position changed are much faster - float play_position_pos = 0; + real_t play_position_pos = 0; Ref<Animation> animation; bool read_only = false; @@ -112,25 +116,37 @@ class AnimationBezierTrackEdit : public Control { Vector2 box_selection_from; Vector2 box_selection_to; - int moving_handle = 0; //0 no move -1 or +1 out + int moving_handle = 0; //0 no move -1 or +1 out, 2 both (drawing only) int moving_handle_key = 0; int moving_handle_track = 0; Vector2 moving_handle_left; Vector2 moving_handle_right; int moving_handle_mode = 0; // value from Animation::HandleMode + struct PairHasher { + static _FORCE_INLINE_ uint32_t hash(const Pair<int, int> &p_value) { + int32_t hash = 23; + hash = hash * 31 * hash_one_uint64(p_value.first); + hash = hash * 31 * hash_one_uint64(p_value.second); + return hash; + } + }; + + HashMap<Pair<int, int>, Vector2, PairHasher> additional_moving_handle_lefts; + HashMap<Pair<int, int>, Vector2, PairHasher> additional_moving_handle_rights; + void _clear_selection(); void _clear_selection_for_anim(const Ref<Animation> &p_anim); - void _select_at_anim(const Ref<Animation> &p_anim, int p_track, float p_pos); - void _change_selected_keys_handle_mode(Animation::HandleMode p_mode); + void _select_at_anim(const Ref<Animation> &p_anim, int p_track, real_t p_pos); + void _change_selected_keys_handle_mode(Animation::HandleMode p_mode, bool p_auto = false); Vector2 menu_insert_key; struct AnimMoveRestore { int track = 0; - float time = 0; + double time = 0; Variant key; - float transition = 0; + real_t transition = 0; }; AnimationTrackEditor *editor = nullptr; @@ -145,7 +161,7 @@ class AnimationBezierTrackEdit : public Control { Vector<EditPoint> edit_points; - struct SelectionCompare { + struct PairCompare { bool operator()(const IntPair &lh, const IntPair &rh) { if (lh.first == rh.first) { return lh.second < rh.second; @@ -155,7 +171,7 @@ class AnimationBezierTrackEdit : public Control { } }; - typedef RBSet<IntPair, SelectionCompare> SelectionSet; + typedef RBSet<IntPair, PairCompare> SelectionSet; SelectionSet selection; @@ -187,12 +203,14 @@ public: void set_root(Node *p_root); void set_filtered(bool p_filtered); - void set_play_position(float p_pos); + void set_play_position(real_t p_pos); void update_play_position(); void duplicate_selection(); void delete_selection(); + void _bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const Animation::HandleMode p_handle_mode); + AnimationBezierTrackEdit(); }; diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 3df3a3b76a..ddce4f8a36 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -38,6 +38,7 @@ #include "editor/editor_undo_redo_manager.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "scene/animation/animation_player.h" +#include "scene/animation/tween.h" #include "scene/gui/separator.h" #include "scene/gui/view_panner.h" #include "scene/main/window.h" @@ -59,17 +60,17 @@ public: return true; } - bool _read_only() { + bool _is_read_only() { return animation_read_only; } static void _bind_methods() { - ClassDB::bind_method("_update_obj", &AnimationTrackKeyEdit::_update_obj); - ClassDB::bind_method("_key_ofs_changed", &AnimationTrackKeyEdit::_key_ofs_changed); - ClassDB::bind_method("_hide_script_from_inspector", &AnimationTrackKeyEdit::_hide_script_from_inspector); - ClassDB::bind_method("get_root_path", &AnimationTrackKeyEdit::get_root_path); - ClassDB::bind_method("_dont_undo_redo", &AnimationTrackKeyEdit::_dont_undo_redo); - ClassDB::bind_method("_read_only", &AnimationTrackKeyEdit::_read_only); + ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationTrackKeyEdit::_update_obj); + ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationTrackKeyEdit::_key_ofs_changed); + ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationTrackKeyEdit::_hide_script_from_inspector); + ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationTrackKeyEdit::get_root_path); + ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationTrackKeyEdit::_dont_undo_redo); + ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationTrackKeyEdit::_is_read_only); } void _fix_node_path(Variant &value) { @@ -350,8 +351,8 @@ public: setting = true; undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS); int prev = animation->bezier_track_get_key_handle_mode(track, key); - undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key, value); - undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key, prev); + undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value); + undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev); undo_redo->add_do_method(this, "_update_obj", animation); undo_redo->add_undo_method(this, "_update_obj", animation); undo_redo->commit_action(); @@ -636,10 +637,16 @@ public: } break; case Animation::TYPE_BEZIER: { + Animation::HandleMode hm = animation->bezier_track_get_key_handle_mode(track, key); p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("value"))); - p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle"))); - p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle"))); - p_list->push_back(PropertyInfo(Variant::INT, PNAME("handle_mode"), PROPERTY_HINT_ENUM, "Free,Balanced")); + if (hm == Animation::HANDLE_MODE_LINEAR) { + p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY)); + p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY)); + } else { + p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle"))); + p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle"))); + } + p_list->push_back(PropertyInfo(Variant::INT, PNAME("handle_mode"), PROPERTY_HINT_ENUM, "Free,Linear,Balanced,Mirrored")); } break; case Animation::TYPE_AUDIO: { @@ -720,17 +727,17 @@ public: return true; } - bool _read_only() { + bool _is_read_only() { return animation_read_only; } static void _bind_methods() { - ClassDB::bind_method("_update_obj", &AnimationMultiTrackKeyEdit::_update_obj); - ClassDB::bind_method("_key_ofs_changed", &AnimationMultiTrackKeyEdit::_key_ofs_changed); - ClassDB::bind_method("_hide_script_from_inspector", &AnimationMultiTrackKeyEdit::_hide_script_from_inspector); - ClassDB::bind_method("get_root_path", &AnimationMultiTrackKeyEdit::get_root_path); - ClassDB::bind_method("_dont_undo_redo", &AnimationMultiTrackKeyEdit::_dont_undo_redo); - ClassDB::bind_method("_read_only", &AnimationMultiTrackKeyEdit::_read_only); + ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationMultiTrackKeyEdit::_update_obj); + ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationMultiTrackKeyEdit::_key_ofs_changed); + ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_script_from_inspector); + ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationMultiTrackKeyEdit::get_root_path); + ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationMultiTrackKeyEdit::_dont_undo_redo); + ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationMultiTrackKeyEdit::_is_read_only); } void _fix_node_path(Variant &value, NodePath &base) { @@ -971,8 +978,8 @@ public: undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } Vector2 prev = animation->bezier_track_get_key_in_handle(track, key); - undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, value); - undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, prev); + undo_redo->add_do_method(this, "_bezier_track_set_key_in_handle", track, key, value); + undo_redo->add_undo_method(this, "_bezier_track_set_key_in_handle", track, key, prev); update_obj = true; } else if (name == "out_handle") { const Variant &value = p_value; @@ -982,8 +989,8 @@ public: undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } Vector2 prev = animation->bezier_track_get_key_out_handle(track, key); - undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, value); - undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, prev); + undo_redo->add_do_method(this, "_bezier_track_set_key_out_handle", track, key, value); + undo_redo->add_undo_method(this, "_bezier_track_set_key_out_handle", track, key, prev); update_obj = true; } else if (name == "handle_mode") { const Variant &value = p_value; @@ -993,8 +1000,8 @@ public: undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } int prev = animation->bezier_track_get_key_handle_mode(track, key); - undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key, value); - undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key, prev); + undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value); + undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev); update_obj = true; } } break; @@ -1325,7 +1332,7 @@ public: p_list->push_back(PropertyInfo(Variant::FLOAT, "value")); p_list->push_back(PropertyInfo(Variant::VECTOR2, "in_handle")); p_list->push_back(PropertyInfo(Variant::VECTOR2, "out_handle")); - p_list->push_back(PropertyInfo(Variant::INT, "handle_mode", PROPERTY_HINT_ENUM, "Free,Balanced")); + p_list->push_back(PropertyInfo(Variant::INT, "handle_mode", PROPERTY_HINT_ENUM, "Free,Linear,Balanced,Mirrored")); } break; case Animation::TYPE_AUDIO: { p_list->push_back(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream")); @@ -2115,11 +2122,10 @@ void AnimationTrackEdit::_notification(int p_what) { get_theme_icon(SNAME("InterpWrapClamp"), SNAME("EditorIcons")), get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")), }; - Ref<Texture2D> interp_icon[4] = { + Ref<Texture2D> interp_icon[3] = { get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")), get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")), get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")), - get_theme_icon(SNAME("InterpCubicInTime"), SNAME("EditorIcons")) }; Ref<Texture2D> cont_icon[4] = { get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")), @@ -2725,9 +2731,15 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const { case Animation::HANDLE_MODE_FREE: { text += TTR("Handle mode: Free\n"); } break; + case Animation::HANDLE_MODE_LINEAR: { + text += TTR("Handle mode: Linear\n"); + } break; case Animation::HANDLE_MODE_BALANCED: { text += TTR("Handle mode: Balanced\n"); } break; + case Animation::HANDLE_MODE_MIRRORED: { + text += TTR("Handle mode: Mirrored\n"); + } break; } } break; case Animation::TYPE_AUDIO: { @@ -2836,7 +2848,6 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { menu->add_icon_item(get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")), TTR("Nearest"), MENU_INTERPOLATION_NEAREST); menu->add_icon_item(get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")), TTR("Linear"), MENU_INTERPOLATION_LINEAR); menu->add_icon_item(get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")), TTR("Cubic"), MENU_INTERPOLATION_CUBIC); - menu->add_icon_item(get_theme_icon(SNAME("InterpCubicInTime"), SNAME("EditorIcons")), TTR("CubicInTime"), MENU_INTERPOLATION_CUBIC_IN_TIME); menu->reset_size(); Vector2 popup_pos = get_screen_position() + interp_mode_rect.position + Vector2(0, interp_mode_rect.size.height); @@ -3177,8 +3188,7 @@ void AnimationTrackEdit::_menu_selected(int p_index) { } break; case MENU_INTERPOLATION_NEAREST: case MENU_INTERPOLATION_LINEAR: - case MENU_INTERPOLATION_CUBIC: - case MENU_INTERPOLATION_CUBIC_IN_TIME: { + case MENU_INTERPOLATION_CUBIC: { Animation::InterpolationType interp_mode = Animation::InterpolationType(p_index - MENU_INTERPOLATION_NEAREST); undo_redo->create_action(TTR("Change Animation Interpolation Mode")); undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", track, interp_mode); @@ -3258,7 +3268,6 @@ void AnimationTrackEdit::_bind_methods() { ADD_SIGNAL(MethodInfo("insert_key", PropertyInfo(Variant::FLOAT, "offset"))); ADD_SIGNAL(MethodInfo("select_key", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "single"))); ADD_SIGNAL(MethodInfo("deselect_key", PropertyInfo(Variant::INT, "index"))); - ADD_SIGNAL(MethodInfo("bezier_edit")); ADD_SIGNAL(MethodInfo("move_selection_begin")); ADD_SIGNAL(MethodInfo("move_selection", PropertyInfo(Variant::FLOAT, "offset"))); @@ -3421,7 +3430,8 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re track_edits[_get_track_selected()]->release_focus(); } if (animation.is_valid()) { - animation->disconnect("changed", callable_mp(this, &AnimationTrackEditor::_animation_changed)); + animation->disconnect("tracks_changed", callable_mp(this, &AnimationTrackEditor::_animation_changed)); + animation->disconnect("changed", callable_mp(this, &AnimationTrackEditor::_sync_animation_change)); _clear_selection(); } animation = p_anim; @@ -3432,7 +3442,8 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re _update_tracks(); if (animation.is_valid()) { - animation->connect("changed", callable_mp(this, &AnimationTrackEditor::_animation_changed)); + animation->connect("tracks_changed", callable_mp(this, &AnimationTrackEditor::_animation_changed), CONNECT_DEFERRED); + animation->connect("changed", callable_mp(this, &AnimationTrackEditor::_sync_animation_change), CONNECT_DEFERRED); hscroll->show(); edit->set_disabled(read_only); @@ -4347,13 +4358,12 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD } break; case Animation::TYPE_BEZIER: { Array array; - array.resize(6); + array.resize(5); array[0] = p_id.value; array[1] = -0.25; array[2] = 0; array[3] = 0.25; array[4] = 0; - array[5] = Animation::HANDLE_MODE_BALANCED; value = array; bezier_edit_icon->set_disabled(false); @@ -4616,11 +4626,19 @@ void AnimationTrackEditor::_update_tracks() { } } +void AnimationTrackEditor::_sync_animation_change() { + bezier_edit->update(); +} + void AnimationTrackEditor::_animation_changed() { if (animation_changing_awaiting_update) { return; // All will be updated, don't bother with anything. } + if (key_edit) { + _update_key_edit(); + } + if (key_edit && key_edit->setting) { // If editing a key, just update the edited track, makes refresh less costly. if (key_edit->track < track_edits.size()) { @@ -5080,13 +5098,12 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) { Variant value; _find_hint_for_track(p_track, bp, &value); Array arr; - arr.resize(6); + arr.resize(5); arr[0] = value; arr[1] = -0.25; arr[2] = 0; arr[3] = 0.25; arr[4] = 0; - arr[5] = 0; undo_redo->create_action(TTR("Add Track Key")); undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, arr); @@ -5565,6 +5582,13 @@ void AnimationTrackEditor::_bezier_edit(int p_for_track) { // Search everything within the track and curve - edit it. } +void AnimationTrackEditor::_bezier_track_set_key_handle_mode(Animation *p_anim, int p_track, int p_index, Animation::HandleMode p_mode, Animation::HandleSetMode p_set_mode) { + if (!p_anim) { + return; + } + p_anim->bezier_track_set_key_handle_mode(p_track, p_index, p_mode, p_set_mode); +} + void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) { // Duplicait! if (selection.size() && animation.is_valid() && (!transpose || (_get_track_selected() >= 0 && _get_track_selected() < animation->get_track_count()))) { @@ -5970,6 +5994,89 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { #undef NEW_POS undo_redo->commit_action(); } break; + + case EDIT_EASE_SELECTION: { + ease_dialog->popup_centered(Size2(200, 100) * EDSCALE); + } break; + case EDIT_EASE_CONFIRM: { + undo_redo->create_action(TTR("Make Easing Keys")); + + Tween::TransitionType transition_type = static_cast<Tween::TransitionType>(transition_selection->get_selected_id()); + Tween::EaseType ease_type = static_cast<Tween::EaseType>(ease_selection->get_selected_id()); + float fps = ease_fps->get_value(); + double dur_step = 1.0 / fps; + + // Organize track and key. + HashMap<int, Vector<int>> keymap; + Vector<int> tracks; + for (const KeyValue<SelectedKey, KeyInfo> &E : selection) { + if (!tracks.has(E.key.track)) { + tracks.append(E.key.track); + } + } + for (int i = 0; i < tracks.size(); i++) { + switch (animation->track_get_type(tracks[i])) { + case Animation::TYPE_VALUE: + case Animation::TYPE_POSITION_3D: + case Animation::TYPE_ROTATION_3D: + case Animation::TYPE_SCALE_3D: + case Animation::TYPE_BLEND_SHAPE: { + Vector<int> keys; + for (const KeyValue<SelectedKey, KeyInfo> &E : selection) { + if (E.key.track == tracks[i]) { + keys.append(E.key.key); + } + } + keys.sort(); + keymap.insert(tracks[i], keys); + } break; + default: { + } break; + } + } + + // Make easing. + HashMap<int, Vector<int>>::Iterator E = keymap.begin(); + while (E) { + int track = E->key; + Vector<int> keys = E->value; + int len = keys.size() - 1; + + // Make insert queue. + Vector<Pair<double, Variant>> insert_queue; + for (int i = 0; i < len; i++) { + // Check neighboring keys. + if (keys[i] + 1 == keys[i + 1]) { + double from_t = animation->track_get_key_time(track, keys[i]); + double to_t = animation->track_get_key_time(track, keys[i + 1]); + Variant from_v = animation->track_get_key_value(track, keys[i]); + Variant to_v = animation->track_get_key_value(track, keys[i + 1]); + Variant delta_v; + Variant::sub(to_v, from_v, delta_v); + double duration = to_t - from_t; + double fixed_duration = duration - 0.01; // Prevent to overwrap keys... + for (double delta_t = dur_step; delta_t < fixed_duration; delta_t += dur_step) { + Pair<double, Variant> keydata; + keydata.first = from_t + delta_t; + keydata.second = Tween::interpolate_variant(from_v, delta_v, delta_t, duration, transition_type, ease_type); + insert_queue.append(keydata); + } + } + } + + // Do insertion. + for (int i = 0; i < insert_queue.size(); i++) { + undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, insert_queue[i].first, insert_queue[i].second); + undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, insert_queue[i].first); + } + + ++E; + } + + undo_redo->commit_action(); + + } break; + case EDIT_DUPLICATE_SELECTION: { if (bezier_edit->is_visible()) { bezier_edit->duplicate_selection(); @@ -6061,8 +6168,115 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } break; case EDIT_APPLY_RESET: { AnimationPlayerEditor::get_singleton()->get_player()->apply_reset(true); + } break; + + case EDIT_BAKE_ANIMATION: { + bake_dialog->popup_centered(Size2(200, 100) * EDSCALE); + } break; + case EDIT_BAKE_ANIMATION_CONFIRM: { + undo_redo->create_action(TTR("Bake Animation as Linear keys.")); + + int track_len = animation->get_track_count(); + bool b_trs = bake_trs->is_pressed(); + bool b_bs = bake_blendshape->is_pressed(); + bool b_v = bake_value->is_pressed(); + + double anim_len = animation->get_length() + CMP_EPSILON; // For end key. + float fps = bake_fps->get_value(); + double dur_step = 1.0 / fps; + + for (int i = 0; i < track_len; i++) { + bool do_bake = false; + Animation::TrackType type = animation->track_get_type(i); + do_bake |= b_trs && (type == Animation::TYPE_POSITION_3D || type == Animation::TYPE_ROTATION_3D || type == Animation::TYPE_SCALE_3D); + do_bake |= b_bs && type == Animation::TYPE_BLEND_SHAPE; + do_bake |= b_v && type == Animation::TYPE_VALUE; + if (do_bake && !animation->track_is_compressed(i)) { + if (animation->track_get_interpolation_type(i) == Animation::INTERPOLATION_NEAREST) { + continue; // Nearest interpolation cannot be baked. + } + + // Make insert queue. + Vector<Pair<double, Variant>> insert_queue; + + switch (type) { + case Animation::TYPE_POSITION_3D: { + for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) { + Pair<double, Variant> keydata; + keydata.first = delta_t; + Vector3 v; + animation->position_track_interpolate(i, delta_t, &v); + keydata.second = v; + insert_queue.append(keydata); + } + } break; + case Animation::TYPE_ROTATION_3D: { + for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) { + Pair<double, Variant> keydata; + keydata.first = delta_t; + Quaternion v; + animation->rotation_track_interpolate(i, delta_t, &v); + keydata.second = v; + insert_queue.append(keydata); + } + } break; + case Animation::TYPE_SCALE_3D: { + for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) { + Pair<double, Variant> keydata; + keydata.first = delta_t; + Vector3 v; + animation->scale_track_interpolate(i, delta_t, &v); + keydata.second = v; + insert_queue.append(keydata); + } + } break; + case Animation::TYPE_BLEND_SHAPE: { + for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) { + Pair<double, Variant> keydata; + keydata.first = delta_t; + float v; + animation->blend_shape_track_interpolate(i, delta_t, &v); + keydata.second = v; + insert_queue.append(keydata); + } + } break; + case Animation::TYPE_VALUE: { + for (double delta_t = 0.0; delta_t < anim_len; delta_t += dur_step) { + Pair<double, Variant> keydata; + keydata.first = delta_t; + keydata.second = animation->value_track_interpolate(i, delta_t); + insert_queue.append(keydata); + } + } break; + default: { + } break; + } + + // Cleanup keys. + int key_len = animation->track_get_key_count(i); + for (int j = key_len - 1; j >= 0; j--) { + undo_redo->add_do_method(animation.ptr(), "track_remove_key", i, j); + } + + // Insert keys. + undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", i, Animation::INTERPOLATION_LINEAR); + for (int j = insert_queue.size() - 1; j >= 0; j--) { + undo_redo->add_do_method(animation.ptr(), "track_insert_key", i, insert_queue[j].first, insert_queue[j].second); + undo_redo->add_undo_method(animation.ptr(), "track_remove_key", i, j); + } + + // Undo methods. + undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_type", i, animation->track_get_interpolation_type(i)); + for (int j = key_len - 1; j >= 0; j--) { + undo_redo->add_undo_method(animation.ptr(), "track_insert_key", i, animation->track_get_key_time(i, j), animation->track_get_key_value(i, j), animation->track_get_key_transition(i, j)); + } + } + } + + undo_redo->commit_action(); } break; + case EDIT_OPTIMIZE_ANIMATION: { optimize_dialog->popup_centered(Size2(250, 180) * EDSCALE); @@ -6225,15 +6439,17 @@ void AnimationTrackEditor::_select_all_tracks_for_copy() { } void AnimationTrackEditor::_bind_methods() { - ClassDB::bind_method("_animation_update", &AnimationTrackEditor::_animation_update); - ClassDB::bind_method("_track_grab_focus", &AnimationTrackEditor::_track_grab_focus); - ClassDB::bind_method("_update_tracks", &AnimationTrackEditor::_update_tracks); - ClassDB::bind_method("_clear_selection_for_anim", &AnimationTrackEditor::_clear_selection_for_anim); - ClassDB::bind_method("_select_at_anim", &AnimationTrackEditor::_select_at_anim); + ClassDB::bind_method(D_METHOD("_animation_update"), &AnimationTrackEditor::_animation_update); + ClassDB::bind_method(D_METHOD("_track_grab_focus"), &AnimationTrackEditor::_track_grab_focus); + ClassDB::bind_method(D_METHOD("_update_tracks"), &AnimationTrackEditor::_update_tracks); + ClassDB::bind_method(D_METHOD("_clear_selection_for_anim"), &AnimationTrackEditor::_clear_selection_for_anim); + ClassDB::bind_method(D_METHOD("_select_at_anim"), &AnimationTrackEditor::_select_at_anim); - ClassDB::bind_method("_key_selected", &AnimationTrackEditor::_key_selected); // Still used by some connect_compat. - ClassDB::bind_method("_key_deselected", &AnimationTrackEditor::_key_deselected); // Still used by some connect_compat. - ClassDB::bind_method("_clear_selection", &AnimationTrackEditor::_clear_selection); // Still used by some connect_compat. + ClassDB::bind_method(D_METHOD("_key_selected"), &AnimationTrackEditor::_key_selected); // Still used by some connect_compat. + ClassDB::bind_method(D_METHOD("_key_deselected"), &AnimationTrackEditor::_key_deselected); // Still used by some connect_compat. + ClassDB::bind_method(D_METHOD("_clear_selection"), &AnimationTrackEditor::_clear_selection); // Still used by some connect_compat. + + ClassDB::bind_method(D_METHOD("_bezier_track_set_key_handle_mode", "animation", "track_idx", "key_idx", "key_handle_mode", "key_handle_set_mode"), &AnimationTrackEditor::_bezier_track_set_key_handle_mode, DEFVAL(Animation::HANDLE_SET_MODE_NONE)); ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::FLOAT, "position"), PropertyInfo(Variant::BOOL, "drag"), PropertyInfo(Variant::BOOL, "timeline_only"))); ADD_SIGNAL(MethodInfo("keying_changed")); @@ -6470,6 +6686,8 @@ AnimationTrackEditor::AnimationTrackEditor() { edit->get_popup()->add_item(TTR("Scale Selection"), EDIT_SCALE_SELECTION); edit->get_popup()->add_item(TTR("Scale From Cursor"), EDIT_SCALE_FROM_CURSOR); edit->get_popup()->add_separator(); + edit->get_popup()->add_item(TTR("Make Easing Selection"), EDIT_EASE_SELECTION); + edit->get_popup()->add_separator(); edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/duplicate_selection", TTR("Duplicate Selection"), KeyModifierMask::CMD | Key::D), EDIT_DUPLICATE_SELECTION); edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/duplicate_selection_transposed", TTR("Duplicate Transposed"), KeyModifierMask::SHIFT | KeyModifierMask::CMD | Key::D), EDIT_DUPLICATE_TRANSPOSED); edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/add_reset_value", TTR("Add RESET Value(s)"))); @@ -6482,6 +6700,7 @@ AnimationTrackEditor::AnimationTrackEditor() { edit->get_popup()->add_separator(); edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/apply_reset", TTR("Apply Reset")), EDIT_APPLY_RESET); edit->get_popup()->add_separator(); + edit->get_popup()->add_item(TTR("Bake Animation"), EDIT_BAKE_ANIMATION); edit->get_popup()->add_item(TTR("Optimize Animation"), EDIT_OPTIMIZE_ANIMATION); edit->get_popup()->add_item(TTR("Clean-Up Animation"), EDIT_CLEAN_UP_ANIMATION); @@ -6604,6 +6823,88 @@ AnimationTrackEditor::AnimationTrackEditor() { scale_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_SCALE_CONFIRM)); add_child(scale_dialog); + // + ease_dialog = memnew(ConfirmationDialog); + ease_dialog->set_title(TTR("Select Transition and Easing")); + ease_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_EASE_CONFIRM)); + add_child(ease_dialog); + GridContainer *ease_grid = memnew(GridContainer); + ease_grid->set_columns(2); + ease_dialog->add_child(ease_grid); + transition_selection = memnew(OptionButton); + transition_selection->add_item("Linear", Tween::TRANS_LINEAR); + transition_selection->add_item("Sine", Tween::TRANS_SINE); + transition_selection->add_item("Quint", Tween::TRANS_QUINT); + transition_selection->add_item("Quart", Tween::TRANS_QUART); + transition_selection->add_item("Quad", Tween::TRANS_QUAD); + transition_selection->add_item("Expo", Tween::TRANS_EXPO); + transition_selection->add_item("Elastic", Tween::TRANS_ELASTIC); + transition_selection->add_item("Cubic", Tween::TRANS_CUBIC); + transition_selection->add_item("Circ", Tween::TRANS_CIRC); + transition_selection->add_item("Bounce", Tween::TRANS_BOUNCE); + transition_selection->add_item("Back", Tween::TRANS_BACK); + transition_selection->select(Tween::TRANS_LINEAR); // Default + ease_selection = memnew(OptionButton); + ease_selection->add_item("In", Tween::EASE_IN); + ease_selection->add_item("Out", Tween::EASE_OUT); + ease_selection->add_item("InOut", Tween::EASE_IN_OUT); + ease_selection->add_item("OutIn", Tween::EASE_OUT_IN); + ease_selection->select(Tween::EASE_IN_OUT); // Default + ease_fps = memnew(SpinBox); + ease_fps->set_min(1); + ease_fps->set_max(999); + ease_fps->set_step(1); + ease_fps->set_value(30); // Default + Label *ease_label1 = memnew(Label); + Label *ease_label2 = memnew(Label); + Label *ease_label3 = memnew(Label); + ease_label1->set_text("Transition Type:"); + ease_label2->set_text("Ease Type:"); + ease_label3->set_text("FPS:"); + ease_grid->add_child(ease_label1); + ease_grid->add_child(transition_selection); + ease_grid->add_child(ease_label2); + ease_grid->add_child(ease_selection); + ease_grid->add_child(ease_label3); + ease_grid->add_child(ease_fps); + + // + bake_dialog = memnew(ConfirmationDialog); + bake_dialog->set_title(TTR("Anim. Baker")); + bake_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_BAKE_ANIMATION_CONFIRM)); + add_child(bake_dialog); + GridContainer *bake_grid = memnew(GridContainer); + bake_grid->set_columns(2); + bake_dialog->add_child(bake_grid); + bake_trs = memnew(CheckBox); + bake_trs->set_pressed(true); + bake_blendshape = memnew(CheckBox); + bake_blendshape->set_pressed(true); + bake_value = memnew(CheckBox); + bake_value->set_pressed(true); + bake_fps = memnew(SpinBox); + bake_fps->set_min(1); + bake_fps->set_max(999); + bake_fps->set_step(1); + bake_fps->set_value(30); // Default + Label *bake_label1 = memnew(Label); + Label *bake_label2 = memnew(Label); + Label *bake_label3 = memnew(Label); + Label *bake_label4 = memnew(Label); + bake_label1->set_text("Pos/Rot/Scl3D Track:"); + bake_label2->set_text("Blendshape Track:"); + bake_label3->set_text("Value Track:"); + bake_label4->set_text("FPS:"); + bake_grid->add_child(bake_label1); + bake_grid->add_child(bake_trs); + bake_grid->add_child(bake_label2); + bake_grid->add_child(bake_blendshape); + bake_grid->add_child(bake_label3); + bake_grid->add_child(bake_value); + bake_grid->add_child(bake_label4); + bake_grid->add_child(bake_fps); + + // track_copy_dialog = memnew(ConfirmationDialog); add_child(track_copy_dialog); track_copy_dialog->set_title(TTR("Select Tracks to Copy")); diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index 806d3ffb14..025f910578 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -32,6 +32,7 @@ #define ANIMATION_TRACK_EDITOR_H #include "editor/editor_data.h" +#include "editor/editor_properties.h" #include "editor/editor_spin_slider.h" #include "editor/property_selector.h" @@ -143,7 +144,6 @@ class AnimationTrackEdit : public Control { MENU_INTERPOLATION_NEAREST, MENU_INTERPOLATION_LINEAR, MENU_INTERPOLATION_CUBIC, - MENU_INTERPOLATION_CUBIC_IN_TIME, MENU_LOOP_WRAP, MENU_LOOP_CLAMP, MENU_KEY_INSERT, @@ -323,8 +323,9 @@ class AnimationTrackEditor : public VBoxContainer { Vector<AnimationTrackEditGroup *> groups; bool animation_changing_awaiting_update = false; - void _animation_update(); + void _animation_update(); // Updated by AnimationTrackEditor(this) int _get_track_selected(); + void _sync_animation_change(); void _animation_changed(); void _update_tracks(); @@ -448,9 +449,16 @@ class AnimationTrackEditor : public VBoxContainer { void _toggle_bezier_edit(); void _cancel_bezier_edit(); void _bezier_edit(int p_for_track); + void _bezier_track_set_key_handle_mode(Animation *p_anim, int p_track, int p_index, Animation::HandleMode p_mode, Animation::HandleSetMode p_set_mode = Animation::HANDLE_SET_MODE_NONE); ////////////// edit menu stuff + ConfirmationDialog *bake_dialog = nullptr; + CheckBox *bake_trs = nullptr; + CheckBox *bake_blendshape = nullptr; + CheckBox *bake_value = nullptr; + SpinBox *bake_fps = nullptr; + ConfirmationDialog *optimize_dialog = nullptr; SpinBox *optimize_velocity_error = nullptr; SpinBox *optimize_angular_error = nullptr; @@ -464,6 +472,11 @@ class AnimationTrackEditor : public VBoxContainer { ConfirmationDialog *scale_dialog = nullptr; SpinBox *scale = nullptr; + ConfirmationDialog *ease_dialog = nullptr; + OptionButton *transition_selection = nullptr; + OptionButton *ease_selection = nullptr; + SpinBox *ease_fps = nullptr; + void _select_all_tracks_for_copy(); void _edit_menu_about_to_popup(); @@ -487,7 +500,7 @@ class AnimationTrackEditor : public VBoxContainer { NodePath full_path; NodePath base_path; Animation::TrackType track_type = Animation::TYPE_ANIMATION; - Animation::InterpolationType interp_type = Animation::INTERPOLATION_CUBIC_IN_TIME; + Animation::InterpolationType interp_type = Animation::INTERPOLATION_CUBIC; Animation::UpdateMode update_mode = Animation::UPDATE_CAPTURE; Animation::LoopMode loop_mode = Animation::LOOP_PINGPONG; bool loop_wrap = false; @@ -521,6 +534,8 @@ public: EDIT_SCALE_SELECTION, EDIT_SCALE_FROM_CURSOR, EDIT_SCALE_CONFIRM, + EDIT_EASE_SELECTION, + EDIT_EASE_CONFIRM, EDIT_DUPLICATE_SELECTION, EDIT_DUPLICATE_TRANSPOSED, EDIT_ADD_RESET_KEY, @@ -529,6 +544,8 @@ public: EDIT_GOTO_NEXT_STEP_TIMELINE_ONLY, // Next step without updating animation. EDIT_GOTO_PREV_STEP, EDIT_APPLY_RESET, + EDIT_BAKE_ANIMATION, + EDIT_BAKE_ANIMATION_CONFIRM, EDIT_OPTIMIZE_ANIMATION, EDIT_OPTIMIZE_ANIMATION_CONFIRM, EDIT_CLEAN_UP_ANIMATION, diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 9e72c8ec10..bdd30dc653 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1789,7 +1789,7 @@ void CodeTextEditor::toggle_bookmark() { } void CodeTextEditor::goto_next_bookmark() { - Array bmarks = text_editor->get_bookmarked_lines(); + PackedInt32Array bmarks = text_editor->get_bookmarked_lines(); if (bmarks.size() <= 0) { return; } @@ -1813,7 +1813,7 @@ void CodeTextEditor::goto_next_bookmark() { } void CodeTextEditor::goto_prev_bookmark() { - Array bmarks = text_editor->get_bookmarked_lines(); + PackedInt32Array bmarks = text_editor->get_bookmarked_lines(); if (bmarks.size() <= 0) { return; } diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 6c86b341da..dc8a64d904 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -840,6 +840,9 @@ void ConnectionsDock::_handle_signal_menu_option(int p_option) { disconnect_all_dialog->set_text(vformat(TTR("Are you sure you want to remove all connections from the \"%s\" signal?"), signal_name)); disconnect_all_dialog->popup_centered(); } break; + case COPY_NAME: { + DisplayServer::get_singleton()->clipboard_set(item->get_metadata(0).operator Dictionary()["name"]); + } break; } } @@ -1164,6 +1167,7 @@ ConnectionsDock::ConnectionsDock() { signal_menu->connect("id_pressed", callable_mp(this, &ConnectionsDock::_handle_signal_menu_option)); signal_menu->add_item(TTR("Connect..."), CONNECT); signal_menu->add_item(TTR("Disconnect All"), DISCONNECT_ALL); + signal_menu->add_item(TTR("Copy Name"), COPY_NAME); slot_menu = memnew(PopupMenu); add_child(slot_menu); diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h index 7e7192019b..352c5c99d6 100644 --- a/editor/connections_dialog.h +++ b/editor/connections_dialog.h @@ -177,13 +177,14 @@ class ConnectionsDock : public VBoxContainer { //Right-click Pop-up Menu Options. enum SignalMenuOption { CONNECT, - DISCONNECT_ALL + DISCONNECT_ALL, + COPY_NAME, }; enum SlotMenuOption { EDIT, GO_TO_SCRIPT, - DISCONNECT + DISCONNECT, }; Node *selected_node = nullptr; diff --git a/editor/debugger/editor_debugger_inspector.cpp b/editor/debugger/editor_debugger_inspector.cpp index 58206efc20..6c0ba55ec8 100644 --- a/editor/debugger/editor_debugger_inspector.cpp +++ b/editor/debugger/editor_debugger_inspector.cpp @@ -85,6 +85,7 @@ void EditorDebuggerRemoteObject::_bind_methods() { ClassDB::bind_method(D_METHOD("get_variant"), &EditorDebuggerRemoteObject::get_variant); ClassDB::bind_method(D_METHOD("clear"), &EditorDebuggerRemoteObject::clear); ClassDB::bind_method(D_METHOD("get_remote_object_id"), &EditorDebuggerRemoteObject::get_remote_object_id); + ClassDB::bind_method(D_METHOD("_is_read_only"), &EditorDebuggerRemoteObject::_is_read_only); ADD_SIGNAL(MethodInfo("value_edited", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "property"), PropertyInfo("value"))); } diff --git a/editor/debugger/editor_debugger_inspector.h b/editor/debugger/editor_debugger_inspector.h index 5aac4dbf11..c595e0acaa 100644 --- a/editor/debugger/editor_debugger_inspector.h +++ b/editor/debugger/editor_debugger_inspector.h @@ -50,6 +50,7 @@ public: HashMap<StringName, Variant> prop_values; ObjectID get_remote_object_id() { return remote_object_id; }; + bool _is_read_only() { return true; }; String get_title(); Variant get_variant(const StringName &p_name); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 64bdac1e77..231ae198d2 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -1143,8 +1143,8 @@ void EditorSelection::_emit_change() { emitted = false; } -Array EditorSelection::_get_transformable_selected_nodes() { - Array ret; +TypedArray<Node> EditorSelection::_get_transformable_selected_nodes() { + TypedArray<Node> ret; for (const Node *E : selected_node_list) { ret.push_back(E); diff --git a/editor/editor_data.h b/editor/editor_data.h index 655a62a9ae..1da188c546 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -271,7 +271,7 @@ class EditorSelection : public Object { List<Node *> selected_node_list; void _update_node_list(); - Array _get_transformable_selected_nodes(); + TypedArray<Node> _get_transformable_selected_nodes(); void _emit_change(); protected: diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 855f4b1366..122e6ad021 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -340,6 +340,8 @@ void EditorProperty::_notification(int p_what) { draw_string(font, Point2(ofs, v_ofs + font->get_ascent(font_size)), label, HORIZONTAL_ALIGNMENT_LEFT, text_limit, font_size, color); } + ofs = size.width; + if (keying) { Ref<Texture2D> key; @@ -349,7 +351,7 @@ void EditorProperty::_notification(int p_what) { key = get_theme_icon(SNAME("Key"), SNAME("EditorIcons")); } - ofs = size.width - key->get_width() - get_theme_constant(SNAME("hseparator"), SNAME("Tree")); + ofs -= key->get_width() + get_theme_constant(SNAME("hseparator"), SNAME("Tree")); Color color2(1, 1, 1); if (keying_hover) { @@ -373,7 +375,7 @@ void EditorProperty::_notification(int p_what) { close = get_theme_icon(SNAME("Close"), SNAME("EditorIcons")); - ofs = size.width - close->get_width() - get_theme_constant(SNAME("hseparator"), SNAME("Tree")); + ofs -= close->get_width() + get_theme_constant(SNAME("hseparator"), SNAME("Tree")); Color color2(1, 1, 1); if (delete_hover) { @@ -2628,15 +2630,28 @@ void EditorInspector::update_tree() { valid_plugins.push_back(inspector_plugins[i]); } - // Decide if properties should be drawn with the warning color (yellow). + // Decide if properties should be drawn with the warning color (yellow), + // or if the whole object should be considered read-only. bool draw_warning = false; + bool all_read_only = false; if (is_inside_tree()) { + if (object->has_method("_is_read_only")) { + all_read_only = object->call("_is_read_only"); + } + Node *nod = Object::cast_to<Node>(object); Node *es = EditorNode::get_singleton()->get_edited_scene(); if (nod && es != nod && nod->get_owner() != es) { // Draw in warning color edited nodes that are not in the currently edited scene, // as changes may be lost in the future. draw_warning = true; + } else { + if (!all_read_only) { + Resource *res = Object::cast_to<Resource>(object); + if (res) { + all_read_only = EditorNode::get_singleton()->is_resource_read_only(res); + } + } } } @@ -3179,7 +3194,6 @@ void EditorInspector::update_tree() { ep->property_usage = p.usage; //and set label? } - if (!editors[i].label.is_empty()) { ep->set_label(editors[i].label); } else { @@ -3206,7 +3220,7 @@ void EditorInspector::update_tree() { ep->set_checkable(checkable); ep->set_checked(checked); ep->set_keying(keying); - ep->set_read_only(property_read_only); + ep->set_read_only(property_read_only || all_read_only); ep->set_deletable(deletable_properties || p.name.begins_with("metadata/")); } @@ -3253,6 +3267,9 @@ void EditorInspector::update_tree() { add_md->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); add_md->connect(SNAME("pressed"), callable_mp(this, &EditorInspector::_show_add_meta_dialog)); main_vbox->add_child(add_md); + if (all_read_only) { + add_md->set_disabled(true); + } } // Get the lists of to add at the end. diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index dc03a1f270..f540e2b2a1 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -252,6 +252,11 @@ void EditorLog::_rebuild_log() { } void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) { + if (!is_inside_tree()) { + // The log will be built all at once when it enters the tree and has its theme items. + return; + } + // Only add the message to the log if it passes the filters. bool filter_active = type_filter_map[p_message.type]->is_active(); String search_text = search_box->get_text(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 362159cb56..d22b0ed554 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1250,7 +1250,9 @@ void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const St } void EditorNode::save_resource(const Ref<Resource> &p_resource) { - if (p_resource->get_path().is_resource_file()) { + // If the resource has been imported, ask the user to use a different path in order to save it. + String path = p_resource->get_path(); + if (path.is_resource_file() && !FileAccess::exists(path + ".import")) { save_resource_in_path(p_resource, p_resource->get_path()); } else { save_resource_as(p_resource); @@ -1260,11 +1262,18 @@ void EditorNode::save_resource(const Ref<Resource> &p_resource) { void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String &p_at_path) { { String path = p_resource->get_path(); - int srpos = path.find("::"); - if (srpos != -1) { - String base = path.substr(0, srpos); - if (!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base) { - show_warning(TTR("This resource can't be saved because it does not belong to the edited scene. Make it unique first.")); + if (!path.is_resource_file()) { + int srpos = path.find("::"); + if (srpos != -1) { + String base = path.substr(0, srpos); + if (!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base) { + show_warning(TTR("This resource can't be saved because it does not belong to the edited scene. Make it unique first.")); + return; + } + } + } else { + if (FileAccess::exists(path + ".import")) { + show_warning(TTR("This resource can't be saved because it was imported from another file. Make it unique first.")); return; } } @@ -2223,7 +2232,14 @@ void EditorNode::_edit_current(bool p_skip_foreign) { bool stay_in_script_editor_on_node_selected = bool(EDITOR_GET("text_editor/behavior/navigation/stay_in_script_editor_on_node_selected")); bool skip_main_plugin = false; - String editable_warning; // None by default. + String editable_info; // None by default. + bool info_is_warning = false; + + if (current_obj->has_method("_is_read_only")) { + if (current_obj->call("_is_read_only")) { + editable_info = TTR("This object is marked as read-only, so it's not editable."); + } + } if (is_resource) { Resource *current_res = Object::cast_to<Resource>(current_obj); @@ -2237,16 +2253,25 @@ void EditorNode::_edit_current(bool p_skip_foreign) { int subr_idx = current_res->get_path().find("::"); if (subr_idx != -1) { String base_path = current_res->get_path().substr(0, subr_idx); - if (FileAccess::exists(base_path + ".import")) { - editable_warning = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow."); + if (!base_path.is_resource_file()) { + if (FileAccess::exists(base_path + ".import")) { + if (get_edited_scene() && get_edited_scene()->get_scene_file_path() == base_path) { + info_is_warning = true; + } + editable_info = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow."); + } else { + if ((!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base_path) && ResourceLoader::get_resource_type(base_path) == "PackedScene") { + editable_info = TTR("This resource belongs to a scene that was instantiated or inherited.\nChanges to it must be made inside the original scene."); + } + } } else { - if ((!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base_path) && ResourceLoader::get_resource_type(base_path) == "PackedScene") { - editable_warning = TTR("This resource belongs to a scene that was instantiated or inherited.\nChanges to it won't be kept when saving the current scene."); + if (FileAccess::exists(base_path + ".import")) { + editable_info = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow."); } } } else if (current_res->get_path().is_resource_file()) { if (FileAccess::exists(current_res->get_path() + ".import")) { - editable_warning = TTR("This resource was imported, so it's not editable. Change its settings in the import panel and then re-import."); + editable_info = TTR("This resource was imported, so it's not editable. Change its settings in the import panel and then re-import."); } } } else if (is_node) { @@ -2270,7 +2295,8 @@ void EditorNode::_edit_current(bool p_skip_foreign) { if (get_edited_scene() && !get_edited_scene()->get_scene_file_path().is_empty()) { String source_scene = get_edited_scene()->get_scene_file_path(); if (FileAccess::exists(source_scene + ".import")) { - editable_warning = TTR("This scene was imported, so changes to it won't be kept.\nInstancing it or inheriting will allow making changes to it.\nPlease read the documentation relevant to importing scenes to better understand this workflow."); + editable_info = TTR("This scene was imported, so changes to it won't be kept.\nInstancing it or inheriting will allow making changes to it.\nPlease read the documentation relevant to importing scenes to better understand this workflow."); + info_is_warning = true; } } @@ -2278,7 +2304,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) { Node *selected_node = nullptr; if (current_obj->is_class("EditorDebuggerRemoteObject")) { - editable_warning = TTR("This is a remote object, so changes to it won't be kept.\nPlease read the documentation relevant to debugging to better understand this workflow."); + editable_info = TTR("This is a remote object, so it's not editable.\nPlease read the documentation relevant to debugging to better understand this workflow."); disable_folding = true; } else if (current_obj->is_class("MultiNodeEdit")) { Node *scene = get_edited_scene(); @@ -2313,7 +2339,10 @@ void EditorNode::_edit_current(bool p_skip_foreign) { InspectorDock::get_inspector_singleton()->update_tree(); } - InspectorDock::get_singleton()->set_warning(editable_warning); + InspectorDock::get_singleton()->set_info( + info_is_warning ? TTR("Changes may be lost!") : TTR("This object is read-only."), + editable_info, + info_is_warning); if (InspectorDock::get_inspector_singleton()->is_using_folding() == disable_folding) { InspectorDock::get_inspector_singleton()->set_use_folding(!disable_folding); @@ -2403,7 +2432,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) { String run_filename; - if (p_current || (editor_data.get_edited_scene_root() && !p_custom.is_empty() && p_custom == editor_data.get_edited_scene_root()->get_scene_file_path())) { + if ((p_current && p_custom.is_empty()) || (editor_data.get_edited_scene_root() && !p_custom.is_empty() && p_custom == editor_data.get_edited_scene_root()->get_scene_file_path())) { Node *scene = editor_data.get_edited_scene_root(); if (!scene) { @@ -2465,15 +2494,19 @@ void EditorNode::_run(bool p_current, const String &p_custom) { emit_signal(SNAME("play_pressed")); if (p_current) { + run_current_filename = run_filename; play_scene_button->set_pressed(true); play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"))); + play_scene_button->set_tooltip(TTR("Reload the played scene.")); } else if (!p_custom.is_empty()) { run_custom_filename = p_custom; play_custom_scene_button->set_pressed(true); play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"))); + play_custom_scene_button->set_tooltip(TTR("Reload the played scene.")); } else { play_button->set_pressed(true); play_button->set_icon(gui_base->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"))); + play_button->set_tooltip(TTR("Reload the played scene.")); } stop_button->set_disabled(false); @@ -2498,9 +2531,22 @@ void EditorNode::_run_native(const Ref<EditorExportPreset> &p_preset) { } } +void EditorNode::_reset_play_buttons() { + play_button->set_pressed(false); + play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); + play_button->set_tooltip(TTR("Play the project.")); + play_scene_button->set_pressed(false); + play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayScene"), SNAME("EditorIcons"))); + play_scene_button->set_tooltip(TTR("Play the edited scene.")); + play_custom_scene_button->set_pressed(false); + play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons"))); + play_custom_scene_button->set_tooltip(TTR("Play a custom scene.")); +} + void EditorNode::_android_build_source_selected(const String &p_file) { export_template_manager->install_android_template_from_file(p_file); } + void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if (!p_confirmed) { // FIXME: this may be a hack. current_menu_option = (MenuOptions)p_option; @@ -2792,7 +2838,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { quick_run->set_title(TTR("Quick Run Scene...")); play_custom_scene_button->set_pressed(false); } else { - String last_custom_scene = run_custom_filename; + String last_custom_scene = run_custom_filename; // This is necessary to have a copy of the string. run_play_custom(last_custom_scene); } @@ -2804,13 +2850,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { editor_run.stop(); run_custom_filename.clear(); - play_button->set_pressed(false); - play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); - play_scene_button->set_pressed(false); - play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayScene"), SNAME("EditorIcons"))); - play_custom_scene_button->set_pressed(false); - play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons"))); + run_current_filename.clear(); stop_button->set_disabled(true); + _reset_play_buttons(); if (bool(EDITOR_GET("run/output/always_close_output_on_stop"))) { for (int i = 0; i < bottom_panel_items.size(); i++) { @@ -2833,7 +2875,12 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } break; case RUN_PLAY_SCENE: { - run_play_current(); + if (run_current_filename.is_empty() || editor_run.get_status() == EditorRun::STATUS_STOP) { + run_play_current(); + } else { + String last_current_scene = run_current_filename; // This is necessary to have a copy of the string. + run_play_custom(last_current_scene); + } } break; case RUN_SETTINGS: { @@ -3828,6 +3875,37 @@ void EditorNode::edit_foreign_resource(Ref<Resource> p_resource) { InspectorDock::get_singleton()->call_deferred("edit_resource", p_resource); } +bool EditorNode::is_resource_read_only(Ref<Resource> p_resource) { + ERR_FAIL_COND_V(p_resource.is_null(), false); + + String path = p_resource->get_path(); + if (!path.is_resource_file()) { + // If the resource name contains '::', that means it is a subresource embedded in another resource. + int srpos = path.find("::"); + if (srpos != -1) { + String base = path.substr(0, srpos); + // If the base resource is a packed scene, we treat it as read-only if it is not the currently edited scene. + if (ResourceLoader::get_resource_type(base) == "PackedScene") { + if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) { + return true; + } + } else { + // If a corresponding .import file exists for the base file, we assume it to be imported and should therefore treated as read-only. + if (FileAccess::exists(base + ".import")) { + return true; + } + } + } + } else { + // The resource is not a subresource, but if it has an .import file, it's imported so treat it as read only. + if (FileAccess::exists(path + ".import")) { + return true; + } + } + + return false; +} + void EditorNode::request_instance_scene(const String &p_path) { SceneTreeDock::get_singleton()->instantiate(p_path); } @@ -5006,8 +5084,9 @@ void EditorNode::run_play_current() { } void EditorNode::run_play_custom(const String &p_custom) { + bool is_current = !run_current_filename.is_empty(); _menu_option_confirm(RUN_STOP, true); - _run(false, p_custom); + _run(is_current, p_custom); } void EditorNode::run_stop() { @@ -5837,6 +5916,7 @@ void EditorNode::_bind_methods() { ClassDB::bind_method("set_edited_scene", &EditorNode::set_edited_scene); ClassDB::bind_method("open_request", &EditorNode::open_request); ClassDB::bind_method("edit_foreign_resource", &EditorNode::edit_foreign_resource); + ClassDB::bind_method("is_resource_read_only", &EditorNode::is_resource_read_only); ClassDB::bind_method("_close_messages", &EditorNode::_close_messages); ClassDB::bind_method("_show_messages", &EditorNode::_show_messages); @@ -6166,6 +6246,7 @@ EditorNode::EditorNode() { add_child(editor_export); // Exporters might need the theme. + EditorColorMap::create(); theme = create_custom_theme(); register_exporters(); @@ -6720,10 +6801,8 @@ EditorNode::EditorNode() { play_button->set_flat(true); play_hb->add_child(play_button); play_button->set_toggle_mode(true); - play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); play_button->set_focus_mode(Control::FOCUS_NONE); play_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY)); - play_button->set_tooltip(TTR("Play the project.")); ED_SHORTCUT_AND_COMMAND("editor/play", TTR("Play"), Key::F5); ED_SHORTCUT_OVERRIDE("editor/play", "macos", KeyModifierMask::CMD | Key::B); @@ -6764,9 +6843,7 @@ EditorNode::EditorNode() { play_hb->add_child(play_scene_button); play_scene_button->set_toggle_mode(true); play_scene_button->set_focus_mode(Control::FOCUS_NONE); - play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayScene"), SNAME("EditorIcons"))); play_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_SCENE)); - play_scene_button->set_tooltip(TTR("Play the edited scene.")); ED_SHORTCUT_AND_COMMAND("editor/play_scene", TTR("Play Scene"), Key::F6); ED_SHORTCUT_OVERRIDE("editor/play_scene", "macos", KeyModifierMask::CMD | Key::R); @@ -6777,9 +6854,9 @@ EditorNode::EditorNode() { play_hb->add_child(play_custom_scene_button); play_custom_scene_button->set_toggle_mode(true); play_custom_scene_button->set_focus_mode(Control::FOCUS_NONE); - play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons"))); play_custom_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_CUSTOM_SCENE)); - play_custom_scene_button->set_tooltip(TTR("Play custom scene")); + + _reset_play_buttons(); ED_SHORTCUT_AND_COMMAND("editor/play_custom_scene", TTR("Play Custom Scene"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::F5); ED_SHORTCUT_OVERRIDE("editor/play_custom_scene", "macos", KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::R); @@ -7232,7 +7309,7 @@ EditorNode::EditorNode() { canvas_item_mat_convert.instantiate(); resource_conversion_plugins.push_back(canvas_item_mat_convert); - Ref<ParticlesMaterialConversionPlugin> particles_mat_convert; + Ref<ParticleProcessMaterialConversionPlugin> particles_mat_convert; particles_mat_convert.instantiate(); resource_conversion_plugins.push_back(particles_mat_convert); diff --git a/editor/editor_node.h b/editor/editor_node.h index 7400bcd422..afddcebcf0 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -470,7 +470,9 @@ private: String _tmp_import_path; String external_file; String open_navigate; + String run_custom_filename; + String run_current_filename; DynamicFontImportSettings *fontdata_import_settings = nullptr; SceneImportSettings *scene_import_settings = nullptr; @@ -580,6 +582,7 @@ private: void _run(bool p_current = false, const String &p_custom = ""); void _run_native(const Ref<EditorExportPreset> &p_preset); + void _reset_play_buttons(); void _add_to_recent_scenes(const String &p_scene); void _update_recent_scenes(); @@ -776,6 +779,8 @@ public: void open_request(const String &p_path); void edit_foreign_resource(Ref<Resource> p_resource); + bool is_resource_read_only(Ref<Resource> p_resource); + bool is_changing_scene() const; Control *get_main_control(); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 2e64e46519..b0bd500ef8 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -48,7 +48,7 @@ #include "scene/gui/popup_menu.h" #include "servers/rendering_server.h" -Array EditorInterface::_make_mesh_previews(const Array &p_meshes, int p_preview_size) { +TypedArray<Texture2D> EditorInterface::_make_mesh_previews(const Array &p_meshes, int p_preview_size) { Vector<Ref<Mesh>> meshes; for (int i = 0; i < p_meshes.size(); i++) { @@ -56,7 +56,7 @@ Array EditorInterface::_make_mesh_previews(const Array &p_meshes, int p_preview_ } Vector<Ref<Texture2D>> textures = make_mesh_previews(meshes, nullptr, p_preview_size); - Array ret; + TypedArray<Texture2D> ret; for (int i = 0; i < textures.size(); i++) { ret.push_back(textures[i]); } @@ -216,8 +216,8 @@ Node *EditorInterface::get_edited_scene_root() { return EditorNode::get_singleton()->get_edited_scene(); } -Array EditorInterface::get_open_scenes() const { - Array ret; +PackedStringArray EditorInterface::get_open_scenes() const { + PackedStringArray ret; Vector<EditorData::EditedScene> scenes = EditorNode::get_editor_data().get_edited_scenes(); int scns_amount = scenes.size(); diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 201c7790a3..8357f0960a 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -67,7 +67,7 @@ protected: static void _bind_methods(); static EditorInterface *singleton; - Array _make_mesh_previews(const Array &p_meshes, int p_preview_size); + TypedArray<Texture2D> _make_mesh_previews(const Array &p_meshes, int p_preview_size); public: static EditorInterface *get_singleton() { return singleton; } @@ -87,7 +87,7 @@ public: String get_playing_scene() const; Node *get_edited_scene_root(); - Array get_open_scenes() const; + PackedStringArray get_open_scenes() const; ScriptEditor *get_script_editor(); EditorCommandPalette *get_command_palette() const; diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index f434df3a1e..84c4c9c877 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -2613,8 +2613,47 @@ void EditorPropertyQuaternion::_set_read_only(bool p_read_only) { for (int i = 0; i < 4; i++) { spin[i]->set_read_only(p_read_only); } + for (int i = 0; i < 3; i++) { + euler[i]->set_read_only(p_read_only); + } }; +void EditorPropertyQuaternion::_edit_custom_value() { + if (edit_button->is_pressed()) { + edit_custom_bc->show(); + for (int i = 0; i < 3; i++) { + euler[i]->grab_focus(); + } + } else { + edit_custom_bc->hide(); + for (int i = 0; i < 4; i++) { + spin[i]->grab_focus(); + } + } + update_property(); +} + +void EditorPropertyQuaternion::_custom_value_changed(double val) { + if (setting) { + return; + } + + edit_euler.x = euler[0]->get_value(); + edit_euler.y = euler[1]->get_value(); + edit_euler.z = euler[2]->get_value(); + + Vector3 v; + v.x = Math::deg2rad(edit_euler.x); + v.y = Math::deg2rad(edit_euler.y); + v.z = Math::deg2rad(edit_euler.z); + + Quaternion temp_q = Quaternion(v); + spin[0]->set_value(temp_q.x); + spin[1]->set_value(temp_q.y); + spin[2]->set_value(temp_q.z); + spin[3]->set_value(temp_q.w); +} + void EditorPropertyQuaternion::_value_changed(double val, const String &p_name) { if (setting) { return; @@ -2625,9 +2664,18 @@ void EditorPropertyQuaternion::_value_changed(double val, const String &p_name) p.y = spin[1]->get_value(); p.z = spin[2]->get_value(); p.w = spin[3]->get_value(); + emit_changed(get_edited_property(), p, p_name); } +bool EditorPropertyQuaternion::is_grabbing_euler() { + bool is_grabbing = false; + for (int i = 0; i < 3; i++) { + is_grabbing |= euler[i]->is_grabbing(); + } + return is_grabbing; +} + void EditorPropertyQuaternion::update_property() { Quaternion val = get_edited_object()->get(get_edited_property()); setting = true; @@ -2635,9 +2683,22 @@ void EditorPropertyQuaternion::update_property() { spin[1]->set_value(val.y); spin[2]->set_value(val.z); spin[3]->set_value(val.w); + if (!is_grabbing_euler()) { + Vector3 v = val.normalized().get_euler_yxz(); + edit_euler.x = Math::rad2deg(v.x); + edit_euler.y = Math::rad2deg(v.y); + edit_euler.z = Math::rad2deg(v.z); + euler[0]->set_value(edit_euler.x); + euler[1]->set_value(edit_euler.y); + euler[2]->set_value(edit_euler.z); + } setting = false; } +void EditorPropertyQuaternion::_warning_pressed() { + warning_dialog->popup_centered(); +} + void EditorPropertyQuaternion::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: @@ -2646,6 +2707,13 @@ void EditorPropertyQuaternion::_notification(int p_what) { for (int i = 0; i < 4; i++) { spin[i]->add_theme_color_override("label_color", colors[i]); } + for (int i = 0; i < 3; i++) { + euler[i]->add_theme_color_override("label_color", colors[i]); + } + edit_button->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons"))); + euler_label->add_theme_color_override(SNAME("font_color"), get_theme_color(SNAME("property_color"), SNAME("Editor"))); + warning->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons"))); + warning->add_theme_color_override(SNAME("font_color"), get_theme_color(SNAME("warning_color"), SNAME("Editor"))); } break; } } @@ -2653,7 +2721,7 @@ void EditorPropertyQuaternion::_notification(int p_what) { void EditorPropertyQuaternion::_bind_methods() { } -void EditorPropertyQuaternion::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) { +void EditorPropertyQuaternion::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix, bool p_hide_editor) { for (int i = 0; i < 4; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); @@ -2665,28 +2733,50 @@ void EditorPropertyQuaternion::setup(double p_min, double p_max, double p_step, // a generic way to store 4 values, so we'll still respect the suffix. spin[i]->set_suffix(p_suffix); } + + for (int i = 0; i < 3; i++) { + euler[i]->set_min(-360); + euler[i]->set_max(360); + euler[i]->set_step(0.1); + euler[i]->set_hide_slider(false); + euler[i]->set_allow_greater(true); + euler[i]->set_allow_lesser(true); + euler[i]->set_suffix(U"\u00B0"); + } + + if (p_hide_editor) { + edit_button->hide(); + } } EditorPropertyQuaternion::EditorPropertyQuaternion() { bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector_types_editing"); - BoxContainer *bc; - + VBoxContainer *bc = memnew(VBoxContainer); + edit_custom_bc = memnew(VBoxContainer); + BoxContainer *edit_custom_layout; if (horizontal) { - bc = memnew(HBoxContainer); - add_child(bc); + default_layout = memnew(HBoxContainer); + edit_custom_layout = memnew(HBoxContainer); set_bottom_editor(bc); } else { - bc = memnew(VBoxContainer); - add_child(bc); + default_layout = memnew(VBoxContainer); + edit_custom_layout = memnew(VBoxContainer); } + edit_custom_bc->hide(); + add_child(bc); + edit_custom_bc->set_h_size_flags(SIZE_EXPAND_FILL); + default_layout->set_h_size_flags(SIZE_EXPAND_FILL); + edit_custom_layout->set_h_size_flags(SIZE_EXPAND_FILL); + bc->add_child(default_layout); + bc->add_child(edit_custom_bc); static const char *desc[4] = { "x", "y", "z", "w" }; for (int i = 0; i < 4; i++) { spin[i] = memnew(EditorSpinSlider); spin[i]->set_flat(true); spin[i]->set_label(desc[i]); - bc->add_child(spin[i]); + default_layout->add_child(spin[i]); add_focusable(spin[i]); spin[i]->connect("value_changed", callable_mp(this, &EditorPropertyQuaternion::_value_changed).bind(desc[i])); if (horizontal) { @@ -2694,6 +2784,41 @@ EditorPropertyQuaternion::EditorPropertyQuaternion() { } } + warning = memnew(Button); + warning->set_text(TTR("Temporary Euler may be changed implicitly!")); + warning->set_clip_text(true); + warning->connect("pressed", callable_mp(this, &EditorPropertyQuaternion::_warning_pressed)); + warning_dialog = memnew(AcceptDialog); + add_child(warning_dialog); + warning_dialog->set_text(TTR("Temporary Euler will not be stored in the object with the original value. Instead, it will be stored as Quaternion with irreversible conversion.\nThis is due to the fact that the result of Euler->Quaternion can be determined uniquely, but the result of Quaternion->Euler can be multi-existent.")); + + euler_label = memnew(Label); + euler_label->set_text("Temporary Euler"); + + edit_custom_bc->add_child(warning); + edit_custom_bc->add_child(edit_custom_layout); + edit_custom_layout->add_child(euler_label); + + for (int i = 0; i < 3; i++) { + euler[i] = memnew(EditorSpinSlider); + euler[i]->set_flat(true); + euler[i]->set_label(desc[i]); + edit_custom_layout->add_child(euler[i]); + add_focusable(euler[i]); + euler[i]->connect("value_changed", callable_mp(this, &EditorPropertyQuaternion::_custom_value_changed)); + if (horizontal) { + euler[i]->set_h_size_flags(SIZE_EXPAND_FILL); + } + } + + edit_button = memnew(Button); + edit_button->set_flat(true); + edit_button->set_toggle_mode(true); + default_layout->add_child(edit_button); + edit_button->connect("pressed", callable_mp(this, &EditorPropertyQuaternion::_edit_custom_value)); + + add_focusable(edit_button); + if (!horizontal) { set_label_reference(spin[0]); //show text and buttons around this } @@ -3653,20 +3778,24 @@ void EditorPropertyResource::_set_read_only(bool p_read_only) { resource_picker->set_editable(!p_read_only); }; -void EditorPropertyResource::_resource_selected(const Ref<Resource> &p_resource, bool p_edit) { +void EditorPropertyResource::_resource_selected(const Ref<Resource> &p_resource, bool p_inspect) { if (p_resource->is_built_in() && !p_resource->get_path().is_empty()) { String parent = p_resource->get_path().get_slice("::", 0); List<String> extensions; ResourceLoader::get_recognized_extensions_for_type("PackedScene", &extensions); - if (extensions.find(parent.get_extension()) && (!EditorNode::get_singleton()->get_edited_scene() || EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path() != parent)) { - // If the resource belongs to another scene, edit it in that scene instead. - EditorNode::get_singleton()->call_deferred("edit_foreign_resource", p_resource); - return; + if (p_inspect) { + if (extensions.find(parent.get_extension()) && (!EditorNode::get_singleton()->get_edited_scene() || EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path() != parent)) { + // If the resource belongs to another (non-imported) scene, edit it in that scene instead. + if (!FileAccess::exists(parent + ".import")) { + EditorNode::get_singleton()->call_deferred("edit_foreign_resource", p_resource); + return; + } + } } } - if (!p_edit && use_sub_inspector) { + if (!p_inspect && use_sub_inspector) { bool unfold = !get_edited_object()->editor_is_section_unfolded(get_edited_property()); get_edited_object()->editor_set_section_unfold(get_edited_property(), unfold); update_property(); @@ -4357,7 +4486,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_ case Variant::QUATERNION: { EditorPropertyQuaternion *editor = memnew(EditorPropertyQuaternion); EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step); - editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix); + editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix, p_hint == PROPERTY_HINT_HIDE_QUATERNION_EDIT); return editor; } break; case Variant::AABB: { diff --git a/editor/editor_properties.h b/editor/editor_properties.h index c1dfb5cb1e..6ac3973303 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -625,9 +625,26 @@ public: class EditorPropertyQuaternion : public EditorProperty { GDCLASS(EditorPropertyQuaternion, EditorProperty); + BoxContainer *default_layout = nullptr; EditorSpinSlider *spin[4]; bool setting = false; + + Button *warning = nullptr; + AcceptDialog *warning_dialog = nullptr; + + Label *euler_label = nullptr; + VBoxContainer *edit_custom_bc = nullptr; + EditorSpinSlider *euler[3]; + Button *edit_button = nullptr; + + Vector3 edit_euler = Vector3(); + void _value_changed(double p_val, const String &p_name); + void _edit_custom_value(); + void _custom_value_changed(double p_val); + void _warning_pressed(); + + bool is_grabbing_euler(); protected: virtual void _set_read_only(bool p_read_only) override; @@ -636,7 +653,7 @@ protected: public: virtual void update_property() override; - void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String()); + void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String(), bool p_hide_editor = false); EditorPropertyQuaternion(); }; @@ -835,7 +852,7 @@ class EditorPropertyResource : public EditorProperty { bool updating_theme = false; bool opened_editor = false; - void _resource_selected(const Ref<Resource> &p_resource, bool p_edit); + void _resource_selected(const Ref<Resource> &p_resource, bool p_inspect); void _resource_changed(const Ref<Resource> &p_resource); void _viewport_selected(const NodePath &p_path); diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index e5c1836205..7e42c45b01 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -81,6 +81,8 @@ void EditorResourcePicker::_update_resource() { } else if (edited_resource.is_valid()) { assign_button->set_tooltip(resource_path + TTR("Type:") + " " + edited_resource->get_class()); } + + assign_button->set_disabled(!editable && !edited_resource.is_valid()); } void EditorResourcePicker::_update_resource_preview(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, ObjectID p_obj) { @@ -171,35 +173,50 @@ void EditorResourcePicker::_update_menu_items() { edit_menu->clear(); // Add options for creating specific subtypes of the base resource type. - set_create_options(edit_menu); + if (is_editable()) { + set_create_options(edit_menu); - // Add an option to load a resource from a file using the QuickOpen dialog. - edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Quick Load"), OBJ_MENU_QUICKLOAD); + // Add an option to load a resource from a file using the QuickOpen dialog. + edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Quick Load"), OBJ_MENU_QUICKLOAD); - // Add an option to load a resource from a file using the regular file dialog. - edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Load"), OBJ_MENU_LOAD); + // Add an option to load a resource from a file using the regular file dialog. + edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Load"), OBJ_MENU_LOAD); + } // Add options for changing existing value of the resource. if (edited_resource.is_valid()) { - edit_menu->add_icon_item(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")), TTR("Edit"), OBJ_MENU_EDIT); - edit_menu->add_icon_item(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")), TTR("Clear"), OBJ_MENU_CLEAR); - edit_menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE); - - // Check whether the resource has subresources. - List<PropertyInfo> property_list; - edited_resource->get_property_list(&property_list); - bool has_subresources = false; - for (PropertyInfo &p : property_list) { - if ((p.type == Variant::OBJECT) && (p.hint == PROPERTY_HINT_RESOURCE_TYPE) && (p.name != "script")) { - has_subresources = true; - break; - } - } - if (has_subresources) { - edit_menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Make Unique (Recursive)"), OBJ_MENU_MAKE_UNIQUE_RECURSIVE); + // Determine if the edited resource is part of another scene (foreign) which was imported + bool is_edited_resource_foreign_import = EditorNode::get_singleton()->is_resource_read_only(edited_resource); + + // If the resource is determined to be foreign and imported, change the menu entry's description to 'inspect' rather than 'edit' + // since will only be able to view its properties in read-only mode. + if (is_edited_resource_foreign_import) { + // The 'Search' icon is a magnifying glass, which seems appropriate, but maybe a bespoke icon is preferred here. + edit_menu->add_icon_item(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")), TTR("Inspect"), OBJ_MENU_INSPECT); + } else { + edit_menu->add_icon_item(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")), TTR("Edit"), OBJ_MENU_INSPECT); } - edit_menu->add_icon_item(get_theme_icon(SNAME("Save"), SNAME("EditorIcons")), TTR("Save"), OBJ_MENU_SAVE); + if (is_editable()) { + edit_menu->add_icon_item(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")), TTR("Clear"), OBJ_MENU_CLEAR); + edit_menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE); + + // Check whether the resource has subresources. + List<PropertyInfo> property_list; + edited_resource->get_property_list(&property_list); + bool has_subresources = false; + for (PropertyInfo &p : property_list) { + if ((p.type == Variant::OBJECT) && (p.hint == PROPERTY_HINT_RESOURCE_TYPE) && (p.name != "script")) { + has_subresources = true; + break; + } + } + if (has_subresources) { + edit_menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Make Unique (Recursive)"), OBJ_MENU_MAKE_UNIQUE_RECURSIVE); + } + + edit_menu->add_icon_item(get_theme_icon(SNAME("Save"), SNAME("EditorIcons")), TTR("Save"), OBJ_MENU_SAVE); + } if (edited_resource->get_path().is_resource_file()) { edit_menu->add_separator(); @@ -210,14 +227,16 @@ void EditorResourcePicker::_update_menu_items() { // Add options to copy/paste resource. Ref<Resource> cb = EditorSettings::get_singleton()->get_resource_clipboard(); bool paste_valid = false; - if (cb.is_valid()) { - if (base_type.is_empty()) { - paste_valid = true; - } else { - for (int i = 0; i < base_type.get_slice_count(","); i++) { - if (ClassDB::is_parent_class(cb->get_class(), base_type.get_slice(",", i))) { - paste_valid = true; - break; + if (is_editable()) { + if (cb.is_valid()) { + if (base_type.is_empty()) { + paste_valid = true; + } else { + for (int i = 0; i < base_type.get_slice_count(","); i++) { + if (ClassDB::is_parent_class(cb->get_class(), base_type.get_slice(",", i))) { + paste_valid = true; + break; + } } } } @@ -236,7 +255,7 @@ void EditorResourcePicker::_update_menu_items() { } // Add options to convert existing resource to another type of resource. - if (edited_resource.is_valid()) { + if (is_editable() && edited_resource.is_valid()) { Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(edited_resource); if (conversions.size()) { edit_menu->add_separator(); @@ -295,7 +314,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) { quick_open->set_title(TTR("Resource")); } break; - case OBJ_MENU_EDIT: { + case OBJ_MENU_INSPECT: { if (edited_resource.is_valid()) { emit_signal(SNAME("resource_selected"), edited_resource, true); } @@ -491,20 +510,21 @@ void EditorResourcePicker::_button_draw() { } void EditorResourcePicker::_button_input(const Ref<InputEvent> &p_event) { - if (!editable) { - return; - } - Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { if (mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) { - _update_menu_items(); - - Vector2 pos = get_screen_position() + mb->get_position(); - edit_menu->reset_size(); - edit_menu->set_position(pos); - edit_menu->popup(); + // Only attempt to update and show the menu if we have + // a valid resource or the Picker is editable, as + // there will otherwise be nothing to display. + if (edited_resource.is_valid() || is_editable()) { + _update_menu_items(); + + Vector2 pos = get_screen_position() + mb->get_position(); + edit_menu->reset_size(); + edit_menu->set_position(pos); + edit_menu->popup(); + } } } } @@ -734,7 +754,7 @@ void EditorResourcePicker::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toggle_mode"), "set_toggle_mode", "is_toggle_mode"); - ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::BOOL, "edit"))); + ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::BOOL, "inspect"))); ADD_SIGNAL(MethodInfo("resource_changed", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); } @@ -866,7 +886,7 @@ void EditorResourcePicker::set_toggle_pressed(bool p_pressed) { void EditorResourcePicker::set_editable(bool p_editable) { editable = p_editable; - assign_button->set_disabled(!editable); + assign_button->set_disabled(!editable && !edited_resource.is_valid()); edit_button->set_visible(editable); } diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h index 3a4d5985bd..3d6127e656 100644 --- a/editor/editor_resource_picker.h +++ b/editor/editor_resource_picker.h @@ -63,7 +63,7 @@ class EditorResourcePicker : public HBoxContainer { enum MenuOption { OBJ_MENU_LOAD, OBJ_MENU_QUICKLOAD, - OBJ_MENU_EDIT, + OBJ_MENU_INSPECT, OBJ_MENU_CLEAR, OBJ_MENU_MAKE_UNIQUE, OBJ_MENU_MAKE_UNIQUE_RECURSIVE, diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp index cbca3e9dcd..1faefb5af7 100644 --- a/editor/editor_sectioned_inspector.cpp +++ b/editor/editor_sectioned_inspector.cpp @@ -113,11 +113,11 @@ class SectionedInspectorFilter : public Object { } } - bool property_can_revert(const String &p_name) { + bool property_can_revert(const StringName &p_name) { return edited->property_can_revert(section + "/" + p_name); } - Variant property_get_revert(const String &p_name) { + Variant property_get_revert(const StringName &p_name) { return edited->property_get_revert(section + "/" + p_name); } diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 509488a66a..353dfb777c 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -963,8 +963,8 @@ void EditorSettings::save() { } } -Array EditorSettings::get_changed_settings() const { - Array arr; +PackedStringArray EditorSettings::get_changed_settings() const { + PackedStringArray arr; for (const String &setting : changed_settings) { arr.push_back(setting); } diff --git a/editor/editor_settings.h b/editor/editor_settings.h index f921171c57..09bc4caa22 100644 --- a/editor/editor_settings.h +++ b/editor/editor_settings.h @@ -141,7 +141,7 @@ public: } } void add_property_hint(const PropertyInfo &p_hint); - Array get_changed_settings() const; + PackedStringArray get_changed_settings() const; bool check_changed_settings_in_group(const String &p_setting_prefix) const; void mark_setting_changed(const String &p_setting); diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index 20e9d7a3df..5b98460e8e 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -605,6 +605,10 @@ bool EditorSpinSlider::is_flat() const { return flat; } +bool EditorSpinSlider::is_grabbing() const { + return grabbing_grabber || grabbing_spinner; +} + void EditorSpinSlider::_focus_entered() { _ensure_input_popup(); Rect2 gr = get_screen_rect(); diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h index f0adf5b7a1..afcaa3e4b6 100644 --- a/editor/editor_spin_slider.h +++ b/editor/editor_spin_slider.h @@ -110,6 +110,8 @@ public: void set_flat(bool p_enable); bool is_flat() const; + bool is_grabbing() const; + void setup_and_show() { _focus_entered(); } LineEdit *get_line_edit(); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 3da9899052..827a657a31 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -32,7 +32,6 @@ #include "core/error/error_macros.h" #include "core/io/resource_loader.h" -#include "core/variant/dictionary.h" #include "editor/editor_fonts.h" #include "editor/editor_icons.gen.h" #include "editor/editor_scale.h" @@ -43,6 +42,118 @@ #include "modules/svg/image_loader_svg.h" #endif +HashMap<Color, Color> EditorColorMap::editor_color_map; + +void EditorColorMap::add_color_pair(const String p_from_color, const String p_to_color) { + editor_color_map[Color::html(p_from_color)] = Color::html(p_to_color); +} + +void EditorColorMap::create() { + // Some of the colors below are listed for completeness sake. + // This can be a basis for proper palette validation later. + + // Convert: FROM TO + add_color_pair("#478cbf", "#478cbf"); // Godot Blue + add_color_pair("#414042", "#414042"); // Godot Gray + + add_color_pair("#ffffff", "#414141"); // Pure white + add_color_pair("#000000", "#bfbfbf"); // Pure black + // Keep pure RGB colors as is, but list them for explicitly. + add_color_pair("#ff0000", "#ff0000"); // Pure red + add_color_pair("#00ff00", "#00ff00"); // Pure green + add_color_pair("#0000ff", "#0000ff"); // Pure blue + + // GUI Colors + add_color_pair("#e0e0e0", "#5a5a5a"); // Common icon color + add_color_pair("#fefefe", "#fefefe"); // Forced light color + add_color_pair("#808080", "#808080"); // GUI disabled color + add_color_pair("#b3b3b3", "#363636"); // GUI disabled light color + add_color_pair("#699ce8", "#699ce8"); // GUI highlight color + add_color_pair("#f9f9f9", "#606060"); // Scrollbar grabber highlight color + + add_color_pair("#c38ef1", "#a85de9"); // Animation + add_color_pair("#fc7f7f", "#cd3838"); // Spatial + add_color_pair("#8da5f3", "#3d64dd"); // 2D + add_color_pair("#4b70ea", "#1a3eac"); // 2D Dark + add_color_pair("#8eef97", "#2fa139"); // Control + + add_color_pair("#5fb2ff", "#0079f0"); // Selection (blue) + add_color_pair("#003e7a", "#2b74bb"); // Selection (darker blue) + add_color_pair("#f7f5cf", "#615f3a"); // Gizmo (yellow) + + // Rainbow + add_color_pair("#ff4545", "#ff2929"); // Red + add_color_pair("#ffe345", "#ffe337"); // Yellow + add_color_pair("#80ff45", "#74ff34"); // Green + add_color_pair("#45ffa2", "#2cff98"); // Aqua + add_color_pair("#45d7ff", "#22ccff"); // Blue + add_color_pair("#8045ff", "#702aff"); // Purple + add_color_pair("#ff4596", "#ff2781"); // Pink + + // Audio gradients + add_color_pair("#e1da5b", "#d6cf4b"); // Yellow + + add_color_pair("#62aeff", "#1678e0"); // Frozen gradient top + add_color_pair("#75d1e6", "#41acc5"); // Frozen gradient middle + add_color_pair("#84ffee", "#49ccba"); // Frozen gradient bottom + + add_color_pair("#f70000", "#c91616"); // Color track red + add_color_pair("#eec315", "#d58c0b"); // Color track orange + add_color_pair("#dbee15", "#b7d10a"); // Color track yellow + add_color_pair("#288027", "#218309"); // Color track green + + // Resource groups + add_color_pair("#ffca5f", "#fea900"); // Mesh resource (orange) + add_color_pair("#2998ff", "#68b6ff"); // Shape resource (blue) + add_color_pair("#a2d2ff", "#4998e3"); // Shape resource (light blue) + + // Animation editor tracks + // The property track icon color is set by the common icon color. + add_color_pair("#ea7940", "#bd5e2c"); // 3D Position track + add_color_pair("#ff2b88", "#bd165f"); // 3D Rotation track + add_color_pair("#eac840", "#bd9d1f"); // 3D Scale track + add_color_pair("#3cf34e", "#16a827"); // Call Method track + add_color_pair("#2877f6", "#236be6"); // Bezier Curve track + add_color_pair("#eae440", "#9f9722"); // Audio Playback track + add_color_pair("#a448f0", "#9853ce"); // Animation Playback track + add_color_pair("#5ad5c4", "#0a9c88"); // Blend Shape track + + // Control layouts + add_color_pair("#d6d6d6", "#474747"); // Highlighted part + add_color_pair("#474747", "#d6d6d6"); // Background part + add_color_pair("#919191", "#6e6e6e"); // Border part + + // TileSet editor icons + add_color_pair("#fce00e", "#aa8d24"); // New Single Tile + add_color_pair("#0e71fc", "#0350bd"); // New Autotile + add_color_pair("#c6ced4", "#828f9b"); // New Atlas + + // Visual script + add_color_pair("#41ecad", "#25e3a0"); // VisualScript variant + add_color_pair("#6f91f0", "#6d8eeb"); // VisualScript bool + add_color_pair("#5abbef", "#4fb2e9"); // VisualScript int + add_color_pair("#35d4f4", "#27ccf0"); // VisualScript float + add_color_pair("#4593ec", "#4690e7"); // VisualScript String + add_color_pair("#ac73f1", "#ad76ee"); // VisualScript Vector2 + add_color_pair("#f1738f", "#ee758e"); // VisualScript Rect2 + add_color_pair("#de66f0", "#dc6aed"); // VisualScript Vector3 + add_color_pair("#b9ec41", "#96ce1a"); // VisualScript Transform2D + add_color_pair("#f74949", "#f77070"); // VisualScript Plane + add_color_pair("#ec418e", "#ec69a3"); // VisualScript Quat + add_color_pair("#ee5677", "#ee7991"); // VisualScript AABB + add_color_pair("#e1ec41", "#b2bb19"); // VisualScript Basis + add_color_pair("#f68f45", "#f49047"); // VisualScript Transform + add_color_pair("#417aec", "#6993ec"); // VisualScript NodePath + add_color_pair("#41ec80", "#2ce573"); // VisualScript RID + add_color_pair("#55f3e3", "#12d5c3"); // VisualScript Object + add_color_pair("#54ed9e", "#57e99f"); // VisualScript Dictionary + // Visual shaders + add_color_pair("#77ce57", "#67c046"); // Vector funcs + add_color_pair("#ea686c", "#d95256"); // Vector transforms + add_color_pair("#eac968", "#d9b64f"); // Textures and cubemaps + add_color_pair("#cf68ea", "#c050dd"); // Functions and expressions +} + static Ref<StyleBoxTexture> make_stylebox(Ref<Texture2D> p_texture, float p_left, float p_top, float p_right, float p_bottom, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, bool p_draw_center = true) { Ref<StyleBoxTexture> style(memnew(StyleBoxTexture)); style->set_texture(p_texture); @@ -113,7 +224,7 @@ static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false, #ifdef MODULE_SVG_ENABLED // See also `generate_icon()` in `scene/resources/default_theme.cpp`. -static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color, float p_scale = EDSCALE, float p_saturation = 1.0, Dictionary p_convert_colors = Dictionary()) { +static Ref<ImageTexture> editor_generate_icon(int p_index, float p_scale, float p_saturation, const HashMap<Color, Color> &p_convert_colors = HashMap<Color, Color>()) { Ref<Image> img = memnew(Image); // Upsample icon generation only if the editor scale isn't an integer multiplier. @@ -121,8 +232,7 @@ static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color, // with integer editor scales. const bool upsample = !Math::is_equal_approx(Math::round(p_scale), p_scale); ImageLoaderSVG img_loader; - img_loader.set_replace_colors(p_convert_colors); - img_loader.create_image_from_string(img, editor_icons_sources[p_index], p_scale, upsample, p_convert_color); + img_loader.create_image_from_string(img, editor_icons_sources[p_index], p_scale, upsample, p_convert_colors); if (p_saturation != 1.0) { img->adjust_bcs(1.0, 1.0, p_saturation); } @@ -132,126 +242,18 @@ static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color, } #endif -#ifndef ADD_CONVERT_COLOR -#define ADD_CONVERT_COLOR(dictionary, old_color, new_color) dictionary[Color::html(old_color)] = Color::html(new_color) -#endif - void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = true, int p_thumb_size = 32, bool p_only_thumbs = false, float p_icon_saturation = 1.0) { #ifdef MODULE_SVG_ENABLED - // The default icon theme is designed to be used for a dark theme. - // This dictionary stores Color values to convert to other colors - // for better readability on a light theme. - // Godot Color values are used to avoid the ambiguity of strings - // (where "#ffffff", "fff", and "white" are all equivalent). - Dictionary dark_icon_color_dictionary; + HashMap<Color, Color> icon_color_map; // The names of the icons to never convert, even if one of their colors // are contained in the dictionary above. HashSet<StringName> exceptions; - // Some of the colors below are listed for completeness sake. - // This can be a basis for proper palette validation later. if (!p_dark_theme) { - // Convert color: FROM TO - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#478cbf", "#478cbf"); // Godot Blue - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#414042", "#414042"); // Godot Gray - - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffffff", "#414141"); // Pure white - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#000000", "#bfbfbf"); // Pure black - // Keep pure RGB colors as is, but list them for explicitly. - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff0000", "#ff0000"); // Pure red - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#00ff00", "#00ff00"); // Pure green - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#0000ff", "#0000ff"); // Pure blue - - // GUI Colors - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e0e0e0", "#5a5a5a"); // Common icon color - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fefefe", "#fefefe"); // Forced light color - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#808080", "#808080"); // GUI disabled color - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#b3b3b3", "#363636"); // GUI disabled light color - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#699ce8", "#699ce8"); // GUI highlight color - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f9f9f9", "#606060"); // Scrollbar grabber highlight color - - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#c38ef1", "#a85de9"); // Animation - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fc7f7f", "#cd3838"); // Spatial - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#8da5f3", "#3d64dd"); // 2D - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#4b70ea", "#1a3eac"); // 2D Dark - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#8eef97", "#2fa139"); // Control - - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#5fb2ff", "#0079f0"); // Selection (blue) - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#003e7a", "#2b74bb"); // Selection (darker blue) - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f7f5cf", "#615f3a"); // Gizmo (yellow) - - // Rainbow - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff4545", "#ff2929"); // Red - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffe345", "#ffe337"); // Yellow - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#80ff45", "#74ff34"); // Green - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#45ffa2", "#2cff98"); // Aqua - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#45d7ff", "#22ccff"); // Blue - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#8045ff", "#702aff"); // Purple - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff4596", "#ff2781"); // Pink - - // Audio gradients - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e1da5b", "#d6cf4b"); // Yellow - - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#62aeff", "#1678e0"); // Frozen gradient top - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#75d1e6", "#41acc5"); // Frozen gradient middle - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#84ffee", "#49ccba"); // Frozen gradient bottom - - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f70000", "#c91616"); // Color track red - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eec315", "#d58c0b"); // Color track orange - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#dbee15", "#b7d10a"); // Color track yellow - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#288027", "#218309"); // Color track green - - // Resource groups - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffca5f", "#fea900"); // Mesh resource (orange) - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#2998ff", "#68b6ff"); // Shape resource (blue) - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#a2d2ff", "#4998e3"); // Shape resource (light blue) - - // Animation editor tracks - // The property track icon color is set by the common icon color. - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ea7940", "#bd5e2c"); // 3D Position track - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff2b88", "#bd165f"); // 3D Rotation track - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eac840", "#bd9d1f"); // 3D Scale track - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#3cf34e", "#16a827"); // Call Method track - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#2877f6", "#236be6"); // Bezier Curve track - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eae440", "#9f9722"); // Audio Playback track - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#a448f0", "#9853ce"); // Animation Playback track - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#5ad5c4", "#0a9c88"); // Blend Shape track - - // Control layouts - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#d6d6d6", "#474747"); // Highlighted part - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#474747", "#d6d6d6"); // Background part - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#919191", "#6e6e6e"); // Border part - - // TileSet editor icons - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fce00e", "#aa8d24"); // New Single Tile - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#0e71fc", "#0350bd"); // New Autotile - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#c6ced4", "#828f9b"); // New Atlas - - // Visual script - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#41ecad", "#25e3a0"); // VisualScript variant - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#6f91f0", "#6d8eeb"); // VisualScript bool - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#5abbef", "#4fb2e9"); // VisualScript int - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#35d4f4", "#27ccf0"); // VisualScript float - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#4593ec", "#4690e7"); // VisualScript String - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ac73f1", "#ad76ee"); // VisualScript Vector2 - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f1738f", "#ee758e"); // VisualScript Rect2 - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#de66f0", "#dc6aed"); // VisualScript Vector3 - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#b9ec41", "#96ce1a"); // VisualScript Transform2D - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f74949", "#f77070"); // VisualScript Plane - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ec418e", "#ec69a3"); // VisualScript Quat - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ee5677", "#ee7991"); // VisualScript AABB - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e1ec41", "#b2bb19"); // VisualScript Basis - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f68f45", "#f49047"); // VisualScript Transform - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#417aec", "#6993ec"); // VisualScript NodePath - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#41ec80", "#2ce573"); // VisualScript RID - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#55f3e3", "#12d5c3"); // VisualScript Object - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#54ed9e", "#57e99f"); // VisualScript Dictionary - // Visual shaders - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#77ce57", "#67c046"); // Vector funcs - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ea686c", "#d95256"); // Vector transforms - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eac968", "#d9b64f"); // Textures and cubemaps - ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#cf68ea", "#c050dd"); // Functions and expressions + for (KeyValue<Color, Color> &E : EditorColorMap::get()) { + icon_color_map[E.key] = E.value; + } exceptions.insert("EditorPivot"); exceptions.insert("EditorHandle"); @@ -291,18 +293,18 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = const Color error_color = p_theme->get_color(SNAME("error_color"), SNAME("Editor")); const Color success_color = p_theme->get_color(SNAME("success_color"), SNAME("Editor")); const Color warning_color = p_theme->get_color(SNAME("warning_color"), SNAME("Editor")); - dark_icon_color_dictionary[Color::html("#ff5f5f")] = error_color; - dark_icon_color_dictionary[Color::html("#5fff97")] = success_color; - dark_icon_color_dictionary[Color::html("#ffdd65")] = warning_color; + icon_color_map[Color::html("#ff5f5f")] = error_color; + icon_color_map[Color::html("#5fff97")] = success_color; + icon_color_map[Color::html("#ffdd65")] = warning_color; // Use the accent color for some icons (checkbox, radio, toggle, etc.). - Dictionary accent_color_icon_color_dictionary; + HashMap<Color, Color> accent_color_map; HashSet<StringName> accent_color_icons; const Color accent_color = p_theme->get_color(SNAME("accent_color"), SNAME("Editor")); - accent_color_icon_color_dictionary[Color::html("699ce8")] = accent_color; + accent_color_map[Color::html("699ce8")] = accent_color; if (accent_color.get_luminance() > 0.75) { - accent_color_icon_color_dictionary[Color::html("ffffff")] = Color(0.2, 0.2, 0.2); + accent_color_map[Color::html("ffffff")] = Color(0.2, 0.2, 0.2); } accent_color_icons.insert("GuiChecked"); @@ -318,7 +320,7 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = Ref<ImageTexture> icon; if (accent_color_icons.has(editor_icons_names[i])) { - icon = editor_generate_icon(i, true, EDSCALE, 1.0, accent_color_icon_color_dictionary); + icon = editor_generate_icon(i, EDSCALE, 1.0, accent_color_map); } else { float saturation = p_icon_saturation; @@ -327,7 +329,11 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = } const int is_exception = exceptions.has(editor_icons_names[i]); - icon = editor_generate_icon(i, !is_exception, EDSCALE, saturation, dark_icon_color_dictionary); + if (is_exception) { + icon = editor_generate_icon(i, EDSCALE, saturation); + } else { + icon = editor_generate_icon(i, EDSCALE, saturation, icon_color_map); + } } p_theme->set_icon(editor_icons_names[i], SNAME("EditorIcons"), icon); @@ -342,7 +348,13 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = for (int i = 0; i < editor_bg_thumbs_count; i++) { const int index = editor_bg_thumbs_indices[i]; const int is_exception = exceptions.has(editor_icons_names[index]); - const Ref<ImageTexture> icon = editor_generate_icon(index, !p_dark_theme && !is_exception, scale, force_filter, dark_icon_color_dictionary); + + Ref<ImageTexture> icon; + if (!p_dark_theme && !is_exception) { + icon = editor_generate_icon(index, scale, force_filter, icon_color_map); + } else { + icon = editor_generate_icon(index, scale, force_filter); + } p_theme->set_icon(editor_icons_names[index], SNAME("EditorIcons"), icon); } @@ -351,7 +363,13 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = for (int i = 0; i < editor_md_thumbs_count; i++) { const int index = editor_md_thumbs_indices[i]; const bool is_exception = exceptions.has(editor_icons_names[index]); - const Ref<ImageTexture> icon = editor_generate_icon(index, !p_dark_theme && !is_exception, scale, force_filter, dark_icon_color_dictionary); + + Ref<ImageTexture> icon; + if (!p_dark_theme && !is_exception) { + icon = editor_generate_icon(index, scale, force_filter, icon_color_map); + } else { + icon = editor_generate_icon(index, scale, force_filter); + } p_theme->set_icon(editor_icons_names[index], SNAME("EditorIcons"), icon); } @@ -518,8 +536,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Color warning_color = Color(1, 0.87, 0.4); Color error_color = Color(1, 0.47, 0.42); Color property_color = font_color.lerp(Color(0.5, 0.5, 0.5), 0.5); - Color readonly_color = property_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.5); - Color readonly_warning_color = error_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.5); + Color readonly_color = property_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.25); + Color readonly_warning_color = error_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.25); if (!dark_theme) { // Darken some colors to be readable on a light background @@ -1849,14 +1867,14 @@ Ref<Theme> create_custom_theme(const Ref<Theme> p_theme) { return theme; } -Ref<ImageTexture> create_unscaled_default_project_icon() { -#ifdef MODULE_SVG_ENABLED +/** + * Returns the SVG code for the default project icon. + */ +String get_default_project_icon() { for (int i = 0; i < editor_icons_count; i++) { - // ESCALE should never affect size of the icon if (strcmp(editor_icons_names[i], "DefaultProjectIcon") == 0) { - return editor_generate_icon(i, false, 1.0); + return String(editor_icons_sources[i]); } } -#endif - return Ref<ImageTexture>(memnew(ImageTexture)); + return String(); } diff --git a/editor/editor_themes.h b/editor/editor_themes.h index 95184b9d4a..37db8160fa 100644 --- a/editor/editor_themes.h +++ b/editor/editor_themes.h @@ -34,10 +34,24 @@ #include "scene/resources/texture.h" #include "scene/resources/theme.h" +// The default icon theme is designed to be used for a dark theme. This map stores +// Color values to convert to other colors for better readability on a light theme. +class EditorColorMap { + // Godot Color values are used to avoid the ambiguity of strings + // (where "#ffffff", "fff", and "white" are all equivalent). + static HashMap<Color, Color> editor_color_map; + +public: + static void create(); + static void add_color_pair(const String p_from_color, const String p_to_color); + + static HashMap<Color, Color> &get() { return editor_color_map; }; +}; + Ref<Theme> create_editor_theme(Ref<Theme> p_theme = nullptr); Ref<Theme> create_custom_theme(Ref<Theme> p_theme = nullptr); -Ref<ImageTexture> create_unscaled_default_project_icon(); +String get_default_project_icon(); #endif // EDITOR_THEMES_H diff --git a/editor/editor_vcs_interface.cpp b/editor/editor_vcs_interface.cpp index 3f2012cc16..cb188f9c3e 100644 --- a/editor/editor_vcs_interface.cpp +++ b/editor/editor_vcs_interface.cpp @@ -82,8 +82,8 @@ void EditorVCSInterface::_unstage_file(String p_file_path) { void EditorVCSInterface::_commit(String p_msg) { } -Array EditorVCSInterface::_get_file_diff(String p_file_path) { - return Array(); +TypedArray<Dictionary> EditorVCSInterface::_get_file_diff(String p_file_path) { + return TypedArray<Dictionary>(); } bool EditorVCSInterface::_shut_down() { @@ -133,11 +133,11 @@ void EditorVCSInterface::commit(String p_msg) { } } -Array EditorVCSInterface::get_file_diff(String p_file_path) { +TypedArray<Dictionary> EditorVCSInterface::get_file_diff(String p_file_path) { if (is_addon_ready()) { return call("_get_file_diff", p_file_path); } - return Array(); + return TypedArray<Dictionary>(); } bool EditorVCSInterface::shut_down() { diff --git a/editor/editor_vcs_interface.h b/editor/editor_vcs_interface.h index 6a6fca7eba..d6d7ffa0e9 100644 --- a/editor/editor_vcs_interface.h +++ b/editor/editor_vcs_interface.h @@ -52,7 +52,7 @@ protected: virtual void _stage_file(String p_file_path); virtual void _unstage_file(String p_file_path); virtual void _commit(String p_msg); - virtual Array _get_file_diff(String p_file_path); + virtual TypedArray<Dictionary> _get_file_diff(String p_file_path); virtual bool _shut_down(); virtual String _get_project_name(); virtual String _get_vcs_name(); @@ -76,7 +76,7 @@ public: void stage_file(String p_file_path); void unstage_file(String p_file_path); void commit(String p_msg); - Array get_file_diff(String p_file_path); + TypedArray<Dictionary> get_file_diff(String p_file_path); bool shut_down(); String get_project_name(); String get_vcs_name(); diff --git a/editor/icons/BezierHandlesBalanced.svg b/editor/icons/BezierHandlesBalanced.svg index 911029e431..b1778b1a5e 100644 --- a/editor/icons/BezierHandlesBalanced.svg +++ b/editor/icons/BezierHandlesBalanced.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#5fb2ff" stroke-miterlimit="4.9" stroke-width="1.7"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m7.4559186 5.1473018-4.7355323 1.5541798" fill="none" stroke="#5fb2ff" stroke-width=".618"/><path d="m10.790357 4.2063094-2.5009748.9433136" fill="none" stroke="#5fb2ff" stroke-width=".614897"/><g fill="#e0e0e0"><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m1.7157324 5.8754878a1.2675855 1.1997888 0 0 0 -1.26757806 1.1992188 1.2675855 1.1997888 0 0 0 1.26757806 1.1992187 1.2675855 1.1997888 0 0 0 1.2675781-1.1992187 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.84765616-.8007812.84677333.80148375 0 0 1 .84765616-.8007812z"/><path d="m11.909414 2.4642073a1.2836218 1.231838 0 0 0 -1.283614 1.2312528 1.2836218 1.231838 0 0 0 1.283614 1.2312527 1.2836218 1.231838 0 0 0 1.283614-1.2312527 1.2836218 1.231838 0 0 0 -1.283614-1.2312528zm.002.4351497a.85748593.82289328 0 0 1 .858383.8221719.85748593.82289328 0 0 1 -.85838.822172.85748593.82289328 0 0 1 -.858379-.822172.85748593.82289328 0 0 1 .858379-.8221719z"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#87b1d7" stroke-miterlimit="4.9" stroke-width=".5"/><path d="m2.4962504 7.6963851 10.1811806-3.7166314" fill="none" stroke="#61b2ff" stroke-width="1.5"/><g fill="#e0e0e0"><ellipse cx="1.898304" cy="13.491526" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" rx="1.267586" ry="1.199789"/><ellipse cx="8.338983" cy="5.491526" rx="1.267586" ry="1.199789"/><path d="m1.6910776 6.7273a1.2675855 1.1997888 0 0 0 -1.26757808 1.1992188 1.2675855 1.1997888 0 0 0 1.26757808 1.1992187 1.2675855 1.1997888 0 0 0 1.2675781-1.1992187 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.84765618-.8007812.84677333.80148375 0 0 1 .84765618-.8007812z"/><path d="m13.40948 2.2963899a1.2836218 1.231838 0 0 0 -1.283614 1.2312528 1.2836218 1.231838 0 0 0 1.283614 1.2312526 1.2836218 1.231838 0 0 0 1.283614-1.2312526 1.2836218 1.231838 0 0 0 -1.283614-1.2312528zm.002.4351497a.85748593.82289328 0 0 1 .858383.8221719.85748593.82289328 0 0 1 -.85838.8221719.85748593.82289328 0 0 1 -.858379-.8221719.85748593.82289328 0 0 1 .858379-.8221719z"/></g></svg> diff --git a/editor/icons/BezierHandlesFree.svg b/editor/icons/BezierHandlesFree.svg index 6e91288c79..c7bff530ae 100644 --- a/editor/icons/BezierHandlesFree.svg +++ b/editor/icons/BezierHandlesFree.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#5fb2ff" stroke-miterlimit="4.9" stroke-width="1.7"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m7.6850253 4.7560401-3.776127.6607599" fill="none" stroke="#5fb2ff" stroke-width=".805138"/><path d="m11.695505 2.3941651-2.999121 2.2935078" fill="none" stroke="#5fb2ff" stroke-width=".730798"/><g fill="#e0e0e0"><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m2.4961199 4.3976698a1.1997888 1.2675855 80.074672 0 0 -1.0419038 1.3997559 1.1997888 1.2675855 80.074672 0 0 1.4553094.9627848 1.1997888 1.2675855 80.074672 0 0 1.0419037-1.3997558 1.1997888 1.2675855 80.074672 0 0 -1.4553093-.9627849zm.074974.4171488a.80148375.84677333 80.074672 0 1 .9729986.6426896.80148375.84677333 80.074672 0 1 -.6969432.934902.80148375.84677333 80.074672 0 1 -.9729958-.6426902.80148375.84677333 80.074672 0 1 .6969432-.934902z"/><path d="m11.838896.64428913a1.231838 1.2836218 52.593897 0 0 -.271701 1.75779027 1.231838 1.2836218 52.593897 0 0 1.767576.1983008 1.231838 1.2836218 52.593897 0 0 .271701-1.75779027 1.231838 1.2836218 52.593897 0 0 -1.767576-.1983008zm.265925.3444462a.82289328.85748593 52.593897 0 1 1.181294.13165847.82289328.85748593 52.593897 0 1 -.182417 1.1745241.82289328.85748593 52.593897 0 1 -1.181291-.1316609.82289328.85748593 52.593897 0 1 .182417-1.17452347z"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.3064631-5.1979735 6.5945988-6.486109c5.0847463.9491522 5.9477733 6.486108 5.9477733 6.486108" fill="none" stroke="#87b1d7" stroke-miterlimit="4.9" stroke-width=".5"/><path d="m2.3554991 8.5165019 6.0018116-1.3754919 2.0717113-4.6377276" fill="none" stroke="#61b3ff" stroke-width="1.5"/><g fill="#e0e0e0"><ellipse cx="1.898304" cy="13.491526" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" rx="1.267586" ry="1.199789"/><ellipse cx="8.35731" cy="7.14101" rx="1.267586" ry="1.199789"/><path d="m1.3048251 7.4400522a1.1997888 1.2675855 80.074672 0 0 -1.04190379 1.3997559 1.1997888 1.2675855 80.074672 0 0 1.45530939.9627848 1.1997888 1.2675855 80.074672 0 0 1.0419037-1.3997558 1.1997888 1.2675855 80.074672 0 0 -1.4553093-.9627849zm.074974.4171488a.80148375.84677333 80.074672 0 1 .9729986.6426896.80148375.84677333 80.074672 0 1 -.6969432.934902.80148375.84677333 80.074672 0 1 -.97299579-.6426902.80148375.84677333 80.074672 0 1 .69694319-.934902z"/><path d="m10.024463.73592688a1.231838 1.2836218 52.593897 0 0 -.2717015 1.75779042 1.231838 1.2836218 52.593897 0 0 1.7675765.1983008 1.231838 1.2836218 52.593897 0 0 .271701-1.75779042 1.231838 1.2836218 52.593897 0 0 -1.767576-.1983008zm.265925.34444622a.82289328.85748593 52.593897 0 1 1.181294.1316585.82289328.85748593 52.593897 0 1 -.182417 1.1745242.82289328.85748593 52.593897 0 1 -1.181291-.1316609.82289328.85748593 52.593897 0 1 .182417-1.1745236z"/></g></svg> diff --git a/editor/icons/BezierHandlesLinear.svg b/editor/icons/BezierHandlesLinear.svg new file mode 100644 index 0000000000..2667779dcb --- /dev/null +++ b/editor/icons/BezierHandlesLinear.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8.2711868 4.7796612-6.3728828 8.7118648z" fill="none" stroke="#87b1d7" stroke-miterlimit="4.9" stroke-width=".5"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m14.237288 13.491526-5.9661012-8.7118648" fill="none" stroke="#87b1d7" stroke-miterlimit="4.9" stroke-width=".5"/><path d="m5.6316733 8.3879317 2.6395135-3.6082705 2.4416832 3.5654122" fill="none" stroke="#61b2ff" stroke-width="1.5"/><g fill="#e0e0e0"><ellipse cx="14.237288" cy="13.491526" rx="1.267586" ry="1.199789"/><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m5.0847454 7.9363749a1.2675855 1.1997888 0 0 0 -1.2675781 1.1992188 1.2675855 1.1997888 0 0 0 1.2675781 1.1992183 1.2675855 1.1997888 0 0 0 1.2675781-1.1992183 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.8476562-.8007812.84677333.80148375 0 0 1 .8476562-.8007812z"/><path d="m11.254237 7.9043407a1.2836218 1.231838 0 0 0 -1.2836135 1.2312528 1.2836218 1.231838 0 0 0 1.2836135 1.2312525 1.2836218 1.231838 0 0 0 1.283614-1.2312525 1.2836218 1.231838 0 0 0 -1.283614-1.2312528zm.002.4351497a.85748593.82289328 0 0 1 .858383.8221719.85748593.82289328 0 0 1 -.85838.822172.85748593.82289328 0 0 1 -.858379-.822172.85748593.82289328 0 0 1 .858379-.8221719z"/></g></svg> diff --git a/editor/icons/BezierHandlesMirror.svg b/editor/icons/BezierHandlesMirror.svg index 9180e31921..07817f7247 100644 --- a/editor/icons/BezierHandlesMirror.svg +++ b/editor/icons/BezierHandlesMirror.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#5fb2ff" stroke-miterlimit="4.9" stroke-width="1.7"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m8.2033896 4.6779662h-3.8335021" fill="none" stroke="#5fb2ff" stroke-width=".805138"/><path d="m11.931789 4.6440679h-3.7283994" fill="none" stroke="#5fb2ff" stroke-width=".716709"/><g fill="#e0e0e0"><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m3.1539157 3.4305762a1.2675855 1.1997888 0 0 0 -1.2675781 1.1992188 1.2675855 1.1997888 0 0 0 1.2675781 1.1992187 1.2675855 1.1997888 0 0 0 1.2675781-1.1992187 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.8476562-.8007812.84677333.80148375 0 0 1 .8476562-.8007812z"/><path d="m13.093969 3.3750567a1.2675855 1.1997888 0 0 0 -1.267578 1.1992188 1.2675855 1.1997888 0 0 0 1.267578 1.1992187 1.2675855 1.1997888 0 0 0 1.267578-1.1992187 1.2675855 1.1997888 0 0 0 -1.267578-1.1992188zm.002.4238282a.84677333.80148375 0 0 1 .847659.8007812.84677333.80148375 0 0 1 -.847656.8007812.84677333.80148375 0 0 1 -.847656-.8007812.84677333.80148375 0 0 1 .847656-.8007812z"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#87b1d7" stroke-miterlimit="4.9" stroke-width=".5"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m8.3389831 5.4915255-5.8519685.0395137" fill="none" stroke="#5fb2ff" stroke-width="1.5"/><path d="m13.814033 5.4419288-5.4750499.0156984" fill="none" stroke="#5fb2ff" stroke-width="1.5"/><g fill="#e0e0e0"><ellipse cx="8.40678" cy="5.593221" rx="1.267586" ry="1.199789"/><path d="m1.6400247 4.2441355a1.2675855 1.1997888 0 0 0 -1.26757814 1.1992188 1.2675855 1.1997888 0 0 0 1.26757814 1.1992187 1.2675855 1.1997888 0 0 0 1.2675781-1.1992187 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.84765624-.8007812.84677333.80148375 0 0 1 .84765624-.8007812z"/><path d="m14.659116 4.188616a1.2675855 1.1997888 0 0 0 -1.267578 1.1992188 1.2675855 1.1997888 0 0 0 1.267578 1.1992187 1.2675855 1.1997888 0 0 0 1.267578-1.1992187 1.2675855 1.1997888 0 0 0 -1.267578-1.1992188zm.002.4238282a.84677333.80148375 0 0 1 .847659.8007812.84677333.80148375 0 0 1 -.847656.8007812.84677333.80148375 0 0 1 -.847656-.8007812.84677333.80148375 0 0 1 .847656-.8007812z"/></g></svg> diff --git a/editor/icons/CurveIn.svg b/editor/icons/CurveIn.svg index 2ad44dc654..fefad9ce6c 100644 --- a/editor/icons/CurveIn.svg +++ b/editor/icons/CurveIn.svg @@ -1 +1 @@ -<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c5 0 8-3 8-8" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg> +<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c5 0 8-3 8-8" fill="none" stroke="#80ff45" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg> diff --git a/editor/icons/CurveInOut.svg b/editor/icons/CurveInOut.svg index 292dac4573..f099cb83f1 100644 --- a/editor/icons/CurveInOut.svg +++ b/editor/icons/CurveInOut.svg @@ -1 +1 @@ -<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c5 0 3-8 8-8" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg> +<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c5 0 3-8 8-8" fill="none" stroke="#45d7ff" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg> diff --git a/editor/icons/CurveLinear.svg b/editor/icons/CurveLinear.svg index 3c1fb2a0e2..41d37c9329 100644 --- a/editor/icons/CurveLinear.svg +++ b/editor/icons/CurveLinear.svg @@ -1 +1 @@ -<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4 8-8" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg> +<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4 8-8" fill="none" stroke="#ffe345" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg> diff --git a/editor/icons/CurveOut.svg b/editor/icons/CurveOut.svg index dfa9a26144..19710aa38d 100644 --- a/editor/icons/CurveOut.svg +++ b/editor/icons/CurveOut.svg @@ -1 +1 @@ -<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c0-5 3-8 8-8" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg> +<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c0-5 3-8 8-8" fill="none" stroke="#45ffa2" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg> diff --git a/editor/icons/CurveOutIn.svg b/editor/icons/CurveOutIn.svg index 9a6463d0e9..7f200432bf 100644 --- a/editor/icons/CurveOutIn.svg +++ b/editor/icons/CurveOutIn.svg @@ -1 +1 @@ -<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c0-5 8-3 8-8" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg> +<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c0-5 8-3 8-8" fill="none" stroke="#ff4596" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg> diff --git a/editor/icons/InterpCubicInTime.svg b/editor/icons/InterpCubicInTime.svg deleted file mode 100644 index 81027f798a..0000000000 --- a/editor/icons/InterpCubicInTime.svg +++ /dev/null @@ -1 +0,0 @@ -<svg enable-background="new -595.5 420.5 16 8" height="8" viewBox="-595.5 420.5 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m-593.5 426.5c1-4 3.5-5.5 6-2s5 2 6-2" fill="none" stroke="#ff92cb" stroke-linecap="round" stroke-width="2"/></svg> diff --git a/editor/icons/Position2D.svg b/editor/icons/Marker2D.svg index 191f0b2a03..191f0b2a03 100644 --- a/editor/icons/Position2D.svg +++ b/editor/icons/Marker2D.svg diff --git a/editor/icons/Position3D.svg b/editor/icons/Marker3D.svg index 894b195589..894b195589 100644 --- a/editor/icons/Position3D.svg +++ b/editor/icons/Marker3D.svg diff --git a/editor/icons/NodeInfo.svg b/editor/icons/NodeInfo.svg new file mode 100644 index 0000000000..4e3f0c42d0 --- /dev/null +++ b/editor/icons/NodeInfo.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm-1 3h2v2h-2zm0 3h2v5h-2z" fill="#fff"/></svg> diff --git a/editor/icons/ParticlesMaterial.svg b/editor/icons/ParticleProcessMaterial.svg index 33598980a5..33598980a5 100644 --- a/editor/icons/ParticlesMaterial.svg +++ b/editor/icons/ParticleProcessMaterial.svg diff --git a/editor/import/editor_import_plugin.cpp b/editor/import/editor_import_plugin.cpp index e822b4963a..3305f241c0 100644 --- a/editor/import/editor_import_plugin.cpp +++ b/editor/import/editor_import_plugin.cpp @@ -115,7 +115,7 @@ void EditorImportPlugin::get_import_options(const String &p_path, List<ResourceI Array needed; needed.push_back("name"); needed.push_back("default_value"); - Array options; + TypedArray<Dictionary> options; if (GDVIRTUAL_CALL(_get_import_options, p_path, p_preset, options)) { for (int i = 0; i < options.size(); i++) { Dictionary d = options[i]; diff --git a/editor/import/editor_import_plugin.h b/editor/import/editor_import_plugin.h index 4548513b6f..e9749c240f 100644 --- a/editor/import/editor_import_plugin.h +++ b/editor/import/editor_import_plugin.h @@ -32,6 +32,7 @@ #define EDITOR_IMPORT_PLUGIN_H #include "core/io/resource_importer.h" +#include "core/variant/typed_array.h" class EditorImportPlugin : public ResourceImporter { GDCLASS(EditorImportPlugin, ResourceImporter); @@ -44,7 +45,7 @@ protected: GDVIRTUAL0RC(int, _get_preset_count) GDVIRTUAL1RC(String, _get_preset_name, int) GDVIRTUAL0RC(Vector<String>, _get_recognized_extensions) - GDVIRTUAL2RC(Array, _get_import_options, String, int) + GDVIRTUAL2RC(TypedArray<Dictionary>, _get_import_options, String, int) GDVIRTUAL0RC(String, _get_save_extension) GDVIRTUAL0RC(String, _get_resource_type) GDVIRTUAL0RC(float, _get_priority) diff --git a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp index 2fa602846c..685cb16eb1 100644 --- a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp +++ b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp @@ -41,14 +41,13 @@ void PostImportPluginSkeletonRestFixer::get_internal_import_options(InternalImpo r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/apply_node_transforms"), true)); r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/normalize_position_tracks"), true)); r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/overwrite_axis"), true)); - r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/fix_silhouette/enable"), false)); - r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "retarget/rest_fixer/fix_silhouette/threshold"), 15)); - // TODO: PostImportPlugin need to be implemented such as validate_option(PropertyInfo &property, const Dictionary &p_options). // get_internal_option_visibility() is not sufficient because it can only retrieve options implemented in the core and can only read option values. // r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::ARRAY, "retarget/rest_fixer/filter", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::STRING_NAME, PROPERTY_HINT_ENUM, "Hips,Spine,Chest")), Array())); r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::ARRAY, "retarget/rest_fixer/fix_silhouette/filter", PROPERTY_HINT_ARRAY_TYPE, "StringName"), Array())); + r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "retarget/rest_fixer/fix_silhouette/threshold"), 15)); + r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "retarget/rest_fixer/fix_silhouette/base_height_adjustment", PROPERTY_HINT_RANGE, "-1,1,0.01"), 0.0)); } } @@ -192,53 +191,6 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory is_rest_changed = true; } - // Set motion scale to Skeleton if normalize position tracks. - if (bool(p_options["retarget/rest_fixer/normalize_position_tracks"])) { - int src_bone_idx = src_skeleton->find_bone(profile->get_scale_base_bone()); - if (src_bone_idx >= 0) { - real_t motion_scale = abs(src_skeleton->get_bone_global_rest(src_bone_idx).origin.y); - if (motion_scale > 0) { - src_skeleton->set_motion_scale(motion_scale); - } - } - - TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer"); - while (nodes.size()) { - AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back()); - List<StringName> anims; - ap->get_animation_list(&anims); - for (const StringName &name : anims) { - Ref<Animation> anim = ap->get_animation(name); - int track_len = anim->get_track_count(); - for (int i = 0; i < track_len; i++) { - if (anim->track_get_path(i).get_subname_count() != 1 || anim->track_get_type(i) != Animation::TYPE_POSITION_3D) { - continue; - } - - if (anim->track_is_compressed(i)) { - continue; // Shouldn't occur in internal_process(). - } - - String track_path = String(anim->track_get_path(i).get_concatenated_names()); - Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); - if (node) { - Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node); - if (track_skeleton) { - if (track_skeleton && track_skeleton == src_skeleton) { - real_t mlt = 1 / src_skeleton->get_motion_scale(); - int key_len = anim->track_get_key_count(i); - for (int j = 0; j < key_len; j++) { - Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j)); - anim->track_set_key_value(i, j, pos * mlt); - } - } - } - } - } - } - } - } - // Complement Rotation track for compatibility between different rests. { TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer"); @@ -406,6 +358,52 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory } } + // Adjust scale base bone height. + float base_adjustment = float(p_options["retarget/rest_fixer/fix_silhouette/base_height_adjustment"]); + if (!Math::is_zero_approx(base_adjustment)) { + StringName scale_base_bone_name = profile->get_scale_base_bone(); + int src_bone_idx = src_skeleton->find_bone(scale_base_bone_name); + Transform3D src_rest = src_skeleton->get_bone_rest(src_bone_idx); + src_skeleton->set_bone_rest(src_bone_idx, Transform3D(src_rest.basis, Vector3(src_rest.origin.x, src_rest.origin.y + base_adjustment, src_rest.origin.z))); + + TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer"); + while (nodes.size()) { + AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back()); + List<StringName> anims; + ap->get_animation_list(&anims); + for (const StringName &name : anims) { + Ref<Animation> anim = ap->get_animation(name); + int track_len = anim->get_track_count(); + for (int i = 0; i < track_len; i++) { + if (anim->track_get_path(i).get_subname_count() != 1 || anim->track_get_type(i) != Animation::TYPE_POSITION_3D) { + continue; + } + + if (anim->track_is_compressed(i)) { + continue; // Shouldn't occur in internal_process(). + } + + String track_path = String(anim->track_get_path(i).get_concatenated_names()); + Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); + if (node) { + Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node); + if (track_skeleton && track_skeleton == src_skeleton) { + StringName bn = anim->track_get_path(i).get_concatenated_subnames(); + if (bn == scale_base_bone_name) { + int key_len = anim->track_get_key_count(i); + for (int j = 0; j < key_len; j++) { + Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j)); + pos.y += base_adjustment; + anim->track_set_key_value(i, j, pos); + } + } + } + } + } + } + } + } + // For skin modification in overwrite rest. for (int i = 0; i < src_skeleton->get_bone_count(); i++) { silhouette_diff_w[i] = old_skeleton_global_rest[i] * src_skeleton->get_bone_global_rest(i).inverse(); @@ -414,6 +412,51 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory is_rest_changed = true; } + // Set motion scale to Skeleton if normalize position tracks. + if (bool(p_options["retarget/rest_fixer/normalize_position_tracks"])) { + int src_bone_idx = src_skeleton->find_bone(profile->get_scale_base_bone()); + if (src_bone_idx >= 0) { + real_t motion_scale = abs(src_skeleton->get_bone_global_rest(src_bone_idx).origin.y); + if (motion_scale > 0) { + src_skeleton->set_motion_scale(motion_scale); + } + } + + TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer"); + while (nodes.size()) { + AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back()); + List<StringName> anims; + ap->get_animation_list(&anims); + for (const StringName &name : anims) { + Ref<Animation> anim = ap->get_animation(name); + int track_len = anim->get_track_count(); + for (int i = 0; i < track_len; i++) { + if (anim->track_get_path(i).get_subname_count() != 1 || anim->track_get_type(i) != Animation::TYPE_POSITION_3D) { + continue; + } + + if (anim->track_is_compressed(i)) { + continue; // Shouldn't occur in internal_process(). + } + + String track_path = String(anim->track_get_path(i).get_concatenated_names()); + Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); + if (node) { + Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node); + if (track_skeleton && track_skeleton == src_skeleton) { + real_t mlt = 1 / src_skeleton->get_motion_scale(); + int key_len = anim->track_get_key_count(i); + for (int j = 0; j < key_len; j++) { + Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j)); + anim->track_set_key_value(i, j, pos * mlt); + } + } + } + } + } + } + } + // Overwrite axis. if (bool(p_options["retarget/rest_fixer/overwrite_axis"])) { LocalVector<Transform3D> old_skeleton_rest; diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp index b301bbf0f9..ed83535421 100644 --- a/editor/import/resource_importer_layered_texture.cpp +++ b/editor/import/resource_importer_layered_texture.cpp @@ -327,7 +327,7 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const Ref<Image> image; image.instantiate(); - Error err = ImageLoader::load_image(p_source_file, image, nullptr, false, 1.0); + Error err = ImageLoader::load_image(p_source_file, image); if (err != OK) { return err; } diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index 0eed6184c0..17b94ec706 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -409,11 +409,26 @@ void ResourceImporterTexture::_save_ctex(const Ref<Image> &p_image, const String } Error ResourceImporterTexture::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { + // Parse import options. + int32_t loader_flags = ImageFormatLoader::FLAG_NONE; + + // Compression. CompressMode compress_mode = CompressMode(int(p_options["compress/mode"])); const float lossy = p_options["compress/lossy_quality"]; const int pack_channels = p_options["compress/channel_pack"]; + const int normal = p_options["compress/normal_map"]; + const int hdr_compression = p_options["compress/hdr_compression"]; + const int bptc_ldr = p_options["compress/bptc_ldr"]; + + // Mipmaps. const bool mipmaps = p_options["mipmaps/generate"]; const uint32_t mipmap_limit = mipmaps ? uint32_t(p_options["mipmaps/limit"]) : uint32_t(-1); + + // Roughness. + const int roughness = p_options["roughness/mode"]; + const String normal_map = p_options["roughness/src_normal"]; + + // Processing. const bool fix_alpha_border = p_options["process/fix_alpha_border"]; const bool premult_alpha = p_options["process/premult_alpha"]; const bool normal_map_invert_y = p_options["process/normal_map_invert_y"]; @@ -421,29 +436,29 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String const bool stream = false; const int size_limit = p_options["process/size_limit"]; const bool hdr_as_srgb = p_options["process/hdr_as_srgb"]; + if (hdr_as_srgb) { + loader_flags |= ImageFormatLoader::FLAG_FORCE_LINEAR; + } const bool hdr_clamp_exposure = p_options["process/hdr_clamp_exposure"]; - const int normal = p_options["compress/normal_map"]; - const int hdr_compression = p_options["compress/hdr_compression"]; - const int bptc_ldr = p_options["compress/bptc_ldr"]; - const int roughness = p_options["roughness/mode"]; - const String normal_map = p_options["roughness/src_normal"]; + float scale = 1.0; + // SVG-specific options. if (p_options.has("svg/scale")) { scale = p_options["svg/scale"]; } Ref<Image> normal_image; Image::RoughnessChannel roughness_channel = Image::ROUGHNESS_CHANNEL_R; - if (mipmaps && roughness > 1 && FileAccess::exists(normal_map)) { normal_image.instantiate(); if (ImageLoader::load_image(normal_map, normal_image) == OK) { roughness_channel = Image::RoughnessChannel(roughness - 2); } } + Ref<Image> image; image.instantiate(); - Error err = ImageLoader::load_image(p_source_file, image, nullptr, hdr_as_srgb, scale); + Error err = ImageLoader::load_image(p_source_file, image, nullptr, loader_flags, scale); if (err != OK) { return err; } diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 1bcbd2fe00..b0ff678a3e 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -247,7 +247,7 @@ void InspectorDock::_resource_file_selected(String p_file) { } if (res.is_null()) { - warning_dialog->set_text(TTR("Failed to load resource.")); + info_dialog->set_text(TTR("Failed to load resource.")); return; }; @@ -409,8 +409,8 @@ void InspectorDock::_menu_expand_revertable() { inspector->expand_revertable(); } -void InspectorDock::_warning_pressed() { - warning_dialog->popup_centered(); +void InspectorDock::_info_pressed() { + info_dialog->popup_centered(); } Container *InspectorDock::get_addon_area() { @@ -446,8 +446,13 @@ void InspectorDock::_notification(int p_what) { history_menu->set_icon(get_theme_icon(SNAME("History"), SNAME("EditorIcons"))); object_menu->set_icon(get_theme_icon(SNAME("Tools"), SNAME("EditorIcons"))); search->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); - warning->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons"))); - warning->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor"))); + if (info_is_warning) { + info->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons"))); + info->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor"))); + } else { + info->set_icon(get_theme_icon(SNAME("NodeInfo"), SNAME("EditorIcons"))); + info->add_theme_color_override("font_color", get_theme_color(SNAME("font_color"), SNAME("Editor"))); + } } break; } } @@ -476,11 +481,22 @@ void InspectorDock::open_resource(const String &p_type) { _load_resource(p_type); } -void InspectorDock::set_warning(const String &p_message) { - warning->hide(); - if (!p_message.is_empty()) { - warning->show(); - warning_dialog->set_text(p_message); +void InspectorDock::set_info(const String &p_button_text, const String &p_message, bool p_is_warning) { + info->hide(); + info_is_warning = p_is_warning; + + if (info_is_warning) { + info->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons"))); + info->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor"))); + } else { + info->set_icon(get_theme_icon(SNAME("NodeInfo"), SNAME("EditorIcons"))); + info->add_theme_color_override("font_color", get_theme_color(SNAME("font_color"), SNAME("Editor"))); + } + + if (!p_button_text.is_empty() && !p_message.is_empty()) { + info->show(); + info->set_text(p_button_text); + info_dialog->set_text(p_message); } } @@ -515,7 +531,7 @@ void InspectorDock::update(Object *p_object) { resource_extra_popup->set_item_disabled(resource_extra_popup->get_item_index(RESOURCE_MAKE_BUILT_IN), !is_resource || is_text_file); if (!is_object || is_text_file) { - warning->hide(); + info->hide(); editor_path->clear_path(); return; } @@ -707,12 +723,11 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { object_menu->get_popup()->connect("about_to_popup", callable_mp(this, &InspectorDock::_prepare_menu)); object_menu->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_menu_option)); - warning = memnew(Button); - add_child(warning); - warning->set_text(TTR("Changes may be lost!")); - warning->set_clip_text(true); - warning->hide(); - warning->connect("pressed", callable_mp(this, &InspectorDock::_warning_pressed)); + info = memnew(Button); + add_child(info); + info->set_clip_text(true); + info->hide(); + info->connect("pressed", callable_mp(this, &InspectorDock::_info_pressed)); unique_resources_confirmation = memnew(ConfirmationDialog); add_child(unique_resources_confirmation); @@ -737,8 +752,8 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { unique_resources_confirmation->connect("confirmed", callable_mp(this, &InspectorDock::_menu_confirm_current)); - warning_dialog = memnew(AcceptDialog); - EditorNode::get_singleton()->get_gui_base()->add_child(warning_dialog); + info_dialog = memnew(AcceptDialog); + EditorNode::get_singleton()->get_gui_base()->add_child(info_dialog); load_resource_dialog = memnew(EditorFileDialog); add_child(load_resource_dialog); diff --git a/editor/inspector_dock.h b/editor/inspector_dock.h index e32410151f..5ebcbf70c7 100644 --- a/editor/inspector_dock.h +++ b/editor/inspector_dock.h @@ -93,8 +93,9 @@ class InspectorDock : public VBoxContainer { MenuButton *object_menu = nullptr; EditorPath *editor_path = nullptr; - Button *warning = nullptr; - AcceptDialog *warning_dialog = nullptr; + bool info_is_warning = false; // Display in yellow and use warning icon if true. + Button *info = nullptr; + AcceptDialog *info_dialog = nullptr; int current_option = -1; ConfirmationDialog *unique_resources_confirmation = nullptr; @@ -118,7 +119,7 @@ class InspectorDock : public VBoxContainer { void _paste_resource(); void _prepare_resource_extra_popup(); - void _warning_pressed(); + void _info_pressed(); void _resource_created(); void _resource_selected(const Ref<Resource> &p_res, const String &p_property); void _edit_forward(); @@ -145,7 +146,7 @@ public: void edit_resource(const Ref<Resource> &p_resource); void open_resource(const String &p_type); void clear(); - void set_warning(const String &p_message); + void set_info(const String &p_button_text, const String &p_message, bool p_is_warning); void update(Object *p_object); Container *get_addon_area(); EditorInspector *get_inspector() { return inspector; } diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp index 70775c1ee2..5db9249af1 100644 --- a/editor/plugins/bone_map_editor_plugin.cpp +++ b/editor/plugins/bone_map_editor_plugin.cpp @@ -47,6 +47,9 @@ void BoneMapperButton::fetch_textures() { set_offset(SIDE_TOP, 0); set_offset(SIDE_BOTTOM, 0); + // Hack to avoid handle color darkening... + set_modulate(EditorSettings::get_singleton()->is_dark_theme() ? Color(1, 1, 1) : Color(4.25, 4.25, 4.25)); + circle = memnew(TextureRect); circle->set_texture(get_theme_icon(SNAME("BoneMapperHandleCircle"), SNAME("EditorIcons"))); add_child(circle); @@ -98,14 +101,24 @@ BoneMapperButton::~BoneMapperButton() { } void BoneMapperItem::create_editor() { - skeleton_bone_selector = memnew(EditorPropertyTextEnum); - skeleton_bone_selector->setup(skeleton_bone_names, false, true); + HBoxContainer *hbox = memnew(HBoxContainer); + add_child(hbox); + + skeleton_bone_selector = memnew(EditorPropertyText); skeleton_bone_selector->set_label(profile_bone_name); skeleton_bone_selector->set_selectable(false); + skeleton_bone_selector->set_h_size_flags(SIZE_EXPAND_FILL); skeleton_bone_selector->set_object_and_property(bone_map.ptr(), "bone_map/" + String(profile_bone_name)); skeleton_bone_selector->update_property(); skeleton_bone_selector->connect("property_changed", callable_mp(this, &BoneMapperItem::_value_changed)); - add_child(skeleton_bone_selector); + hbox->add_child(skeleton_bone_selector); + + picker_button = memnew(Button); + picker_button->set_icon(get_theme_icon(SNAME("ClassList"), SNAME("EditorIcons"))); + picker_button->connect("pressed", callable_mp(this, &BoneMapperItem::_open_picker)); + hbox->add_child(picker_button); + + add_child(memnew(HSeparator)); } void BoneMapperItem::_update_property() { @@ -114,6 +127,10 @@ void BoneMapperItem::_update_property() { } } +void BoneMapperItem::_open_picker() { + emit_signal(SNAME("pick"), profile_bone_name); +} + void BoneMapperItem::_value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { bone_map->set(p_property, p_value); } @@ -133,25 +150,153 @@ void BoneMapperItem::_notification(int p_what) { } void BoneMapperItem::_bind_methods() { + ADD_SIGNAL(MethodInfo("pick", PropertyInfo(Variant::STRING_NAME, "profile_bone_name"))); } -BoneMapperItem::BoneMapperItem(Ref<BoneMap> &p_bone_map, PackedStringArray p_skeleton_bone_names, const StringName &p_profile_bone_name) { +BoneMapperItem::BoneMapperItem(Ref<BoneMap> &p_bone_map, const StringName &p_profile_bone_name) { bone_map = p_bone_map; - skeleton_bone_names = p_skeleton_bone_names; profile_bone_name = p_profile_bone_name; } BoneMapperItem::~BoneMapperItem() { } +void BonePicker::create_editors() { + set_title(TTR("Bone Picker:")); + + VBoxContainer *vbox = memnew(VBoxContainer); + add_child(vbox); + + bones = memnew(Tree); + bones->set_select_mode(Tree::SELECT_SINGLE); + bones->set_v_size_flags(Control::SIZE_EXPAND_FILL); + bones->set_hide_root(true); + bones->connect("item_activated", callable_mp(this, &BonePicker::_confirm)); + vbox->add_child(bones); + + create_bones_tree(skeleton); +} + +void BonePicker::create_bones_tree(Skeleton3D *p_skeleton) { + bones->clear(); + + if (!p_skeleton) { + return; + } + + TreeItem *root = bones->create_item(); + + HashMap<int, TreeItem *> items; + + items.insert(-1, root); + + Ref<Texture> bone_icon = get_theme_icon(SNAME("BoneAttachment3D"), SNAME("EditorIcons")); + + Vector<int> bones_to_process = p_skeleton->get_parentless_bones(); + bool is_first = true; + while (bones_to_process.size() > 0) { + int current_bone_idx = bones_to_process[0]; + bones_to_process.erase(current_bone_idx); + + Vector<int> current_bone_child_bones = p_skeleton->get_bone_children(current_bone_idx); + int child_bone_size = current_bone_child_bones.size(); + for (int i = 0; i < child_bone_size; i++) { + bones_to_process.push_back(current_bone_child_bones[i]); + } + + const int parent_idx = p_skeleton->get_bone_parent(current_bone_idx); + TreeItem *parent_item = items.find(parent_idx)->value; + + TreeItem *joint_item = bones->create_item(parent_item); + items.insert(current_bone_idx, joint_item); + + joint_item->set_text(0, p_skeleton->get_bone_name(current_bone_idx)); + joint_item->set_icon(0, bone_icon); + joint_item->set_selectable(0, true); + joint_item->set_metadata(0, "bones/" + itos(current_bone_idx)); + if (is_first) { + is_first = false; + } else { + joint_item->set_collapsed(true); + } + } +} + +void BonePicker::_confirm() { + _ok_pressed(); +} + +void BonePicker::popup_bones_tree(const Size2i &p_minsize) { + popup_centered(p_minsize); +} + +bool BonePicker::has_selected_bone() { + TreeItem *selected = bones->get_selected(); + if (!selected) { + return false; + } + return true; +} + +StringName BonePicker::get_selected_bone() { + TreeItem *selected = bones->get_selected(); + if (!selected) { + return StringName(); + } + return selected->get_text(0); +} + +void BonePicker::_bind_methods() { +} + +void BonePicker::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + create_editors(); + } break; + } +} + +BonePicker::BonePicker(Skeleton3D *p_skeleton) { + skeleton = p_skeleton; +} + +BonePicker::~BonePicker() { +} + void BoneMapper::create_editor() { + // Create Bone picker. + picker = memnew(BonePicker(skeleton)); + picker->connect("confirmed", callable_mp(this, &BoneMapper::_apply_picker_selection)); + add_child(picker, false, INTERNAL_MODE_FRONT); + + profile_selector = memnew(EditorPropertyResource); + profile_selector->setup(bone_map.ptr(), "profile", "SkeletonProfile"); + profile_selector->set_label("Profile"); + profile_selector->set_selectable(false); + profile_selector->set_object_and_property(bone_map.ptr(), "profile"); + profile_selector->update_property(); + profile_selector->connect("property_changed", callable_mp(this, &BoneMapper::_profile_changed)); + add_child(profile_selector); + add_child(memnew(HSeparator)); + + HBoxContainer *group_hbox = memnew(HBoxContainer); + add_child(group_hbox); + profile_group_selector = memnew(EditorPropertyEnum); profile_group_selector->set_label("Group"); profile_group_selector->set_selectable(false); + profile_group_selector->set_h_size_flags(SIZE_EXPAND_FILL); profile_group_selector->set_object_and_property(this, "current_group_idx"); profile_group_selector->update_property(); profile_group_selector->connect("property_changed", callable_mp(this, &BoneMapper::_value_changed)); - add_child(profile_group_selector); + group_hbox->add_child(profile_group_selector); + + clear_mapping_button = memnew(Button); + clear_mapping_button->set_icon(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons"))); + clear_mapping_button->set_tooltip(TTR("Clear mappings in current group.")); + clear_mapping_button->connect("pressed", callable_mp(this, &BoneMapper::_clear_mapping_current_group)); + group_hbox->add_child(clear_mapping_button); bone_mapper_field = memnew(AspectRatioContainer); bone_mapper_field->set_stretch_mode(AspectRatioContainer::STRETCH_FIT); @@ -175,9 +320,6 @@ void BoneMapper::create_editor() { mapper_item_vbox = memnew(VBoxContainer); add_child(mapper_item_vbox); - separator = memnew(HSeparator); - add_child(separator); - recreate_items(); } @@ -201,6 +343,18 @@ void BoneMapper::update_group_idx() { } } +void BoneMapper::_pick_bone(const StringName &p_bone_name) { + picker_key_name = p_bone_name; + picker->popup_bones_tree(Size2(500, 500) * EDSCALE); +} + +void BoneMapper::_apply_picker_selection() { + if (!picker->has_selected_bone()) { + return; + } + bone_map->set_skeleton_bone_name(picker_key_name, picker->get_selected_bone()); +} + void BoneMapper::set_current_group_idx(int p_group_idx) { current_group_idx = p_group_idx; recreate_editor(); @@ -282,6 +436,7 @@ void BoneMapper::clear_items() { // Clear items. int len = bone_mapper_items.size(); for (int i = 0; i < len; i++) { + bone_mapper_items[i]->disconnect("pick", callable_mp(this, &BoneMapper::_pick_bone)); mapper_item_vbox->remove_child(bone_mapper_items[i]); memdelete(bone_mapper_items[i]); } @@ -293,16 +448,11 @@ void BoneMapper::recreate_items() { // Create items by profile. Ref<SkeletonProfile> profile = bone_map->get_profile(); if (profile.is_valid()) { - PackedStringArray skeleton_bone_names; - int len = skeleton->get_bone_count(); - for (int i = 0; i < len; i++) { - skeleton_bone_names.push_back(skeleton->get_bone_name(i)); - } - - len = profile->get_bone_size(); + int len = profile->get_bone_size(); for (int i = 0; i < len; i++) { StringName bn = profile->get_bone_name(i); - bone_mapper_items.append(memnew(BoneMapperItem(bone_map, skeleton_bone_names, bn))); + bone_mapper_items.append(memnew(BoneMapperItem(bone_map, bn))); + bone_mapper_items[i]->connect("pick", callable_mp(this, &BoneMapper::_pick_bone), CONNECT_DEFERRED); mapper_item_vbox->add_child(bone_mapper_items[i]); } } @@ -363,11 +513,754 @@ void BoneMapper::_update_state() { } } +void BoneMapper::_clear_mapping_current_group() { + if (bone_map.is_valid()) { + Ref<SkeletonProfile> profile = bone_map->get_profile(); + if (profile.is_valid() && profile->get_group_size() > 0) { + int len = profile->get_bone_size(); + for (int i = 0; i < len; i++) { + if (profile->get_group(i) == profile->get_group_name(current_group_idx)) { + bone_map->_set_skeleton_bone_name(profile->get_bone_name(i), StringName()); + } + } + recreate_items(); + } + } +} + +#ifdef MODULE_REGEX_ENABLED +int BoneMapper::search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_picklist, BoneSegregation p_segregation, int p_parent, int p_child, int p_children_count) { + // There may be multiple candidates hit by existing the subsidiary bone. + // The one with the shortest name is probably the original. + LocalVector<String> hit_list; + String shortest = ""; + + for (int word_idx = 0; word_idx < p_picklist.size(); word_idx++) { + RegEx re = RegEx(p_picklist[word_idx]); + if (p_child == -1) { + Vector<int> bones_to_process = p_parent == -1 ? p_skeleton->get_parentless_bones() : p_skeleton->get_bone_children(p_parent); + while (bones_to_process.size() > 0) { + int idx = bones_to_process[0]; + bones_to_process.erase(idx); + Vector<int> children = p_skeleton->get_bone_children(idx); + for (int i = 0; i < children.size(); i++) { + bones_to_process.push_back(children[i]); + } + + if (p_children_count == 0 && children.size() > 0) { + continue; + } + if (p_children_count > 0 && children.size() < p_children_count) { + continue; + } + + String bn = skeleton->get_bone_name(idx); + if (!re.search(bn.to_lower()).is_null() && guess_bone_segregation(bn) == p_segregation) { + hit_list.push_back(bn); + } + } + + if (hit_list.size() > 0) { + shortest = hit_list[0]; + for (uint32_t i = 0; i < hit_list.size(); i++) { + if (hit_list[i].length() < shortest.length()) { + shortest = hit_list[i]; // Prioritize parent. + } + } + } + } else { + int idx = skeleton->get_bone_parent(p_child); + while (idx != p_parent && idx >= 0) { + Vector<int> children = p_skeleton->get_bone_children(idx); + if (p_children_count == 0 && children.size() > 0) { + continue; + } + if (p_children_count > 0 && children.size() < p_children_count) { + continue; + } + + String bn = skeleton->get_bone_name(idx); + if (!re.search(bn.to_lower()).is_null() && guess_bone_segregation(bn) == p_segregation) { + hit_list.push_back(bn); + } + idx = skeleton->get_bone_parent(idx); + } + + if (hit_list.size() > 0) { + shortest = hit_list[0]; + for (uint32_t i = 0; i < hit_list.size(); i++) { + if (hit_list[i].length() <= shortest.length()) { + shortest = hit_list[i]; // Prioritize parent. + } + } + } + } + + if (shortest != "") { + break; + } + } + + if (shortest == "") { + return -1; + } + + return skeleton->find_bone(shortest); +} + +BoneMapper::BoneSegregation BoneMapper::guess_bone_segregation(String p_bone_name) { + String fixed_bn = p_bone_name.camelcase_to_underscore().to_lower(); + + LocalVector<String> left_words; + left_words.push_back("(?<![a-zA-Z])left"); + left_words.push_back("(?<![a-zA-Z0-9])l(?![a-zA-Z0-9])"); + + LocalVector<String> right_words; + right_words.push_back("(?<![a-zA-Z])right"); + right_words.push_back("(?<![a-zA-Z0-9])r(?![a-zA-Z0-9])"); + + for (uint32_t i = 0; i < left_words.size(); i++) { + RegEx re_l = RegEx(left_words[i]); + if (!re_l.search(fixed_bn).is_null()) { + return BONE_SEGREGATION_LEFT; + } + RegEx re_r = RegEx(right_words[i]); + if (!re_r.search(fixed_bn).is_null()) { + return BONE_SEGREGATION_RIGHT; + } + } + + return BONE_SEGREGATION_NONE; +} + +void BoneMapper::_run_auto_mapping() { + auto_mapping_process(bone_map); + recreate_items(); +} + +void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) { + WARN_PRINT("Run auto mapping."); + + int bone_idx = -1; + Vector<String> picklist; // Use Vector<String> because match words have priority. + Vector<int> search_path; + + // 1. Guess Hips + picklist.push_back("hip"); + picklist.push_back("pelvis"); + picklist.push_back("waist"); + picklist.push_back("torso"); + int hips = search_bone_by_name(skeleton, picklist); + if (hips == -1) { + WARN_PRINT("Auto Mapping couldn't guess Hips. Abort auto mapping."); + return; // If there is no Hips, we cannot guess bone after then. + } else { + p_bone_map->_set_skeleton_bone_name("Hips", skeleton->get_bone_name(hips)); + } + picklist.clear(); + + // 2. Guess Root + bone_idx = skeleton->get_bone_parent(hips); + while (bone_idx >= 0) { + search_path.push_back(bone_idx); + bone_idx = skeleton->get_bone_parent(bone_idx); + } + if (search_path.size() == 0) { + bone_idx = -1; + } else if (search_path.size() == 1) { + bone_idx = search_path[0]; // It is only one bone which can be root. + } else { + bool found = false; + for (int i = 0; i < search_path.size(); i++) { + RegEx re = RegEx("root"); + if (!re.search(skeleton->get_bone_name(search_path[i]).to_lower()).is_null()) { + bone_idx = search_path[i]; // Name match is preferred. + found = true; + break; + } + } + if (!found) { + for (int i = 0; i < search_path.size(); i++) { + if (Vector3(0, 0, 0).is_equal_approx(skeleton->get_bone_global_rest(search_path[i]).origin)) { + bone_idx = search_path[i]; // The bone existing at the origin is appropriate as a root. + found = true; + break; + } + } + } + if (!found) { + bone_idx = search_path[search_path.size() - 1]; // Ambiguous, but most parental bone selected. + } + } + if (bone_idx == -1) { + WARN_PRINT("Auto Mapping couldn't guess Root."); // Root is not required, so continue. + } else { + p_bone_map->_set_skeleton_bone_name("Root", skeleton->get_bone_name(bone_idx)); + } + bone_idx = -1; + search_path.clear(); + + // 3. Guess Neck + picklist.push_back("neck"); + picklist.push_back("head"); // For no neck model. + picklist.push_back("face"); // Same above. + int neck = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_NONE, hips); + picklist.clear(); + + // 4. Guess Head + picklist.push_back("head"); + picklist.push_back("face"); + int head = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_NONE, neck); + if (head == -1) { + search_path = skeleton->get_bone_children(neck); + if (search_path.size() == 1) { + head = search_path[0]; // Maybe only one child of the Neck is Head. + } + } + if (head == -1) { + if (neck != -1) { + head = neck; // The head animation should have more movement. + neck = -1; + p_bone_map->_set_skeleton_bone_name("Head", skeleton->get_bone_name(head)); + } else { + WARN_PRINT("Auto Mapping couldn't guess Neck or Head."); // Continued for guessing on the other bones. But abort when guessing spines step. + } + } else { + p_bone_map->_set_skeleton_bone_name("Neck", skeleton->get_bone_name(neck)); + p_bone_map->_set_skeleton_bone_name("Head", skeleton->get_bone_name(head)); + } + picklist.clear(); + search_path.clear(); + + int neck_or_head = neck != -1 ? neck : (head != -1 ? head : -1); + if (neck_or_head != -1) { + // 4-1. Guess Eyes + picklist.push_back("eye(?!.*(brow|lash|lid))"); + bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, neck_or_head); + if (bone_idx == -1) { + WARN_PRINT("Auto Mapping couldn't guess LeftEye."); + } else { + p_bone_map->_set_skeleton_bone_name("LeftEye", skeleton->get_bone_name(bone_idx)); + } + bone_idx = -1; + + bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, neck_or_head); + if (bone_idx == -1) { + WARN_PRINT("Auto Mapping couldn't guess RightEye."); + } else { + p_bone_map->_set_skeleton_bone_name("RightEye", skeleton->get_bone_name(bone_idx)); + } + bone_idx = -1; + picklist.clear(); + + // 4-2. Guess Jaw + picklist.push_back("jaw"); + bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_NONE, neck_or_head); + if (bone_idx == -1) { + WARN_PRINT("Auto Mapping couldn't guess Jaw."); + } else { + p_bone_map->_set_skeleton_bone_name("Jaw", skeleton->get_bone_name(bone_idx)); + } + bone_idx = -1; + picklist.clear(); + } + + // 5. Guess Foots + picklist.push_back("foot"); + picklist.push_back("ankle"); + int left_foot = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips); + if (left_foot == -1) { + WARN_PRINT("Auto Mapping couldn't guess LeftFoot."); + } else { + p_bone_map->_set_skeleton_bone_name("LeftFoot", skeleton->get_bone_name(left_foot)); + } + int right_foot = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips); + if (right_foot == -1) { + WARN_PRINT("Auto Mapping couldn't guess RightFoot."); + } else { + p_bone_map->_set_skeleton_bone_name("RightFoot", skeleton->get_bone_name(right_foot)); + } + picklist.clear(); + + // 5-1. Guess LowerLegs + picklist.push_back("(low|under).*leg"); + picklist.push_back("knee"); + picklist.push_back("shin"); + picklist.push_back("calf"); + picklist.push_back("leg"); + int left_lower_leg = -1; + if (left_foot != -1) { + left_lower_leg = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips, left_foot); + } + if (left_lower_leg == -1) { + WARN_PRINT("Auto Mapping couldn't guess LeftLowerLeg."); + } else { + p_bone_map->_set_skeleton_bone_name("LeftLowerLeg", skeleton->get_bone_name(left_lower_leg)); + } + int right_lower_leg = -1; + if (right_foot != -1) { + right_lower_leg = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips, right_foot); + } + if (right_lower_leg == -1) { + WARN_PRINT("Auto Mapping couldn't guess RightLowerLeg."); + } else { + p_bone_map->_set_skeleton_bone_name("RightLowerLeg", skeleton->get_bone_name(right_lower_leg)); + } + picklist.clear(); + + // 5-2. Guess UpperLegs + picklist.push_back("up.*leg"); + picklist.push_back("thigh"); + picklist.push_back("leg"); + if (left_lower_leg != -1) { + bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips, left_lower_leg); + } + if (bone_idx == -1) { + WARN_PRINT("Auto Mapping couldn't guess LeftUpperLeg."); + } else { + p_bone_map->_set_skeleton_bone_name("LeftUpperLeg", skeleton->get_bone_name(bone_idx)); + } + bone_idx = -1; + if (right_lower_leg != -1) { + bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips, right_lower_leg); + } + if (bone_idx == -1) { + WARN_PRINT("Auto Mapping couldn't guess RightUpperLeg."); + } else { + p_bone_map->_set_skeleton_bone_name("RightUpperLeg", skeleton->get_bone_name(bone_idx)); + } + bone_idx = -1; + picklist.clear(); + + // 5-3. Guess Toes + picklist.push_back("toe"); + picklist.push_back("ball"); + if (left_foot != -1) { + bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, left_foot); + if (bone_idx == -1) { + search_path = skeleton->get_bone_children(left_foot); + if (search_path.size() == 1) { + bone_idx = search_path[0]; // Maybe only one child of the Foot is Toes. + } + search_path.clear(); + } + } + if (bone_idx == -1) { + WARN_PRINT("Auto Mapping couldn't guess LeftToes."); + } else { + p_bone_map->_set_skeleton_bone_name("LeftToes", skeleton->get_bone_name(bone_idx)); + } + bone_idx = -1; + if (right_foot != -1) { + bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, right_foot); + if (bone_idx == -1) { + search_path = skeleton->get_bone_children(right_foot); + if (search_path.size() == 1) { + bone_idx = search_path[0]; // Maybe only one child of the Foot is Toes. + } + search_path.clear(); + } + } + if (bone_idx == -1) { + WARN_PRINT("Auto Mapping couldn't guess RightToes."); + } else { + p_bone_map->_set_skeleton_bone_name("RightToes", skeleton->get_bone_name(bone_idx)); + } + bone_idx = -1; + picklist.clear(); + + // 6. Guess Hands + picklist.push_back("hand"); + picklist.push_back("wrist"); + picklist.push_back("palm"); + picklist.push_back("fingers"); + int left_hand_or_palm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips, -1, 5); + if (left_hand_or_palm == -1) { + // Ambiguous, but try again for fewer finger models. + left_hand_or_palm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips); + } + int left_hand = left_hand_or_palm; // Check for the presence of a wrist, since bones with five children may be palmar. + while (left_hand != -1) { + bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips, left_hand); + if (bone_idx == -1) { + break; + } + left_hand = bone_idx; + } + if (left_hand == -1) { + WARN_PRINT("Auto Mapping couldn't guess LeftHand."); + } else { + p_bone_map->_set_skeleton_bone_name("LeftHand", skeleton->get_bone_name(left_hand)); + } + bone_idx = -1; + int right_hand_or_palm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips, -1, 5); + if (right_hand_or_palm == -1) { + // Ambiguous, but try again for fewer finger models. + right_hand_or_palm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips); + } + int right_hand = right_hand_or_palm; + while (right_hand != -1) { + bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips, right_hand); + if (bone_idx == -1) { + break; + } + right_hand = bone_idx; + } + if (right_hand == -1) { + WARN_PRINT("Auto Mapping couldn't guess RightHand."); + } else { + p_bone_map->_set_skeleton_bone_name("RightHand", skeleton->get_bone_name(right_hand)); + } + bone_idx = -1; + picklist.clear(); + + // 6-1. Guess Finger + bool named_finger_is_found = false; + LocalVector<String> fingers; + fingers.push_back("thumb|pollex"); + fingers.push_back("index|fore"); + fingers.push_back("middle"); + fingers.push_back("ring"); + fingers.push_back("little|pinkie|pinky"); + if (left_hand_or_palm != -1) { + LocalVector<LocalVector<String>> left_fingers_map; + left_fingers_map.resize(5); + left_fingers_map[0].push_back("LeftThumbMetacarpal"); + left_fingers_map[0].push_back("LeftThumbProximal"); + left_fingers_map[0].push_back("LeftThumbDistal"); + left_fingers_map[1].push_back("LeftIndexProximal"); + left_fingers_map[1].push_back("LeftIndexIntermediate"); + left_fingers_map[1].push_back("LeftIndexDistal"); + left_fingers_map[2].push_back("LeftMiddleProximal"); + left_fingers_map[2].push_back("LeftMiddleIntermediate"); + left_fingers_map[2].push_back("LeftMiddleDistal"); + left_fingers_map[3].push_back("LeftRingProximal"); + left_fingers_map[3].push_back("LeftRingIntermediate"); + left_fingers_map[3].push_back("LeftRingDistal"); + left_fingers_map[4].push_back("LeftLittleProximal"); + left_fingers_map[4].push_back("LeftLittleIntermediate"); + left_fingers_map[4].push_back("LeftLittleDistal"); + for (int i = 0; i < 5; i++) { + picklist.push_back(fingers[i]); + int finger = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, left_hand_or_palm, -1, 0); + if (finger != -1) { + while (finger != left_hand_or_palm && finger >= 0) { + search_path.push_back(finger); + finger = skeleton->get_bone_parent(finger); + } + search_path.reverse(); + if (search_path.size() == 1) { + p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0])); + named_finger_is_found = true; + } else if (search_path.size() == 2) { + p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0])); + p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][1], skeleton->get_bone_name(search_path[1])); + named_finger_is_found = true; + } else if (search_path.size() >= 3) { + search_path = search_path.slice(-3); // Eliminate the possibility of carpal bone. + p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0])); + p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][1], skeleton->get_bone_name(search_path[1])); + p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][2], skeleton->get_bone_name(search_path[2])); + named_finger_is_found = true; + } + } + picklist.clear(); + search_path.clear(); + } + + // It is a bit corner case, but possibly the finger names are sequentially numbered... + if (!named_finger_is_found) { + picklist.push_back("finger"); + RegEx finger_re = RegEx("finger"); + search_path = skeleton->get_bone_children(left_hand_or_palm); + Vector<String> finger_names; + for (int i = 0; i < search_path.size(); i++) { + String bn = skeleton->get_bone_name(search_path[i]); + if (!finger_re.search(bn.to_lower()).is_null()) { + finger_names.push_back(bn); + } + } + finger_names.sort(); // Order by lexicographic, normal use cases never have more than 10 fingers in one hand. + search_path.clear(); + for (int i = 0; i < finger_names.size(); i++) { + if (i >= 5) { + break; + } + int finger_root = skeleton->find_bone(finger_names[i]); + int finger = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, finger_root, -1, 0); + if (finger != -1) { + while (finger != finger_root && finger >= 0) { + search_path.push_back(finger); + finger = skeleton->get_bone_parent(finger); + } + } + search_path.push_back(finger_root); + search_path.reverse(); + if (search_path.size() == 1) { + p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0])); + } else if (search_path.size() == 2) { + p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0])); + p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][1], skeleton->get_bone_name(search_path[1])); + } else if (search_path.size() >= 3) { + search_path = search_path.slice(-3); // Eliminate the possibility of carpal bone. + p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0])); + p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][1], skeleton->get_bone_name(search_path[1])); + p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][2], skeleton->get_bone_name(search_path[2])); + } + search_path.clear(); + } + picklist.clear(); + } + } + named_finger_is_found = false; + if (right_hand_or_palm != -1) { + LocalVector<LocalVector<String>> right_fingers_map; + right_fingers_map.resize(5); + right_fingers_map[0].push_back("RightThumbMetacarpal"); + right_fingers_map[0].push_back("RightThumbProximal"); + right_fingers_map[0].push_back("RightThumbDistal"); + right_fingers_map[1].push_back("RightIndexProximal"); + right_fingers_map[1].push_back("RightIndexIntermediate"); + right_fingers_map[1].push_back("RightIndexDistal"); + right_fingers_map[2].push_back("RightMiddleProximal"); + right_fingers_map[2].push_back("RightMiddleIntermediate"); + right_fingers_map[2].push_back("RightMiddleDistal"); + right_fingers_map[3].push_back("RightRingProximal"); + right_fingers_map[3].push_back("RightRingIntermediate"); + right_fingers_map[3].push_back("RightRingDistal"); + right_fingers_map[4].push_back("RightLittleProximal"); + right_fingers_map[4].push_back("RightLittleIntermediate"); + right_fingers_map[4].push_back("RightLittleDistal"); + for (int i = 0; i < 5; i++) { + picklist.push_back(fingers[i]); + int finger = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, right_hand_or_palm, -1, 0); + if (finger != -1) { + while (finger != right_hand_or_palm && finger >= 0) { + search_path.push_back(finger); + finger = skeleton->get_bone_parent(finger); + } + search_path.reverse(); + if (search_path.size() == 1) { + p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0])); + named_finger_is_found = true; + } else if (search_path.size() == 2) { + p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0])); + p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][1], skeleton->get_bone_name(search_path[1])); + named_finger_is_found = true; + } else if (search_path.size() >= 3) { + search_path = search_path.slice(-3); // Eliminate the possibility of carpal bone. + p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0])); + p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][1], skeleton->get_bone_name(search_path[1])); + p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][2], skeleton->get_bone_name(search_path[2])); + named_finger_is_found = true; + } + } + picklist.clear(); + search_path.clear(); + } + + // It is a bit corner case, but possibly the finger names are sequentially numbered... + if (!named_finger_is_found) { + picklist.push_back("finger"); + RegEx finger_re = RegEx("finger"); + search_path = skeleton->get_bone_children(right_hand_or_palm); + Vector<String> finger_names; + for (int i = 0; i < search_path.size(); i++) { + String bn = skeleton->get_bone_name(search_path[i]); + if (!finger_re.search(bn.to_lower()).is_null()) { + finger_names.push_back(bn); + } + } + finger_names.sort(); // Order by lexicographic, normal use cases never have more than 10 fingers in one hand. + search_path.clear(); + for (int i = 0; i < finger_names.size(); i++) { + if (i >= 5) { + break; + } + int finger_root = skeleton->find_bone(finger_names[i]); + int finger = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, finger_root, -1, 0); + if (finger != -1) { + while (finger != finger_root && finger >= 0) { + search_path.push_back(finger); + finger = skeleton->get_bone_parent(finger); + } + } + search_path.push_back(finger_root); + search_path.reverse(); + if (search_path.size() == 1) { + p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0])); + } else if (search_path.size() == 2) { + p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0])); + p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][1], skeleton->get_bone_name(search_path[1])); + } else if (search_path.size() >= 3) { + search_path = search_path.slice(-3); // Eliminate the possibility of carpal bone. + p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0])); + p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][1], skeleton->get_bone_name(search_path[1])); + p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][2], skeleton->get_bone_name(search_path[2])); + } + search_path.clear(); + } + picklist.clear(); + } + } + + // 7. Guess Arms + picklist.push_back("shoulder"); + picklist.push_back("clavicle"); + picklist.push_back("collar"); + int left_shoulder = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips); + if (left_shoulder == -1) { + WARN_PRINT("Auto Mapping couldn't guess LeftShoulder."); + } else { + p_bone_map->_set_skeleton_bone_name("LeftShoulder", skeleton->get_bone_name(left_shoulder)); + } + int right_shoulder = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips); + if (right_shoulder == -1) { + WARN_PRINT("Auto Mapping couldn't guess RightShoulder."); + } else { + p_bone_map->_set_skeleton_bone_name("RightShoulder", skeleton->get_bone_name(right_shoulder)); + } + picklist.clear(); + + // 7-1. Guess LowerArms + picklist.push_back("(low|fore).*arm"); + picklist.push_back("elbow"); + picklist.push_back("arm"); + int left_lower_arm = -1; + if (left_shoulder != -1 && left_hand_or_palm != -1) { + left_lower_arm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, left_shoulder, left_hand_or_palm); + } + if (left_lower_arm == -1) { + WARN_PRINT("Auto Mapping couldn't guess LeftLowerArm."); + } else { + p_bone_map->_set_skeleton_bone_name("LeftLowerArm", skeleton->get_bone_name(left_lower_arm)); + } + int right_lower_arm = -1; + if (right_shoulder != -1 && right_hand_or_palm != -1) { + right_lower_arm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, right_shoulder, right_hand_or_palm); + } + if (right_lower_arm == -1) { + WARN_PRINT("Auto Mapping couldn't guess RightLowerArm."); + } else { + p_bone_map->_set_skeleton_bone_name("RightLowerArm", skeleton->get_bone_name(right_lower_arm)); + } + picklist.clear(); + + // 7-2. Guess UpperArms + picklist.push_back("up.*arm"); + picklist.push_back("arm"); + if (left_shoulder != -1 && left_lower_arm != -1) { + bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, left_shoulder, left_lower_arm); + } + if (bone_idx == -1) { + WARN_PRINT("Auto Mapping couldn't guess LeftUpperArm."); + } else { + p_bone_map->_set_skeleton_bone_name("LeftUpperArm", skeleton->get_bone_name(bone_idx)); + } + bone_idx = -1; + if (right_shoulder != -1 && right_lower_arm != -1) { + bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, right_shoulder, right_lower_arm); + } + if (bone_idx == -1) { + WARN_PRINT("Auto Mapping couldn't guess RightUpperArm."); + } else { + p_bone_map->_set_skeleton_bone_name("RightUpperArm", skeleton->get_bone_name(bone_idx)); + } + bone_idx = -1; + picklist.clear(); + + // 8. Guess UpperChest or Chest + if (neck_or_head == -1) { + return; // Abort. + } + int chest_or_upper_chest = skeleton->get_bone_parent(neck_or_head); + bool is_appropriate = true; + if (left_shoulder != -1) { + bone_idx = skeleton->get_bone_parent(left_shoulder); + bool detect = false; + while (bone_idx != hips && bone_idx >= 0) { + if (bone_idx == chest_or_upper_chest) { + detect = true; + break; + } + bone_idx = skeleton->get_bone_parent(bone_idx); + } + if (!detect) { + is_appropriate = false; + } + bone_idx = -1; + } + if (right_shoulder != -1) { + bone_idx = skeleton->get_bone_parent(right_shoulder); + bool detect = false; + while (bone_idx != hips && bone_idx >= 0) { + if (bone_idx == chest_or_upper_chest) { + detect = true; + break; + } + bone_idx = skeleton->get_bone_parent(bone_idx); + } + if (!detect) { + is_appropriate = false; + } + bone_idx = -1; + } + if (!is_appropriate) { + if (skeleton->get_bone_parent(left_shoulder) == skeleton->get_bone_parent(right_shoulder)) { + chest_or_upper_chest = skeleton->get_bone_parent(left_shoulder); + } else { + chest_or_upper_chest = -1; + } + } + if (chest_or_upper_chest == -1) { + WARN_PRINT("Auto Mapping couldn't guess Chest or UpperChest. Abort auto mapping."); + return; // Will be not able to guess Spines. + } + + // 9. Guess Spines + bone_idx = skeleton->get_bone_parent(chest_or_upper_chest); + while (bone_idx != hips && bone_idx >= 0) { + search_path.push_back(bone_idx); + bone_idx = skeleton->get_bone_parent(bone_idx); + } + search_path.reverse(); + if (search_path.size() == 0) { + p_bone_map->_set_skeleton_bone_name("Spine", skeleton->get_bone_name(chest_or_upper_chest)); // Maybe chibi model...? + } else if (search_path.size() == 1) { + p_bone_map->_set_skeleton_bone_name("Spine", skeleton->get_bone_name(search_path[0])); + p_bone_map->_set_skeleton_bone_name("Chest", skeleton->get_bone_name(chest_or_upper_chest)); + } else if (search_path.size() >= 2) { + p_bone_map->_set_skeleton_bone_name("Spine", skeleton->get_bone_name(search_path[0])); + p_bone_map->_set_skeleton_bone_name("Chest", skeleton->get_bone_name(search_path[search_path.size() - 1])); // Probably UppeChest's parent is appropriate. + p_bone_map->_set_skeleton_bone_name("UpperChest", skeleton->get_bone_name(chest_or_upper_chest)); + } + bone_idx = -1; + search_path.clear(); + + WARN_PRINT("Finish auto mapping."); +} +#endif // MODULE_REGEX_ENABLED + void BoneMapper::_value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { set(p_property, p_value); recreate_editor(); } +void BoneMapper::_profile_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { + bone_map->set(p_property, p_value); + + // Run auto mapping when setting SkeletonProfileHumanoid by GUI Editor. + Ref<SkeletonProfile> profile = bone_map->get_profile(); + if (profile.is_valid()) { + SkeletonProfileHumanoid *hmn = Object::cast_to<SkeletonProfileHumanoid>(profile.ptr()); + if (hmn) { +#ifdef MODULE_REGEX_ENABLED + _run_auto_mapping(); +#endif // MODULE_REGEX_ENABLED + } + } +} + void BoneMapper::_bind_methods() { ClassDB::bind_method(D_METHOD("set_current_group_idx", "current_group_idx"), &BoneMapper::set_current_group_idx); ClassDB::bind_method(D_METHOD("get_current_group_idx"), &BoneMapper::get_current_group_idx); @@ -444,10 +1337,6 @@ void BoneMapEditor::_notification(int p_what) { create_editors(); } break; case NOTIFICATION_EXIT_TREE: { - if (bone_mapper) { - remove_child(bone_mapper); - bone_mapper->queue_delete(); - } skeleton = nullptr; } break; } diff --git a/editor/plugins/bone_map_editor_plugin.h b/editor/plugins/bone_map_editor_plugin.h index 339547ea10..0541ce6eac 100644 --- a/editor/plugins/bone_map_editor_plugin.h +++ b/editor/plugins/bone_map_editor_plugin.h @@ -34,6 +34,12 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" #include "editor/editor_properties.h" + +#include "modules/modules_enabled.gen.h" // For regex. +#ifdef MODULE_REGEX_ENABLED +#include "modules/regex/regex.h" +#endif + #include "scene/3d/skeleton_3d.h" #include "scene/gui/color_rect.h" #include "scene/gui/dialogs.h" @@ -79,12 +85,13 @@ class BoneMapperItem : public VBoxContainer { int button_id = -1; StringName profile_bone_name; - PackedStringArray skeleton_bone_names; Ref<BoneMap> bone_map; - EditorPropertyTextEnum *skeleton_bone_selector; + EditorPropertyText *skeleton_bone_selector; + Button *picker_button; void _update_property(); + void _open_picker(); protected: void _notification(int p_what); @@ -95,20 +102,49 @@ protected: public: void assign_button_id(int p_button_id); - BoneMapperItem(Ref<BoneMap> &p_bone_map, PackedStringArray p_skeleton_bone_names, const StringName &p_profile_bone_name = StringName()); + BoneMapperItem(Ref<BoneMap> &p_bone_map, const StringName &p_profile_bone_name = StringName()); ~BoneMapperItem(); }; +class BonePicker : public AcceptDialog { + GDCLASS(BonePicker, AcceptDialog); + + Skeleton3D *skeleton = nullptr; + Tree *bones = nullptr; + +public: + void popup_bones_tree(const Size2i &p_minsize = Size2i()); + bool has_selected_bone(); + StringName get_selected_bone(); + +protected: + void _notification(int p_what); + static void _bind_methods(); + + void _confirm(); + +private: + void create_editors(); + void create_bones_tree(Skeleton3D *p_skeleton); + +public: + BonePicker(Skeleton3D *p_skeleton); + ~BonePicker(); +}; + class BoneMapper : public VBoxContainer { GDCLASS(BoneMapper, VBoxContainer); Skeleton3D *skeleton; Ref<BoneMap> bone_map; + EditorPropertyResource *profile_selector; + Vector<BoneMapperItem *> bone_mapper_items; + Button *clear_mapping_button; + VBoxContainer *mapper_item_vbox; - HSeparator *separator; int current_group_idx = 0; int current_bone_idx = -1; @@ -126,10 +162,31 @@ class BoneMapper : public VBoxContainer { void update_group_idx(); void _update_state(); + /* Bone picker */ + BonePicker *picker = nullptr; + StringName picker_key_name; + void _pick_bone(const StringName &p_bone_name); + void _apply_picker_selection(); + void _clear_mapping_current_group(); + +#ifdef MODULE_REGEX_ENABLED + /* For auto mapping */ + enum BoneSegregation { + BONE_SEGREGATION_NONE, + BONE_SEGREGATION_LEFT, + BONE_SEGREGATION_RIGHT + }; + int search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_picklist, BoneSegregation p_segregation = BONE_SEGREGATION_NONE, int p_parent = -1, int p_child = -1, int p_children_count = -1); + BoneSegregation guess_bone_segregation(String p_bone_name); + void auto_mapping_process(Ref<BoneMap> &p_bone_map); + void _run_auto_mapping(); +#endif // MODULE_REGEX_ENABLED + protected: void _notification(int p_what); static void _bind_methods(); virtual void _value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing); + virtual void _profile_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing); public: void set_current_group_idx(int p_group_idx); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 5682df845e..17c2d26dc2 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -2958,6 +2958,9 @@ void CanvasItemEditor::_draw_ruler_tool() { Point2 corner = Point2(begin.x, end.y); Vector2 length_vector = (begin - end).abs() / zoom; + const real_t horizontal_angle_rad = length_vector.angle(); + const real_t vertical_angle_rad = Math_PI / 2.0 - horizontal_angle_rad; + Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts")); int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")); Color font_color = get_theme_color(SNAME("font_color"), SNAME("Editor")); @@ -2974,6 +2977,42 @@ void CanvasItemEditor::_draw_ruler_tool() { text_pos.x = CLAMP(text_pos.x, text_width / 2, viewport->get_rect().size.x - text_width * 1.5); text_pos.y = CLAMP(text_pos.y, text_height * 1.5, viewport->get_rect().size.y - text_height * 1.5); + // Draw lines. + viewport->draw_line(begin, end, ruler_primary_color, Math::round(EDSCALE * 3)); + + bool draw_secondary_lines = !(Math::is_equal_approx(begin.y, corner.y) || Math::is_equal_approx(end.x, corner.x)); + if (draw_secondary_lines) { + viewport->draw_line(begin, corner, ruler_secondary_color, Math::round(EDSCALE)); + viewport->draw_line(corner, end, ruler_secondary_color, Math::round(EDSCALE)); + + // Angle arcs. + int arc_point_count = 8; + real_t arc_radius_max_length_percent = 0.1; + real_t ruler_length = length_vector.length() * zoom; + real_t arc_max_radius = 50.0; + real_t arc_line_width = 2.0; + + const Vector2 end_to_begin = (end - begin); + + real_t arc_1_start_angle = end_to_begin.x < 0 + ? (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 - vertical_angle_rad : Math_PI / 2.0) + : (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 : Math_PI / 2.0 - vertical_angle_rad); + real_t arc_1_end_angle = arc_1_start_angle + vertical_angle_rad; + // Constrain arc to triangle height & max size. + real_t arc_1_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.y)), arc_max_radius); + + real_t arc_2_start_angle = end_to_begin.x < 0 + ? (end_to_begin.y < 0 ? 0.0 : -horizontal_angle_rad) + : (end_to_begin.y < 0 ? Math_PI - horizontal_angle_rad : Math_PI); + real_t arc_2_end_angle = arc_2_start_angle + horizontal_angle_rad; + // Constrain arc to triangle width & max size. + real_t arc_2_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.x)), arc_max_radius); + + viewport->draw_arc(begin, arc_1_radius, arc_1_start_angle, arc_1_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width)); + viewport->draw_arc(end, arc_2_radius, arc_2_start_angle, arc_2_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width)); + } + + // Draw text. if (begin.is_equal_approx(end)) { viewport->draw_string_outline(font, text_pos, (String)ruler_tool_origin, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color); viewport->draw_string(font, text_pos, (String)ruler_tool_origin, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color); @@ -2985,17 +3024,7 @@ void CanvasItemEditor::_draw_ruler_tool() { viewport->draw_string_outline(font, text_pos, TS->format_number(vformat("%.1f px", length_vector.length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color); viewport->draw_string(font, text_pos, TS->format_number(vformat("%.1f px", length_vector.length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color); - bool draw_secondary_lines = !(Math::is_equal_approx(begin.y, corner.y) || Math::is_equal_approx(end.x, corner.x)); - - viewport->draw_line(begin, end, ruler_primary_color, Math::round(EDSCALE * 3)); if (draw_secondary_lines) { - viewport->draw_line(begin, corner, ruler_secondary_color, Math::round(EDSCALE)); - viewport->draw_line(corner, end, ruler_secondary_color, Math::round(EDSCALE)); - } - - if (draw_secondary_lines) { - const real_t horizontal_angle_rad = length_vector.angle(); - const real_t vertical_angle_rad = Math_PI / 2.0 - horizontal_angle_rad; const int horizontal_angle = round(180 * horizontal_angle_rad / Math_PI); const int vertical_angle = round(180 * vertical_angle_rad / Math_PI); @@ -3032,32 +3061,6 @@ void CanvasItemEditor::_draw_ruler_tool() { } viewport->draw_string_outline(font, h_angle_text_pos, TS->format_number(vformat(String::utf8("%d°"), horizontal_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color); viewport->draw_string(font, h_angle_text_pos, TS->format_number(vformat(String::utf8("%d°"), horizontal_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color); - - // Angle arcs - int arc_point_count = 8; - real_t arc_radius_max_length_percent = 0.1; - real_t ruler_length = length_vector.length() * zoom; - real_t arc_max_radius = 50.0; - real_t arc_line_width = 2.0; - - const Vector2 end_to_begin = (end - begin); - - real_t arc_1_start_angle = end_to_begin.x < 0 - ? (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 - vertical_angle_rad : Math_PI / 2.0) - : (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 : Math_PI / 2.0 - vertical_angle_rad); - real_t arc_1_end_angle = arc_1_start_angle + vertical_angle_rad; - // Constrain arc to triangle height & max size - real_t arc_1_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.y)), arc_max_radius); - - real_t arc_2_start_angle = end_to_begin.x < 0 - ? (end_to_begin.y < 0 ? 0.0 : -horizontal_angle_rad) - : (end_to_begin.y < 0 ? Math_PI - horizontal_angle_rad : Math_PI); - real_t arc_2_end_angle = arc_2_start_angle + horizontal_angle_rad; - // Constrain arc to triangle width & max size - real_t arc_2_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.x)), arc_max_radius); - - viewport->draw_arc(begin, arc_1_radius, arc_1_start_angle, arc_1_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width)); - viewport->draw_arc(end, arc_2_radius, arc_2_start_angle, arc_2_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width)); } if (grid_snap_active) { @@ -5560,19 +5563,7 @@ bool CanvasItemEditorViewport::_cyclical_dependency_exists(const String &p_targe void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &path, const Point2 &p_point) { // Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others. String name = path.get_file().get_basename(); - switch (ProjectSettings::get_singleton()->get("editor/node_naming/name_casing").operator int()) { - case NAME_CASING_PASCAL_CASE: - name = name.capitalize().replace(" ", ""); - break; - case NAME_CASING_CAMEL_CASE: - name = name.capitalize().replace(" ", ""); - name[0] = name.to_lower()[0]; - break; - case NAME_CASING_SNAKE_CASE: - name = name.capitalize().replace(" ", "_").to_lower(); - break; - } - child->set_name(name); + child->set_name(Node::adjust_name_casing(name)); Ref<Texture2D> texture = ResourceCache::get_ref(path); diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index e20d298195..e56fd5dfe3 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -37,7 +37,7 @@ #include "editor/editor_undo_redo_manager.h" #include "scene/2d/cpu_particles_2d.h" #include "scene/gui/separator.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" void CPUParticles2DEditorPlugin::edit(Object *p_object) { particles = Object::cast_to<CPUParticles2D>(p_object); diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp index 1487f8b7bc..e2d19c34e6 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp @@ -38,7 +38,7 @@ #include "editor/scene_tree_dock.h" #include "scene/2d/cpu_particles_2d.h" #include "scene/gui/separator.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" void GPUParticles2DEditorPlugin::edit(Object *p_object) { particles = Object::cast_to<GPUParticles2D>(p_object); @@ -167,9 +167,9 @@ void GPUParticles2DEditorPlugin::_generate_visibility_rect() { } void GPUParticles2DEditorPlugin::_generate_emission_mask() { - Ref<ParticlesMaterial> pm = particles->get_process_material(); + Ref<ParticleProcessMaterial> pm = particles->get_process_material(); if (!pm.is_valid()) { - EditorNode::get_singleton()->show_warning(TTR("Can only set point into a ParticlesMaterial process material")); + EditorNode::get_singleton()->show_warning(TTR("Can only set point into a ParticleProcessMaterial process material")); return; } @@ -320,7 +320,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() { } if (valid_normals.size()) { - pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS); + pm->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_DIRECTED_POINTS); Vector<uint8_t> normdata; normdata.resize(w * h * 2 * sizeof(float)); //use RG texture @@ -339,7 +339,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() { pm->set_emission_normal_texture(ImageTexture::create_from_image(img)); } else { - pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS); + pm->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_POINTS); } } diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp index 335efd6949..ebc92bf531 100644 --- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp @@ -36,7 +36,7 @@ #include "editor/plugins/node_3d_editor_plugin.h" #include "editor/scene_tree_dock.h" #include "scene/3d/cpu_particles_3d.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" bool GPUParticles3DEditorBase::_generate(Vector<Vector3> &points, Vector<Vector3> &normals) { bool use_normals = emission_fill->get_selected() == 1; @@ -255,9 +255,9 @@ void GPUParticles3DEditor::_menu_option(int p_option) { } } break; case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: { - Ref<ParticlesMaterial> material = node->get_process_material(); + Ref<ParticleProcessMaterial> material = node->get_process_material(); if (material.is_null()) { - EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticlesMaterial' is required.")); + EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticleProcessMaterial' is required.")); return; } @@ -366,11 +366,11 @@ void GPUParticles3DEditor::_generate_emission_points() { Ref<Image> image = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img)); Ref<ImageTexture> tex = ImageTexture::create_from_image(image); - Ref<ParticlesMaterial> material = node->get_process_material(); + Ref<ParticleProcessMaterial> material = node->get_process_material(); ERR_FAIL_COND(material.is_null()); if (normals.size() > 0) { - material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS); + material->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_DIRECTED_POINTS); material->set_emission_point_count(point_count); material->set_emission_point_texture(tex); @@ -392,7 +392,7 @@ void GPUParticles3DEditor::_generate_emission_points() { Ref<Image> image2 = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img2)); material->set_emission_normal_texture(ImageTexture::create_from_image(image2)); } else { - material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS); + material->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_POINTS); material->set_emission_point_count(point_count); material->set_emission_point_texture(tex); } diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index 5d59f62f05..9fcb6619c0 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -36,7 +36,7 @@ #include "editor/editor_undo_redo_manager.h" #include "scene/gui/subviewport_container.h" #include "scene/resources/fog_material.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" #include "scene/resources/sky_material.h" void MaterialEditor::_notification(int p_what) { @@ -405,17 +405,17 @@ Ref<Resource> ORMMaterial3DConversionPlugin::convert(const Ref<Resource> &p_reso return smat; } -String ParticlesMaterialConversionPlugin::converts_to() const { +String ParticleProcessMaterialConversionPlugin::converts_to() const { return "ShaderMaterial"; } -bool ParticlesMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const { - Ref<ParticlesMaterial> mat = p_resource; +bool ParticleProcessMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const { + Ref<ParticleProcessMaterial> mat = p_resource; return mat.is_valid(); } -Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const { - Ref<ParticlesMaterial> mat = p_resource; +Ref<Resource> ParticleProcessMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const { + Ref<ParticleProcessMaterial> mat = p_resource; ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); Ref<ShaderMaterial> smat; diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h index fc3da5fd9f..06ae43e6d7 100644 --- a/editor/plugins/material_editor_plugin.h +++ b/editor/plugins/material_editor_plugin.h @@ -122,8 +122,8 @@ public: virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override; }; -class ParticlesMaterialConversionPlugin : public EditorResourceConversionPlugin { - GDCLASS(ParticlesMaterialConversionPlugin, EditorResourceConversionPlugin); +class ParticleProcessMaterialConversionPlugin : public EditorResourceConversionPlugin { + GDCLASS(ParticleProcessMaterialConversionPlugin, EditorResourceConversionPlugin); public: virtual String converts_to() const override; diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index 8f1e6c9ec2..043848080f 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -52,10 +52,10 @@ #include "scene/3d/light_3d.h" #include "scene/3d/lightmap_gi.h" #include "scene/3d/lightmap_probe.h" +#include "scene/3d/marker_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/navigation_region_3d.h" #include "scene/3d/occluder_instance_3d.h" -#include "scene/3d/position_3d.h" #include "scene/3d/ray_cast_3d.h" #include "scene/3d/reflection_probe.h" #include "scene/3d/shape_cast_3d.h" @@ -2292,7 +2292,7 @@ void Label3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { /// -Position3DGizmoPlugin::Position3DGizmoPlugin() { +Marker3DGizmoPlugin::Marker3DGizmoPlugin() { pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); cursor_points = Vector<Vector3>(); @@ -2316,7 +2316,7 @@ Position3DGizmoPlugin::Position3DGizmoPlugin() { // Use the axis color which is brighter for the positive axis. // Use a darkened axis color for the negative axis. - // This makes it possible to see in which direction the Position3D node is rotated + // This makes it possible to see in which direction the Marker3D node is rotated // (which can be important depending on how it's used). const Color color_x = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("axis_x_color"), SNAME("Editor")); cursor_colors.push_back(color_x); @@ -2352,19 +2352,19 @@ Position3DGizmoPlugin::Position3DGizmoPlugin() { pos3d_mesh->surface_set_material(0, mat); } -bool Position3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to<Position3D>(p_spatial) != nullptr; +bool Marker3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to<Marker3D>(p_spatial) != nullptr; } -String Position3DGizmoPlugin::get_gizmo_name() const { - return "Position3D"; +String Marker3DGizmoPlugin::get_gizmo_name() const { + return "Marker3D"; } -int Position3DGizmoPlugin::get_priority() const { +int Marker3DGizmoPlugin::get_priority() const { return -1; } -void Position3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { +void Marker3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { p_gizmo->clear(); p_gizmo->add_mesh(pos3d_mesh); p_gizmo->add_collision_segments(cursor_points); diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h index 739bf1b929..7dac1bd360 100644 --- a/editor/plugins/node_3d_editor_gizmos.h +++ b/editor/plugins/node_3d_editor_gizmos.h @@ -334,8 +334,8 @@ public: Label3DGizmoPlugin(); }; -class Position3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(Position3DGizmoPlugin, EditorNode3DGizmoPlugin); +class Marker3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(Marker3DGizmoPlugin, EditorNode3DGizmoPlugin); Ref<ArrayMesh> pos3d_mesh; Vector<Vector3> cursor_points; @@ -346,7 +346,7 @@ public: int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; - Position3DGizmoPlugin(); + Marker3DGizmoPlugin(); }; class PhysicalBone3DGizmoPlugin : public EditorNode3DGizmoPlugin { diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 2798f3d93e..1214024098 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -46,6 +46,7 @@ #include "editor/scene_tree_dock.h" #include "scene/3d/camera_3d.h" #include "scene/3d/collision_shape_3d.h" +#include "scene/3d/decal.h" #include "scene/3d/light_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/physics_body_3d.h" @@ -2972,6 +2973,13 @@ void Node3DEditorViewport::_menu_option(int p_option) { xform.scale_basis(sp->get_scale()); } + if (Object::cast_to<Decal>(E)) { + // Adjust rotation to match Decal's default orientation. + // This makes the decal "look" in the same direction as the camera, + // rather than pointing down relative to the camera orientation. + xform.basis.rotate_local(Vector3(1, 0, 0), Math_TAU * 0.25); + } + undo_redo->add_do_method(sp, "set_global_transform", xform); undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_gizmo_transform()); } @@ -2999,7 +3007,16 @@ void Node3DEditorViewport::_menu_option(int p_option) { continue; } - undo_redo->add_do_method(sp, "set_rotation", camera_transform.basis.get_euler_normalized()); + Basis basis = camera_transform.basis; + + if (Object::cast_to<Decal>(E)) { + // Adjust rotation to match Decal's default orientation. + // This makes the decal "look" in the same direction as the camera, + // rather than pointing down relative to the camera orientation. + basis.rotate_local(Vector3(1, 0, 0), Math_TAU * 0.25); + } + + undo_redo->add_do_method(sp, "set_rotation", basis.get_euler_normalized()); undo_redo->add_undo_method(sp, "set_rotation", sp->get_rotation()); } undo_redo->commit_action(); @@ -3964,19 +3981,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po // Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others. String name = path.get_file().get_basename(); - switch (ProjectSettings::get_singleton()->get("editor/node_naming/name_casing").operator int()) { - case NAME_CASING_PASCAL_CASE: - name = name.capitalize().replace(" ", ""); - break; - case NAME_CASING_CAMEL_CASE: - name = name.capitalize().replace(" ", ""); - name[0] = name.to_lower()[0]; - break; - case NAME_CASING_SNAKE_CASE: - name = name.capitalize().replace(" ", "_").to_lower(); - break; - } - mesh_instance->set_name(name); + mesh_instance->set_name(Node::adjust_name_casing(name)); instantiated_scene = mesh_instance; } else { @@ -4113,6 +4118,7 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant continue; } Ref<PackedScene> scn = res; + Ref<Mesh> mesh = res; Ref<Material> mat = res; Ref<Texture2D> tex = res; if (scn.is_valid()) { @@ -4131,6 +4137,8 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant spatial_editor->set_preview_material(mat); break; + } else if (mesh.is_valid()) { + // Let the mesh pass. } else if (tex.is_valid()) { Ref<StandardMaterial3D> new_mat = memnew(StandardMaterial3D); new_mat->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, tex); @@ -7495,7 +7503,7 @@ void Node3DEditor::_register_all_gizmos() { add_gizmo_plugin(Ref<SoftDynamicBody3DGizmoPlugin>(memnew(SoftDynamicBody3DGizmoPlugin))); add_gizmo_plugin(Ref<Sprite3DGizmoPlugin>(memnew(Sprite3DGizmoPlugin))); add_gizmo_plugin(Ref<Label3DGizmoPlugin>(memnew(Label3DGizmoPlugin))); - add_gizmo_plugin(Ref<Position3DGizmoPlugin>(memnew(Position3DGizmoPlugin))); + add_gizmo_plugin(Ref<Marker3DGizmoPlugin>(memnew(Marker3DGizmoPlugin))); add_gizmo_plugin(Ref<RayCast3DGizmoPlugin>(memnew(RayCast3DGizmoPlugin))); add_gizmo_plugin(Ref<ShapeCast3DGizmoPlugin>(memnew(ShapeCast3DGizmoPlugin))); add_gizmo_plugin(Ref<SpringArm3DGizmoPlugin>(memnew(SpringArm3DGizmoPlugin))); @@ -7615,7 +7623,7 @@ void Node3DEditor::_load_default_preview_settings() { environ_tonemap_button->set_pressed(true); environ_ao_button->set_pressed(false); environ_gi_button->set_pressed(false); - sun_max_distance->set_value(250); + sun_max_distance->set_value(100); sun_color->set_pick_color(Color(1, 1, 1)); sun_energy->set_value(1.0); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index de13c77e1a..a0c9ddb14b 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -49,7 +49,6 @@ #include "editor/find_in_files.h" #include "editor/node_dock.h" #include "editor/plugins/shader_editor_plugin.h" -#include "modules/visual_script/editor/visual_script_editor.h" #include "scene/main/window.h" #include "scene/scene_string_names.h" #include "script_text_editor.h" @@ -66,12 +65,12 @@ String EditorSyntaxHighlighter::_get_name() const { return "Unnamed"; } -Array EditorSyntaxHighlighter::_get_supported_languages() const { - Array ret; +PackedStringArray EditorSyntaxHighlighter::_get_supported_languages() const { + PackedStringArray ret; if (GDVIRTUAL_CALL(_get_supported_languages, ret)) { return ret; } - return Array(); + return PackedStringArray(); } Ref<EditorSyntaxHighlighter> EditorSyntaxHighlighter::_create() const { @@ -1156,8 +1155,8 @@ Ref<Script> ScriptEditor::_get_current_script() { } } -Array ScriptEditor::_get_open_scripts() const { - Array ret; +TypedArray<Script> ScriptEditor::_get_open_scripts() const { + TypedArray<Script> ret; Vector<Ref<Script>> scripts = get_open_scripts(); int scrits_amount = scripts.size(); for (int idx_script = 0; idx_script < scrits_amount; idx_script++) { @@ -1732,7 +1731,7 @@ void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) { continue; } - Array bpoints = se->get_breakpoints(); + PackedInt32Array bpoints = se->get_breakpoints(); for (int j = 0; j < bpoints.size(); j++) { p_breakpoints->push_back(base + ":" + itos((int)bpoints[j] + 1)); } @@ -2380,8 +2379,8 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col, se->add_syntax_highlighter(highlighter); if (script != nullptr && !highlighter_set) { - Array languages = highlighter->_get_supported_languages(); - if (languages.find(script->get_language()->get_name()) > -1) { + PackedStringArray languages = highlighter->_get_supported_languages(); + if (languages.has(script->get_language()->get_name())) { se->set_syntax_highlighter(highlighter); highlighter_set = true; } @@ -3446,8 +3445,8 @@ Vector<Ref<Script>> ScriptEditor::get_open_scripts() const { return out_scripts; } -Array ScriptEditor::_get_open_script_editors() const { - Array script_editors; +TypedArray<ScriptEditorBase> ScriptEditor::_get_open_script_editors() const { + TypedArray<ScriptEditorBase> script_editors; for (int i = 0; i < tab_container->get_tab_count(); i++) { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i)); if (!se) { diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 9f088aac49..d1898efb69 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -59,11 +59,11 @@ protected: static void _bind_methods(); GDVIRTUAL0RC(String, _get_name) - GDVIRTUAL0RC(Array, _get_supported_languages) + GDVIRTUAL0RC(PackedStringArray, _get_supported_languages) public: virtual String _get_name() const; - virtual Array _get_supported_languages() const; + virtual PackedStringArray _get_supported_languages() const; void _set_edited_resource(const Ref<Resource> &p_res) { edited_resourse = p_res; } Ref<RefCounted> _get_edited_resource() { return edited_resourse; } @@ -156,7 +156,7 @@ public: virtual void ensure_focus() = 0; virtual void tag_saved_version() = 0; virtual void reload(bool p_soft) {} - virtual Array get_breakpoints() = 0; + virtual PackedInt32Array get_breakpoints() = 0; virtual void set_breakpoint(int p_line, bool p_enabled) = 0; virtual void clear_breakpoints() = 0; virtual void add_callback(const String &p_function, PackedStringArray p_args) = 0; @@ -386,7 +386,7 @@ class ScriptEditor : public PanelContainer { Array _get_cached_breakpoints_for_script(const String &p_path) const; ScriptEditorBase *_get_current_editor() const; - Array _get_open_script_editors() const; + TypedArray<ScriptEditorBase> _get_open_script_editors() const; Ref<ConfigFile> script_editor_cache; void _save_editor_state(ScriptEditorBase *p_editor); @@ -452,7 +452,7 @@ class ScriptEditor : public PanelContainer { void _file_dialog_action(String p_file); Ref<Script> _get_current_script(); - Array _get_open_scripts() const; + TypedArray<Script> _get_open_scripts() const; HashSet<String> textfile_extensions; Ref<TextFile> _load_text_file(const String &p_path, Error *r_error) const; diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 5d5f452390..5e7db17edf 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -596,7 +596,7 @@ void ScriptTextEditor::_update_bookmark_list() { bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT); bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV); - Array bookmark_list = code_editor->get_text_editor()->get_bookmarked_lines(); + PackedInt32Array bookmark_list = code_editor->get_text_editor()->get_bookmarked_lines(); if (bookmark_list.size() == 0) { return; } @@ -751,7 +751,7 @@ void ScriptTextEditor::_update_breakpoint_list() { breakpoints_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_breakpoint"), DEBUG_GOTO_NEXT_BREAKPOINT); breakpoints_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_breakpoint"), DEBUG_GOTO_PREV_BREAKPOINT); - Array breakpoint_list = code_editor->get_text_editor()->get_breakpointed_lines(); + PackedInt32Array breakpoint_list = code_editor->get_text_editor()->get_breakpointed_lines(); if (breakpoint_list.size() == 0) { return; } @@ -1264,7 +1264,7 @@ void ScriptTextEditor::_edit_option(int p_op) { EditorDebuggerNode::get_singleton()->set_breakpoint(script->get_path(), line + 1, dobreak); } break; case DEBUG_REMOVE_ALL_BREAKPOINTS: { - Array bpoints = tx->get_breakpointed_lines(); + PackedInt32Array bpoints = tx->get_breakpointed_lines(); for (int i = 0; i < bpoints.size(); i++) { int line = bpoints[i]; @@ -1274,7 +1274,7 @@ void ScriptTextEditor::_edit_option(int p_op) { } } break; case DEBUG_GOTO_NEXT_BREAKPOINT: { - Array bpoints = tx->get_breakpointed_lines(); + PackedInt32Array bpoints = tx->get_breakpointed_lines(); if (bpoints.size() <= 0) { return; } @@ -1300,7 +1300,7 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case DEBUG_GOTO_PREV_BREAKPOINT: { - Array bpoints = tx->get_breakpointed_lines(); + PackedInt32Array bpoints = tx->get_breakpointed_lines(); if (bpoints.size() <= 0) { return; } @@ -1441,7 +1441,7 @@ void ScriptTextEditor::reload(bool p_soft) { scr->get_language()->reload_tool_script(scr, soft); } -Array ScriptTextEditor::get_breakpoints() { +PackedInt32Array ScriptTextEditor::get_breakpoints() { return code_editor->get_text_editor()->get_breakpointed_lines(); } diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index fc87c84a2c..8d2fb98721 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -229,7 +229,7 @@ public: virtual void clear_executing_line() override; virtual void reload(bool p_soft) override; - virtual Array get_breakpoints() override; + virtual PackedInt32Array get_breakpoints() override; virtual void set_breakpoint(int p_line, bool p_enabled) override; virtual void clear_breakpoints() override; diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index d70c50f72a..53bc6fbdf4 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -994,7 +994,7 @@ void ShaderEditor::_update_bookmark_list() { bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT); bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV); - Array bookmark_list = shader_editor->get_text_editor()->get_bookmarked_lines(); + PackedInt32Array bookmark_list = shader_editor->get_text_editor()->get_bookmarked_lines(); if (bookmark_list.size() == 0) { return; } @@ -1257,6 +1257,17 @@ void ShaderEditorPlugin::_update_shader_list_status() { } } +void ShaderEditorPlugin::_move_shader_tab(int p_from, int p_to) { + if (p_from == p_to) { + return; + } + EditedShader es = edited_shaders[p_from]; + edited_shaders.remove_at(p_from); + edited_shaders.insert(p_to, es); + shader_tabs->move_child(shader_tabs->get_tab_control(p_from), p_to); + _update_shader_list(); +} + void ShaderEditorPlugin::edit(Object *p_object) { EditedShader es; @@ -1451,6 +1462,109 @@ void ShaderEditorPlugin::_shader_include_created(Ref<ShaderInclude> p_shader_inc EditorNode::get_singleton()->push_item(p_shader_inc.ptr()); } +Variant ShaderEditorPlugin::get_drag_data_fw(const Point2 &p_point, Control *p_from) { + if (shader_list->get_item_count() == 0) { + return Variant(); + } + + int idx = shader_list->get_item_at_position(p_point); + if (idx < 0) { + return Variant(); + } + + HBoxContainer *drag_preview = memnew(HBoxContainer); + String preview_name = shader_list->get_item_text(idx); + Ref<Texture2D> preview_icon = shader_list->get_item_icon(idx); + + if (!preview_icon.is_null()) { + TextureRect *tf = memnew(TextureRect); + tf->set_texture(preview_icon); + tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); + drag_preview->add_child(tf); + } + Label *label = memnew(Label(preview_name)); + drag_preview->add_child(label); + main_split->set_drag_preview(drag_preview); + + Dictionary drag_data; + drag_data["type"] = "shader_list_element"; + drag_data["shader_list_element"] = idx; + + return drag_data; +} + +bool ShaderEditorPlugin::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { + Dictionary d = p_data; + if (!d.has("type")) { + return false; + } + + if (String(d["type"]) == "shader_list_element") { + return true; + } + + if (String(d["type"]) == "files") { + Vector<String> files = d["files"]; + + if (files.size() == 0) { + return false; + } + + for (int i = 0; i < files.size(); i++) { + String file = files[i]; + if (ResourceLoader::exists(file, "Shader")) { + Ref<Shader> shader = ResourceLoader::load(file); + if (shader.is_valid()) { + return true; + } + } + } + return false; + } + + return false; +} + +void ShaderEditorPlugin::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { + if (!can_drop_data_fw(p_point, p_data, p_from)) { + return; + } + + Dictionary d = p_data; + if (!d.has("type")) { + return; + } + + if (String(d["type"]) == "shader_list_element") { + int idx = d["shader_list_element"]; + int new_idx = shader_list->get_item_at_position(p_point); + _move_shader_tab(idx, new_idx); + return; + } + + if (String(d["type"]) == "files") { + Vector<String> files = d["files"]; + + for (int i = 0; i < files.size(); i++) { + String file = files[i]; + if (!ResourceLoader::exists(file, "Shader")) { + continue; + } + + Ref<Resource> res = ResourceLoader::load(file); + if (res.is_valid()) { + edit(res.ptr()); + } + } + } +} + +void ShaderEditorPlugin::_bind_methods() { + ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "point", "from"), &ShaderEditorPlugin::get_drag_data_fw); + ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "point", "data", "from"), &ShaderEditorPlugin::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("_drop_data_fw", "point", "data", "from"), &ShaderEditorPlugin::drop_data_fw); +} + ShaderEditorPlugin::ShaderEditorPlugin() { main_split = memnew(HSplitContainer); @@ -1483,6 +1597,7 @@ ShaderEditorPlugin::ShaderEditorPlugin() { vb->add_child(shader_list); shader_list->connect("item_selected", callable_mp(this, &ShaderEditorPlugin::_shader_selected)); shader_list->connect("item_clicked", callable_mp(this, &ShaderEditorPlugin::_shader_list_clicked)); + shader_list->set_drag_forwarding(this); main_split->add_child(vb); vb->set_custom_minimum_size(Size2(200, 300) * EDSCALE); diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h index 0980cc4db2..afd38ef71a 100644 --- a/editor/plugins/shader_editor_plugin.h +++ b/editor/plugins/shader_editor_plugin.h @@ -250,6 +250,14 @@ class ShaderEditorPlugin : public EditorPlugin { void _shader_created(Ref<Shader> p_shader); void _shader_include_created(Ref<ShaderInclude> p_shader_inc); void _update_shader_list_status(); + void _move_shader_tab(int p_from, int p_to); + + Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); + bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; + void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); + +protected: + static void _bind_methods(); public: virtual void edit(Object *p_object) override; diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 1e4ef217f0..c25f2bb25c 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -31,7 +31,6 @@ #include "skeleton_3d_editor_plugin.h" #include "core/io/resource_saver.h" -#include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h index f51d4e60e8..9747ed8374 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.h +++ b/editor/plugins/skeleton_3d_editor_plugin.h @@ -31,6 +31,7 @@ #ifndef SKELETON_3D_EDITOR_PLUGIN_H #define SKELETON_3D_EDITOR_PLUGIN_H +#include "editor/editor_file_dialog.h" #include "editor/editor_plugin.h" #include "editor/editor_properties.h" #include "node_3d_editor_plugin.h" diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 196d87da36..0900415b04 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -128,8 +128,8 @@ Control *TextEditor::get_base_editor() const { return code_editor->get_text_editor(); } -Array TextEditor::get_breakpoints() { - return Array(); +PackedInt32Array TextEditor::get_breakpoints() { + return PackedInt32Array(); } void TextEditor::reload_text() { @@ -165,7 +165,7 @@ void TextEditor::_update_bookmark_list() { bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT); bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV); - Array bookmark_list = code_editor->get_text_editor()->get_bookmarked_lines(); + PackedInt32Array bookmark_list = code_editor->get_text_editor()->get_bookmarked_lines(); if (bookmark_list.size() == 0) { return; } diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index 4f0121da52..15f7c45653 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -118,7 +118,7 @@ public: virtual Variant get_edit_state() override; virtual void set_edit_state(const Variant &p_state) override; virtual Vector<String> get_functions() override; - virtual Array get_breakpoints() override; + virtual PackedInt32Array get_breakpoints() override; virtual void set_breakpoint(int p_line, bool p_enabled) override{}; virtual void clear_breakpoints() override{}; virtual void goto_line(int p_line, bool p_with_error = false) override; diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp index f119ada810..54ba28833c 100644 --- a/editor/plugins/tiles/tile_atlas_view.cpp +++ b/editor/plugins/tiles/tile_atlas_view.cpp @@ -127,8 +127,8 @@ void TileAtlasView::_update_zoom_and_panning(bool p_zoom_on_mouse_pos) { } // Update the backgrounds. - background_left->update(); - background_right->update(); + background_left->set_size(base_tiles_root_control->get_custom_minimum_size()); + background_right->set_size(alternative_tiles_root_control->get_custom_minimum_size()); // Zoom on the position. if (p_zoom_on_mouse_pos) { @@ -374,13 +374,11 @@ void TileAtlasView::_draw_alternatives() { void TileAtlasView::_draw_background_left() { Ref<Texture2D> texture = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons")); - background_left->set_size(base_tiles_root_control->get_custom_minimum_size()); background_left->draw_texture_rect(texture, Rect2(Vector2(), background_left->get_size()), true); } void TileAtlasView::_draw_background_right() { Ref<Texture2D> texture = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons")); - background_right->set_size(alternative_tiles_root_control->get_custom_minimum_size()); background_right->draw_texture_rect(texture, Rect2(Vector2(), background_right->get_size()), true); } @@ -405,23 +403,6 @@ void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_ // Update everything. _update_zoom_and_panning(); - // Change children control size. - Size2i base_tiles_control_size = _compute_base_tiles_control_size(); - for (int i = 0; i < base_tiles_drawing_root->get_child_count(); i++) { - Control *control = Object::cast_to<Control>(base_tiles_drawing_root->get_child(i)); - if (control) { - control->set_size(base_tiles_control_size); - } - } - - Size2i alternative_control_size = _compute_alternative_tiles_control_size(); - for (int i = 0; i < alternative_tiles_drawing_root->get_child_count(); i++) { - Control *control = Object::cast_to<Control>(alternative_tiles_drawing_root->get_child(i)); - if (control) { - control->set_size(alternative_control_size); - } - } - // Update. base_tiles_draw->update(); base_tiles_texture_grid->update(); @@ -613,7 +594,7 @@ TileAtlasView::TileAtlasView() { background_left = memnew(Control); background_left->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); - background_left->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); + background_left->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT); background_left->set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED); background_left->connect("draw", callable_mp(this, &TileAtlasView::_draw_background_left)); base_tiles_root_control->add_child(background_left); @@ -651,23 +632,26 @@ TileAtlasView::TileAtlasView() { alternative_tiles_root_control = memnew(Control); alternative_tiles_root_control->set_mouse_filter(Control::MOUSE_FILTER_PASS); + alternative_tiles_root_control->set_v_size_flags(Control::SIZE_EXPAND_FILL); alternative_tiles_root_control->connect("gui_input", callable_mp(this, &TileAtlasView::_alternative_tiles_root_control_gui_input)); right_vbox->add_child(alternative_tiles_root_control); background_right = memnew(Control); background_right->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); + background_right->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT); background_right->set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED); background_right->connect("draw", callable_mp(this, &TileAtlasView::_draw_background_right)); - alternative_tiles_root_control->add_child(background_right); alternative_tiles_drawing_root = memnew(Control); alternative_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); + alternative_tiles_drawing_root->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); alternative_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST); alternative_tiles_root_control->add_child(alternative_tiles_drawing_root); alternatives_draw = memnew(Control); alternatives_draw->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); + alternatives_draw->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); alternatives_draw->connect("draw", callable_mp(this, &TileAtlasView::_draw_alternatives)); alternative_tiles_drawing_root->add_child(alternatives_draw); } diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h index 196a642283..1c0b622bb1 100644 --- a/editor/plugins/tiles/tile_atlas_view.h +++ b/editor/plugins/tiles/tile_atlas_view.h @@ -136,6 +136,7 @@ public: } else { base_tiles_root_control->add_child(p_control); } + p_control->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); p_control->set_mouse_filter(Control::MOUSE_FILTER_PASS); }; @@ -149,6 +150,7 @@ public: } else { alternative_tiles_root_control->add_child(p_control); } + p_control->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); p_control->set_mouse_filter(Control::MOUSE_FILTER_PASS); }; diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 09722d3d65..6bdf279537 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -1888,7 +1888,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In alternative_tiles_control_unscaled->update(); if (drag_type == DRAG_TYPE_MAY_POPUP_MENU) { - if (Vector2(drag_start_mouse_pos).distance_to(tile_atlas_control->get_local_mouse_position()) > 5.0 * EDSCALE) { + if (Vector2(drag_start_mouse_pos).distance_to(alternative_tiles_control->get_local_mouse_position()) > 5.0 * EDSCALE) { drag_type = DRAG_TYPE_NONE; } } @@ -1896,8 +1896,6 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { - drag_type = DRAG_TYPE_NONE; - Vector2 mouse_local_pos = alternative_tiles_control->get_local_mouse_position(); if (mb->get_button_index() == MouseButton::LEFT) { if (mb->is_pressed()) { @@ -1919,25 +1917,29 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In if (mb->is_pressed()) { drag_type = DRAG_TYPE_MAY_POPUP_MENU; drag_start_mouse_pos = alternative_tiles_control->get_local_mouse_position(); - } else if (drag_type == DRAG_TYPE_MAY_POPUP_MENU) { - // Right click released and wasn't dragged too far - Vector3 tile = tile_atlas_view->get_alternative_tile_at_pos(mouse_local_pos); + } else { + if (drag_type == DRAG_TYPE_MAY_POPUP_MENU) { + // Right click released and wasn't dragged too far + Vector3 tile = tile_atlas_view->get_alternative_tile_at_pos(mouse_local_pos); - selection.clear(); - TileSelection selected = { Vector2i(tile.x, tile.y), int(tile.z) }; - if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) { - selection.insert(selected); - } + selection.clear(); + TileSelection selected = { Vector2i(tile.x, tile.y), int(tile.z) }; + if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) { + selection.insert(selected); + } - _update_tile_inspector(); - _update_tile_id_label(); + _update_tile_inspector(); + _update_tile_id_label(); - if (selection.size() == 1) { - selected = selection.front()->get(); - menu_option_coords = selected.tile; - menu_option_alternative = selected.alternative; - alternative_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i())); + if (selection.size() == 1) { + selected = selection.front()->get(); + menu_option_coords = selected.tile; + menu_option_alternative = selected.alternative; + alternative_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i())); + } } + + drag_type = DRAG_TYPE_NONE; } } tile_atlas_control->update(); @@ -2524,7 +2526,6 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { tile_atlas_view->add_control_over_atlas_tiles(tile_atlas_control); tile_atlas_control_unscaled = memnew(Control); - tile_atlas_control_unscaled->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); tile_atlas_control_unscaled->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw)); tile_atlas_view->add_control_over_atlas_tiles(tile_atlas_control_unscaled, false); tile_atlas_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); @@ -2541,7 +2542,6 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { tile_atlas_view->add_control_over_alternative_tiles(alternative_tiles_control); alternative_tiles_control_unscaled = memnew(Control); - alternative_tiles_control_unscaled->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); alternative_tiles_control_unscaled->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw)); tile_atlas_view->add_control_over_alternative_tiles(alternative_tiles_control_unscaled, false); alternative_tiles_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp index cf55465417..6db499f2c7 100644 --- a/editor/plugins/version_control_editor_plugin.cpp +++ b/editor/plugins/version_control_editor_plugin.cpp @@ -242,7 +242,7 @@ void VersionControlEditorPlugin::_view_file_diff() { } void VersionControlEditorPlugin::_display_file_diff(String p_file_path) { - Array diff_content = EditorVCSInterface::get_singleton()->get_file_diff(p_file_path); + TypedArray<Dictionary> diff_content = EditorVCSInterface::get_singleton()->get_file_diff(p_file_path); diff_file_name->set_text(p_file_path); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 961f092650..e048ee2698 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -4312,6 +4312,9 @@ void VisualShaderEditor::_update_varying_tree() { case VisualShader::VARYING_TYPE_FLOAT: item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("float"), SNAME("EditorIcons"))); break; + case VisualShader::VARYING_TYPE_INT: + item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("int"), SNAME("EditorIcons"))); + break; case VisualShader::VARYING_TYPE_VECTOR_2D: item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector2"), SNAME("EditorIcons"))); break; @@ -4321,8 +4324,8 @@ void VisualShaderEditor::_update_varying_tree() { case VisualShader::VARYING_TYPE_VECTOR_4D: item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector4"), SNAME("EditorIcons"))); break; - case VisualShader::VARYING_TYPE_COLOR: - item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Color"), SNAME("EditorIcons"))); + case VisualShader::VARYING_TYPE_BOOLEAN: + item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("bool"), SNAME("EditorIcons"))); break; case VisualShader::VARYING_TYPE_TRANSFORM: item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Transform3D"), SNAME("EditorIcons"))); @@ -4963,10 +4966,11 @@ VisualShaderEditor::VisualShaderEditor() { varying_type = memnew(OptionButton); hb->add_child(varying_type); varying_type->add_item("Float"); + varying_type->add_item("Int"); varying_type->add_item("Vector2"); varying_type->add_item("Vector3"); varying_type->add_item("Vector4"); - varying_type->add_item("Color"); + varying_type->add_item("Boolean"); varying_type->add_item("Transform"); varying_name = memnew(LineEdit); @@ -5759,10 +5763,11 @@ public: Ref<Texture2D> type_icon[] = { EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("float"), SNAME("EditorIcons")), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("int"), SNAME("EditorIcons")), EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector2"), SNAME("EditorIcons")), EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector3"), SNAME("EditorIcons")), EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector4"), SNAME("EditorIcons")), - EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Color"), SNAME("EditorIcons")), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("bool"), SNAME("EditorIcons")), EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Transform3D"), SNAME("EditorIcons")), }; diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index a302adc34e..b78c583c16 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -201,11 +201,12 @@ static const char *gdscript_function_renames[][2] = { // { "set_color", "surface_set_color"}, // ImmediateMesh broke Light2D, Theme, SurfaceTool // { "set_event", "set_shortcut" }, // BaseButton - Cyclic Rename // { "set_extents", "set_size"}, // BoxShape, RectangleShape broke ReflectionProbe - // { "set_flag", "set_particle_flag"}, // ParticlesMaterial broke Window, HingeJoint3D + // { "set_flag", "set_particle_flag"}, // ParticleProcessMaterial broke Window, HingeJoint3D // { "set_h_offset", "set_drag_horizontal_offset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D // { "set_margin", "set_offset" }, // Control broke Shape3D, AtlasTexture // { "set_mode", "set_mode_file_mode" }, // FileDialog broke Panel, Shader, CSGPolygon, Tilemap // { "set_normal", "surface_set_normal"}, // ImmediateGeometry broke SurfaceTool, WorldMarginShape2D + // { "set_offset", "set_progress" }, // PathFollow2D, PathFollow3D - Too common // { "set_process_mode", "set_process_callback" }, // AnimationTree broke Node, Tween, Sky // { "set_refuse_new_network_connections", "set_refuse_new_connections"}, // MultiplayerAPI broke SceneTree // { "set_uv", "surface_set_uv" }, // ImmediateMesh broke Polygon2D @@ -371,6 +372,7 @@ static const char *gdscript_function_renames[][2] = { { "get_theme_item_types", "get_theme_item_type_list" }, // Theme { "get_timer_process_mode", "get_timer_process_callback" }, // Timer { "get_translation", "get_position" }, // Node3D broke GLTFNode which is used rarely + { "get_unit_offset", "get_progress_ratio" }, // PathFollow2D, PathFollow3D { "get_use_in_baked_light", "is_baking_navigation" }, // GridMap { "get_used_cells_by_id", "get_used_cells" }, // TileMap { "get_v_scrollbar", "get_v_scroll_bar" }, //ScrollContainer @@ -532,6 +534,7 @@ static const char *gdscript_function_renames[][2] = { { "set_timer_process_mode", "set_timer_process_callback" }, // Timer { "set_tonemap_auto_exposure", "set_tonemap_auto_exposure_enabled" }, // Environment { "set_translation", "set_position" }, // Node3D - this broke GLTFNode which is used rarely + { "set_unit_offset", "set_progress_ratio" }, // PathFollow2D, PathFollow3D { "set_uv2", "surface_set_uv2" }, // ImmediateMesh broke Surffacetool { "set_v_drag_enabled", "set_drag_vertical_enabled" }, // Camera2D { "set_valign", "set_vertical_alignment" }, // Label @@ -607,11 +610,12 @@ static const char *csharp_function_renames[][2] = { // { "SetColor", "SurfaceSetColor"}, // ImmediateMesh broke Light2D, Theme, SurfaceTool // { "SetEvent", "SetShortcut" }, // BaseButton - Cyclic Rename // { "SetExtents", "SetSize"}, // BoxShape, RectangleShape broke ReflectionProbe - // { "SetFlag", "SetParticleFlag"}, // ParticlesMaterial broke Window, HingeJoint3D + // { "SetFlag", "SetParticleFlag"}, // ParticleProcessMaterial broke Window, HingeJoint3D // { "SetHOffset", "SetDragHorizontalOffset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D // { "SetMargin", "SetOffset" }, // Control broke Shape3D, AtlasTexture // { "SetMode", "SetModeFileMode" }, // FileDialog broke Panel, Shader, CSGPolygon, Tilemap // { "SetNormal", "SurfaceSetNormal"}, // ImmediateGeometry broke SurfaceTool, WorldMarginShape2D + // { "SetOffset", "SetProgress" }, // PathFollow2D, PathFollow3D - Too common // { "SetProcessMode", "SetProcessCallback" }, // AnimationTree broke Node, Tween, Sky // { "SetRefuseNewNetworkConnections", "SetRefuseNewConnections"}, // MultiplayerAPI broke SceneTree // { "SetUv", "SurfaceSetUv" }, // ImmediateMesh broke Polygon2D @@ -767,6 +771,7 @@ static const char *csharp_function_renames[][2] = { { "GetThemeItemTypes", "GetThemeItemTypeList" }, // Theme { "GetTimerProcessMode", "GetTimerProcessCallback" }, // Timer { "GetTranslation", "GetPosition" }, // Node3D broke GLTFNode which is used rarely + { "GetUnitOffset", "GetProgressRatio" }, // PathFollow2D, PathFollow3D { "GetUseInBakedLight", "IsBakingNavigation" }, // GridMap { "GetUsedCellsById", "GetUsedCells" }, // TileMap { "GetVScrollbar", "GetVScrollBar" }, //ScrollContainer @@ -918,6 +923,7 @@ static const char *csharp_function_renames[][2] = { { "SetTimerProcessMode", "SetTimerProcessCallback" }, // Timer { "SetTonemapAutoExposure", "SetTonemapAutoExposureEnabled" }, // Environment { "SetTranslation", "SetPosition" }, // Node3D - this broke GLTFNode which is used rarely + { "SetUnitOffset", "SetProgressRatio" }, // PathFollow2D, PathFollow3D { "SetUv2", "SurfaceSetUv2" }, // ImmediateMesh broke Surffacetool { "SetVDragEnabled", "SetDragVerticalEnabled" }, // Camera2D { "SetValign", "SetVerticalAlignment" }, // Label @@ -969,6 +975,7 @@ static const char *gdscript_properties_renames[][2] = { // // {"meta","meta_pressed"},// This may broke a lot of comments and user variables // // {"pause_mode","process_mode"}, // Node - Cyclic rename, look for others // // {"rotate","rotates"}, // PathFollow2D - probably function exists with same name + // // {"offset","progress"}, // PathFollow2D, PathFollow3D - Name is way too vague // // {"shift","shift_pressed"},// This may broke a lot of comments and user variables // { "autowrap", "autowrap_mode" }, // Label // { "cast_to", "target_position" }, // RayCast2D, RayCast3D @@ -990,6 +997,7 @@ static const char *gdscript_properties_renames[][2] = { { "close_h_ofs", "close_h_offset" }, // Theme { "close_v_ofs", "close_v_offset" }, // Theme { "commentfocus", "comment_focus" }, // Theme + { "contacts_reported", "max_contacts_reported" }, // RigidDynamicBody { "drag_margin_bottom", "drag_bottom_margin" }, // Camera2D { "drag_margin_h_enabled", "drag_horizontal_enabled" }, // Camera2D { "drag_margin_left", "drag_left_margin" }, // Camera2D @@ -1008,6 +1016,7 @@ static const char *gdscript_properties_renames[][2] = { { "gravity_vec", "gravity_direction" }, // Area2D { "hseparation", "h_separation" }, // Theme { "iterations_per_second", "physics_ticks_per_second" }, // Engine + { "invert_enable", "invert_enabled" }, // Polygon2D { "margin_bottom", "offset_bottom" }, // Control broke NinePatchRect, StyleBox { "margin_left", "offset_left" }, // Control broke NinePatchRect, StyleBox { "margin_right", "offset_right" }, // Control broke NinePatchRect, StyleBox @@ -1036,6 +1045,7 @@ static const char *gdscript_properties_renames[][2] = { { "table_hseparation", "table_h_separation" }, // Theme { "table_vseparation", "table_v_separation" }, // Theme { "translation", "position" }, // Node3D - broke GLTFNode + { "unit_offset", "progress_ratio" }, // PathFollow2D, PathFollow3D { "vseparation", "v_separation" }, // Theme { nullptr, nullptr }, @@ -1051,6 +1061,7 @@ static const char *csharp_properties_renames[][2] = { // // {"Meta","MetaPressed"},// This may broke a lot of comments and user variables // // {"PauseMode","ProcessMode"}, // Node - Cyclic rename, look for others // // {"Rotate","Rotates"}, // PathFollow2D - probably function exists with same name + // // {"Offset","Progress"}, // PathFollow2D, PathFollow3D - Name is way too vague // // {"Shift","ShiftPressed"},// This may broke a lot of comments and user variables // { "Autowrap", "AutowrapMode" }, // Label // { "CastTo", "TargetPosition" }, // RayCast2D, RayCast3D @@ -1089,6 +1100,7 @@ static const char *csharp_properties_renames[][2] = { { "GravityVec", "GravityDirection" }, // Area2D { "Hseparation", "HSeparation" }, // Theme { "IterationsPerSecond", "PhysicsTicksPerSecond" }, // Engine + { "InvertEnable", "InvertEnabled" }, // Polygon2D { "MarginBottom", "OffsetBottom" }, // Control broke NinePatchRect, StyleBox { "MarginLeft", "OffsetLeft" }, // Control broke NinePatchRect, StyleBox { "MarginRight", "OffsetRight" }, // Control broke NinePatchRect, StyleBox @@ -1117,6 +1129,7 @@ static const char *csharp_properties_renames[][2] = { { "TableHseparation", "TableHSeparation" }, // Theme { "TableVseparation", "TableVSeparation" }, // Theme { "Translation", "Position" }, // Node3D - broke GLTFNode + { "UnitOffset", "ProgressRatio" }, // PathFollow2D, PathFollow3D { "Vseparation", "VSeparation" }, // Theme { nullptr, nullptr }, @@ -1344,6 +1357,7 @@ static const char *class_renames[][2] = { { "PanoramaSky", "Sky" }, { "Particles", "GPUParticles3D" }, // Be careful, this will be used everywhere { "Particles2D", "GPUParticles2D" }, + { "ParticlesMaterial", "ParticleProcessMaterial" }, { "Path", "Path3D" }, // Be careful, this will be used everywhere { "PathFollow", "PathFollow3D" }, { "PhysicalBone", "PhysicalBone3D" }, @@ -1362,6 +1376,8 @@ static const char *class_renames[][2] = { { "PinJoint", "PinJoint3D" }, { "PlaneShape", "WorldBoundaryShape3D" }, { "PopupDialog", "Popup" }, + { "Position2D", "Marker2D" }, + { "Position3D", "Marker3D" }, { "ProceduralSky", "Sky" }, { "RayCast", "RayCast3D" }, { "RayShape", "SeparationRayShape3D" }, diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 46eb7ac17c..cce71d9508 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -484,12 +484,20 @@ private: project_features.sort(); initial_settings["application/config/features"] = project_features; initial_settings["application/config/name"] = project_name->get_text().strip_edges(); - initial_settings["application/config/icon"] = "res://icon.png"; + initial_settings["application/config/icon"] = "res://icon.svg"; if (ProjectSettings::get_singleton()->save_custom(dir.plus_file("project.godot"), initial_settings, Vector<String>(), false) != OK) { set_message(TTR("Couldn't create project.godot in project path."), MESSAGE_ERROR); } else { - ResourceSaver::save(create_unscaled_default_project_icon(), dir.plus_file("icon.png")); + // Store default project icon in SVG format. + Error err; + Ref<FileAccess> fa_icon = FileAccess::open(dir.plus_file("icon.svg"), FileAccess::WRITE, &err); + fa_icon->store_string(get_default_project_icon()); + + if (err != OK) { + set_message(TTR("Couldn't create icon.svg in project path."), MESSAGE_ERROR); + } + EditorVCSInterface::create_vcs_metadata_files(EditorVCSInterface::VCSMetadata(vcs_metadata_selection->get_selected()), dir); } } else if (mode == MODE_INSTALL) { diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index b977b012a8..00fd0c3aac 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -279,7 +279,19 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { warning_icon = SNAME("NodeWarnings4Plus"); } - item->add_button(0, get_theme_icon(warning_icon, SNAME("EditorIcons")), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + warning); + // Improve looks on tooltip, extra spacing on non-bullet point newlines. + const String bullet_point = String::utf8("• "); + int next_newline = 0; + while (next_newline != -1) { + next_newline = warning.find("\n", next_newline + 2); + if (warning.substr(next_newline + 1, bullet_point.length()) != bullet_point) { + warning = warning.insert(next_newline + 1, " "); + } + } + + String newline = (num_warnings == 1 ? "\n" : "\n\n"); + + item->add_button(0, get_theme_icon(warning_icon, SNAME("EditorIcons")), BUTTON_WARNING, false, TTR("Node configuration warning:") + newline + warning); } if (p_node->is_unique_name_in_owner()) { diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 77e0321f83..15e992ce18 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -166,6 +166,7 @@ void ScriptCreateDialog::config(const String &p_base_name, const String &p_base_ class_name->deselect(); parent_name->set_text(p_base_name); parent_name->deselect(); + internal_name->set_text(""); if (!p_base_path.is_empty()) { initial_bp = p_base_path.get_basename(); diff --git a/main/main.cpp b/main/main.cpp index 8a25827e02..126ac59070 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -725,11 +725,16 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->get()); forwardable_cli_arguments[CLI_SCOPE_PROJECT].push_back(I->get()); } - if (I->get() == "--single-window" || - I->get() == "--audio-driver" || + if (I->get() == "--single-window") { + forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->get()); + } + if (I->get() == "--audio-driver" || I->get() == "--display-driver" || I->get() == "--rendering-driver") { - forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->get()); + if (I->next()) { + forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->get()); + forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->next()->get()); + } } #endif diff --git a/main/performance.cpp b/main/performance.cpp index 0de525134e..bdcd07a216 100644 --- a/main/performance.cpp +++ b/main/performance.cpp @@ -32,6 +32,7 @@ #include "core/object/message_queue.h" #include "core/os/os.h" +#include "core/variant/typed_array.h" #include "scene/main/node.h" #include "scene/main/scene_tree.h" #include "servers/audio_server.h" @@ -240,11 +241,11 @@ Variant Performance::get_custom_monitor(const StringName &p_id) { return return_value; } -Array Performance::get_custom_monitor_names() { +TypedArray<StringName> Performance::get_custom_monitor_names() { if (!_monitor_map.size()) { - return Array(); + return TypedArray<StringName>(); } - Array return_array; + TypedArray<StringName> return_array; return_array.resize(_monitor_map.size()); int index = 0; for (KeyValue<StringName, MonitorCall> i : _monitor_map) { diff --git a/main/performance.h b/main/performance.h index 00e00886ef..597666b57d 100644 --- a/main/performance.h +++ b/main/performance.h @@ -37,6 +37,9 @@ #define PERF_WARN_OFFLINE_FUNCTION #define PERF_WARN_PROCESS_SYNC +template <typename T> +class TypedArray; + class Performance : public Object { GDCLASS(Performance, Object); @@ -107,7 +110,7 @@ public: void remove_custom_monitor(const StringName &p_id); bool has_custom_monitor(const StringName &p_id); Variant get_custom_monitor(const StringName &p_id); - Array get_custom_monitor_names(); + TypedArray<StringName> get_custom_monitor_names(); uint64_t get_monitor_modification_time(); diff --git a/methods.py b/methods.py index c02517d137..9b60d4251f 100644 --- a/methods.py +++ b/methods.py @@ -540,7 +540,7 @@ def detect_visual_c_compiler_version(tools_env): # and not scons setup environment (env)... so make sure you call the right environment on it or it will fail to detect # the proper vc version that will be called - # There is no flag to give to visual c compilers to set the architecture, i.e. scons bits argument (32,64,ARM etc) + # There is no flag to give to visual c compilers to set the architecture, i.e. scons arch argument (x86_32, x86_64, arm64, etc.). # There are many different cl.exe files that are run, and each one compiles & links to a different architecture # As far as I know, the only way to figure out what compiler will be run when Scons calls cl.exe via Program() # is to check the PATH variable and figure out which one will be called first. Code below does that and returns: diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp index 8813c3827a..ae03abca50 100644 --- a/modules/bmp/image_loader_bmp.cpp +++ b/modules/bmp/image_loader_bmp.cpp @@ -200,7 +200,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image, return err; } -Error ImageLoaderBMP::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { +Error ImageLoaderBMP::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) { bmp_header_s bmp_header; Error err = ERR_INVALID_DATA; diff --git a/modules/bmp/image_loader_bmp.h b/modules/bmp/image_loader_bmp.h index 63dee0a969..cf8346ecad 100644 --- a/modules/bmp/image_loader_bmp.h +++ b/modules/bmp/image_loader_bmp.h @@ -83,7 +83,7 @@ protected: const bmp_header_s &p_header); public: - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderBMP(); }; diff --git a/modules/denoise/config.py b/modules/denoise/config.py index 521115dae5..350839651a 100644 --- a/modules/denoise/config.py +++ b/modules/denoise/config.py @@ -5,14 +5,7 @@ def can_build(env, platform): # as doing lightmap generation and denoising on Android or HTML5 # would be a bit far-fetched. desktop_platforms = ["linuxbsd", "macos", "windows"] - supported_arch = env["bits"] == "64" - if env["arch"] == "arm64": - supported_arch = False - if env["arch"].startswith("ppc"): - supported_arch = False - if env["arch"].startswith("rv"): - supported_arch = False - return env["tools"] and platform in desktop_platforms and supported_arch + return env["tools"] and platform in desktop_platforms and env["arch"] == "x86_64" def configure(env): diff --git a/modules/enet/doc_classes/ENetConnection.xml b/modules/enet/doc_classes/ENetConnection.xml index c9bf1c65e1..8c84fe87d7 100644 --- a/modules/enet/doc_classes/ENetConnection.xml +++ b/modules/enet/doc_classes/ENetConnection.xml @@ -118,7 +118,7 @@ </description> </method> <method name="get_peers"> - <return type="Array" /> + <return type="ENetPacketPeer[]" /> <description> Returns the list of peers associated with this host. [b]Note:[/b] This list might include some peers that are not fully connected or are still being disconnected. diff --git a/modules/enet/enet_connection.cpp b/modules/enet/enet_connection.cpp index 629974d7c7..6a4bbecf6a 100644 --- a/modules/enet/enet_connection.cpp +++ b/modules/enet/enet_connection.cpp @@ -34,6 +34,7 @@ #include "core/io/compression.h" #include "core/io/ip.h" +#include "core/variant/typed_array.h" void ENetConnection::broadcast(enet_uint8 p_channel, ENetPacket *p_packet) { ERR_FAIL_COND_MSG(!host, "The ENetConnection instance isn't currently active."); @@ -263,9 +264,9 @@ void ENetConnection::get_peers(List<Ref<ENetPacketPeer>> &r_peers) { } } -Array ENetConnection::_get_peers() { +TypedArray<ENetPacketPeer> ENetConnection::_get_peers() { ERR_FAIL_COND_V_MSG(!host, Array(), "The ENetConnection instance isn't currently active."); - Array out; + TypedArray<ENetPacketPeer> out; for (const Ref<ENetPacketPeer> &I : peers) { out.push_back(I); } diff --git a/modules/enet/enet_connection.h b/modules/enet/enet_connection.h index 0c873b6c55..5cd8f6be9a 100644 --- a/modules/enet/enet_connection.h +++ b/modules/enet/enet_connection.h @@ -38,6 +38,9 @@ #include <enet/enet.h> +template <typename T> +class TypedArray; + class ENetConnection : public RefCounted { GDCLASS(ENetConnection, RefCounted); @@ -83,7 +86,7 @@ private: Error _create(ENetAddress *p_address, int p_max_peers, int p_max_channels, int p_in_bandwidth, int p_out_bandwidth); Array _service(int p_timeout = 0); void _broadcast(int p_channel, PackedByteArray p_packet, int p_flags); - Array _get_peers(); + TypedArray<ENetPacketPeer> _get_peers(); class Compressor { private: diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index e7299b4d3a..b9560ea69b 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -526,8 +526,8 @@ String GDScriptSyntaxHighlighter::_get_name() const { return "GDScript"; } -Array GDScriptSyntaxHighlighter::_get_supported_languages() const { - Array languages; +PackedStringArray GDScriptSyntaxHighlighter::_get_supported_languages() const { + PackedStringArray languages; languages.push_back("GDScript"); return languages; } @@ -646,13 +646,13 @@ void GDScriptSyntaxHighlighter::_update_cache() { node_path_color = Color(0.72, 0.77, 0.49); node_ref_color = Color(0.39, 0.76, 0.35); annotation_color = Color(1.0, 0.7, 0.45); - string_name_color = Color(1.0, 0.66, 0.72); + string_name_color = Color(1.0, 0.76, 0.65); } else { function_definition_color = Color(0, 0.6, 0.6); node_path_color = Color(0.18, 0.55, 0); node_ref_color = Color(0.0, 0.5, 0); annotation_color = Color(0.8, 0.37, 0); - string_name_color = Color(0.8, 0.46, 0.52); + string_name_color = Color(0.8, 0.56, 0.45); } EDITOR_DEF("text_editor/theme/highlighting/gdscript/function_definition_color", function_definition_color); diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h index 7987582f07..f434d03a31 100644 --- a/modules/gdscript/editor/gdscript_highlighter.h +++ b/modules/gdscript/editor/gdscript_highlighter.h @@ -88,7 +88,7 @@ public: virtual Dictionary _get_line_syntax_highlighting_impl(int p_line) override; virtual String _get_name() const override; - virtual Array _get_supported_languages() const override; + virtual PackedStringArray _get_supported_languages() const override; virtual Ref<EditorSyntaxHighlighter> _create() const override; }; diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp index 4b97486cb3..38893a422d 100644 --- a/modules/gdscript/gdscript_utility_functions.cpp +++ b/modules/gdscript/gdscript_utility_functions.cpp @@ -36,6 +36,7 @@ #include "core/object/object.h" #include "core/templates/oa_hash_map.h" #include "core/templates/vector.h" +#include "core/variant/typed_array.h" #include "gdscript.h" #ifdef DEBUG_ENABLED @@ -468,12 +469,12 @@ struct GDScriptUtilityFunctionsDefinitions { static inline void get_stack(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { VALIDATE_ARG_COUNT(0); if (Thread::get_caller_id() != Thread::get_main_id()) { - *r_ret = Array(); + *r_ret = TypedArray<Dictionary>(); return; } ScriptLanguage *script = GDScriptLanguage::get_singleton(); - Array ret; + TypedArray<Dictionary> ret; for (int i = 0; i < script->debug_get_stack_level_count(); i++) { Dictionary frame; frame["source"] = script->debug_get_stack_level_source(i); diff --git a/modules/gdscript/gdscript_utility_functions.h b/modules/gdscript/gdscript_utility_functions.h index 9ca7cf33d8..0f07db857f 100644 --- a/modules/gdscript/gdscript_utility_functions.h +++ b/modules/gdscript/gdscript_utility_functions.h @@ -34,6 +34,9 @@ #include "core/string/string_name.h" #include "core/variant/variant.h" +template <typename T> +class TypedArray; + class GDScriptUtilityFunctions { public: typedef void (*FunctionPtr)(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error); diff --git a/modules/gltf/doc_classes/GLTFSkeleton.xml b/modules/gltf/doc_classes/GLTFSkeleton.xml index e1276d0e21..d6ec09f113 100644 --- a/modules/gltf/doc_classes/GLTFSkeleton.xml +++ b/modules/gltf/doc_classes/GLTFSkeleton.xml @@ -29,7 +29,7 @@ </description> </method> <method name="get_unique_names"> - <return type="Array" /> + <return type="String[]" /> <description> </description> </method> @@ -41,7 +41,7 @@ </method> <method name="set_unique_names"> <return type="void" /> - <param index="0" name="unique_names" type="Array" /> + <param index="0" name="unique_names" type="String[]" /> <description> </description> </method> diff --git a/modules/gltf/doc_classes/GLTFSkin.xml b/modules/gltf/doc_classes/GLTFSkin.xml index 5abdf33360..4de32857b5 100644 --- a/modules/gltf/doc_classes/GLTFSkin.xml +++ b/modules/gltf/doc_classes/GLTFSkin.xml @@ -8,7 +8,7 @@ </tutorials> <methods> <method name="get_inverse_binds"> - <return type="Array" /> + <return type="Transform3D[]" /> <description> </description> </method> @@ -24,7 +24,7 @@ </method> <method name="set_inverse_binds"> <return type="void" /> - <param index="0" name="inverse_binds" type="Array" /> + <param index="0" name="inverse_binds" type="Transform3D[]" /> <description> </description> </method> diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml index adf51ab59e..1dbd89aed8 100644 --- a/modules/gltf/doc_classes/GLTFState.xml +++ b/modules/gltf/doc_classes/GLTFState.xml @@ -8,7 +8,7 @@ </tutorials> <methods> <method name="get_accessors"> - <return type="Array" /> + <return type="GLTFAccessor[]" /> <description> </description> </method> @@ -25,42 +25,42 @@ </description> </method> <method name="get_animations"> - <return type="Array" /> + <return type="GLTFAnimation[]" /> <description> </description> </method> <method name="get_buffer_views"> - <return type="Array" /> + <return type="GLTFBufferView[]" /> <description> </description> </method> <method name="get_cameras"> - <return type="Array" /> + <return type="GLTFCamera[]" /> <description> </description> </method> <method name="get_images"> - <return type="Array" /> + <return type="Texture2D[]" /> <description> </description> </method> <method name="get_lights"> - <return type="Array" /> + <return type="GLTFLight[]" /> <description> </description> </method> <method name="get_materials"> - <return type="Array" /> + <return type="BaseMaterial3D[]" /> <description> </description> </method> <method name="get_meshes"> - <return type="Array" /> + <return type="GLTFMesh[]" /> <description> </description> </method> <method name="get_nodes"> - <return type="Array" /> + <return type="GLTFNode[]" /> <description> </description> </method> @@ -76,81 +76,81 @@ </description> </method> <method name="get_skeletons"> - <return type="Array" /> + <return type="GLTFSkeleton[]" /> <description> </description> </method> <method name="get_skins"> - <return type="Array" /> + <return type="GLTFSkin[]" /> <description> </description> </method> <method name="get_textures"> - <return type="Array" /> + <return type="GLTFTexture[]" /> <description> </description> </method> <method name="get_unique_animation_names"> - <return type="Array" /> + <return type="String[]" /> <description> </description> </method> <method name="get_unique_names"> - <return type="Array" /> + <return type="String[]" /> <description> </description> </method> <method name="set_accessors"> <return type="void" /> - <param index="0" name="accessors" type="Array" /> + <param index="0" name="accessors" type="GLTFAccessor[]" /> <description> </description> </method> <method name="set_animations"> <return type="void" /> - <param index="0" name="animations" type="Array" /> + <param index="0" name="animations" type="GLTFAnimation[]" /> <description> </description> </method> <method name="set_buffer_views"> <return type="void" /> - <param index="0" name="buffer_views" type="Array" /> + <param index="0" name="buffer_views" type="GLTFBufferView[]" /> <description> </description> </method> <method name="set_cameras"> <return type="void" /> - <param index="0" name="cameras" type="Array" /> + <param index="0" name="cameras" type="GLTFCamera[]" /> <description> </description> </method> <method name="set_images"> <return type="void" /> - <param index="0" name="images" type="Array" /> + <param index="0" name="images" type="Texture2D[]" /> <description> </description> </method> <method name="set_lights"> <return type="void" /> - <param index="0" name="lights" type="Array" /> + <param index="0" name="lights" type="GLTFLight[]" /> <description> </description> </method> <method name="set_materials"> <return type="void" /> - <param index="0" name="materials" type="Array" /> + <param index="0" name="materials" type="BaseMaterial3D[]" /> <description> </description> </method> <method name="set_meshes"> <return type="void" /> - <param index="0" name="meshes" type="Array" /> + <param index="0" name="meshes" type="GLTFMesh[]" /> <description> </description> </method> <method name="set_nodes"> <return type="void" /> - <param index="0" name="nodes" type="Array" /> + <param index="0" name="nodes" type="GLTFNode[]" /> <description> </description> </method> @@ -162,31 +162,31 @@ </method> <method name="set_skeletons"> <return type="void" /> - <param index="0" name="skeletons" type="Array" /> + <param index="0" name="skeletons" type="GLTFSkeleton[]" /> <description> </description> </method> <method name="set_skins"> <return type="void" /> - <param index="0" name="skins" type="Array" /> + <param index="0" name="skins" type="GLTFSkin[]" /> <description> </description> </method> <method name="set_textures"> <return type="void" /> - <param index="0" name="textures" type="Array" /> + <param index="0" name="textures" type="GLTFTexture[]" /> <description> </description> </method> <method name="set_unique_animation_names"> <return type="void" /> - <param index="0" name="unique_animation_names" type="Array" /> + <param index="0" name="unique_animation_names" type="String[]" /> <description> </description> </method> <method name="set_unique_names"> <return type="void" /> - <param index="0" name="unique_names" type="Array" /> + <param index="0" name="unique_names" type="String[]" /> <description> </description> </method> @@ -194,7 +194,7 @@ <members> <member name="base_path" type="String" setter="set_base_path" getter="get_base_path" default=""""> </member> - <member name="buffers" type="Array" setter="set_buffers" getter="get_buffers" default="[]"> + <member name="buffers" type="PackedByteArray[]" setter="set_buffers" getter="get_buffers" default="[]"> </member> <member name="create_animations" type="bool" setter="set_create_animations" getter="get_create_animations" default="true"> </member> @@ -206,7 +206,7 @@ </member> <member name="minor_version" type="int" setter="set_minor_version" getter="get_minor_version" default="0"> </member> - <member name="root_nodes" type="Array" setter="set_root_nodes" getter="get_root_nodes" default="[]"> + <member name="root_nodes" type="PackedInt32Array" setter="set_root_nodes" getter="get_root_nodes" default="PackedInt32Array()"> </member> <member name="scene_name" type="String" setter="set_scene_name" getter="get_scene_name" default=""""> </member> diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp index 8212e4c22f..85bac446cc 100644 --- a/modules/gltf/gltf_state.cpp +++ b/modules/gltf/gltf_state.cpp @@ -152,51 +152,51 @@ void GLTFState::set_use_named_skin_binds(bool p_use_named_skin_binds) { use_named_skin_binds = p_use_named_skin_binds; } -Array GLTFState::get_nodes() { +TypedArray<GLTFNode> GLTFState::get_nodes() { return GLTFTemplateConvert::to_array(nodes); } -void GLTFState::set_nodes(Array p_nodes) { +void GLTFState::set_nodes(TypedArray<GLTFNode> p_nodes) { GLTFTemplateConvert::set_from_array(nodes, p_nodes); } -Array GLTFState::get_buffers() { +TypedArray<PackedByteArray> GLTFState::get_buffers() { return GLTFTemplateConvert::to_array(buffers); } -void GLTFState::set_buffers(Array p_buffers) { +void GLTFState::set_buffers(TypedArray<PackedByteArray> p_buffers) { GLTFTemplateConvert::set_from_array(buffers, p_buffers); } -Array GLTFState::get_buffer_views() { +TypedArray<GLTFBufferView> GLTFState::get_buffer_views() { return GLTFTemplateConvert::to_array(buffer_views); } -void GLTFState::set_buffer_views(Array p_buffer_views) { +void GLTFState::set_buffer_views(TypedArray<GLTFBufferView> p_buffer_views) { GLTFTemplateConvert::set_from_array(buffer_views, p_buffer_views); } -Array GLTFState::get_accessors() { +TypedArray<GLTFAccessor> GLTFState::get_accessors() { return GLTFTemplateConvert::to_array(accessors); } -void GLTFState::set_accessors(Array p_accessors) { +void GLTFState::set_accessors(TypedArray<GLTFAccessor> p_accessors) { GLTFTemplateConvert::set_from_array(accessors, p_accessors); } -Array GLTFState::get_meshes() { +TypedArray<GLTFMesh> GLTFState::get_meshes() { return GLTFTemplateConvert::to_array(meshes); } -void GLTFState::set_meshes(Array p_meshes) { +void GLTFState::set_meshes(TypedArray<GLTFMesh> p_meshes) { GLTFTemplateConvert::set_from_array(meshes, p_meshes); } -Array GLTFState::get_materials() { +TypedArray<BaseMaterial3D> GLTFState::get_materials() { return GLTFTemplateConvert::to_array(materials); } -void GLTFState::set_materials(Array p_materials) { +void GLTFState::set_materials(TypedArray<BaseMaterial3D> p_materials) { GLTFTemplateConvert::set_from_array(materials, p_materials); } @@ -208,75 +208,75 @@ void GLTFState::set_scene_name(String p_scene_name) { scene_name = p_scene_name; } -Array GLTFState::get_root_nodes() { - return GLTFTemplateConvert::to_array(root_nodes); +PackedInt32Array GLTFState::get_root_nodes() { + return root_nodes; } -void GLTFState::set_root_nodes(Array p_root_nodes) { - GLTFTemplateConvert::set_from_array(root_nodes, p_root_nodes); +void GLTFState::set_root_nodes(PackedInt32Array p_root_nodes) { + root_nodes = p_root_nodes; } -Array GLTFState::get_textures() { +TypedArray<GLTFTexture> GLTFState::get_textures() { return GLTFTemplateConvert::to_array(textures); } -void GLTFState::set_textures(Array p_textures) { +void GLTFState::set_textures(TypedArray<GLTFTexture> p_textures) { GLTFTemplateConvert::set_from_array(textures, p_textures); } -Array GLTFState::get_images() { +TypedArray<Texture2D> GLTFState::get_images() { return GLTFTemplateConvert::to_array(images); } -void GLTFState::set_images(Array p_images) { +void GLTFState::set_images(TypedArray<Texture2D> p_images) { GLTFTemplateConvert::set_from_array(images, p_images); } -Array GLTFState::get_skins() { +TypedArray<GLTFSkin> GLTFState::get_skins() { return GLTFTemplateConvert::to_array(skins); } -void GLTFState::set_skins(Array p_skins) { +void GLTFState::set_skins(TypedArray<GLTFSkin> p_skins) { GLTFTemplateConvert::set_from_array(skins, p_skins); } -Array GLTFState::get_cameras() { +TypedArray<GLTFCamera> GLTFState::get_cameras() { return GLTFTemplateConvert::to_array(cameras); } -void GLTFState::set_cameras(Array p_cameras) { +void GLTFState::set_cameras(TypedArray<GLTFCamera> p_cameras) { GLTFTemplateConvert::set_from_array(cameras, p_cameras); } -Array GLTFState::get_lights() { +TypedArray<GLTFLight> GLTFState::get_lights() { return GLTFTemplateConvert::to_array(lights); } -void GLTFState::set_lights(Array p_lights) { +void GLTFState::set_lights(TypedArray<GLTFLight> p_lights) { GLTFTemplateConvert::set_from_array(lights, p_lights); } -Array GLTFState::get_unique_names() { +TypedArray<String> GLTFState::get_unique_names() { return GLTFTemplateConvert::to_array(unique_names); } -void GLTFState::set_unique_names(Array p_unique_names) { +void GLTFState::set_unique_names(TypedArray<String> p_unique_names) { GLTFTemplateConvert::set_from_array(unique_names, p_unique_names); } -Array GLTFState::get_unique_animation_names() { +TypedArray<String> GLTFState::get_unique_animation_names() { return GLTFTemplateConvert::to_array(unique_animation_names); } -void GLTFState::set_unique_animation_names(Array p_unique_animation_names) { +void GLTFState::set_unique_animation_names(TypedArray<String> p_unique_animation_names) { GLTFTemplateConvert::set_from_array(unique_animation_names, p_unique_animation_names); } -Array GLTFState::get_skeletons() { +TypedArray<GLTFSkeleton> GLTFState::get_skeletons() { return GLTFTemplateConvert::to_array(skeletons); } -void GLTFState::set_skeletons(Array p_skeletons) { +void GLTFState::set_skeletons(TypedArray<GLTFSkeleton> p_skeletons) { GLTFTemplateConvert::set_from_array(skeletons, p_skeletons); } @@ -296,11 +296,11 @@ void GLTFState::set_create_animations(bool p_create_animations) { create_animations = p_create_animations; } -Array GLTFState::get_animations() { +TypedArray<GLTFAnimation> GLTFState::get_animations() { return GLTFTemplateConvert::to_array(animations); } -void GLTFState::set_animations(Array p_animations) { +void GLTFState::set_animations(TypedArray<GLTFAnimation> p_animations) { GLTFTemplateConvert::set_from_array(animations, p_animations); } diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index c08132f874..6b2d1ca228 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -115,23 +115,23 @@ public: bool get_discard_meshes_and_materials(); void set_discard_meshes_and_materials(bool p_discard_meshes_and_materials); - Array get_nodes(); - void set_nodes(Array p_nodes); + TypedArray<GLTFNode> get_nodes(); + void set_nodes(TypedArray<GLTFNode> p_nodes); - Array get_buffers(); - void set_buffers(Array p_buffers); + TypedArray<PackedByteArray> get_buffers(); + void set_buffers(TypedArray<PackedByteArray> p_buffers); - Array get_buffer_views(); - void set_buffer_views(Array p_buffer_views); + TypedArray<GLTFBufferView> get_buffer_views(); + void set_buffer_views(TypedArray<GLTFBufferView> p_buffer_views); - Array get_accessors(); - void set_accessors(Array p_accessors); + TypedArray<GLTFAccessor> get_accessors(); + void set_accessors(TypedArray<GLTFAccessor> p_accessors); - Array get_meshes(); - void set_meshes(Array p_meshes); + TypedArray<GLTFMesh> get_meshes(); + void set_meshes(TypedArray<GLTFMesh> p_meshes); - Array get_materials(); - void set_materials(Array p_materials); + TypedArray<BaseMaterial3D> get_materials(); + void set_materials(TypedArray<BaseMaterial3D> p_materials); String get_scene_name(); void set_scene_name(String p_scene_name); @@ -139,32 +139,32 @@ public: String get_base_path(); void set_base_path(String p_base_path); - Array get_root_nodes(); - void set_root_nodes(Array p_root_nodes); + PackedInt32Array get_root_nodes(); + void set_root_nodes(PackedInt32Array p_root_nodes); - Array get_textures(); - void set_textures(Array p_textures); + TypedArray<GLTFTexture> get_textures(); + void set_textures(TypedArray<GLTFTexture> p_textures); - Array get_images(); - void set_images(Array p_images); + TypedArray<Texture2D> get_images(); + void set_images(TypedArray<Texture2D> p_images); - Array get_skins(); - void set_skins(Array p_skins); + TypedArray<GLTFSkin> get_skins(); + void set_skins(TypedArray<GLTFSkin> p_skins); - Array get_cameras(); - void set_cameras(Array p_cameras); + TypedArray<GLTFCamera> get_cameras(); + void set_cameras(TypedArray<GLTFCamera> p_cameras); - Array get_lights(); - void set_lights(Array p_lights); + TypedArray<GLTFLight> get_lights(); + void set_lights(TypedArray<GLTFLight> p_lights); - Array get_unique_names(); - void set_unique_names(Array p_unique_names); + TypedArray<String> get_unique_names(); + void set_unique_names(TypedArray<String> p_unique_names); - Array get_unique_animation_names(); - void set_unique_animation_names(Array p_unique_names); + TypedArray<String> get_unique_animation_names(); + void set_unique_animation_names(TypedArray<String> p_unique_names); - Array get_skeletons(); - void set_skeletons(Array p_skeletons); + TypedArray<GLTFSkeleton> get_skeletons(); + void set_skeletons(TypedArray<GLTFSkeleton> p_skeletons); Dictionary get_skeleton_to_node(); void set_skeleton_to_node(Dictionary p_skeleton_to_node); @@ -172,8 +172,8 @@ public: bool get_create_animations(); void set_create_animations(bool p_create_animations); - Array get_animations(); - void set_animations(Array p_animations); + TypedArray<GLTFAnimation> get_animations(); + void set_animations(TypedArray<GLTFAnimation> p_animations); Node *get_scene_node(GLTFNodeIndex idx); diff --git a/modules/gltf/gltf_template_convert.h b/modules/gltf/gltf_template_convert.h index c915d3deb0..8a4b595c9f 100644 --- a/modules/gltf/gltf_template_convert.h +++ b/modules/gltf/gltf_template_convert.h @@ -46,8 +46,8 @@ static Array to_array(const Vector<T> &p_inp) { } template <class T> -static Array to_array(const HashSet<T> &p_inp) { - Array ret; +static TypedArray<T> to_array(const HashSet<T> &p_inp) { + TypedArray<T> ret; typename HashSet<T>::Iterator elem = p_inp.begin(); while (elem) { ret.push_back(*elem); @@ -65,7 +65,7 @@ static void set_from_array(Vector<T> &r_out, const Array &p_inp) { } template <class T> -static void set_from_array(HashSet<T> &r_out, const Array &p_inp) { +static void set_from_array(HashSet<T> &r_out, const TypedArray<T> &p_inp) { r_out.clear(); for (int i = 0; i < p_inp.size(); i++) { r_out.insert(p_inp[i]); diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp index 1e1204aa57..dbbccc9bcc 100644 --- a/modules/gltf/register_types.cpp +++ b/modules/gltf/register_types.cpp @@ -66,17 +66,24 @@ static void _editor_init() { bool blend_enabled = GLOBAL_GET("filesystem/import/blender/enabled"); // Defined here because EditorSettings doesn't exist in `register_gltf_types` yet. - EDITOR_DEF_RST("filesystem/import/blender/blender3_path", ""); + String blender3_path = EDITOR_DEF_RST("filesystem/import/blender/blender3_path", ""); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "filesystem/import/blender/blender3_path", PROPERTY_HINT_GLOBAL_DIR)); if (blend_enabled) { - Ref<EditorSceneFormatImporterBlend> importer; - importer.instantiate(); - ResourceImporterScene::add_importer(importer); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (blender3_path.is_empty()) { + WARN_PRINT("Blend file import is enabled in the project settings, but no Blender path is configured in the editor settings. Blend files will not be imported."); + } else if (!da->dir_exists(blender3_path)) { + WARN_PRINT("Blend file import is enabled, but the Blender path doesn't point to an accessible directory. Blend files will not be imported."); + } else { + Ref<EditorSceneFormatImporterBlend> importer; + importer.instantiate(); + ResourceImporterScene::add_importer(importer); - Ref<EditorFileSystemImportFormatSupportQueryBlend> blend_import_query; - blend_import_query.instantiate(); - EditorFileSystem::get_singleton()->add_import_format_support_query(blend_import_query); + Ref<EditorFileSystemImportFormatSupportQueryBlend> blend_import_query; + blend_import_query.instantiate(); + EditorFileSystem::get_singleton()->add_import_format_support_query(blend_import_query); + } } // FBX to glTF importer. @@ -89,9 +96,9 @@ static void _editor_init() { if (fbx_enabled) { Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); if (fbx2gltf_path.is_empty()) { - WARN_PRINT("FBX file import is enabled, but no FBX2glTF path is configured. FBX files will not be imported."); + WARN_PRINT("FBX file import is enabled in the project settings, but no FBX2glTF path is configured in the editor settings. FBX files will not be imported."); } else if (!da->file_exists(fbx2gltf_path)) { - WARN_PRINT("FBX file import is enabled, but the FBX2glTF path doesn't point to a valid FBX2glTF executable. FBX files will not be imported."); + WARN_PRINT("FBX file import is enabled, but the FBX2glTF path doesn't point to an accessible file. FBX files will not be imported."); } else { Ref<EditorSceneFormatImporterFBX> importer; importer.instantiate(); diff --git a/modules/gltf/structures/gltf_skeleton.cpp b/modules/gltf/structures/gltf_skeleton.cpp index 90a6b0f50f..0073357eda 100644 --- a/modules/gltf/structures/gltf_skeleton.cpp +++ b/modules/gltf/structures/gltf_skeleton.cpp @@ -72,11 +72,11 @@ Skeleton3D *GLTFSkeleton::get_godot_skeleton() { return godot_skeleton; } -Array GLTFSkeleton::get_unique_names() { +TypedArray<String> GLTFSkeleton::get_unique_names() { return GLTFTemplateConvert::to_array(unique_names); } -void GLTFSkeleton::set_unique_names(Array p_unique_names) { +void GLTFSkeleton::set_unique_names(TypedArray<String> p_unique_names) { GLTFTemplateConvert::set_from_array(unique_names, p_unique_names); } diff --git a/modules/gltf/structures/gltf_skeleton.h b/modules/gltf/structures/gltf_skeleton.h index db88623213..0f20b493b6 100644 --- a/modules/gltf/structures/gltf_skeleton.h +++ b/modules/gltf/structures/gltf_skeleton.h @@ -75,8 +75,8 @@ public: // this->godot_skeleton = p_godot_skeleton; // } - Array get_unique_names(); - void set_unique_names(Array p_unique_names); + TypedArray<String> get_unique_names(); + void set_unique_names(TypedArray<String> p_unique_names); //RBMap<int32_t, GLTFNodeIndex> get_godot_bone_node() { // return this->godot_bone_node; diff --git a/modules/gltf/structures/gltf_skin.cpp b/modules/gltf/structures/gltf_skin.cpp index 2e46ee3be2..9717a66048 100644 --- a/modules/gltf/structures/gltf_skin.cpp +++ b/modules/gltf/structures/gltf_skin.cpp @@ -31,6 +31,7 @@ #include "gltf_skin.h" #include "../gltf_template_convert.h" +#include "core/variant/typed_array.h" #include "scene/resources/skin.h" void GLTFSkin::_bind_methods() { @@ -83,11 +84,11 @@ void GLTFSkin::set_joints_original(Vector<GLTFNodeIndex> p_joints_original) { joints_original = p_joints_original; } -Array GLTFSkin::get_inverse_binds() { +TypedArray<Transform3D> GLTFSkin::get_inverse_binds() { return GLTFTemplateConvert::to_array(inverse_binds); } -void GLTFSkin::set_inverse_binds(Array p_inverse_binds) { +void GLTFSkin::set_inverse_binds(TypedArray<Transform3D> p_inverse_binds) { GLTFTemplateConvert::set_from_array(inverse_binds, p_inverse_binds); } diff --git a/modules/gltf/structures/gltf_skin.h b/modules/gltf/structures/gltf_skin.h index 59b6a300ac..1a4d54b380 100644 --- a/modules/gltf/structures/gltf_skin.h +++ b/modules/gltf/structures/gltf_skin.h @@ -34,6 +34,9 @@ #include "../gltf_defines.h" #include "core/io/resource.h" +template <typename T> +class TypedArray; + class GLTFSkin : public Resource { GDCLASS(GLTFSkin, Resource); friend class GLTFDocument; @@ -82,8 +85,8 @@ public: Vector<GLTFNodeIndex> get_joints_original(); void set_joints_original(Vector<GLTFNodeIndex> p_joints_original); - Array get_inverse_binds(); - void set_inverse_binds(Array p_inverse_binds); + TypedArray<Transform3D> get_inverse_binds(); + void set_inverse_binds(TypedArray<Transform3D> p_inverse_binds); Vector<GLTFNodeIndex> get_joints(); void set_joints(Vector<GLTFNodeIndex> p_joints); diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index 209890a333..6717f23057 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -102,13 +102,13 @@ </description> </method> <method name="get_used_cells" qualifiers="const"> - <return type="Array" /> + <return type="Vector3i[]" /> <description> Returns an array of [Vector3] with the non-empty cell coordinates in the grid map. </description> </method> <method name="get_used_cells_by_item" qualifiers="const"> - <return type="Array" /> + <return type="Vector3i[]" /> <param index="0" name="item" type="int" /> <description> Returns an array of all cells with the given item index specified in [code]item[/code]. diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 6384446bce..f207d4a741 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -1049,23 +1049,23 @@ float GridMap::get_cell_scale() const { return cell_scale; } -Array GridMap::get_used_cells() const { - Array a; +TypedArray<Vector3i> GridMap::get_used_cells() const { + TypedArray<Vector3i> a; a.resize(cell_map.size()); int i = 0; for (const KeyValue<IndexKey, Cell> &E : cell_map) { - Vector3 p(E.key.x, E.key.y, E.key.z); + Vector3i p(E.key.x, E.key.y, E.key.z); a[i++] = p; } return a; } -Array GridMap::get_used_cells_by_item(int p_item) const { - Array a; +TypedArray<Vector3i> GridMap::get_used_cells_by_item(int p_item) const { + TypedArray<Vector3i> a; for (const KeyValue<IndexKey, Cell> &E : cell_map) { if (E.value.item == p_item) { - Vector3 p(E.key.x, E.key.y, E.key.z); + Vector3i p(E.key.x, E.key.y, E.key.z); a.push_back(p); } } diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index 00cebd35e9..0ed4695fb9 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -273,8 +273,8 @@ public: void set_cell_scale(float p_scale); float get_cell_scale() const; - Array get_used_cells() const; - Array get_used_cells_by_item(int p_item) const; + TypedArray<Vector3i> get_used_cells() const; + TypedArray<Vector3i> get_used_cells_by_item(int p_item) const; Array get_meshes() const; diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp index eca689e87a..e7c6fe592d 100644 --- a/modules/hdr/image_loader_hdr.cpp +++ b/modules/hdr/image_loader_hdr.cpp @@ -33,7 +33,7 @@ #include "core/os/os.h" #include "core/string/print_string.h" -Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { +Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) { String header = f->get_token(); ERR_FAIL_COND_V_MSG(header != "#?RADIANCE" && header != "#?RGBE", ERR_FILE_UNRECOGNIZED, "Unsupported header information in HDR: " + header + "."); @@ -131,7 +131,7 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_f ptr[1] * exp / 255.0, ptr[2] * exp / 255.0); - if (p_force_linear) { + if (p_flags & FLAG_FORCE_LINEAR) { c = c.srgb_to_linear(); } diff --git a/modules/hdr/image_loader_hdr.h b/modules/hdr/image_loader_hdr.h index 16c0816562..1bff05129b 100644 --- a/modules/hdr/image_loader_hdr.h +++ b/modules/hdr/image_loader_hdr.h @@ -35,7 +35,7 @@ class ImageLoaderHDR : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderHDR(); }; diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp index 0e03fa65c8..3e138bf633 100644 --- a/modules/jpg/image_loader_jpegd.cpp +++ b/modules/jpg/image_loader_jpegd.cpp @@ -104,7 +104,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p return OK; } -Error ImageLoaderJPG::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { +Error ImageLoaderJPG::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); diff --git a/modules/jpg/image_loader_jpegd.h b/modules/jpg/image_loader_jpegd.h index 6d631446e7..caa0461d05 100644 --- a/modules/jpg/image_loader_jpegd.h +++ b/modules/jpg/image_loader_jpegd.h @@ -35,7 +35,7 @@ class ImageLoaderJPG : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderJPG(); }; diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py index c7f9b39b48..3277f9beeb 100644 --- a/modules/mono/build_scripts/mono_configure.py +++ b/modules/mono/build_scripts/mono_configure.py @@ -3,11 +3,11 @@ import os.path def is_desktop(platform): - return platform in ["windows", "macos", "linuxbsd", "server", "uwp", "haiku"] + return platform in ["windows", "macos", "linuxbsd", "uwp", "haiku"] def is_unix_like(platform): - return platform in ["macos", "linuxbsd", "server", "android", "haiku", "ios"] + return platform in ["macos", "linuxbsd", "android", "haiku", "ios"] def module_supports_tools_on(platform): @@ -18,7 +18,7 @@ def configure(env, env_mono): # is_android = env["platform"] == "android" # is_javascript = env["platform"] == "javascript" # is_ios = env["platform"] == "ios" - # is_ios_sim = is_ios and env["arch"] in ["x86", "x86_64"] + # is_ios_sim = is_ios and env["arch"] in ["x86_32", "x86_64"] tools_enabled = env["tools"] @@ -82,7 +82,7 @@ def find_dotnet_app_host_dir(env): dotnet_root = env["dotnet_root"] if not dotnet_root: - dotnet_cmd = find_executable("dotnet") + dotnet_cmd = find_dotnet_executable(env["arch"]) if dotnet_cmd: sdk_path = find_dotnet_sdk(dotnet_cmd, dotnet_version) if sdk_path: @@ -128,27 +128,22 @@ def find_dotnet_app_host_dir(env): def determine_runtime_identifier(env): + # The keys are Godot's names, the values are the Microsoft's names. + # List: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog names_map = { "windows": "win", "macos": "osx", "linuxbsd": "linux", - "server": "linux", # FIXME: Is server linux only, or also macos? } - - # .NET RID architectures: x86, x64, arm, or arm64 - + arch_map = { + "x86_64": "x64", + "x86_32": "x86", + "arm64": "arm64", + "arm32": "arm", + } platform = env["platform"] - if is_desktop(platform): - if env["arch"] in ["arm", "arm32"]: - rid = "arm" - elif env["arch"] == "arm64": - rid = "arm64" - else: - bits = env["bits"] - bit_arch_map = {"64": "x64", "32": "x86"} - rid = bit_arch_map[bits] - return "%s-%s" % (names_map[platform], rid) + return "%s-%s" % (names_map[platform], arch_map[env["arch"]]) else: raise NotImplementedError() @@ -186,6 +181,35 @@ def find_app_host_version(dotnet_cmd, search_version_str): return "" +def find_dotnet_arch(dotnet_cmd): + import subprocess + + try: + env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US") + lines = subprocess.check_output([dotnet_cmd, "--info"], env=env).splitlines() + + for line_bytes in lines: + line = line_bytes.decode("utf-8") + + parts = line.split(":", 1) + if len(parts) < 2: + continue + + arch_str = parts[0].strip() + if arch_str != "Architecture": + continue + + arch_value = parts[1].strip() + arch_map = {"x64": "x86_64", "x86": "x86_32", "arm64": "arm64", "arm32": "arm32"} + return arch_map[arch_value] + except (subprocess.CalledProcessError, OSError) as e: + import sys + + print(e, file=sys.stderr) + + return "" + + def find_dotnet_sdk(dotnet_cmd, search_version_str): import subprocess from distutils.version import LooseVersion @@ -248,24 +272,44 @@ def find_dotnet_cli_rid(dotnet_cmd): ENV_PATH_SEP = ";" if os.name == "nt" else ":" -def find_executable(name): +def find_dotnet_executable(arch): is_windows = os.name == "nt" windows_exts = os.environ["PATHEXT"].split(ENV_PATH_SEP) if is_windows else None path_dirs = os.environ["PATH"].split(ENV_PATH_SEP) search_dirs = path_dirs + [os.getcwd()] # cwd is last in the list + for dir in path_dirs: + search_dirs += [ + os.path.join(dir, "x64"), + os.path.join(dir, "x86"), + os.path.join(dir, "arm64"), + os.path.join(dir, "arm32"), + ] # search subfolders for cross compiling + + # `dotnet --info` may not specify architecture. In such cases, + # we fallback to the first one we find without architecture. + sdk_path_unknown_arch = "" + for dir in search_dirs: - path = os.path.join(dir, name) + path = os.path.join(dir, "dotnet") if is_windows: for extension in windows_exts: path_with_ext = path + extension if os.path.isfile(path_with_ext) and os.access(path_with_ext, os.X_OK): - return path_with_ext + sdk_arch = find_dotnet_arch(path_with_ext) + if sdk_arch == arch or arch == "": + return path_with_ext + elif sdk_arch == "": + sdk_path_unknown_arch = path_with_ext else: if os.path.isfile(path) and os.access(path, os.X_OK): - return path + sdk_arch = find_dotnet_arch(path) + if sdk_arch == arch or arch == "": + return path + elif sdk_arch == "": + sdk_path_unknown_arch = path - return "" + return sdk_path_unknown_arch diff --git a/modules/mono/config.py b/modules/mono/config.py index d156877929..b599414a2c 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -1,6 +1,6 @@ -# Prior to .NET Core, we supported these: ["windows", "macos", "linuxbsd", "server", "android", "haiku", "javascript", "ios"] +# Prior to .NET Core, we supported these: ["windows", "macos", "linuxbsd", "android", "haiku", "javascript", "ios"] # Eventually support for each them should be added back (except Haiku if not supported by .NET Core) -supported_platforms = ["windows", "macos", "linuxbsd", "server"] +supported_platforms = ["windows", "macos", "linuxbsd"] def can_build(env, platform): diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props index 652b9e8e43..ad41ab04d5 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props @@ -77,7 +77,6 @@ <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'windows' ">GODOT_WINDOWS;GODOT_PC</GodotPlatformConstants> <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'linuxbsd' ">GODOT_LINUXBSD;GODOT_PC</GodotPlatformConstants> <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'macos' ">GODOT_OSX;GODOT_MACOS;GODOT_PC</GodotPlatformConstants> - <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'server' ">GODOT_SERVER;GODOT_PC</GodotPlatformConstants> <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'uwp' ">GODOT_UWP;GODOT_PC</GodotPlatformConstants> <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'haiku' ">GODOT_HAIKU;GODOT_PC</GodotPlatformConstants> <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'android' ">GODOT_ANDROID;GODOT_MOBILE</GodotPlatformConstants> diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs index c1ae993251..3dfa8000ba 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs @@ -1,6 +1,7 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; namespace Godot.SourceGenerators { @@ -19,7 +20,7 @@ namespace Godot.SourceGenerators "must be declared with the partial modifier."; context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor(id: "GODOT-G0001", + new DiagnosticDescriptor(id: "GD0001", title: message, messageFormat: message, category: "Usage", @@ -51,7 +52,7 @@ namespace Godot.SourceGenerators "containing types must be declared with the partial modifier."; context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor(id: "GODOT-G0002", + new DiagnosticDescriptor(id: "GD0002", title: message, messageFormat: message, category: "Usage", @@ -78,7 +79,7 @@ namespace Godot.SourceGenerators " Remove the 'static' modifier or the '[Export]' attribute."; context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor(id: "GODOT-G0101", + new DiagnosticDescriptor(id: "GD0101", title: message, messageFormat: message, category: "Usage", @@ -104,7 +105,7 @@ namespace Godot.SourceGenerators string description = $"{message}. Use a supported type or remove the '[Export]' attribute."; context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor(id: "GODOT-G0102", + new DiagnosticDescriptor(id: "GD0102", title: message, messageFormat: message, category: "Usage", @@ -132,7 +133,7 @@ namespace Godot.SourceGenerators $"{message}. Exported properties must be writable."; context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor(id: "GODOT-G0103", + new DiagnosticDescriptor(id: "GD0103", title: message, messageFormat: message, category: "Usage", @@ -156,7 +157,7 @@ namespace Godot.SourceGenerators string description = $"{message}. Exported properties must be readable."; context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor(id: "GODOT-G0104", + new DiagnosticDescriptor(id: "GD0104", title: message, messageFormat: message, category: "Usage", @@ -181,7 +182,7 @@ namespace Godot.SourceGenerators string description = $"{message}. Rename the delegate accordingly or remove the '[Signal]' attribute."; context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor(id: "GODOT-G0201", + new DiagnosticDescriptor(id: "GD0201", title: message, messageFormat: message, category: "Usage", @@ -192,7 +193,31 @@ namespace Godot.SourceGenerators location?.SourceTree?.FilePath)); } - public static void ReportSignalDelegateSignatureNotSupported( + public static void ReportSignalParameterTypeNotSupported( + GeneratorExecutionContext context, + IParameterSymbol parameterSymbol) + { + var locations = parameterSymbol.Locations; + var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault(); + + string message = "The parameter of the delegate signature of the signal " + + $"is not supported: '{parameterSymbol.ToDisplayString()}'"; + + string description = $"{message}. Use supported types only or remove the '[Signal]' attribute."; + + context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor(id: "GD0202", + title: message, + messageFormat: message, + category: "Usage", + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description), + location, + location?.SourceTree?.FilePath)); + } + + public static void ReportSignalDelegateSignatureMustReturnVoid( GeneratorExecutionContext context, INamedTypeSymbol delegateSymbol) { @@ -200,12 +225,12 @@ namespace Godot.SourceGenerators var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault(); string message = "The delegate signature of the signal " + - $"is not supported: '{delegateSymbol.ToDisplayString()}'"; + $"must return void: '{delegateSymbol.ToDisplayString()}'"; - string description = $"{message}. Use supported types only or remove the '[Signal]' attribute."; + string description = $"{message}. Return void or remove the '[Signal]' attribute."; context.ReportDiagnostic(Diagnostic.Create( - new DiagnosticDescriptor(id: "GODOT-G0202", + new DiagnosticDescriptor(id: "GD0203", title: message, messageFormat: message, category: "Usage", @@ -215,5 +240,97 @@ namespace Godot.SourceGenerators location, location?.SourceTree?.FilePath)); } + + public static readonly DiagnosticDescriptor GenericTypeArgumentMustBeVariantRule = + new DiagnosticDescriptor(id: "GD0301", + title: "The generic type argument must be a Variant compatible type", + messageFormat: "The generic type argument must be a Variant compatible type: {0}", + category: "Usage", + DiagnosticSeverity.Error, + isEnabledByDefault: true, + "The generic type argument must be a Variant compatible type. Use a Variant compatible type as the generic type argument."); + + public static void ReportGenericTypeArgumentMustBeVariant( + SyntaxNodeAnalysisContext context, + SyntaxNode typeArgumentSyntax, + ISymbol typeArgumentSymbol) + { + string message = "The generic type argument " + + $"must be a Variant compatible type: '{typeArgumentSymbol.ToDisplayString()}'"; + + string description = $"{message}. Use a Variant compatible type as the generic type argument."; + + context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor(id: "GD0301", + title: message, + messageFormat: message, + category: "Usage", + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description), + typeArgumentSyntax.GetLocation(), + typeArgumentSyntax.SyntaxTree.FilePath)); + } + + public static readonly DiagnosticDescriptor GenericTypeParameterMustBeVariantAnnotatedRule = + new DiagnosticDescriptor(id: "GD0302", + title: "The generic type parameter must be annotated with the MustBeVariant attribute", + messageFormat: "The generic type argument must be a Variant type: {0}", + category: "Usage", + DiagnosticSeverity.Error, + isEnabledByDefault: true, + "The generic type argument must be a Variant type. Use a Variant type as the generic type argument."); + + public static void ReportGenericTypeParameterMustBeVariantAnnotated( + SyntaxNodeAnalysisContext context, + SyntaxNode typeArgumentSyntax, + ISymbol typeArgumentSymbol) + { + string message = "The generic type parameter must be annotated with the MustBeVariant attribute"; + + string description = $"{message}. Add the MustBeVariant attribute to the generic type parameter."; + + context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor(id: "GD0302", + title: message, + messageFormat: message, + category: "Usage", + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description), + typeArgumentSyntax.GetLocation(), + typeArgumentSyntax.SyntaxTree.FilePath)); + } + + public static readonly DiagnosticDescriptor TypeArgumentParentSymbolUnhandledRule = + new DiagnosticDescriptor(id: "GD0303", + title: "The generic type parameter must be annotated with the MustBeVariant attribute", + messageFormat: "The generic type argument must be a Variant type: {0}", + category: "Usage", + DiagnosticSeverity.Error, + isEnabledByDefault: true, + "The generic type argument must be a Variant type. Use a Variant type as the generic type argument."); + + public static void ReportTypeArgumentParentSymbolUnhandled( + SyntaxNodeAnalysisContext context, + SyntaxNode typeArgumentSyntax, + ISymbol parentSymbol) + { + string message = $"Symbol '{parentSymbol.ToDisplayString()}' parent of a type argument " + + "that must be Variant compatible was not handled."; + + string description = $"{message}. Handle type arguments that are children of the unhandled symbol type."; + + context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor(id: "GD0303", + title: message, + messageFormat: message, + category: "Usage", + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description), + typeArgumentSyntax.GetLocation(), + typeArgumentSyntax.SyntaxTree.FilePath)); + } } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs index bac4708165..de3b6c862a 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs @@ -177,6 +177,9 @@ namespace Godot.SourceGenerators public static bool IsGodotSignalAttribute(this INamedTypeSymbol symbol) => symbol.ToString() == GodotClasses.SignalAttr; + public static bool IsGodotMustBeVariantAttribute(this INamedTypeSymbol symbol) + => symbol.ToString() == GodotClasses.MustBeVariantAttr; + public static bool IsGodotClassNameAttribute(this INamedTypeSymbol symbol) => symbol.ToString() == GodotClasses.GodotClassNameAttr; @@ -272,5 +275,13 @@ namespace Godot.SourceGenerators yield return new GodotFieldData(field, marshalType.Value); } } + + public static string Path(this Location location) + => location.SourceTree?.GetLineSpan(location.SourceSpan).Path + ?? location.GetLineSpan().Path; + + public static int StartLine(this Location location) + => location.SourceTree?.GetLineSpan(location.SourceSpan).StartLinePosition.Line + ?? location.GetLineSpan().StartLinePosition.Line; } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs index 9ba8bb89b8..1d8ddbabf2 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs @@ -5,7 +5,11 @@ namespace Godot.SourceGenerators public const string Object = "Godot.Object"; public const string AssemblyHasScriptsAttr = "Godot.AssemblyHasScriptsAttribute"; public const string ExportAttr = "Godot.ExportAttribute"; + public const string ExportCategoryAttr = "Godot.ExportCategoryAttribute"; + public const string ExportGroupAttr = "Godot.ExportGroupAttribute"; + public const string ExportSubgroupAttr = "Godot.ExportSubgroupAttribute"; public const string SignalAttr = "Godot.SignalAttribute"; + public const string MustBeVariantAttr = "Godot.MustBeVariantAttribute"; public const string GodotClassNameAttr = "Godot.GodotClassName"; public const string SystemFlagsAttr = "System.FlagsAttribute"; } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs index a3ad8cbabd..db395e21cb 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs @@ -59,4 +59,26 @@ namespace Godot.SourceGenerators public IFieldSymbol FieldSymbol { get; } public MarshalType Type { get; } } + + public struct GodotPropertyOrFieldData + { + public GodotPropertyOrFieldData(ISymbol symbol, MarshalType type) + { + Symbol = symbol; + Type = type; + } + + public GodotPropertyOrFieldData(GodotPropertyData propertyData) + : this(propertyData.PropertySymbol, propertyData.Type) + { + } + + public GodotPropertyOrFieldData(GodotFieldData fieldData) + : this(fieldData.FieldSymbol, fieldData.Type) + { + } + + public ISymbol Symbol { get; } + public MarshalType Type { get; } + } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs index ca84518c0c..831ac3bdeb 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs @@ -11,11 +11,11 @@ namespace Godot.SourceGenerators { public INamedTypeSymbol GodotObjectType { get; } - public TypeCache(GeneratorExecutionContext context) + public TypeCache(Compilation compilation) { INamedTypeSymbol GetTypeByMetadataNameOrThrow(string fullyQualifiedMetadataName) { - return context.Compilation.GetTypeByMetadataName(fullyQualifiedMetadataName) ?? + return compilation.GetTypeByMetadataName(fullyQualifiedMetadataName) ?? throw new InvalidOperationException("Type not found: " + fullyQualifiedMetadataName); } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs new file mode 100644 index 0000000000..7aaadb27be --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs @@ -0,0 +1,100 @@ +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Godot.SourceGenerators +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class MustBeVariantAnalyzer : DiagnosticAnalyzer + { + public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics + => ImmutableArray.Create( + Common.GenericTypeArgumentMustBeVariantRule, + Common.GenericTypeParameterMustBeVariantAnnotatedRule, + Common.TypeArgumentParentSymbolUnhandledRule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.TypeArgumentList); + } + + private void AnalyzeNode(SyntaxNodeAnalysisContext context) + { + var typeArgListSyntax = (TypeArgumentListSyntax)context.Node; + + // Method invocation or variable declaration that contained the type arguments + var parentSyntax = context.Node.Parent; + Debug.Assert(parentSyntax != null); + + var sm = context.SemanticModel; + + var typeCache = new MarshalUtils.TypeCache(context.Compilation); + + for (int i = 0; i < typeArgListSyntax.Arguments.Count; i++) + { + var typeSyntax = typeArgListSyntax.Arguments[i]; + var typeSymbol = sm.GetSymbolInfo(typeSyntax).Symbol as ITypeSymbol; + Debug.Assert(typeSymbol != null); + + var parentSymbol = sm.GetSymbolInfo(parentSyntax).Symbol; + + if (!ShouldCheckTypeArgument(context, parentSyntax, parentSymbol, typeSyntax, typeSymbol, i)) + { + return; + } + + if (typeSymbol is ITypeParameterSymbol typeParamSymbol) + { + if (!typeParamSymbol.GetAttributes().Any(a => a.AttributeClass?.IsGodotMustBeVariantAttribute() ?? false)) + { + Common.ReportGenericTypeParameterMustBeVariantAnnotated(context, typeSyntax, typeSymbol); + } + continue; + } + + var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(typeSymbol, typeCache); + + if (marshalType == null) + { + Common.ReportGenericTypeArgumentMustBeVariant(context, typeSyntax, typeSymbol); + continue; + } + } + } + + /// <summary> + /// Check if the given type argument is being used in a type parameter that contains + /// the <c>MustBeVariantAttribute</c>; otherwise, we ignore the attribute. + /// </summary> + /// <param name="context">Context for a syntax node action.</param> + /// <param name="parentSyntax">The parent node syntax that contains the type node syntax.</param> + /// <param name="parentSymbol">The symbol retrieved for the parent node syntax.</param> + /// <param name="typeArgumentSyntax">The type node syntax of the argument type to check.</param> + /// <param name="typeArgumentSymbol">The symbol retrieved for the type node syntax.</param> + /// <returns><see langword="true"/> if the type must be variant and must be analyzed.</returns> + private bool ShouldCheckTypeArgument(SyntaxNodeAnalysisContext context, SyntaxNode parentSyntax, ISymbol parentSymbol, TypeSyntax typeArgumentSyntax, ITypeSymbol typeArgumentSymbol, int typeArgumentIndex) + { + var typeParamSymbol = parentSymbol switch + { + IMethodSymbol methodSymbol => methodSymbol.TypeParameters[typeArgumentIndex], + INamedTypeSymbol typeSymbol => typeSymbol.TypeParameters[typeArgumentIndex], + _ => null, + }; + + if (typeParamSymbol == null) + { + Common.ReportTypeArgumentParentSymbolUnhandled(context, typeArgumentSyntax, parentSymbol); + return false; + } + + return typeParamSymbol.GetAttributes() + .Any(a => a.AttributeClass?.IsGodotMustBeVariantAttribute() ?? false); + } + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs index 1fdc04a262..5ac4f4a47e 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs @@ -49,7 +49,7 @@ namespace Godot.SourceGenerators if (godotClasses.Length > 0) { - var typeCache = new MarshalUtils.TypeCache(context); + var typeCache = new MarshalUtils.TypeCache(context.Compilation); foreach (var godotClass in godotClasses) { diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs index 12a369fd72..7629595b3a 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.CodeAnalysis; @@ -48,7 +49,7 @@ namespace Godot.SourceGenerators if (godotClasses.Length > 0) { - var typeCache = new MarshalUtils.TypeCache(context); + var typeCache = new MarshalUtils.TypeCache(context.Compilation); foreach (var godotClass in godotClasses) { @@ -224,21 +225,21 @@ namespace Godot.SourceGenerators .Append(dictionaryType) .Append("();\n"); - foreach (var property in godotClassProperties) - { - var propertyInfo = DeterminePropertyInfo(context, typeCache, - property.PropertySymbol, property.Type); - - if (propertyInfo == null) - continue; - - AppendPropertyInfo(source, propertyInfo.Value); - } + // To retain the definition order (and display categories correctly), we want to + // iterate over fields and properties at the same time, sorted by line number. + var godotClassPropertiesAndFields = Enumerable.Empty<GodotPropertyOrFieldData>() + .Concat(godotClassProperties.Select(propertyData => new GodotPropertyOrFieldData(propertyData))) + .Concat(godotClassFields.Select(fieldData => new GodotPropertyOrFieldData(fieldData))) + .OrderBy(data => data.Symbol.Locations[0].Path()) + .ThenBy(data => data.Symbol.Locations[0].StartLine()); - foreach (var field in godotClassFields) + foreach (var member in godotClassPropertiesAndFields) { + foreach (var groupingInfo in DetermineGroupingPropertyInfo(member.Symbol)) + AppendGroupingPropertyInfo(source, groupingInfo); + var propertyInfo = DeterminePropertyInfo(context, typeCache, - field.FieldSymbol, field.Type); + member.Symbol, member.Type); if (propertyInfo == null) continue; @@ -321,6 +322,21 @@ namespace Godot.SourceGenerators .Append(" }\n"); } + private static void AppendGroupingPropertyInfo(StringBuilder source, PropertyInfo propertyInfo) + { + source.Append(" properties.Add(new(type: (Godot.Variant.Type)") + .Append((int)VariantType.Nil) + .Append(", name: \"") + .Append(propertyInfo.Name) + .Append("\", hint: (Godot.PropertyHint)") + .Append((int)PropertyHint.None) + .Append(", hintString: \"") + .Append(propertyInfo.HintString) + .Append("\", usage: (Godot.PropertyUsageFlags)") + .Append((int)propertyInfo.Usage) + .Append(", exported: true));\n"); + } + private static void AppendPropertyInfo(StringBuilder source, PropertyInfo propertyInfo) { source.Append(" properties.Add(new(type: (Godot.Variant.Type)") @@ -338,6 +354,32 @@ namespace Godot.SourceGenerators .Append("));\n"); } + private static IEnumerable<PropertyInfo> DetermineGroupingPropertyInfo(ISymbol memberSymbol) + { + foreach (var attr in memberSymbol.GetAttributes()) + { + PropertyUsageFlags? propertyUsage = attr.AttributeClass?.ToString() switch + { + GodotClasses.ExportCategoryAttr => PropertyUsageFlags.Category, + GodotClasses.ExportGroupAttr => PropertyUsageFlags.Group, + GodotClasses.ExportSubgroupAttr => PropertyUsageFlags.Subgroup, + _ => null + }; + + if (propertyUsage is null) + continue; + + if (attr.ConstructorArguments.Length > 0 && attr.ConstructorArguments[0].Value is string name) + { + string? hintString = null; + if (propertyUsage != PropertyUsageFlags.Category && attr.ConstructorArguments.Length > 1) + hintString = attr.ConstructorArguments[1].Value?.ToString(); + + yield return new PropertyInfo(VariantType.Nil, name, PropertyHint.None, hintString, propertyUsage.Value, true); + } + } + } + private static PropertyInfo? DeterminePropertyInfo( GeneratorExecutionContext context, MarshalUtils.TypeCache typeCache, diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs index 3b8ba21107..85fadaa52e 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs @@ -49,7 +49,7 @@ namespace Godot.SourceGenerators if (godotClasses.Length > 0) { - var typeCache = new MarshalUtils.TypeCache(context); + var typeCache = new MarshalUtils.TypeCache(context.Compilation); foreach (var godotClass in godotClasses) { diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs index 1b87c6e760..5a84122c4c 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs @@ -49,7 +49,7 @@ namespace Godot.SourceGenerators if (godotClasses.Length > 0) { - var typeCache = new MarshalUtils.TypeCache(context); + var typeCache = new MarshalUtils.TypeCache(context.Compilation); foreach (var godotClass in godotClasses) { diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs index 536ddb02f8..6b06f10db1 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs @@ -56,7 +56,7 @@ namespace Godot.SourceGenerators if (godotClasses.Length > 0) { - var typeCache = new MarshalUtils.TypeCache(context); + var typeCache = new MarshalUtils.TypeCache(context.Compilation); foreach (var godotClass in godotClasses) { @@ -117,10 +117,6 @@ namespace Godot.SourceGenerators source.Append(symbol.NameWithTypeParameters()); source.Append("\n{\n"); - // TODO: - // The delegate name already needs to end with 'Signal' to avoid collision with the event name. - // Requiring SignalAttribute is redundant. Should we remove it to make declaration shorter? - var members = symbol.GetMembers(); var signalDelegateSymbols = members @@ -148,8 +144,29 @@ namespace Godot.SourceGenerators if (invokeMethodData == null) { - // TODO: Better error for incompatible signature. We should indicate incompatible argument types, as we do with exported properties. - Common.ReportSignalDelegateSignatureNotSupported(context, signalDelegateSymbol); + if (signalDelegateSymbol.DelegateInvokeMethod is IMethodSymbol methodSymbol) + { + foreach (var parameter in methodSymbol.Parameters) + { + if (parameter.RefKind != RefKind.None) + { + Common.ReportSignalParameterTypeNotSupported(context, parameter); + continue; + } + + var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(parameter.Type, typeCache); + + if (marshalType == null) + { + Common.ReportSignalParameterTypeNotSupported(context, parameter); + } + } + + if (!methodSymbol.ReturnsVoid) + { + Common.ReportSignalDelegateSignatureMustReturnVoid(context, signalDelegateSymbol); + } + } continue; } diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotIdeMetadata.cs b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotIdeMetadata.cs index 686202e81e..2448a2953b 100644 --- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotIdeMetadata.cs +++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotIdeMetadata.cs @@ -25,10 +25,7 @@ namespace GodotTools.IdeMessaging public override bool Equals(object obj) { - if (obj is GodotIdeMetadata metadata) - return metadata == this; - - return false; + return obj is GodotIdeMetadata metadata && metadata == this; } public bool Equals(GodotIdeMetadata other) diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs index 3c5b897719..edbf53a389 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs @@ -27,15 +27,13 @@ namespace GodotTools.Build public override bool Equals(object? obj) { - if (obj is BuildInfo other) - return other.Solution == Solution && - other.Configuration == Configuration && other.RuntimeIdentifier == RuntimeIdentifier && - other.PublishOutputDir == PublishOutputDir && other.Restore == Restore && - other.Rebuild == Rebuild && other.OnlyClean == OnlyClean && - other.CustomProperties == CustomProperties && - other.LogsDirPath == LogsDirPath; - - return false; + return obj is BuildInfo other && + other.Solution == Solution && + other.Configuration == Configuration && other.RuntimeIdentifier == RuntimeIdentifier && + other.PublishOutputDir == PublishOutputDir && other.Restore == Restore && + other.Rebuild == Rebuild && other.OnlyClean == OnlyClean && + other.CustomProperties == CustomProperties && + other.LogsDirPath == LogsDirPath; } public override int GetHashCode() diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs index 87549f61fe..fc325fc25b 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs @@ -75,8 +75,17 @@ namespace GodotTools.Export } else { - string bits = features.Contains("64") ? "64" : features.Contains("32") ? "32" : null; - CompileAssembliesForDesktop(exporter, platform, isDebug, bits, aotOpts, aotTempDir, outputDataDir, assembliesPrepared, bclDir); + string arch = ""; + if (features.Contains("x86_64")) { + arch = "x86_64"; + } else if (features.Contains("x86_32")) { + arch = "x86_32"; + } else if (features.Contains("arm64")) { + arch = "arm64"; + } else if (features.Contains("arm32")) { + arch = "arm32"; + } + CompileAssembliesForDesktop(exporter, platform, isDebug, arch, aotOpts, aotTempDir, outputDataDir, assembliesPrepared, bclDir); } } @@ -112,7 +121,7 @@ namespace GodotTools.Export } } - public static void CompileAssembliesForDesktop(ExportPlugin exporter, string platform, bool isDebug, string bits, AotOptions aotOpts, string aotTempDir, string outputDataDir, IDictionary<string, string> assemblies, string bclDir) + public static void CompileAssembliesForDesktop(ExportPlugin exporter, string platform, bool isDebug, string arch, AotOptions aotOpts, string aotTempDir, string outputDataDir, IDictionary<string, string> assemblies, string bclDir) { foreach (var assembly in assemblies) { @@ -126,9 +135,9 @@ namespace GodotTools.Export string outputFileName = assemblyName + ".dll" + outputFileExtension; string tempOutputFilePath = Path.Combine(aotTempDir, outputFileName); - var compilerArgs = GetAotCompilerArgs(platform, isDebug, bits, aotOpts, assemblyPath, tempOutputFilePath); + var compilerArgs = GetAotCompilerArgs(platform, isDebug, arch, aotOpts, assemblyPath, tempOutputFilePath); - string compilerDirPath = GetMonoCrossDesktopDirName(platform, bits); + string compilerDirPath = GetMonoCrossDesktopDirName(platform, arch); ExecuteCompiler(FindCrossCompiler(compilerDirPath), compilerArgs, bclDir); @@ -432,9 +441,9 @@ MONO_AOT_MODE_LAST = 1000, var androidToolPrefixes = new Dictionary<string, string> { - ["armeabi-v7a"] = "arm-linux-androideabi-", - ["arm64-v8a"] = "aarch64-linux-android-", - ["x86"] = "i686-linux-android-", + ["arm32"] = "arm-linux-androideabi-", + ["arm64"] = "aarch64-linux-android-", + ["x86_32"] = "i686-linux-android-", ["x86_64"] = "x86_64-linux-android-" }; @@ -547,9 +556,9 @@ MONO_AOT_MODE_LAST = 1000, { var androidAbis = new[] { - "armeabi-v7a", - "arm64-v8a", - "x86", + "arm32", + "arm64", + "x86_32", "x86_64" }; @@ -560,9 +569,9 @@ MONO_AOT_MODE_LAST = 1000, { var abiArchs = new Dictionary<string, string> { - ["armeabi-v7a"] = "armv7", - ["arm64-v8a"] = "aarch64-v8a", - ["x86"] = "i686", + ["arm32"] = "armv7", + ["arm64"] = "aarch64-v8a", + ["x86_32"] = "i686", ["x86_64"] = "x86_64" }; @@ -571,31 +580,25 @@ MONO_AOT_MODE_LAST = 1000, return $"{arch}-linux-android"; } - private static string GetMonoCrossDesktopDirName(string platform, string bits) + private static string GetMonoCrossDesktopDirName(string platform, string arch) { switch (platform) { case OS.Platforms.Windows: case OS.Platforms.UWP: { - string arch = bits == "64" ? "x86_64" : "i686"; return $"windows-{arch}"; } case OS.Platforms.MacOS: { - Debug.Assert(bits == null || bits == "64"); - string arch = "x86_64"; return $"{platform}-{arch}"; } case OS.Platforms.LinuxBSD: - case OS.Platforms.Server: { - string arch = bits == "64" ? "x86_64" : "i686"; return $"linux-{arch}"; } case OS.Platforms.Haiku: { - string arch = bits == "64" ? "x86_64" : "i686"; return $"{platform}-{arch}"; } default: diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs index ecf363c106..e1b5530b93 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs @@ -100,7 +100,7 @@ namespace GodotTools.Export if (!DeterminePlatformFromFeatures(features, out string platform)) throw new NotSupportedException("Target platform not supported"); - if (!new[] { OS.Platforms.Windows, OS.Platforms.LinuxBSD, OS.Platforms.MacOS, OS.Platforms.Server } + if (!new[] { OS.Platforms.Windows, OS.Platforms.LinuxBSD, OS.Platforms.MacOS } .Contains(platform)) { throw new NotImplementedException("Target platform not yet implemented"); diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs index 62140d41bc..651922d019 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs @@ -15,6 +15,9 @@ namespace GodotTools.Utils [SuppressMessage("ReSharper", "InconsistentNaming")] public static class OS { + /// <summary> + /// Display names for the OS platforms. + /// </summary> private static class Names { public const string Windows = "Windows"; @@ -23,7 +26,6 @@ namespace GodotTools.Utils public const string FreeBSD = "FreeBSD"; public const string NetBSD = "NetBSD"; public const string BSD = "BSD"; - public const string Server = "Server"; public const string UWP = "UWP"; public const string Haiku = "Haiku"; public const string Android = "Android"; @@ -31,12 +33,14 @@ namespace GodotTools.Utils public const string HTML5 = "HTML5"; } + /// <summary> + /// Godot platform identifiers. + /// </summary> public static class Platforms { public const string Windows = "windows"; public const string MacOS = "macos"; public const string LinuxBSD = "linuxbsd"; - public const string Server = "server"; public const string UWP = "uwp"; public const string Haiku = "haiku"; public const string Android = "android"; @@ -44,6 +48,10 @@ namespace GodotTools.Utils public const string HTML5 = "javascript"; } + /// <summary> + /// OS name part of the .NET runtime identifier (RID). + /// See https://docs.microsoft.com/en-us/dotnet/core/rid-catalog. + /// </summary> public static class DotNetOS { public const string Win = "win"; @@ -65,7 +73,6 @@ namespace GodotTools.Utils ["LinuxBSD"] = Platforms.LinuxBSD, // "X11" for compatibility, temporarily, while we are on an outdated branch ["X11"] = Platforms.LinuxBSD, - ["Server"] = Platforms.Server, ["UWP"] = Platforms.UWP, ["Haiku"] = Platforms.Haiku, ["Android"] = Platforms.Android, @@ -81,7 +88,6 @@ namespace GodotTools.Utils [Names.FreeBSD] = Platforms.LinuxBSD, [Names.NetBSD] = Platforms.LinuxBSD, [Names.BSD] = Platforms.LinuxBSD, - [Names.Server] = Platforms.Server, [Names.UWP] = Platforms.UWP, [Names.Haiku] = Platforms.Haiku, [Names.Android] = Platforms.Android, @@ -98,7 +104,6 @@ namespace GodotTools.Utils // instead of `linux` in the runtime identifier. This would be a problem as // Godot has a single export profile for both, named LinuxBSD. [Platforms.LinuxBSD] = DotNetOS.Linux, - [Platforms.Server] = DotNetOS.Linux, [Platforms.UWP] = DotNetOS.Win10, [Platforms.Android] = DotNetOS.Android, [Platforms.iOS] = DotNetOS.iOS, @@ -129,13 +134,12 @@ namespace GodotTools.Utils new[] { Names.Linux, Names.FreeBSD, Names.NetBSD, Names.BSD }; private static readonly IEnumerable<string> UnixLikePlatforms = - new[] { Names.MacOS, Names.Server, Names.Haiku, Names.Android, Names.iOS } + new[] { Names.MacOS, Names.Haiku, Names.Android, Names.iOS } .Concat(LinuxBSDPlatforms).ToArray(); private static readonly Lazy<bool> _isWindows = new(() => IsOS(Names.Windows)); private static readonly Lazy<bool> _isMacOS = new(() => IsOS(Names.MacOS)); private static readonly Lazy<bool> _isLinuxBSD = new(() => IsAnyOS(LinuxBSDPlatforms)); - private static readonly Lazy<bool> _isServer = new(() => IsOS(Names.Server)); private static readonly Lazy<bool> _isUWP = new(() => IsOS(Names.UWP)); private static readonly Lazy<bool> _isHaiku = new(() => IsOS(Names.Haiku)); private static readonly Lazy<bool> _isAndroid = new(() => IsOS(Names.Android)); @@ -149,8 +153,6 @@ namespace GodotTools.Utils [SupportedOSPlatformGuard("linux")] public static bool IsLinuxBSD => _isLinuxBSD.Value; - [SupportedOSPlatformGuard("linux")] public static bool IsServer => _isServer.Value; - [SupportedOSPlatformGuard("windows")] public static bool IsUWP => _isUWP.Value; public static bool IsHaiku => _isHaiku.Value; diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 73d8f23081..d70a1e6c88 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -87,9 +87,7 @@ StringBuilder &operator<<(StringBuilder &r_sb, const char *p_cstring) { #define CS_STATIC_FIELD_NATIVE_CTOR "NativeCtor" #define CS_STATIC_FIELD_METHOD_BIND_PREFIX "MethodBind" -#define CS_STATIC_FIELD_METHOD_NAME_PREFIX "MethodName_" #define CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX "MethodProxyName_" -#define CS_STATIC_FIELD_SIGNAL_NAME_PREFIX "SignalName_" #define ICALL_PREFIX "godot_icall_" #define ICALL_CLASSDB_GET_METHOD "ClassDB_get_method" @@ -1606,12 +1604,6 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output << MEMBER_BEGIN "// ReSharper disable once InconsistentNaming\n" << INDENT1 "[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n" << INDENT1 "private static readonly StringName " - << CS_STATIC_FIELD_METHOD_NAME_PREFIX << imethod.name - << " = \"" << imethod.name << "\";\n"; - - output << MEMBER_BEGIN "// ReSharper disable once InconsistentNaming\n" - << INDENT1 "[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n" - << INDENT1 "private static readonly StringName " << CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX << imethod.name << " = \"" << imethod.proxy_name << "\";\n"; } @@ -1637,7 +1629,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str // We check both native names (snake_case) and proxy names (PascalCase) output << INDENT2 "if ((method == " << CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX << imethod.name - << " || method == " << CS_STATIC_FIELD_METHOD_NAME_PREFIX << imethod.name + << " || method == MethodName." << imethod.proxy_name << ") && argCount == " << itos(imethod.arguments.size()) << " && " << CS_METHOD_HAS_GODOT_CLASS_METHOD << "((godot_string_name)" << CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX << imethod.name << ".NativeValue))\n" @@ -1713,7 +1705,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str // again, but this time with the respective proxy name (PascalCase). It's the job of // user derived classes to override the method and check for those. Our C# source // generators take care of generating those override methods. - output << INDENT2 "if (method == " << CS_STATIC_FIELD_METHOD_NAME_PREFIX << imethod.name + output << INDENT2 "if (method == MethodName." << imethod.proxy_name << ")\n" INDENT2 "{\n" << INDENT3 "if (" CS_METHOD_HAS_GODOT_CLASS_METHOD "(" << CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX << imethod.name @@ -1731,6 +1723,45 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output << INDENT1 "}\n"; } + //Generate StringName for all class members + bool is_inherit = !itype.is_singleton && obj_types.has(itype.base_name); + //PropertyName + if (is_inherit) { + output << MEMBER_BEGIN "public new class PropertyName : " << obj_types[itype.base_name].proxy_name << ".PropertyName"; + } else { + output << MEMBER_BEGIN "public class PropertyName"; + } + output << "\n" + << INDENT1 "{\n"; + for (const PropertyInterface &iprop : itype.properties) { + output << INDENT2 "public static readonly StringName " << iprop.proxy_name << " = \"" << iprop.cname << "\";\n"; + } + output << INDENT1 "}\n"; + //MethodName + if (is_inherit) { + output << MEMBER_BEGIN "public new class MethodName : " << obj_types[itype.base_name].proxy_name << ".MethodName"; + } else { + output << MEMBER_BEGIN "public class MethodName"; + } + output << "\n" + << INDENT1 "{\n"; + for (const MethodInterface &imethod : itype.methods) { + output << INDENT2 "public static readonly StringName " << imethod.proxy_name << " = \"" << imethod.cname << "\";\n"; + } + output << INDENT1 "}\n"; + //SignalName + if (is_inherit) { + output << MEMBER_BEGIN "public new class SignalName : " << obj_types[itype.base_name].proxy_name << ".SignalName"; + } else { + output << MEMBER_BEGIN "public class SignalName"; + } + output << "\n" + << INDENT1 "{\n"; + for (const SignalInterface &isignal : itype.signals_) { + output << INDENT2 "public static readonly StringName " << isignal.proxy_name << " = \"" << isignal.cname << "\";\n"; + } + output << INDENT1 "}\n"; + output.append(CLOSE_BLOCK /* class */); output.append("\n" @@ -2052,9 +2083,9 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf p_output << "Object."; } - p_output << ICALL_CLASSDB_GET_METHOD "(" BINDINGS_NATIVE_NAME_FIELD ", \"" - << p_imethod.name - << "\");\n"; + p_output << ICALL_CLASSDB_GET_METHOD "(" BINDINGS_NATIVE_NAME_FIELD ", MethodName." + << p_imethod.proxy_name + << ");\n"; } if (p_imethod.method_doc && p_imethod.method_doc->description.size()) { @@ -2226,7 +2257,7 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf } String delegate_name = p_isignal.proxy_name; - delegate_name += "Handler"; // Delegate name is [SignalName]Handler + delegate_name += "EventHandler"; // Delegate name is [SignalName]EventHandler // Generate delegate p_output.append(MEMBER_BEGIN "public delegate void "); @@ -2239,17 +2270,8 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf // Could we assume the StringName instance of signal name will never be freed (it's stored in ClassDB) before the managed world is unloaded? // If so, we could store the pointer we get from `data_unique_pointer()` instead of allocating StringName here. - // Cached signal name (StringName) - p_output.append(MEMBER_BEGIN "// ReSharper disable once InconsistentNaming\n"); - p_output.append(INDENT1 "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN - "private static readonly StringName " CS_STATIC_FIELD_SIGNAL_NAME_PREFIX); - p_output.append(p_isignal.name); - p_output.append(" = \""); - p_output.append(p_isignal.name); - p_output.append("\";\n"); - // Generate event - p_output.append(MEMBER_BEGIN "[Signal]" MEMBER_BEGIN "public "); + p_output.append(MEMBER_BEGIN "public "); if (p_itype.is_singleton) { p_output.append("static "); @@ -2262,21 +2284,21 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf p_output.append("\n" OPEN_BLOCK_L1 INDENT2); if (p_itype.is_singleton) { - p_output.append("add => " CS_PROPERTY_SINGLETON ".Connect(" CS_STATIC_FIELD_SIGNAL_NAME_PREFIX); + p_output.append("add => " CS_PROPERTY_SINGLETON ".Connect(SignalName."); } else { - p_output.append("add => Connect(" CS_STATIC_FIELD_SIGNAL_NAME_PREFIX); + p_output.append("add => Connect(SignalName."); } - p_output.append(p_isignal.name); + p_output.append(p_isignal.proxy_name); p_output.append(", new Callable(value));\n"); if (p_itype.is_singleton) { - p_output.append(INDENT2 "remove => " CS_PROPERTY_SINGLETON ".Disconnect(" CS_STATIC_FIELD_SIGNAL_NAME_PREFIX); + p_output.append(INDENT2 "remove => " CS_PROPERTY_SINGLETON ".Disconnect(SignalName."); } else { - p_output.append(INDENT2 "remove => Disconnect(" CS_STATIC_FIELD_SIGNAL_NAME_PREFIX); + p_output.append(INDENT2 "remove => Disconnect(SignalName."); } - p_output.append(p_isignal.name); + p_output.append(p_isignal.proxy_name); p_output.append(", new Callable(value));\n"); p_output.append(CLOSE_BLOCK_L1); } diff --git a/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs b/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs index 188bbb775c..069908c426 100644 --- a/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs +++ b/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs @@ -26,7 +26,7 @@ public partial class _CLASS_ : _BASE_ // Get the input direction and handle the movement/deceleration. // As good practice, you should replace UI actions with custom gameplay actions. Vector2 inputDir = Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down"); - Vector3 direction = Transform.basis.Xform(new Vector3(inputDir.x, 0, inputDir.y)).Normalized(); + Vector3 direction = (Transform.basis * new Vector3(inputDir.x, 0, inputDir.y)).Normalized(); if (direction != Vector3.Zero) { velocity.x = direction.x * Speed; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs index f87f37bc43..b3a36e8ac8 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs @@ -697,12 +697,7 @@ namespace Godot /// <returns>Whether or not the AABB and the object are equal.</returns> public override bool Equals(object obj) { - if (obj is AABB) - { - return Equals((AABB)obj); - } - - return false; + return obj is AABB other && Equals(other); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs index 81991c6626..f2984bd1fb 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs @@ -483,7 +483,7 @@ namespace Godot.Collections /// <typeparam name="T">The type of the array.</typeparam> [SuppressMessage("ReSharper", "RedundantExtendsListEntry")] [SuppressMessage("Naming", "CA1710", MessageId = "Identifiers should have correct suffix")] - public sealed class Array<T> : + public sealed class Array<[MustBeVariant] T> : IList<T>, IReadOnlyList<T>, ICollection<T>, diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs new file mode 100644 index 0000000000..101e56f8d3 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs @@ -0,0 +1,22 @@ +using System; + +namespace Godot +{ + /// <summary> + /// Define a new category for the following exported properties. This helps to organize properties in the Inspector dock. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public sealed class ExportCategoryAttribute : Attribute + { + private string name; + + /// <summary> + /// Define a new category for the following exported properties. + /// </summary> + /// <param name="name">The name of the category.</param> + public ExportCategoryAttribute(string name) + { + this.name = name; + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs new file mode 100644 index 0000000000..3bd532cec1 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs @@ -0,0 +1,25 @@ +using System; + +namespace Godot +{ + /// <summary> + /// Define a new group for the following exported properties. This helps to organize properties in the Inspector dock. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public sealed class ExportGroupAttribute : Attribute + { + private string name; + private string prefix; + + /// <summary> + /// Define a new group for the following exported properties. + /// </summary> + /// <param name="name">The name of the group.</param> + /// <param name="prefix">If provided, the group would make group to only consider properties that have this prefix.</param> + public ExportGroupAttribute(string name, string prefix = "") + { + this.name = name; + this.prefix = prefix; + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs new file mode 100644 index 0000000000..2ae6eb0b68 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs @@ -0,0 +1,25 @@ +using System; + +namespace Godot +{ + /// <summary> + /// Define a new subgroup for the following exported properties. This helps to organize properties in the Inspector dock. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public sealed class ExportSubgroupAttribute : Attribute + { + private string name; + private string prefix; + + /// <summary> + /// Define a new subgroup for the following exported properties. This helps to organize properties in the Inspector dock. + /// </summary> + /// <param name="name">The name of the subgroup.</param> + /// <param name="prefix">If provided, the subgroup would make group to only consider properties that have this prefix.</param> + public ExportSubgroupAttribute(string name, string prefix = "") + { + this.name = name; + this.prefix = prefix; + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/MustBeVariantAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/MustBeVariantAttribute.cs new file mode 100644 index 0000000000..23088378d1 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/MustBeVariantAttribute.cs @@ -0,0 +1,11 @@ +using System; + +namespace Godot +{ + /// <summary> + /// Attribute that restricts generic type parameters to be only types + /// that can be marshaled from/to a <see cref="Variant"/>. + /// </summary> + [AttributeUsage(AttributeTargets.GenericParameter)] + public class MustBeVariantAttribute : Attribute { } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs index 07a214f543..38e68a89d5 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs @@ -2,6 +2,6 @@ using System; namespace Godot { - [AttributeUsage(AttributeTargets.Delegate | AttributeTargets.Event)] + [AttributeUsage(AttributeTargets.Delegate)] public class SignalAttribute : Attribute { } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index 646681a9b1..87adf9efe5 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -618,41 +618,6 @@ namespace Godot return tr; } - /// <summary> - /// Returns a vector transformed (multiplied) by the basis matrix. - /// </summary> - /// <seealso cref="XformInv(Vector3)"/> - /// <param name="v">A vector to transform.</param> - /// <returns>The transformed vector.</returns> - public Vector3 Xform(Vector3 v) - { - return new Vector3 - ( - Row0.Dot(v), - Row1.Dot(v), - Row2.Dot(v) - ); - } - - /// <summary> - /// Returns a vector transformed (multiplied) by the transposed basis matrix. - /// - /// Note: This results in a multiplication by the inverse of the - /// basis matrix only if it represents a rotation-reflection. - /// </summary> - /// <seealso cref="Xform(Vector3)"/> - /// <param name="v">A vector to inversely transform.</param> - /// <returns>The inversely transformed vector.</returns> - public Vector3 XformInv(Vector3 v) - { - return new Vector3 - ( - Row0[0] * v.x + Row1[0] * v.y + Row2[0] * v.z, - Row0[1] * v.x + Row1[1] * v.y + Row2[1] * v.z, - Row0[2] * v.x + Row1[2] * v.y + Row2[2] * v.z - ); - } - private static readonly Basis[] _orthoBases = { new Basis(1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f), new Basis(0f, -1f, 0f, 1f, 0f, 0f, 0f, 0f, 1f), @@ -857,6 +822,41 @@ namespace Godot } /// <summary> + /// Returns a Vector3 transformed (multiplied) by the basis matrix. + /// </summary> + /// <param name="basis">The basis matrix transformation to apply.</param> + /// <param name="vector">A Vector3 to transform.</param> + /// <returns>The transformed Vector3.</returns> + public static Vector3 operator *(Basis basis, Vector3 vector) + { + return new Vector3 + ( + basis.Row0.Dot(vector), + basis.Row1.Dot(vector), + basis.Row2.Dot(vector) + ); + } + + /// <summary> + /// Returns a Vector3 transformed (multiplied) by the transposed basis matrix. + /// + /// Note: This results in a multiplication by the inverse of the + /// basis matrix only if it represents a rotation-reflection. + /// </summary> + /// <param name="vector">A Vector3 to inversely transform.</param> + /// <param name="basis">The basis matrix transformation to apply.</param> + /// <returns>The inversely transformed vector.</returns> + public static Vector3 operator *(Vector3 vector, Basis basis) + { + return new Vector3 + ( + basis.Row0[0] * vector.x + basis.Row1[0] * vector.y + basis.Row2[0] * vector.z, + basis.Row0[1] * vector.x + basis.Row1[1] * vector.y + basis.Row2[1] * vector.z, + basis.Row0[2] * vector.x + basis.Row1[2] * vector.y + basis.Row2[2] * vector.z + ); + } + + /// <summary> /// Returns <see langword="true"/> if the basis matrices are exactly /// equal. Note: Due to floating-point precision errors, consider using /// <see cref="IsEqualApprox"/> instead, which is more reliable. @@ -892,12 +892,7 @@ namespace Godot /// <returns>Whether or not the basis matrix and the object are exactly equal.</returns> public override bool Equals(object obj) { - if (obj is Basis) - { - return Equals((Basis)obj); - } - - return false; + return obj is Basis other && Equals(other); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs index 8f26967dcd..6d20f95007 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs @@ -4,7 +4,7 @@ using Godot.NativeInterop; namespace Godot.Bridge; -public class GodotSerializationInfo : IDisposable +public sealed class GodotSerializationInfo : IDisposable { private readonly Collections.Dictionary _properties; private readonly Collections.Dictionary _signalEvents; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs index 8d0e77d171..1b7f5158fd 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs @@ -149,11 +149,5 @@ namespace Godot NativeFuncs.godotsharp_callable_call_deferred(callable, (godot_variant**)argsPtr, argc); } } - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern object godot_icall_Callable_Call(ref Callable callable, object[] args); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Callable_CallDeferred(ref Callable callable, object[] args); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index ed0e1efd35..0cbaef3dad 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -1151,12 +1151,7 @@ namespace Godot /// <returns>Whether or not the color and the other object are equal.</returns> public override bool Equals(object obj) { - if (obj is Color) - { - return Equals((Color)obj); - } - - return false; + return obj is Color other && Equals(other); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs index 68c821b447..bacf7c89e6 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs @@ -10,152 +10,152 @@ namespace Godot { // Color names and values are derived from core/math/color_names.inc internal static readonly Dictionary<string, Color> namedColors = new Dictionary<string, Color> { - {"ALICEBLUE", new Color(0.94f, 0.97f, 1.00f)}, - {"ANTIQUEWHITE", new Color(0.98f, 0.92f, 0.84f)}, - {"AQUA", new Color(0.00f, 1.00f, 1.00f)}, - {"AQUAMARINE", new Color(0.50f, 1.00f, 0.83f)}, - {"AZURE", new Color(0.94f, 1.00f, 1.00f)}, - {"BEIGE", new Color(0.96f, 0.96f, 0.86f)}, - {"BISQUE", new Color(1.00f, 0.89f, 0.77f)}, - {"BLACK", new Color(0.00f, 0.00f, 0.00f)}, - {"BLANCHEDALMOND", new Color(1.00f, 0.92f, 0.80f)}, - {"BLUE", new Color(0.00f, 0.00f, 1.00f)}, - {"BLUEVIOLET", new Color(0.54f, 0.17f, 0.89f)}, - {"BROWN", new Color(0.65f, 0.16f, 0.16f)}, - {"BURLYWOOD", new Color(0.87f, 0.72f, 0.53f)}, - {"CADETBLUE", new Color(0.37f, 0.62f, 0.63f)}, - {"CHARTREUSE", new Color(0.50f, 1.00f, 0.00f)}, - {"CHOCOLATE", new Color(0.82f, 0.41f, 0.12f)}, - {"CORAL", new Color(1.00f, 0.50f, 0.31f)}, - {"CORNFLOWERBLUE", new Color(0.39f, 0.58f, 0.93f)}, - {"CORNSILK", new Color(1.00f, 0.97f, 0.86f)}, - {"CRIMSON", new Color(0.86f, 0.08f, 0.24f)}, - {"CYAN", new Color(0.00f, 1.00f, 1.00f)}, - {"DARKBLUE", new Color(0.00f, 0.00f, 0.55f)}, - {"DARKCYAN", new Color(0.00f, 0.55f, 0.55f)}, - {"DARKGOLDENROD", new Color(0.72f, 0.53f, 0.04f)}, - {"DARKGRAY", new Color(0.66f, 0.66f, 0.66f)}, - {"DARKGREEN", new Color(0.00f, 0.39f, 0.00f)}, - {"DARKKHAKI", new Color(0.74f, 0.72f, 0.42f)}, - {"DARKMAGENTA", new Color(0.55f, 0.00f, 0.55f)}, - {"DARKOLIVEGREEN", new Color(0.33f, 0.42f, 0.18f)}, - {"DARKORANGE", new Color(1.00f, 0.55f, 0.00f)}, - {"DARKORCHID", new Color(0.60f, 0.20f, 0.80f)}, - {"DARKRED", new Color(0.55f, 0.00f, 0.00f)}, - {"DARKSALMON", new Color(0.91f, 0.59f, 0.48f)}, - {"DARKSEAGREEN", new Color(0.56f, 0.74f, 0.56f)}, - {"DARKSLATEBLUE", new Color(0.28f, 0.24f, 0.55f)}, - {"DARKSLATEGRAY", new Color(0.18f, 0.31f, 0.31f)}, - {"DARKTURQUOISE", new Color(0.00f, 0.81f, 0.82f)}, - {"DARKVIOLET", new Color(0.58f, 0.00f, 0.83f)}, - {"DEEPPINK", new Color(1.00f, 0.08f, 0.58f)}, - {"DEEPSKYBLUE", new Color(0.00f, 0.75f, 1.00f)}, - {"DIMGRAY", new Color(0.41f, 0.41f, 0.41f)}, - {"DODGERBLUE", new Color(0.12f, 0.56f, 1.00f)}, - {"FIREBRICK", new Color(0.70f, 0.13f, 0.13f)}, - {"FLORALWHITE", new Color(1.00f, 0.98f, 0.94f)}, - {"FORESTGREEN", new Color(0.13f, 0.55f, 0.13f)}, - {"FUCHSIA", new Color(1.00f, 0.00f, 1.00f)}, - {"GAINSBORO", new Color(0.86f, 0.86f, 0.86f)}, - {"GHOSTWHITE", new Color(0.97f, 0.97f, 1.00f)}, - {"GOLD", new Color(1.00f, 0.84f, 0.00f)}, - {"GOLDENROD", new Color(0.85f, 0.65f, 0.13f)}, - {"GRAY", new Color(0.75f, 0.75f, 0.75f)}, - {"GREEN", new Color(0.00f, 1.00f, 0.00f)}, - {"GREENYELLOW", new Color(0.68f, 1.00f, 0.18f)}, - {"HONEYDEW", new Color(0.94f, 1.00f, 0.94f)}, - {"HOTPINK", new Color(1.00f, 0.41f, 0.71f)}, - {"INDIANRED", new Color(0.80f, 0.36f, 0.36f)}, - {"INDIGO", new Color(0.29f, 0.00f, 0.51f)}, - {"IVORY", new Color(1.00f, 1.00f, 0.94f)}, - {"KHAKI", new Color(0.94f, 0.90f, 0.55f)}, - {"LAVENDER", new Color(0.90f, 0.90f, 0.98f)}, - {"LAVENDERBLUSH", new Color(1.00f, 0.94f, 0.96f)}, - {"LAWNGREEN", new Color(0.49f, 0.99f, 0.00f)}, - {"LEMONCHIFFON", new Color(1.00f, 0.98f, 0.80f)}, - {"LIGHTBLUE", new Color(0.68f, 0.85f, 0.90f)}, - {"LIGHTCORAL", new Color(0.94f, 0.50f, 0.50f)}, - {"LIGHTCYAN", new Color(0.88f, 1.00f, 1.00f)}, - {"LIGHTGOLDENROD", new Color(0.98f, 0.98f, 0.82f)}, - {"LIGHTGRAY", new Color(0.83f, 0.83f, 0.83f)}, - {"LIGHTGREEN", new Color(0.56f, 0.93f, 0.56f)}, - {"LIGHTPINK", new Color(1.00f, 0.71f, 0.76f)}, - {"LIGHTSALMON", new Color(1.00f, 0.63f, 0.48f)}, - {"LIGHTSEAGREEN", new Color(0.13f, 0.70f, 0.67f)}, - {"LIGHTSKYBLUE", new Color(0.53f, 0.81f, 0.98f)}, - {"LIGHTSLATEGRAY", new Color(0.47f, 0.53f, 0.60f)}, - {"LIGHTSTEELBLUE", new Color(0.69f, 0.77f, 0.87f)}, - {"LIGHTYELLOW", new Color(1.00f, 1.00f, 0.88f)}, - {"LIME", new Color(0.00f, 1.00f, 0.00f)}, - {"LIMEGREEN", new Color(0.20f, 0.80f, 0.20f)}, - {"LINEN", new Color(0.98f, 0.94f, 0.90f)}, - {"MAGENTA", new Color(1.00f, 0.00f, 1.00f)}, - {"MAROON", new Color(0.69f, 0.19f, 0.38f)}, - {"MEDIUMAQUAMARINE", new Color(0.40f, 0.80f, 0.67f)}, - {"MEDIUMBLUE", new Color(0.00f, 0.00f, 0.80f)}, - {"MEDIUMORCHID", new Color(0.73f, 0.33f, 0.83f)}, - {"MEDIUMPURPLE", new Color(0.58f, 0.44f, 0.86f)}, - {"MEDIUMSEAGREEN", new Color(0.24f, 0.70f, 0.44f)}, - {"MEDIUMSLATEBLUE", new Color(0.48f, 0.41f, 0.93f)}, - {"MEDIUMSPRINGGREEN", new Color(0.00f, 0.98f, 0.60f)}, - {"MEDIUMTURQUOISE", new Color(0.28f, 0.82f, 0.80f)}, - {"MEDIUMVIOLETRED", new Color(0.78f, 0.08f, 0.52f)}, - {"MIDNIGHTBLUE", new Color(0.10f, 0.10f, 0.44f)}, - {"MINTCREAM", new Color(0.96f, 1.00f, 0.98f)}, - {"MISTYROSE", new Color(1.00f, 0.89f, 0.88f)}, - {"MOCCASIN", new Color(1.00f, 0.89f, 0.71f)}, - {"NAVAJOWHITE", new Color(1.00f, 0.87f, 0.68f)}, - {"NAVYBLUE", new Color(0.00f, 0.00f, 0.50f)}, - {"OLDLACE", new Color(0.99f, 0.96f, 0.90f)}, - {"OLIVE", new Color(0.50f, 0.50f, 0.00f)}, - {"OLIVEDRAB", new Color(0.42f, 0.56f, 0.14f)}, - {"ORANGE", new Color(1.00f, 0.65f, 0.00f)}, - {"ORANGERED", new Color(1.00f, 0.27f, 0.00f)}, - {"ORCHID", new Color(0.85f, 0.44f, 0.84f)}, - {"PALEGOLDENROD", new Color(0.93f, 0.91f, 0.67f)}, - {"PALEGREEN", new Color(0.60f, 0.98f, 0.60f)}, - {"PALETURQUOISE", new Color(0.69f, 0.93f, 0.93f)}, - {"PALEVIOLETRED", new Color(0.86f, 0.44f, 0.58f)}, - {"PAPAYAWHIP", new Color(1.00f, 0.94f, 0.84f)}, - {"PEACHPUFF", new Color(1.00f, 0.85f, 0.73f)}, - {"PERU", new Color(0.80f, 0.52f, 0.25f)}, - {"PINK", new Color(1.00f, 0.75f, 0.80f)}, - {"PLUM", new Color(0.87f, 0.63f, 0.87f)}, - {"POWDERBLUE", new Color(0.69f, 0.88f, 0.90f)}, - {"PURPLE", new Color(0.63f, 0.13f, 0.94f)}, - {"REBECCAPURPLE", new Color(0.40f, 0.20f, 0.60f)}, - {"RED", new Color(1.00f, 0.00f, 0.00f)}, - {"ROSYBROWN", new Color(0.74f, 0.56f, 0.56f)}, - {"ROYALBLUE", new Color(0.25f, 0.41f, 0.88f)}, - {"SADDLEBROWN", new Color(0.55f, 0.27f, 0.07f)}, - {"SALMON", new Color(0.98f, 0.50f, 0.45f)}, - {"SANDYBROWN", new Color(0.96f, 0.64f, 0.38f)}, - {"SEAGREEN", new Color(0.18f, 0.55f, 0.34f)}, - {"SEASHELL", new Color(1.00f, 0.96f, 0.93f)}, - {"SIENNA", new Color(0.63f, 0.32f, 0.18f)}, - {"SILVER", new Color(0.75f, 0.75f, 0.75f)}, - {"SKYBLUE", new Color(0.53f, 0.81f, 0.92f)}, - {"SLATEBLUE", new Color(0.42f, 0.35f, 0.80f)}, - {"SLATEGRAY", new Color(0.44f, 0.50f, 0.56f)}, - {"SNOW", new Color(1.00f, 0.98f, 0.98f)}, - {"SPRINGGREEN", new Color(0.00f, 1.00f, 0.50f)}, - {"STEELBLUE", new Color(0.27f, 0.51f, 0.71f)}, - {"TAN", new Color(0.82f, 0.71f, 0.55f)}, - {"TEAL", new Color(0.00f, 0.50f, 0.50f)}, - {"THISTLE", new Color(0.85f, 0.75f, 0.85f)}, - {"TOMATO", new Color(1.00f, 0.39f, 0.28f)}, - {"TRANSPARENT", new Color(1.00f, 1.00f, 1.00f, 0.00f)}, - {"TURQUOISE", new Color(0.25f, 0.88f, 0.82f)}, - {"VIOLET", new Color(0.93f, 0.51f, 0.93f)}, - {"WEBGRAY", new Color(0.50f, 0.50f, 0.50f)}, - {"WEBGREEN", new Color(0.00f, 0.50f, 0.00f)}, - {"WEBMAROON", new Color(0.50f, 0.00f, 0.00f)}, - {"WEBPURPLE", new Color(0.50f, 0.00f, 0.50f)}, - {"WHEAT", new Color(0.96f, 0.87f, 0.70f)}, - {"WHITE", new Color(1.00f, 1.00f, 1.00f)}, - {"WHITESMOKE", new Color(0.96f, 0.96f, 0.96f)}, - {"YELLOW", new Color(1.00f, 1.00f, 0.00f)}, - {"YELLOWGREEN", new Color(0.60f, 0.80f, 0.20f)}, + { "ALICE_BLUE", new Color(0xF0F8FFFF) }, + { "ANTIQUE_WHITE", new Color(0xFAEBD7FF) }, + { "AQUA", new Color(0x00FFFFFF) }, + { "AQUAMARINE", new Color(0x7FFFD4FF) }, + { "AZURE", new Color(0xF0FFFFFF) }, + { "BEIGE", new Color(0xF5F5DCFF) }, + { "BISQUE", new Color(0xFFE4C4FF) }, + { "BLACK", new Color(0x000000FF) }, + { "BLANCHED_ALMOND", new Color(0xFFEBCDFF) }, + { "BLUE", new Color(0x0000FFFF) }, + { "BLUE_VIOLET", new Color(0x8A2BE2FF) }, + { "BROWN", new Color(0xA52A2AFF) }, + { "BURLYWOOD", new Color(0xDEB887FF) }, + { "CADET_BLUE", new Color(0x5F9EA0FF) }, + { "CHARTREUSE", new Color(0x7FFF00FF) }, + { "CHOCOLATE", new Color(0xD2691EFF) }, + { "CORAL", new Color(0xFF7F50FF) }, + { "CORNFLOWER_BLUE", new Color(0x6495EDFF) }, + { "CORNSILK", new Color(0xFFF8DCFF) }, + { "CRIMSON", new Color(0xDC143CFF) }, + { "CYAN", new Color(0x00FFFFFF) }, + { "DARK_BLUE", new Color(0x00008BFF) }, + { "DARK_CYAN", new Color(0x008B8BFF) }, + { "DARK_GOLDENROD", new Color(0xB8860BFF) }, + { "DARK_GRAY", new Color(0xA9A9A9FF) }, + { "DARK_GREEN", new Color(0x006400FF) }, + { "DARK_KHAKI", new Color(0xBDB76BFF) }, + { "DARK_MAGENTA", new Color(0x8B008BFF) }, + { "DARK_OLIVE_GREEN", new Color(0x556B2FFF) }, + { "DARK_ORANGE", new Color(0xFF8C00FF) }, + { "DARK_ORCHID", new Color(0x9932CCFF) }, + { "DARK_RED", new Color(0x8B0000FF) }, + { "DARK_SALMON", new Color(0xE9967AFF) }, + { "DARK_SEA_GREEN", new Color(0x8FBC8FFF) }, + { "DARK_SLATE_BLUE", new Color(0x483D8BFF) }, + { "DARK_SLATE_GRAY", new Color(0x2F4F4FFF) }, + { "DARK_TURQUOISE", new Color(0x00CED1FF) }, + { "DARK_VIOLET", new Color(0x9400D3FF) }, + { "DEEP_PINK", new Color(0xFF1493FF) }, + { "DEEP_SKY_BLUE", new Color(0x00BFFFFF) }, + { "DIM_GRAY", new Color(0x696969FF) }, + { "DODGER_BLUE", new Color(0x1E90FFFF) }, + { "FIREBRICK", new Color(0xB22222FF) }, + { "FLORAL_WHITE", new Color(0xFFFAF0FF) }, + { "FOREST_GREEN", new Color(0x228B22FF) }, + { "FUCHSIA", new Color(0xFF00FFFF) }, + { "GAINSBORO", new Color(0xDCDCDCFF) }, + { "GHOST_WHITE", new Color(0xF8F8FFFF) }, + { "GOLD", new Color(0xFFD700FF) }, + { "GOLDENROD", new Color(0xDAA520FF) }, + { "GRAY", new Color(0xBEBEBEFF) }, + { "GREEN", new Color(0x00FF00FF) }, + { "GREEN_YELLOW", new Color(0xADFF2FFF) }, + { "HONEYDEW", new Color(0xF0FFF0FF) }, + { "HOT_PINK", new Color(0xFF69B4FF) }, + { "INDIAN_RED", new Color(0xCD5C5CFF) }, + { "INDIGO", new Color(0x4B0082FF) }, + { "IVORY", new Color(0xFFFFF0FF) }, + { "KHAKI", new Color(0xF0E68CFF) }, + { "LAVENDER", new Color(0xE6E6FAFF) }, + { "LAVENDER_BLUSH", new Color(0xFFF0F5FF) }, + { "LAWN_GREEN", new Color(0x7CFC00FF) }, + { "LEMON_CHIFFON", new Color(0xFFFACDFF) }, + { "LIGHT_BLUE", new Color(0xADD8E6FF) }, + { "LIGHT_CORAL", new Color(0xF08080FF) }, + { "LIGHT_CYAN", new Color(0xE0FFFFFF) }, + { "LIGHT_GOLDENROD", new Color(0xFAFAD2FF) }, + { "LIGHT_GRAY", new Color(0xD3D3D3FF) }, + { "LIGHT_GREEN", new Color(0x90EE90FF) }, + { "LIGHT_PINK", new Color(0xFFB6C1FF) }, + { "LIGHT_SALMON", new Color(0xFFA07AFF) }, + { "LIGHT_SEA_GREEN", new Color(0x20B2AAFF) }, + { "LIGHT_SKY_BLUE", new Color(0x87CEFAFF) }, + { "LIGHT_SLATE_GRAY", new Color(0x778899FF) }, + { "LIGHT_STEEL_BLUE", new Color(0xB0C4DEFF) }, + { "LIGHT_YELLOW", new Color(0xFFFFE0FF) }, + { "LIME", new Color(0x00FF00FF) }, + { "LIME_GREEN", new Color(0x32CD32FF) }, + { "LINEN", new Color(0xFAF0E6FF) }, + { "MAGENTA", new Color(0xFF00FFFF) }, + { "MAROON", new Color(0xB03060FF) }, + { "MEDIUM_AQUAMARINE", new Color(0x66CDAAFF) }, + { "MEDIUM_BLUE", new Color(0x0000CDFF) }, + { "MEDIUM_ORCHID", new Color(0xBA55D3FF) }, + { "MEDIUM_PURPLE", new Color(0x9370DBFF) }, + { "MEDIUM_SEA_GREEN", new Color(0x3CB371FF) }, + { "MEDIUM_SLATE_BLUE", new Color(0x7B68EEFF) }, + { "MEDIUM_SPRING_GREEN", new Color(0x00FA9AFF) }, + { "MEDIUM_TURQUOISE", new Color(0x48D1CCFF) }, + { "MEDIUM_VIOLET_RED", new Color(0xC71585FF) }, + { "MIDNIGHT_BLUE", new Color(0x191970FF) }, + { "MINT_CREAM", new Color(0xF5FFFAFF) }, + { "MISTY_ROSE", new Color(0xFFE4E1FF) }, + { "MOCCASIN", new Color(0xFFE4B5FF) }, + { "NAVAJO_WHITE", new Color(0xFFDEADFF) }, + { "NAVY_BLUE", new Color(0x000080FF) }, + { "OLD_LACE", new Color(0xFDF5E6FF) }, + { "OLIVE", new Color(0x808000FF) }, + { "OLIVE_DRAB", new Color(0x6B8E23FF) }, + { "ORANGE", new Color(0xFFA500FF) }, + { "ORANGE_RED", new Color(0xFF4500FF) }, + { "ORCHID", new Color(0xDA70D6FF) }, + { "PALE_GOLDENROD", new Color(0xEEE8AAFF) }, + { "PALE_GREEN", new Color(0x98FB98FF) }, + { "PALE_TURQUOISE", new Color(0xAFEEEEFF) }, + { "PALE_VIOLET_RED", new Color(0xDB7093FF) }, + { "PAPAYA_WHIP", new Color(0xFFEFD5FF) }, + { "PEACH_PUFF", new Color(0xFFDAB9FF) }, + { "PERU", new Color(0xCD853FFF) }, + { "PINK", new Color(0xFFC0CBFF) }, + { "PLUM", new Color(0xDDA0DDFF) }, + { "POWDER_BLUE", new Color(0xB0E0E6FF) }, + { "PURPLE", new Color(0xA020F0FF) }, + { "REBECCA_PURPLE", new Color(0x663399FF) }, + { "RED", new Color(0xFF0000FF) }, + { "ROSY_BROWN", new Color(0xBC8F8FFF) }, + { "ROYAL_BLUE", new Color(0x4169E1FF) }, + { "SADDLE_BROWN", new Color(0x8B4513FF) }, + { "SALMON", new Color(0xFA8072FF) }, + { "SANDY_BROWN", new Color(0xF4A460FF) }, + { "SEA_GREEN", new Color(0x2E8B57FF) }, + { "SEASHELL", new Color(0xFFF5EEFF) }, + { "SIENNA", new Color(0xA0522DFF) }, + { "SILVER", new Color(0xC0C0C0FF) }, + { "SKY_BLUE", new Color(0x87CEEBFF) }, + { "SLATE_BLUE", new Color(0x6A5ACDFF) }, + { "SLATE_GRAY", new Color(0x708090FF) }, + { "SNOW", new Color(0xFFFAFAFF) }, + { "SPRING_GREEN", new Color(0x00FF7FFF) }, + { "STEEL_BLUE", new Color(0x4682B4FF) }, + { "TAN", new Color(0xD2B48CFF) }, + { "TEAL", new Color(0x008080FF) }, + { "THISTLE", new Color(0xD8BFD8FF) }, + { "TOMATO", new Color(0xFF6347FF) }, + { "TRANSPARENT", new Color(0xFFFFFF00) }, + { "TURQUOISE", new Color(0x40E0D0FF) }, + { "VIOLET", new Color(0xEE82EEFF) }, + { "WEB_GRAY", new Color(0x808080FF) }, + { "WEB_GREEN", new Color(0x008000FF) }, + { "WEB_MAROON", new Color(0x800000FF) }, + { "WEB_PURPLE", new Color(0x800080FF) }, + { "WHEAT", new Color(0xF5DEB3FF) }, + { "WHITE", new Color(0xFFFFFFFF) }, + { "WHITE_SMOKE", new Color(0xF5F5F5FF) }, + { "YELLOW", new Color(0xFFFF00FF) }, + { "YELLOW_GREEN", new Color(0x9ACD32FF) }, }; #pragma warning disable CS1591 // Disable warning: "Missing XML comment for publicly visible type or member" diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs index 6fbc04702a..c4161d2ded 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs @@ -121,8 +121,8 @@ namespace Godot var sb = new StringBuilder(); - if (methodBase is MethodInfo) - sb.AppendTypeName(((MethodInfo)methodBase).ReturnType); + if (methodBase is MethodInfo methodInfo) + sb.AppendTypeName(methodInfo.ReturnType); sb.Append(methodBase.DeclaringType?.FullName ?? "<unknown>"); sb.Append('.'); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs index fa8c94ed18..95ad097192 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs @@ -352,7 +352,7 @@ namespace Godot.Collections /// </summary> /// <typeparam name="TKey">The type of the dictionary's keys.</typeparam> /// <typeparam name="TValue">The type of the dictionary's values.</typeparam> - public class Dictionary<TKey, TValue> : + public class Dictionary<[MustBeVariant] TKey, [MustBeVariant] TValue> : IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue> { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs index 1dc21b6303..df0e839866 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs @@ -93,8 +93,12 @@ namespace Godot /// Negative indices access the children from the last one. /// To access a child node via its name, use <see cref="GetNode"/>. /// </summary> - /// <seealso cref="GetChildOrNull{T}(int)"/> + /// <seealso cref="GetChildOrNull{T}(int, bool)"/> /// <param name="idx">Child index.</param> + /// <param name="includeInternal"> + /// If <see langword="false"/>, internal children are skipped (see <c>internal</c> + /// parameter in <see cref="AddChild(Node, bool, InternalMode)"/>). + /// </param> /// <exception cref="InvalidCastException"> /// Thrown when the given the fetched node can't be casted to the given type <typeparamref name="T"/>. /// </exception> @@ -102,9 +106,9 @@ namespace Godot /// <returns> /// The child <see cref="Node"/> at the given index <paramref name="idx"/>. /// </returns> - public T GetChild<T>(int idx) where T : class + public T GetChild<T>(int idx, bool includeInternal = false) where T : class { - return (T)(object)GetChild(idx); + return (T)(object)GetChild(idx, includeInternal); } /// <summary> @@ -113,15 +117,20 @@ namespace Godot /// Negative indices access the children from the last one. /// To access a child node via its name, use <see cref="GetNode"/>. /// </summary> - /// <seealso cref="GetChild{T}(int)"/> + /// <seealso cref="GetChild{T}(int, bool)"/> /// <param name="idx">Child index.</param> + /// <param name="includeInternal"> + /// If <see langword="false"/>, internal children are skipped (see <c>internal</c> + /// parameter in <see cref="AddChild(Node, bool, InternalMode)"/>). + /// </param> /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam> /// <returns> /// The child <see cref="Node"/> at the given index <paramref name="idx"/>, or <see langword="null"/> if not found. /// </returns> - public T GetChildOrNull<T>(int idx) where T : class + public T GetChildOrNull<T>(int idx, bool includeInternal = false) where T : class { - return GetChild(idx) as T; + int count = GetChildCount(includeInternal); + return idx >= -count && idx < count ? GetChild(idx, includeInternal) as T : null; } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs index 9348cc1d00..9e7da7757a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs @@ -189,8 +189,6 @@ namespace Godot /// Pushes an error message to Godot's built-in debugger and to the OS terminal. /// /// Note: Errors printed this way will not pause project execution. - /// To print an error message and pause project execution in debug builds, - /// use [code]assert(false, "test error")[/code] instead. /// </summary> /// <example> /// <code> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs index 08beff8104..41a0dd871c 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs @@ -754,9 +754,10 @@ namespace Godot } /// <summary> - /// Returns the [code]value[/code] wrapped between [code]0[/code] and the [code]length[/code]. - /// If the limit is reached, the next value the function returned is decreased to the [code]0[/code] side or increased to the [code]length[/code] side (like a triangle wave). - /// If [code]length[/code] is less than zero, it becomes positive. + /// Returns the <paramref name="value"/> wrapped between <c>0</c> and the <paramref name="length"/>. + /// If the limit is reached, the next value the function returned is decreased to the <c>0</c> side + /// or increased to the <paramref name="length"/> side (like a triangle wave). + /// If <paramref name="length"/> is less than zero, it becomes positive. /// </summary> /// <param name="value">The value to pingpong.</param> /// <param name="length">The maximum value of the function.</param> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs index 50832d7679..13070c8033 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs @@ -353,12 +353,7 @@ namespace Godot /// <returns>Whether or not the plane and the other object are exactly equal.</returns> public override bool Equals(object obj) { - if (obj is Plane) - { - return Equals((Plane)obj); - } - - return false; + return obj is Plane other && Equals(other); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs index df16fe5718..5da1f3b560 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs @@ -39,22 +39,22 @@ namespace Godot } /// <summary> - /// The projections's X column. Also accessible by using the index position <c>[0]</c>. + /// The projection's X column. Also accessible by using the index position <c>[0]</c>. /// </summary> public Vector4 x; /// <summary> - /// The projections's Y column. Also accessible by using the index position <c>[1]</c>. + /// The projection's Y column. Also accessible by using the index position <c>[1]</c>. /// </summary> public Vector4 y; /// <summary> - /// The projections's Z column. Also accessible by using the index position <c>[2]</c>. + /// The projection's Z column. Also accessible by using the index position <c>[2]</c>. /// </summary> public Vector4 z; /// <summary> - /// The projections's W column. Also accessible by using the index position <c>[3]</c>. + /// The projection's W column. Also accessible by using the index position <c>[3]</c>. /// </summary> public Vector4 w; @@ -74,18 +74,6 @@ namespace Godot } /// <summary> - /// Constructs a new <see cref="Projection"/> from an existing <see cref="Projection"/>. - /// </summary> - /// <param name="proj">The existing <see cref="Projection"/>.</param> - public Projection(Projection proj) - { - x = proj.x; - y = proj.y; - z = proj.z; - w = proj.w; - } - - /// <summary> /// Constructs a new <see cref="Projection"/> from a <see cref="Transform3D"/>. /// </summary> /// <param name="transform">The <see cref="Transform3D"/>.</param> @@ -355,7 +343,7 @@ namespace Godot public int GetPixelsPerMeter(int forPixelWidth) { - Vector3 result = Xform(new Vector3(1, 0, -1)); + Vector3 result = this * new Vector3(1, 0, -1); return (int)((result.x * (real_t)0.5 + (real_t)0.5) * forPixelWidth); } @@ -588,19 +576,51 @@ namespace Godot } /// <summary> - /// Returns a vector transformed (multiplied) by this projection. + /// Returns a Vector4 transformed (multiplied) by the projection. /// </summary> /// <param name="proj">The projection to apply.</param> - /// <param name="v">A vector to transform.</param> - /// <returns>The transformed vector.</returns> - public static Vector4 operator *(Projection proj, Vector4 v) + /// <param name="vector">A Vector4 to transform.</param> + /// <returns>The transformed Vector4.</returns> + public static Vector4 operator *(Projection proj, Vector4 vector) { return new Vector4( - proj.x.x * v.x + proj.y.x * v.y + proj.z.x * v.z + proj.w.x * v.w, - proj.x.y * v.x + proj.y.y * v.y + proj.z.y * v.z + proj.w.y * v.w, - proj.x.z * v.x + proj.y.z * v.y + proj.z.z * v.z + proj.w.z * v.w, - proj.x.w * v.x + proj.y.w * v.y + proj.z.w * v.z + proj.w.w * v.w + proj.x.x * vector.x + proj.y.x * vector.y + proj.z.x * vector.z + proj.w.x * vector.w, + proj.x.y * vector.x + proj.y.y * vector.y + proj.z.y * vector.z + proj.w.y * vector.w, + proj.x.z * vector.x + proj.y.z * vector.y + proj.z.z * vector.z + proj.w.z * vector.w, + proj.x.w * vector.x + proj.y.w * vector.y + proj.z.w * vector.z + proj.w.w * vector.w + ); + } + + /// <summary> + /// Returns a Vector4 transformed (multiplied) by the inverse projection. + /// </summary> + /// <param name="proj">The projection to apply.</param> + /// <param name="vector">A Vector4 to transform.</param> + /// <returns>The inversely transformed Vector4.</returns> + public static Vector4 operator *(Vector4 vector, Projection proj) + { + return new Vector4( + proj.x.x * vector.x + proj.x.y * vector.y + proj.x.z * vector.z + proj.x.w * vector.w, + proj.y.x * vector.x + proj.y.y * vector.y + proj.y.z * vector.z + proj.y.w * vector.w, + proj.z.x * vector.x + proj.z.y * vector.y + proj.z.z * vector.z + proj.z.w * vector.w, + proj.w.x * vector.x + proj.w.y * vector.y + proj.w.z * vector.z + proj.w.w * vector.w + ); + } + + /// <summary> + /// Returns a Vector3 transformed (multiplied) by the projection. + /// </summary> + /// <param name="proj">The projection to apply.</param> + /// <param name="vector">A Vector3 to transform.</param> + /// <returns>The transformed Vector3.</returns> + public static Vector3 operator *(Projection proj, Vector3 vector) + { + Vector3 ret = new Vector3( + proj.x.x * vector.x + proj.y.x * vector.y + proj.z.x * vector.z + proj.w.x, + proj.x.y * vector.x + proj.y.y * vector.y + proj.z.y * vector.z + proj.w.y, + proj.x.z * vector.x + proj.y.z * vector.y + proj.z.z * vector.z + proj.w.z ); + return ret / (proj.x.w * vector.x + proj.y.w * vector.y + proj.z.w * vector.z + proj.w.w); } /// <summary> @@ -714,21 +734,6 @@ namespace Godot } } - /// <summary> - /// Returns a vector transformed (multiplied) by this projection. - /// </summary> - /// <param name="v">A vector to transform.</param> - /// <returns>The transformed vector.</returns> - private Vector3 Xform(Vector3 v) - { - Vector3 ret = new Vector3( - x.x * v.x + y.x * v.y + z.x * v.z + w.x, - x.y * v.x + y.y * v.y + z.y * v.z + w.y, - x.z * v.x + y.z * v.y + z.z * v.z + w.z - ); - return ret / (x.w * v.x + y.w * v.y + z.w * v.z + w.w); - } - // Constants private static readonly Projection _zero = new Projection( new Vector4(0, 0, 0, 0), @@ -795,11 +800,7 @@ namespace Godot /// <returns>Whether or not the vector and the object are equal.</returns> public override bool Equals(object obj) { - if (obj is Projection) - { - return Equals((Projection)obj); - } - return false; + return obj is Projection other && Equals(other); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs index 90e4e3b41e..999500ca13 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs @@ -313,24 +313,6 @@ namespace Godot ); } - /// <summary> - /// Returns a vector transformed (multiplied) by this quaternion. - /// </summary> - /// <param name="v">A vector to transform.</param> - /// <returns>The transformed vector.</returns> - public Vector3 Xform(Vector3 v) - { -#if DEBUG - if (!IsNormalized()) - { - throw new InvalidOperationException("Quaternion is not normalized"); - } -#endif - var u = new Vector3(x, y, z); - Vector3 uv = u.Cross(v); - return v + (((uv * w) + u.Cross(uv)) * 2); - } - // Constants private static readonly Quaternion _identity = new Quaternion(0, 0, 0, 1); @@ -358,15 +340,6 @@ namespace Godot } /// <summary> - /// Constructs a <see cref="Quaternion"/> from the given <see cref="Quaternion"/>. - /// </summary> - /// <param name="q">The existing quaternion.</param> - public Quaternion(Quaternion q) - { - this = q; - } - - /// <summary> /// Constructs a <see cref="Quaternion"/> from the given <see cref="Basis"/>. /// </summary> /// <param name="basis">The <see cref="Basis"/> to construct from.</param> @@ -461,6 +434,36 @@ namespace Godot } /// <summary> + /// Returns a Vector3 rotated (multiplied) by the quaternion. + /// </summary> + /// <param name="quaternion">The quaternion to rotate by.</param> + /// <param name="vector">A Vector3 to transform.</param> + /// <returns>The rotated Vector3.</returns> + public static Vector3 operator *(Quaternion quaternion, Vector3 vector) + { +#if DEBUG + if (!quaternion.IsNormalized()) + { + throw new InvalidOperationException("Quaternion is not normalized"); + } +#endif + var u = new Vector3(quaternion.x, quaternion.y, quaternion.z); + Vector3 uv = u.Cross(vector); + return vector + (((uv * quaternion.w) + u.Cross(uv)) * 2); + } + + /// <summary> + /// Returns a Vector3 rotated (multiplied) by the inverse quaternion. + /// </summary> + /// <param name="vector">A Vector3 to inversely rotate.</param> + /// <param name="quaternion">The quaternion to rotate by.</param> + /// <returns>The inversely rotated Vector3.</returns> + public static Vector3 operator *(Vector3 vector, Quaternion quaternion) + { + return quaternion.Inverse() * vector; + } + + /// <summary> /// Adds each component of the left <see cref="Quaternion"/> /// to the right <see cref="Quaternion"/>. This operation is not /// meaningful on its own, but it can be used as a part of a @@ -503,38 +506,6 @@ namespace Godot } /// <summary> - /// Rotates (multiplies) the <see cref="Vector3"/> - /// by the given <see cref="Quaternion"/>. - /// </summary> - /// <param name="quat">The quaternion to rotate by.</param> - /// <param name="vec">The vector to rotate.</param> - /// <returns>The rotated vector.</returns> - public static Vector3 operator *(Quaternion quat, Vector3 vec) - { -#if DEBUG - if (!quat.IsNormalized()) - { - throw new InvalidOperationException("Quaternion is not normalized."); - } -#endif - var u = new Vector3(quat.x, quat.y, quat.z); - Vector3 uv = u.Cross(vec); - return vec + (((uv * quat.w) + u.Cross(uv)) * 2); - } - - /// <summary> - /// Inversely rotates (multiplies) the <see cref="Vector3"/> - /// by the given <see cref="Quaternion"/>. - /// </summary> - /// <param name="vec">The vector to rotate.</param> - /// <param name="quat">The quaternion to rotate by.</param> - /// <returns>The inversely rotated vector.</returns> - public static Vector3 operator *(Vector3 vec, Quaternion quat) - { - return quat.Inverse() * vec; - } - - /// <summary> /// Multiplies each component of the <see cref="Quaternion"/> /// by the given <see cref="real_t"/>. This operation is not /// meaningful on its own, but it can be used as a part of a @@ -609,12 +580,7 @@ namespace Godot /// <returns>Whether or not the quaternion and the other object are exactly equal.</returns> public override bool Equals(object obj) { - if (obj is Quaternion) - { - return Equals((Quaternion)obj); - } - - return false; + return obj is Quaternion other && Equals(other); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs index d2c9b0ca8b..0b475fec19 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs @@ -426,12 +426,7 @@ namespace Godot /// <returns>Whether or not the rect and the other object are exactly equal.</returns> public override bool Equals(object obj) { - if (obj is Rect2) - { - return Equals((Rect2)obj); - } - - return false; + return obj is Rect2 other && Equals(other); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs index 5d53b8330e..8a2a98d6ee 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs @@ -426,12 +426,7 @@ namespace Godot /// <returns>Whether or not the rect and the other object are equal.</returns> public override bool Equals(object obj) { - if (obj is Rect2i) - { - return Equals((Rect2i)obj); - } - - return false; + return obj is Rect2i other && Equals(other); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs index 10739c02a7..b9ee0bc278 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs @@ -59,9 +59,9 @@ namespace Godot } /// <summary> - /// Constructs a <see cref="StringName"/> from the given <paramref name="path"/> string. + /// Constructs a <see cref="StringName"/> from the given <paramref name="name"/> string. /// </summary> - /// <param name="path">String to construct the <see cref="StringName"/> from.</param> + /// <param name="name">String to construct the <see cref="StringName"/> from.</param> public StringName(string name) { if (!string.IsNullOrEmpty(name)) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index ab2c0cd785..33b4f11f62 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -384,31 +384,6 @@ namespace Godot return copy; } - /// <summary> - /// Returns a vector transformed (multiplied) by this transformation matrix. - /// </summary> - /// <seealso cref="XformInv(Vector2)"/> - /// <param name="v">A vector to transform.</param> - /// <returns>The transformed vector.</returns> - [Obsolete("Xform is deprecated. Use the multiplication operator (Transform2D * Vector2) instead.")] - public Vector2 Xform(Vector2 v) - { - return new Vector2(Tdotx(v), Tdoty(v)) + origin; - } - - /// <summary> - /// Returns a vector transformed (multiplied) by the inverse transformation matrix. - /// </summary> - /// <seealso cref="Xform(Vector2)"/> - /// <param name="v">A vector to inversely transform.</param> - /// <returns>The inversely transformed vector.</returns> - [Obsolete("XformInv is deprecated. Use the multiplication operator (Vector2 * Transform2D) instead.")] - public Vector2 XformInv(Vector2 v) - { - Vector2 vInv = v - origin; - return new Vector2(x.Dot(vInv), y.Dot(vInv)); - } - // Constants private static readonly Transform2D _identity = new Transform2D(1, 0, 0, 1, 0, 0); private static readonly Transform2D _flipX = new Transform2D(-1, 0, 0, 1, 0, 0); @@ -502,7 +477,7 @@ namespace Godot } /// <summary> - /// Returns a Vector2 transformed (multiplied) by transformation matrix. + /// Returns a Vector2 transformed (multiplied) by the transformation matrix. /// </summary> /// <param name="transform">The transformation to apply.</param> /// <param name="vector">A Vector2 to transform.</param> @@ -525,7 +500,7 @@ namespace Godot } /// <summary> - /// Returns a Rect2 transformed (multiplied) by transformation matrix. + /// Returns a Rect2 transformed (multiplied) by the transformation matrix. /// </summary> /// <param name="transform">The transformation to apply.</param> /// <param name="rect">A Rect2 to transform.</param> @@ -536,7 +511,7 @@ namespace Godot Vector2 toX = transform.x * rect.Size.x; Vector2 toY = transform.y * rect.Size.y; - return new Rect2(pos, rect.Size).Expand(pos + toX).Expand(pos + toY).Expand(pos + toX + toY); + return new Rect2(pos, new Vector2()).Expand(pos + toX).Expand(pos + toY).Expand(pos + toX + toY); } /// <summary> @@ -552,11 +527,11 @@ namespace Godot Vector2 to2 = new Vector2(rect.Position.x + rect.Size.x, rect.Position.y + rect.Size.y) * transform; Vector2 to3 = new Vector2(rect.Position.x + rect.Size.x, rect.Position.y) * transform; - return new Rect2(pos, rect.Size).Expand(to1).Expand(to2).Expand(to3); + return new Rect2(pos, new Vector2()).Expand(to1).Expand(to2).Expand(to3); } /// <summary> - /// Returns a copy of the given Vector2[] transformed (multiplied) by transformation matrix. + /// Returns a copy of the given Vector2[] transformed (multiplied) by the transformation matrix. /// </summary> /// <param name="transform">The transformation to apply.</param> /// <param name="array">A Vector2[] to transform.</param> @@ -627,7 +602,7 @@ namespace Godot /// <returns>Whether or not the transform and the object are exactly equal.</returns> public override bool Equals(object obj) { - return obj is Transform2D transform2D && Equals(transform2D); + return obj is Transform2D other && Equals(other); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index 810f55e150..4b739bb86b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -108,7 +108,7 @@ namespace Godot public Transform3D AffineInverse() { Basis basisInv = basis.Inverse(); - return new Transform3D(basisInv, basisInv.Xform(-origin)); + return new Transform3D(basisInv, basisInv * -origin); } /// <summary> @@ -147,7 +147,7 @@ namespace Godot public Transform3D Inverse() { Basis basisTr = basis.Transposed(); - return new Transform3D(basisTr, basisTr.Xform(-origin)); + return new Transform3D(basisTr, basisTr * -origin); } /// <summary> @@ -286,43 +286,6 @@ namespace Godot )); } - /// <summary> - /// Returns a vector transformed (multiplied) by this transformation matrix. - /// </summary> - /// <seealso cref="XformInv(Vector3)"/> - /// <param name="v">A vector to transform.</param> - /// <returns>The transformed vector.</returns> - public Vector3 Xform(Vector3 v) - { - return new Vector3 - ( - basis.Row0.Dot(v) + origin.x, - basis.Row1.Dot(v) + origin.y, - basis.Row2.Dot(v) + origin.z - ); - } - - /// <summary> - /// Returns a vector transformed (multiplied) by the transposed transformation matrix. - /// - /// Note: This results in a multiplication by the inverse of the - /// transformation matrix only if it represents a rotation-reflection. - /// </summary> - /// <seealso cref="Xform(Vector3)"/> - /// <param name="v">A vector to inversely transform.</param> - /// <returns>The inversely transformed vector.</returns> - public Vector3 XformInv(Vector3 v) - { - Vector3 vInv = v - origin; - - return new Vector3 - ( - (basis.Row0[0] * vInv.x) + (basis.Row1[0] * vInv.y) + (basis.Row2[0] * vInv.z), - (basis.Row0[1] * vInv.x) + (basis.Row1[1] * vInv.y) + (basis.Row2[1] * vInv.z), - (basis.Row0[2] * vInv.x) + (basis.Row1[2] * vInv.y) + (basis.Row2[2] * vInv.z) - ); - } - // Constants private static readonly Transform3D _identity = new Transform3D(Basis.Identity, Vector3.Zero); private static readonly Transform3D _flipX = new Transform3D(new Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1), Vector3.Zero); @@ -399,12 +362,188 @@ namespace Godot /// <returns>The composed transform.</returns> public static Transform3D operator *(Transform3D left, Transform3D right) { - left.origin = left.Xform(right.origin); + left.origin = left * right.origin; left.basis *= right.basis; return left; } /// <summary> + /// Returns a Vector3 transformed (multiplied) by the transformation matrix. + /// </summary> + /// <param name="transform">The transformation to apply.</param> + /// <param name="vector">A Vector3 to transform.</param> + /// <returns>The transformed Vector3.</returns> + public static Vector3 operator *(Transform3D transform, Vector3 vector) + { + return new Vector3 + ( + transform.basis.Row0.Dot(vector) + transform.origin.x, + transform.basis.Row1.Dot(vector) + transform.origin.y, + transform.basis.Row2.Dot(vector) + transform.origin.z + ); + } + + /// <summary> + /// Returns a Vector3 transformed (multiplied) by the transposed transformation matrix. + /// + /// Note: This results in a multiplication by the inverse of the + /// transformation matrix only if it represents a rotation-reflection. + /// </summary> + /// <param name="vector">A Vector3 to inversely transform.</param> + /// <param name="transform">The transformation to apply.</param> + /// <returns>The inversely transformed Vector3.</returns> + public static Vector3 operator *(Vector3 vector, Transform3D transform) + { + Vector3 vInv = vector - transform.origin; + + return new Vector3 + ( + (transform.basis.Row0[0] * vInv.x) + (transform.basis.Row1[0] * vInv.y) + (transform.basis.Row2[0] * vInv.z), + (transform.basis.Row0[1] * vInv.x) + (transform.basis.Row1[1] * vInv.y) + (transform.basis.Row2[1] * vInv.z), + (transform.basis.Row0[2] * vInv.x) + (transform.basis.Row1[2] * vInv.y) + (transform.basis.Row2[2] * vInv.z) + ); + } + + /// <summary> + /// Returns an AABB transformed (multiplied) by the transformation matrix. + /// </summary> + /// <param name="transform">The transformation to apply.</param> + /// <param name="aabb">An AABB to transform.</param> + /// <returns>The transformed AABB.</returns> + public static AABB operator *(Transform3D transform, AABB aabb) + { + Vector3 min = aabb.Position; + Vector3 max = aabb.Position + aabb.Size; + + Vector3 tmin = transform.origin; + Vector3 tmax = transform.origin; + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + real_t e = transform.basis[i][j] * min[j]; + real_t f = transform.basis[i][j] * max[j]; + if (e < f) + { + tmin[i] += e; + tmax[i] += f; + } + else + { + tmin[i] += f; + tmax[i] += e; + } + } + } + + return new AABB(tmin, tmax - tmin); + } + + /// <summary> + /// Returns an AABB transformed (multiplied) by the inverse transformation matrix. + /// </summary> + /// <param name="aabb">An AABB to inversely transform.</param> + /// <param name="transform">The transformation to apply.</param> + /// <returns>The inversely transformed AABB.</returns> + public static AABB operator *(AABB aabb, Transform3D transform) + { + Vector3 pos = new Vector3(aabb.Position.x + aabb.Size.x, aabb.Position.y + aabb.Size.y, aabb.Position.z + aabb.Size.z) * transform; + Vector3 to1 = new Vector3(aabb.Position.x + aabb.Size.x, aabb.Position.y + aabb.Size.y, aabb.Position.z) * transform; + Vector3 to2 = new Vector3(aabb.Position.x + aabb.Size.x, aabb.Position.y, aabb.Position.z + aabb.Size.z) * transform; + Vector3 to3 = new Vector3(aabb.Position.x + aabb.Size.x, aabb.Position.y, aabb.Position.z) * transform; + Vector3 to4 = new Vector3(aabb.Position.x, aabb.Position.y + aabb.Size.y, aabb.Position.z + aabb.Size.z) * transform; + Vector3 to5 = new Vector3(aabb.Position.x, aabb.Position.y + aabb.Size.y, aabb.Position.z) * transform; + Vector3 to6 = new Vector3(aabb.Position.x, aabb.Position.y, aabb.Position.z + aabb.Size.z) * transform; + Vector3 to7 = new Vector3(aabb.Position.x, aabb.Position.y, aabb.Position.z) * transform; + + return new AABB(pos, new Vector3()).Expand(to1).Expand(to2).Expand(to3).Expand(to4).Expand(to5).Expand(to6).Expand(to7); + } + + /// <summary> + /// Returns a Plane transformed (multiplied) by the transformation matrix. + /// </summary> + /// <param name="transform">The transformation to apply.</param> + /// <param name="plane">A Plane to transform.</param> + /// <returns>The transformed Plane.</returns> + public static Plane operator *(Transform3D transform, Plane plane) + { + Basis bInvTrans = transform.basis.Inverse().Transposed(); + + // Transform a single point on the plane. + Vector3 point = transform * (plane.Normal * plane.D); + + // Use inverse transpose for correct normals with non-uniform scaling. + Vector3 normal = (bInvTrans * plane.Normal).Normalized(); + + real_t d = normal.Dot(point); + return new Plane(normal, d); + } + + /// <summary> + /// Returns a Plane transformed (multiplied) by the inverse transformation matrix. + /// </summary> + /// <param name="plane">A Plane to inversely transform.</param> + /// <param name="transform">The transformation to apply.</param> + /// <returns>The inversely transformed Plane.</returns> + public static Plane operator *(Plane plane, Transform3D transform) + { + Transform3D tInv = transform.AffineInverse(); + Basis bTrans = transform.basis.Transposed(); + + // Transform a single point on the plane. + Vector3 point = tInv * (plane.Normal * plane.D); + + // Note that instead of precalculating the transpose, an alternative + // would be to use the transpose for the basis transform. + // However that would be less SIMD friendly (requiring a swizzle). + // So the cost is one extra precalced value in the calling code. + // This is probably worth it, as this could be used in bottleneck areas. And + // where it is not a bottleneck, the non-fast method is fine. + + // Use transpose for correct normals with non-uniform scaling. + Vector3 normal = (bTrans * plane.Normal).Normalized(); + + real_t d = normal.Dot(point); + return new Plane(normal, d); + } + + /// <summary> + /// Returns a copy of the given Vector3[] transformed (multiplied) by the transformation matrix. + /// </summary> + /// <param name="transform">The transformation to apply.</param> + /// <param name="array">A Vector3[] to transform.</param> + /// <returns>The transformed copy of the Vector3[].</returns> + public static Vector3[] operator *(Transform3D transform, Vector3[] array) + { + Vector3[] newArray = new Vector3[array.Length]; + + for (int i = 0; i < array.Length; i++) + { + newArray[i] = transform * array[i]; + } + + return newArray; + } + + /// <summary> + /// Returns a copy of the given Vector3[] transformed (multiplied) by the inverse transformation matrix. + /// </summary> + /// <param name="array">A Vector3[] to inversely transform.</param> + /// <param name="transform">The transformation to apply.</param> + /// <returns>The inversely transformed copy of the Vector3[].</returns> + public static Vector3[] operator *(Vector3[] array, Transform3D transform) + { + Vector3[] newArray = new Vector3[array.Length]; + + for (int i = 0; i < array.Length; i++) + { + newArray[i] = array[i] * transform; + } + + return newArray; + } + + /// <summary> /// Returns <see langword="true"/> if the transforms are exactly equal. /// Note: Due to floating-point precision errors, consider using /// <see cref="IsEqualApprox"/> instead, which is more reliable. @@ -440,12 +579,7 @@ namespace Godot /// <returns>Whether or not the transform and the object are exactly equal.</returns> public override readonly bool Equals(object obj) { - if (obj is Transform3D) - { - return Equals((Transform3D)obj); - } - - return false; + return obj is Transform3D other && Equals(other); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index e47efacf69..03ee12884b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -639,16 +639,6 @@ namespace Godot } /// <summary> - /// Constructs a new <see cref="Vector2"/> from an existing <see cref="Vector2"/>. - /// </summary> - /// <param name="v">The existing <see cref="Vector2"/>.</param> - public Vector2(Vector2 v) - { - x = v.x; - y = v.y; - } - - /// <summary> /// Creates a unit Vector2 rotated to the given angle. This is equivalent to doing /// <c>Vector2(Mathf.Cos(angle), Mathf.Sin(angle))</c> or <c>Vector2.Right.Rotated(angle)</c>. /// </summary> @@ -935,11 +925,7 @@ namespace Godot /// <returns>Whether or not the vector and the object are equal.</returns> public override bool Equals(object obj) { - if (obj is Vector2) - { - return Equals((Vector2)obj); - } - return false; + return obj is Vector2 other && Equals(other); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs index 84790404d7..666616edec 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs @@ -350,27 +350,6 @@ namespace Godot } /// <summary> - /// Constructs a new <see cref="Vector2i"/> from an existing <see cref="Vector2i"/>. - /// </summary> - /// <param name="vi">The existing <see cref="Vector2i"/>.</param> - public Vector2i(Vector2i vi) - { - this.x = vi.x; - this.y = vi.y; - } - - /// <summary> - /// Constructs a new <see cref="Vector2i"/> from an existing <see cref="Vector2"/> - /// by rounding the components via <see cref="Mathf.RoundToInt(real_t)"/>. - /// </summary> - /// <param name="v">The <see cref="Vector2"/> to convert.</param> - public Vector2i(Vector2 v) - { - this.x = Mathf.RoundToInt(v.x); - this.y = Mathf.RoundToInt(v.y); - } - - /// <summary> /// Adds each component of the <see cref="Vector2i"/> /// with the components of the given <see cref="Vector2i"/>. /// </summary> @@ -674,7 +653,10 @@ namespace Godot /// <param name="value">The vector to convert.</param> public static explicit operator Vector2i(Vector2 value) { - return new Vector2i(value); + return new Vector2i( + Mathf.RoundToInt(value.x), + Mathf.RoundToInt(value.y) + ); } /// <summary> @@ -685,12 +667,7 @@ namespace Godot /// <returns>Whether or not the vector and the object are equal.</returns> public override bool Equals(object obj) { - if (obj is Vector2i) - { - return Equals((Vector2i)obj); - } - - return false; + return obj is Vector2i other && Equals(other); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index e796d2f20f..cdba06c089 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -518,7 +518,7 @@ namespace Godot throw new ArgumentException("Argument is not normalized", nameof(axis)); } #endif - return new Basis(axis, angle).Xform(this); + return new Basis(axis, angle) * this; } /// <summary> @@ -692,17 +692,6 @@ namespace Godot } /// <summary> - /// Constructs a new <see cref="Vector3"/> from an existing <see cref="Vector3"/>. - /// </summary> - /// <param name="v">The existing <see cref="Vector3"/>.</param> - public Vector3(Vector3 v) - { - x = v.x; - y = v.y; - z = v.z; - } - - /// <summary> /// Adds each component of the <see cref="Vector3"/> /// with the components of the given <see cref="Vector3"/>. /// </summary> @@ -1004,12 +993,7 @@ namespace Godot /// <returns>Whether or not the vector and the object are equal.</returns> public override bool Equals(object obj) { - if (obj is Vector3) - { - return Equals((Vector3)obj); - } - - return false; + return obj is Vector3 other && Equals(other); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs index 897e14ae88..2947ef94a7 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs @@ -330,29 +330,6 @@ namespace Godot } /// <summary> - /// Constructs a new <see cref="Vector3i"/> from an existing <see cref="Vector3i"/>. - /// </summary> - /// <param name="vi">The existing <see cref="Vector3i"/>.</param> - public Vector3i(Vector3i vi) - { - this.x = vi.x; - this.y = vi.y; - this.z = vi.z; - } - - /// <summary> - /// Constructs a new <see cref="Vector3i"/> from an existing <see cref="Vector3"/> - /// by rounding the components via <see cref="Mathf.RoundToInt(real_t)"/>. - /// </summary> - /// <param name="v">The <see cref="Vector3"/> to convert.</param> - public Vector3i(Vector3 v) - { - this.x = Mathf.RoundToInt(v.x); - this.y = Mathf.RoundToInt(v.y); - this.z = Mathf.RoundToInt(v.z); - } - - /// <summary> /// Adds each component of the <see cref="Vector3i"/> /// with the components of the given <see cref="Vector3i"/>. /// </summary> @@ -684,7 +661,11 @@ namespace Godot /// <param name="value">The vector to convert.</param> public static explicit operator Vector3i(Vector3 value) { - return new Vector3i(value); + return new Vector3i( + Mathf.RoundToInt(value.x), + Mathf.RoundToInt(value.y), + Mathf.RoundToInt(value.z) + ); } /// <summary> @@ -695,12 +676,7 @@ namespace Godot /// <returns>Whether or not the vector and the object are equal.</returns> public override bool Equals(object obj) { - if (obj is Vector3i) - { - return Equals((Vector3i)obj); - } - - return false; + return obj is Vector3i other && Equals(other); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs index f60033078c..705da04692 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs @@ -477,18 +477,6 @@ namespace Godot } /// <summary> - /// Constructs a new <see cref="Vector4"/> from an existing <see cref="Vector4"/>. - /// </summary> - /// <param name="v">The existing <see cref="Vector4"/>.</param> - public Vector4(Vector4 v) - { - x = v.x; - y = v.y; - z = v.z; - w = v.w; - } - - /// <summary> /// Adds each component of the <see cref="Vector4"/> /// with the components of the given <see cref="Vector4"/>. /// </summary> @@ -766,12 +754,7 @@ namespace Godot /// <returns>Whether or not the vector and the object are equal.</returns> public override bool Equals(object obj) { - if (obj is Vector4) - { - return Equals((Vector4)obj); - } - - return false; + return obj is Vector4 other && Equals(other); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs index 2802c1bb06..73134b0baf 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs @@ -258,31 +258,6 @@ namespace Godot } /// <summary> - /// Constructs a new <see cref="Vector4i"/> from an existing <see cref="Vector4i"/>. - /// </summary> - /// <param name="vi">The existing <see cref="Vector4i"/>.</param> - public Vector4i(Vector4i vi) - { - this.x = vi.x; - this.y = vi.y; - this.z = vi.z; - this.w = vi.w; - } - - /// <summary> - /// Constructs a new <see cref="Vector4i"/> from an existing <see cref="Vector4"/> - /// by rounding the components via <see cref="Mathf.RoundToInt(real_t)"/>. - /// </summary> - /// <param name="v">The <see cref="Vector4"/> to convert.</param> - public Vector4i(Vector4 v) - { - this.x = Mathf.RoundToInt(v.x); - this.y = Mathf.RoundToInt(v.y); - this.z = Mathf.RoundToInt(v.z); - this.w = Mathf.RoundToInt(v.w); - } - - /// <summary> /// Adds each component of the <see cref="Vector4i"/> /// with the components of the given <see cref="Vector4i"/>. /// </summary> @@ -638,7 +613,12 @@ namespace Godot /// <param name="value">The vector to convert.</param> public static explicit operator Vector4i(Vector4 value) { - return new Vector4i(value); + return new Vector4i( + Mathf.RoundToInt(value.x), + Mathf.RoundToInt(value.y), + Mathf.RoundToInt(value.z), + Mathf.RoundToInt(value.w) + ); } /// <summary> @@ -649,12 +629,7 @@ namespace Godot /// <returns>Whether or not the vector and the object are equal.</returns> public override bool Equals(object obj) { - if (obj is Vector4i) - { - return Equals((Vector4i)obj); - } - - return false; + return obj is Vector4i other && Equals(other); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index 111920ecf6..aae7a5ebfa 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -53,6 +53,10 @@ <Compile Include="Core\Array.cs" /> <Compile Include="Core\Attributes\AssemblyHasScriptsAttribute.cs" /> <Compile Include="Core\Attributes\ExportAttribute.cs" /> + <Compile Include="Core\Attributes\ExportCategoryAttribute.cs" /> + <Compile Include="Core\Attributes\ExportGroupAttribute.cs" /> + <Compile Include="Core\Attributes\ExportSubgroupAttribute.cs" /> + <Compile Include="Core\Attributes\MustBeVariantAttribute.cs" /> <Compile Include="Core\Attributes\RPCAttribute.cs" /> <Compile Include="Core\Attributes\ScriptPathAttribute.cs" /> <Compile Include="Core\Attributes\SignalAttribute.cs" /> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs b/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs index eb8b061120..85ef258922 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs @@ -14,7 +14,7 @@ public partial struct Variant : IDisposable private object? _obj; private Disposer? _disposer; - private class Disposer : IDisposable + private sealed class Disposer : IDisposable { private godot_variant.movable _native; @@ -37,7 +37,7 @@ public partial struct Variant : IDisposable GC.SuppressFinalize(this); } - public void Dispose(bool disposing) + private void Dispose(bool disposing) { _native.DangerousSelfRef.Dispose(); diff --git a/modules/mono/glue/callable_glue.cpp b/modules/mono/glue/callable_glue.cpp deleted file mode 100644 index 521dc3dff7..0000000000 --- a/modules/mono/glue/callable_glue.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/*************************************************************************/ -/* callable_glue.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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. */ -/*************************************************************************/ - -#ifdef MONO_GLUE_ENABLED - -#include "../mono_gd/gd_mono_marshal.h" -#include "arguments_vector.h" - -MonoObject *godot_icall_Callable_Call(GDMonoMarshal::M_Callable *p_callable, MonoArray *p_args) { - Callable callable = GDMonoMarshal::managed_to_callable(*p_callable); - - int argc = mono_array_length(p_args); - - ArgumentsVector<Variant> arg_store(argc); - ArgumentsVector<const Variant *> args(argc); - - for (int i = 0; i < argc; i++) { - MonoObject *elem = mono_array_get(p_args, MonoObject *, i); - arg_store.set(i, GDMonoMarshal::mono_object_to_variant(elem)); - args.set(i, &arg_store.get(i)); - } - - Variant result; - Callable::CallError error; - callable.callp(args.ptr(), argc, result, error); - - return GDMonoMarshal::variant_to_mono_object(result); -} - -void godot_icall_Callable_CallDeferred(GDMonoMarshal::M_Callable *p_callable, MonoArray *p_args) { - Callable callable = GDMonoMarshal::managed_to_callable(*p_callable); - - int argc = mono_array_length(p_args); - - ArgumentsVector<Variant> arg_store(argc); - ArgumentsVector<const Variant *> args(argc); - - for (int i = 0; i < argc; i++) { - MonoObject *elem = mono_array_get(p_args, MonoObject *, i); - arg_store.set(i, GDMonoMarshal::mono_object_to_variant(elem)); - args.set(i, &arg_store.get(i)); - } - - callable.call_deferredp(args.ptr(), argc); -} - -void godot_register_callable_icalls() { - GDMonoUtils::add_internal_call("Godot.Callable::godot_icall_Callable_Call", godot_icall_Callable_Call); - GDMonoUtils::add_internal_call("Godot.Callable::godot_icall_Callable_CallDeferred", godot_icall_Callable_CallDeferred); -} - -#endif // MONO_GLUE_ENABLED diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index 2cdb5b7cb4..4191e46f62 100644 --- a/modules/navigation/godot_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -123,8 +123,8 @@ void GodotNavigationServer::add_command(SetCommand *command) const { } } -Array GodotNavigationServer::get_maps() const { - Array all_map_rids; +TypedArray<RID> GodotNavigationServer::get_maps() const { + TypedArray<RID> all_map_rids; List<RID> maps_owned; map_owner.get_owned_list(&maps_owned); if (maps_owned.size()) { @@ -245,8 +245,8 @@ RID GodotNavigationServer::map_get_closest_point_owner(RID p_map, const Vector3 return map->get_closest_point_owner(p_point); } -Array GodotNavigationServer::map_get_regions(RID p_map) const { - Array regions_rids; +TypedArray<RID> GodotNavigationServer::map_get_regions(RID p_map) const { + TypedArray<RID> regions_rids; const NavMap *map = map_owner.get_or_null(p_map); ERR_FAIL_COND_V(map == nullptr, regions_rids); const LocalVector<NavRegion *> regions = map->get_regions(); @@ -257,8 +257,8 @@ Array GodotNavigationServer::map_get_regions(RID p_map) const { return regions_rids; } -Array GodotNavigationServer::map_get_agents(RID p_map) const { - Array agents_rids; +TypedArray<RID> GodotNavigationServer::map_get_agents(RID p_map) const { + TypedArray<RID> agents_rids; const NavMap *map = map_owner.get_or_null(p_map); ERR_FAIL_COND_V(map == nullptr, agents_rids); const LocalVector<RvoAgent *> agents = map->get_agents(); @@ -453,11 +453,11 @@ COMMAND_2(agent_set_map, RID, p_agent, RID, p_map) { } } -COMMAND_2(agent_set_neighbor_dist, RID, p_agent, real_t, p_dist) { +COMMAND_2(agent_set_neighbor_distance, RID, p_agent, real_t, p_distance) { RvoAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_COND(agent == nullptr); - agent->get_agent()->neighborDist_ = p_dist; + agent->get_agent()->neighborDist_ = p_distance; } COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count) { diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h index da1f8cba0b..05ba46ede1 100644 --- a/modules/navigation/godot_navigation_server.h +++ b/modules/navigation/godot_navigation_server.h @@ -85,7 +85,7 @@ public: void add_command(SetCommand *command) const; - virtual Array get_maps() const override; + virtual TypedArray<RID> get_maps() const override; virtual RID map_create() const override; COMMAND_2(map_set_active, RID, p_map, bool, p_active); @@ -107,8 +107,8 @@ public: virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const override; virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const override; - virtual Array map_get_regions(RID p_map) const override; - virtual Array map_get_agents(RID p_map) const override; + virtual TypedArray<RID> map_get_regions(RID p_map) const override; + virtual TypedArray<RID> map_get_agents(RID p_map) const override; virtual void map_force_update(RID p_map) override; @@ -135,7 +135,7 @@ public: virtual RID agent_create() const override; COMMAND_2(agent_set_map, RID, p_agent, RID, p_map); virtual RID agent_get_map(RID p_agent) const override; - COMMAND_2(agent_set_neighbor_dist, RID, p_agent, real_t, p_dist); + COMMAND_2(agent_set_neighbor_distance, RID, p_agent, real_t, p_distance); COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count); COMMAND_2(agent_set_time_horizon, RID, p_agent, real_t, p_time); COMMAND_2(agent_set_radius, RID, p_agent, real_t, p_radius); diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub index ef4c598194..074795759a 100644 --- a/modules/raycast/SCsub +++ b/modules/raycast/SCsub @@ -66,7 +66,7 @@ if env["builtin_embree"]: env_raycast.Append(CPPDEFINES=["EMBREE_TARGET_SSE2", "EMBREE_LOWEST_ISA", "TASKING_INTERNAL", "NDEBUG"]) if not env.msvc: - if env["arch"] in ["x86", "x86_64"]: + if env["arch"] == "x86_64": env_raycast.Append(CPPFLAGS=["-msse2", "-mxsave"]) if env["platform"] == "windows": @@ -83,7 +83,7 @@ if env["builtin_embree"]: env_thirdparty.disable_warnings() env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) - if not env["arch"] in ["x86", "x86_64"] or env.msvc: + if env["arch"] == "arm64" or env.msvc: # Embree needs those, it will automatically use SSE2NEON in ARM env_thirdparty.Append(CPPDEFINES=["__SSE2__", "__SSE__"]) diff --git a/modules/raycast/config.py b/modules/raycast/config.py index 7e8b3e9840..438779343e 100644 --- a/modules/raycast/config.py +++ b/modules/raycast/config.py @@ -1,18 +1,6 @@ def can_build(env, platform): - # Depends on Embree library, which only supports x86_64 and aarch64. - if env["arch"].startswith("rv") or env["arch"].startswith("ppc"): - return False - - if platform == "android": - return env["android_arch"] in ["arm64v8", "x86_64"] - - if platform == "javascript": - return False # No SIMD support yet - - if env["bits"] == "32": - return False - - return True + # Depends on Embree library, which only supports x86_64 and arm64. + return env["arch"] in ["x86_64", "arm64"] def configure(env): diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml index 9adb6acd9c..56404f796c 100644 --- a/modules/regex/doc_classes/RegEx.xml +++ b/modules/regex/doc_classes/RegEx.xml @@ -76,7 +76,7 @@ </description> </method> <method name="get_names" qualifiers="const"> - <return type="Array" /> + <return type="PackedStringArray" /> <description> Returns an array of names of named capturing groups in the compiled pattern. They are ordered by appearance. </description> diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp index 569066867a..b2e6ea1004 100644 --- a/modules/regex/regex.cpp +++ b/modules/regex/regex.cpp @@ -351,8 +351,8 @@ int RegEx::get_group_count() const { return count; } -Array RegEx::get_names() const { - Array result; +PackedStringArray RegEx::get_names() const { + PackedStringArray result; ERR_FAIL_COND_V(!is_valid(), result); diff --git a/modules/regex/regex.h b/modules/regex/regex.h index 9296de929f..6920d2634d 100644 --- a/modules/regex/regex.h +++ b/modules/regex/regex.h @@ -94,7 +94,7 @@ public: bool is_valid() const; String get_pattern() const; int get_group_count() const; - Array get_names() const; + PackedStringArray get_names() const; RegEx(); RegEx(const String &p_pattern); diff --git a/modules/regex/tests/test_regex.h b/modules/regex/tests/test_regex.h index 91af393db1..c81094d3ae 100644 --- a/modules/regex/tests/test_regex.h +++ b/modules/regex/tests/test_regex.h @@ -46,7 +46,7 @@ TEST_CASE("[RegEx] Initialization") { CHECK(re1.get_pattern() == pattern); CHECK(re1.get_group_count() == 1); - Array names = re1.get_names(); + PackedStringArray names = re1.get_names(); CHECK(names.size() == 1); CHECK(names[0] == "vowel"); diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp index 87e2fae2d0..5f839bd979 100644 --- a/modules/svg/image_loader_svg.cpp +++ b/modules/svg/image_loader_svg.cpp @@ -35,13 +35,13 @@ #include <thorvg.h> -void ImageLoaderSVG::_replace_color_property(const String &p_prefix, String &r_string) { - // Replace colors in the SVG based on what is configured in `replace_colors`. +void ImageLoaderSVG::_replace_color_property(const HashMap<Color, Color> &p_color_map, const String &p_prefix, String &r_string) { + // Replace colors in the SVG based on what is passed in `p_color_map`. // Used to change the colors of editor icons based on the used theme. // The strings being replaced are typically of the form: // fill="#5abbef" // But can also be 3-letter codes, include alpha, be "none" or a named color - // string ("blue"). So we convert to Godot Color to compare with `replace_colors`. + // string ("blue"). So we convert to Godot Color to compare with `p_color_map`. const int prefix_len = p_prefix.length(); int pos = r_string.find(p_prefix); @@ -52,8 +52,8 @@ void ImageLoaderSVG::_replace_color_property(const String &p_prefix, String &r_s const String color_code = r_string.substr(pos, end_pos - pos); if (color_code != "none" && !color_code.begins_with("url(")) { const Color color = Color(color_code); // Handles both HTML codes and named colors. - if (replace_colors.has(color)) { - r_string = r_string.left(pos) + "#" + replace_colors[color].operator Color().to_html(false) + r_string.substr(end_pos); + if (p_color_map.has(color)) { + r_string = r_string.left(pos) + "#" + p_color_map[color].to_html(false) + r_string.substr(end_pos); } } // Search for other occurrences. @@ -61,13 +61,13 @@ void ImageLoaderSVG::_replace_color_property(const String &p_prefix, String &r_s } } -void ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, bool p_convert_color) { +void ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map) { ERR_FAIL_COND(Math::is_zero_approx(p_scale)); - if (p_convert_color) { - _replace_color_property("stop-color=\"", p_string); - _replace_color_property("fill=\"", p_string); - _replace_color_property("stroke=\"", p_string); + if (p_color_map.size()) { + _replace_color_property(p_color_map, "stop-color=\"", p_string); + _replace_color_property(p_color_map, "fill=\"", p_string); + _replace_color_property(p_color_map, "stroke=\"", p_string); } std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen(); @@ -136,11 +136,11 @@ void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const p_extensions->push_back("svg"); } -Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) { +Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags, float p_scale) { String svg = p_fileaccess->get_as_utf8_string(); - create_image_from_string(p_image, svg, p_scale, false, false); + create_image_from_string(p_image, svg, p_scale, false, HashMap<Color, Color>()); ERR_FAIL_COND_V(p_image->is_empty(), FAILED); - if (p_force_linear) { + if (p_flags & FLAG_FORCE_LINEAR) { p_image->srgb_to_linear(); } return OK; diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h index 94c17fda43..fc89b63edb 100644 --- a/modules/svg/image_loader_svg.h +++ b/modules/svg/image_loader_svg.h @@ -34,15 +34,12 @@ #include "core/io/image_loader.h" class ImageLoaderSVG : public ImageFormatLoader { - Dictionary replace_colors; - void _replace_color_property(const String &p_prefix, String &r_string); + void _replace_color_property(const HashMap<Color, Color> &p_color_map, const String &p_prefix, String &r_string); public: - // Called by the editor to handle theme icon colors. - void set_replace_colors(Dictionary p_replace_colors) { replace_colors = p_replace_colors; } - void create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, bool p_convert_color); + void create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map); - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) override; + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags, float p_scale) override; virtual void get_recognized_extensions(List<String> *p_extensions) const override; }; diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index f91d0b66b3..366e1ba604 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -2257,12 +2257,12 @@ double TextServerAdvanced::font_get_oversampling(const RID &p_font_rid) const { return fd->oversampling; } -Array TextServerAdvanced::font_get_size_cache_list(const RID &p_font_rid) const { +TypedArray<Vector2i> TextServerAdvanced::font_get_size_cache_list(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, Array()); + ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>()); MutexLock lock(fd->mutex); - Array ret; + TypedArray<Vector2i> ret; for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) { ret.push_back(E.key); } @@ -2541,15 +2541,15 @@ PackedInt32Array TextServerAdvanced::font_get_texture_offsets(const RID &p_font_ return tex.offsets; } -Array TextServerAdvanced::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const { +PackedInt32Array TextServerAdvanced::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, Array()); + ERR_FAIL_COND_V(!fd, PackedInt32Array()); MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Array()); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array()); - Array ret; + PackedInt32Array ret; const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; for (const KeyValue<int32_t, FontGlyph> &E : gl) { ret.push_back(E.key); @@ -2961,16 +2961,16 @@ Dictionary TextServerAdvanced::font_get_glyph_contours(const RID &p_font_rid, in #endif } -Array TextServerAdvanced::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const { +TypedArray<Vector2i> TextServerAdvanced::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, Array()); + ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>()); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Array()); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), TypedArray<Vector2i>()); - Array ret; + TypedArray<Vector2i> ret; for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) { ret.push_back(E.key); } diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index ff8060151d..02abc31c55 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -537,7 +537,7 @@ public: virtual void font_set_oversampling(const RID &p_font_rid, double p_oversampling) override; virtual double font_get_oversampling(const RID &p_font_rid) const override; - virtual Array font_get_size_cache_list(const RID &p_font_rid) const override; + virtual TypedArray<Vector2i> font_get_size_cache_list(const RID &p_font_rid) const override; virtual void font_clear_size_cache(const RID &p_font_rid) override; virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) override; @@ -566,7 +566,7 @@ public: virtual void font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) override; virtual PackedInt32Array font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override; - virtual Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override; + virtual PackedInt32Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override; virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) override; virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) override; @@ -590,7 +590,7 @@ public: virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const override; - virtual Array font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override; + virtual TypedArray<Vector2i> font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override; virtual void font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) override; virtual void font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) override; diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 6fae75f49c..53b303cb20 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -1346,12 +1346,12 @@ double TextServerFallback::font_get_oversampling(const RID &p_font_rid) const { return fd->oversampling; } -Array TextServerFallback::font_get_size_cache_list(const RID &p_font_rid) const { +TypedArray<Vector2i> TextServerFallback::font_get_size_cache_list(const RID &p_font_rid) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, Array()); + ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>()); MutexLock lock(fd->mutex); - Array ret; + TypedArray<Vector2i> ret; for (const KeyValue<Vector2i, FontForSizeFallback *> &E : fd->cache) { ret.push_back(E.key); } @@ -1630,15 +1630,15 @@ PackedInt32Array TextServerFallback::font_get_texture_offsets(const RID &p_font_ return tex.offsets; } -Array TextServerFallback::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const { +PackedInt32Array TextServerFallback::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, Array()); + ERR_FAIL_COND_V(!fd, PackedInt32Array()); MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Array()); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array()); - Array ret; + PackedInt32Array ret; const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; for (const KeyValue<int32_t, FontGlyph> &E : gl) { ret.push_back(E.key); @@ -2036,16 +2036,16 @@ Dictionary TextServerFallback::font_get_glyph_contours(const RID &p_font_rid, in #endif } -Array TextServerFallback::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const { +TypedArray<Vector2i> TextServerFallback::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const { FontFallback *fd = font_owner.get_or_null(p_font_rid); - ERR_FAIL_COND_V(!fd, Array()); + ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>()); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Array()); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), TypedArray<Vector2i>()); - Array ret; + TypedArray<Vector2i> ret; for (const KeyValue<Vector2i, Vector2> &E : fd->cache[size]->kerning_map) { ret.push_back(E.key); } diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index e1609ef500..940c57a354 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -417,7 +417,7 @@ public: virtual void font_set_oversampling(const RID &p_font_rid, double p_oversampling) override; virtual double font_get_oversampling(const RID &p_font_rid) const override; - virtual Array font_get_size_cache_list(const RID &p_font_rid) const override; + virtual TypedArray<Vector2i> font_get_size_cache_list(const RID &p_font_rid) const override; virtual void font_clear_size_cache(const RID &p_font_rid) override; virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) override; @@ -446,7 +446,7 @@ public: virtual void font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) override; virtual PackedInt32Array font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override; - virtual Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override; + virtual PackedInt32Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override; virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) override; virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) override; @@ -469,7 +469,7 @@ public: virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const override; - virtual Array font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override; + virtual TypedArray<Vector2i> font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override; virtual void font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) override; virtual void font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) override; diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp index 08ad1ef9f8..16d9bf7b93 100644 --- a/modules/tga/image_loader_tga.cpp +++ b/modules/tga/image_loader_tga.cpp @@ -230,7 +230,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff return OK; } -Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { +Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h index 9b7cbbac77..d95c5ff30b 100644 --- a/modules/tga/image_loader_tga.h +++ b/modules/tga/image_loader_tga.h @@ -73,7 +73,7 @@ class ImageLoaderTGA : public ImageFormatLoader { static Error convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_input_size); public: - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderTGA(); }; diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp index 864df765ee..6f61251f9b 100644 --- a/modules/tinyexr/image_loader_tinyexr.cpp +++ b/modules/tinyexr/image_loader_tinyexr.cpp @@ -37,7 +37,7 @@ #include "thirdparty/tinyexr/tinyexr.h" -Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { +Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); @@ -229,7 +229,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool color.a = *a_channel++; } - if (p_force_linear) { + if (p_flags & FLAG_FORCE_LINEAR) { color = color.srgb_to_linear(); } @@ -260,7 +260,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool color.a = *a_channel++; } - if (p_force_linear) { + if (p_flags & FLAG_FORCE_LINEAR) { color = color.srgb_to_linear(); } diff --git a/modules/tinyexr/image_loader_tinyexr.h b/modules/tinyexr/image_loader_tinyexr.h index 0d3de93956..8da2a0d4af 100644 --- a/modules/tinyexr/image_loader_tinyexr.h +++ b/modules/tinyexr/image_loader_tinyexr.h @@ -35,7 +35,7 @@ class ImageLoaderTinyEXR : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderTinyEXR(); }; diff --git a/modules/visual_script/SCsub b/modules/visual_script/SCsub deleted file mode 100644 index b91cceae09..0000000000 --- a/modules/visual_script/SCsub +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env python - -Import("env") -Import("env_modules") - -env_vs = env_modules.Clone() - -env_vs.add_source_files(env.modules_sources, "*.cpp") - -if env["tools"]: - env_vs.add_source_files(env.modules_sources, "editor/*.cpp") diff --git a/modules/visual_script/config.py b/modules/visual_script/config.py deleted file mode 100644 index e8990c43c8..0000000000 --- a/modules/visual_script/config.py +++ /dev/null @@ -1,63 +0,0 @@ -def can_build(env, platform): - return True - - -def configure(env): - pass - - -def get_doc_classes(): - return [ - "VisualScriptBasicTypeConstant", - "VisualScriptBuiltinFunc", - "VisualScriptClassConstant", - "VisualScriptComment", - "VisualScriptComposeArray", - "VisualScriptCondition", - "VisualScriptConstant", - "VisualScriptConstructor", - "VisualScriptCustomNode", - "VisualScriptCustomNodes", - "VisualScriptDeconstruct", - "VisualScriptEditor", - "VisualScriptEmitSignal", - "VisualScriptEngineSingleton", - "VisualScriptExpression", - "VisualScriptFunctionCall", - "VisualScriptFunctionState", - "VisualScriptFunction", - "VisualScriptGlobalConstant", - "VisualScriptIndexGet", - "VisualScriptIndexSet", - "VisualScriptInputAction", - "VisualScriptIterator", - "VisualScriptLists", - "VisualScriptLocalVarSet", - "VisualScriptLocalVar", - "VisualScriptMathConstant", - "VisualScriptNode", - "VisualScriptOperator", - "VisualScriptPreload", - "VisualScriptPropertyGet", - "VisualScriptPropertySet", - "VisualScriptResourcePath", - "VisualScriptReturn", - "VisualScriptSceneNode", - "VisualScriptSceneTree", - "VisualScriptSelect", - "VisualScriptSelf", - "VisualScriptSequence", - "VisualScriptSubCall", - "VisualScriptSwitch", - "VisualScriptTypeCast", - "VisualScriptVariableGet", - "VisualScriptVariableSet", - "VisualScriptWhile", - "VisualScript", - "VisualScriptYieldSignal", - "VisualScriptYield", - ] - - -def get_doc_path(): - return "doc_classes" diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml deleted file mode 100644 index ff6b7a8b5f..0000000000 --- a/modules/visual_script/doc_classes/VisualScript.xml +++ /dev/null @@ -1,357 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScript" inherits="Script" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A script implemented in the Visual Script programming environment. - </brief_description> - <description> - A script implemented in the Visual Script programming environment. The script extends the functionality of all objects that instance it. - [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes. - You are most likely to use this class via the Visual Script editor or when writing plugins for it. - </description> - <tutorials> - <link title="VisualScript documentation index">$DOCS_URL/tutorials/scripting/visual_script/index.html</link> - </tutorials> - <methods> - <method name="add_custom_signal"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <description> - Add a custom signal with the specified name to the VisualScript. - </description> - </method> - <method name="add_function"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <param index="1" name="func_node_id" type="int" /> - <description> - Add a function with the specified name to the VisualScript, and assign the root [VisualScriptFunction] node's id as [code]func_node_id[/code]. - </description> - </method> - <method name="add_node"> - <return type="void" /> - <param index="0" name="id" type="int" /> - <param index="1" name="node" type="VisualScriptNode" /> - <param index="2" name="position" type="Vector2" default="Vector2(0, 0)" /> - <description> - Add a node to the VisualScript. - </description> - </method> - <method name="add_variable"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <param index="1" name="default_value" type="Variant" default="null" /> - <param index="2" name="export" type="bool" default="false" /> - <description> - Add a variable to the VisualScript, optionally giving it a default value or marking it as exported. - </description> - </method> - <method name="custom_signal_add_argument"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <param index="1" name="type" type="int" enum="Variant.Type" /> - <param index="2" name="argname" type="String" /> - <param index="3" name="index" type="int" default="-1" /> - <description> - Add an argument to a custom signal added with [method add_custom_signal]. - </description> - </method> - <method name="custom_signal_get_argument_count" qualifiers="const"> - <return type="int" /> - <param index="0" name="name" type="StringName" /> - <description> - Get the count of a custom signal's arguments. - </description> - </method> - <method name="custom_signal_get_argument_name" qualifiers="const"> - <return type="String" /> - <param index="0" name="name" type="StringName" /> - <param index="1" name="argidx" type="int" /> - <description> - Get the name of a custom signal's argument. - </description> - </method> - <method name="custom_signal_get_argument_type" qualifiers="const"> - <return type="int" enum="Variant.Type" /> - <param index="0" name="name" type="StringName" /> - <param index="1" name="argidx" type="int" /> - <description> - Get the type of a custom signal's argument. - </description> - </method> - <method name="custom_signal_remove_argument"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <param index="1" name="argidx" type="int" /> - <description> - Remove a specific custom signal's argument. - </description> - </method> - <method name="custom_signal_set_argument_name"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <param index="1" name="argidx" type="int" /> - <param index="2" name="argname" type="String" /> - <description> - Rename a custom signal's argument. - </description> - </method> - <method name="custom_signal_set_argument_type"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <param index="1" name="argidx" type="int" /> - <param index="2" name="type" type="int" enum="Variant.Type" /> - <description> - Change the type of a custom signal's argument. - </description> - </method> - <method name="custom_signal_swap_argument"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <param index="1" name="argidx" type="int" /> - <param index="2" name="withidx" type="int" /> - <description> - Swap two of the arguments of a custom signal. - </description> - </method> - <method name="data_connect"> - <return type="void" /> - <param index="0" name="from_node" type="int" /> - <param index="1" name="from_port" type="int" /> - <param index="2" name="to_node" type="int" /> - <param index="3" name="to_port" type="int" /> - <description> - Connect two data ports. The value of [code]from_node[/code]'s [code]from_port[/code] would be fed into [code]to_node[/code]'s [code]to_port[/code]. - </description> - </method> - <method name="data_disconnect"> - <return type="void" /> - <param index="0" name="from_node" type="int" /> - <param index="1" name="from_port" type="int" /> - <param index="2" name="to_node" type="int" /> - <param index="3" name="to_port" type="int" /> - <description> - Disconnect two data ports previously connected with [method data_connect]. - </description> - </method> - <method name="get_function_node_id" qualifiers="const"> - <return type="int" /> - <param index="0" name="name" type="StringName" /> - <description> - Returns the id of a function's entry point node. - </description> - </method> - <method name="get_node" qualifiers="const"> - <return type="VisualScriptNode" /> - <param index="0" name="id" type="int" /> - <description> - Returns a node given its id. - </description> - </method> - <method name="get_node_position" qualifiers="const"> - <return type="Vector2" /> - <param index="0" name="id" type="int" /> - <description> - Returns a node's position in pixels. - </description> - </method> - <method name="get_scroll" qualifiers="const"> - <return type="Vector2" /> - <description> - Returns the current position of the center of the screen. - </description> - </method> - <method name="get_variable_default_value" qualifiers="const"> - <return type="Variant" /> - <param index="0" name="name" type="StringName" /> - <description> - Returns the default (initial) value of a variable. - </description> - </method> - <method name="get_variable_export" qualifiers="const"> - <return type="bool" /> - <param index="0" name="name" type="StringName" /> - <description> - Returns whether a variable is exported. - </description> - </method> - <method name="get_variable_info" qualifiers="const"> - <return type="Dictionary" /> - <param index="0" name="name" type="StringName" /> - <description> - Returns the information for a given variable as a dictionary. The information includes its name, type, hint and usage. - </description> - </method> - <method name="has_custom_signal" qualifiers="const"> - <return type="bool" /> - <param index="0" name="name" type="StringName" /> - <description> - Returns whether a signal exists with the specified name. - </description> - </method> - <method name="has_data_connection" qualifiers="const"> - <return type="bool" /> - <param index="0" name="from_node" type="int" /> - <param index="1" name="from_port" type="int" /> - <param index="2" name="to_node" type="int" /> - <param index="3" name="to_port" type="int" /> - <description> - Returns whether the specified data ports are connected. - </description> - </method> - <method name="has_function" qualifiers="const"> - <return type="bool" /> - <param index="0" name="name" type="StringName" /> - <description> - Returns whether a function exists with the specified name. - </description> - </method> - <method name="has_node" qualifiers="const"> - <return type="bool" /> - <param index="0" name="id" type="int" /> - <description> - Returns whether a node exists with the given id. - </description> - </method> - <method name="has_sequence_connection" qualifiers="const"> - <return type="bool" /> - <param index="0" name="from_node" type="int" /> - <param index="1" name="from_output" type="int" /> - <param index="2" name="to_node" type="int" /> - <description> - Returns whether the specified sequence ports are connected. - </description> - </method> - <method name="has_variable" qualifiers="const"> - <return type="bool" /> - <param index="0" name="name" type="StringName" /> - <description> - Returns whether a variable exists with the specified name. - </description> - </method> - <method name="remove_custom_signal"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <description> - Remove a custom signal with the given name. - </description> - </method> - <method name="remove_function"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <description> - Remove a specific function and its nodes from the script. - </description> - </method> - <method name="remove_node"> - <return type="void" /> - <param index="0" name="id" type="int" /> - <description> - Remove the node with the specified id. - </description> - </method> - <method name="remove_variable"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <description> - Remove a variable with the given name. - </description> - </method> - <method name="rename_custom_signal"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <param index="1" name="new_name" type="StringName" /> - <description> - Change the name of a custom signal. - </description> - </method> - <method name="rename_function"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <param index="1" name="new_name" type="StringName" /> - <description> - Change the name of a function. - </description> - </method> - <method name="rename_variable"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <param index="1" name="new_name" type="StringName" /> - <description> - Change the name of a variable. - </description> - </method> - <method name="sequence_connect"> - <return type="void" /> - <param index="0" name="from_node" type="int" /> - <param index="1" name="from_output" type="int" /> - <param index="2" name="to_node" type="int" /> - <description> - Connect two sequence ports. The execution will flow from of [code]from_node[/code]'s [code]from_output[/code] into [code]to_node[/code]. - Unlike [method data_connect], there isn't a [code]to_port[/code], since the target node can have only one sequence port. - </description> - </method> - <method name="sequence_disconnect"> - <return type="void" /> - <param index="0" name="from_node" type="int" /> - <param index="1" name="from_output" type="int" /> - <param index="2" name="to_node" type="int" /> - <description> - Disconnect two sequence ports previously connected with [method sequence_connect]. - </description> - </method> - <method name="set_instance_base_type"> - <return type="void" /> - <param index="0" name="type" type="StringName" /> - <description> - Set the base type of the script. - </description> - </method> - <method name="set_node_position"> - <return type="void" /> - <param index="0" name="id" type="int" /> - <param index="1" name="position" type="Vector2" /> - <description> - Set the node position in the VisualScript graph. - </description> - </method> - <method name="set_scroll"> - <return type="void" /> - <param index="0" name="offset" type="Vector2" /> - <description> - Set the screen center to the given position. - </description> - </method> - <method name="set_variable_default_value"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <param index="1" name="value" type="Variant" /> - <description> - Change the default (initial) value of a variable. - </description> - </method> - <method name="set_variable_export"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <param index="1" name="enable" type="bool" /> - <description> - Change whether a variable is exported. - </description> - </method> - <method name="set_variable_info"> - <return type="void" /> - <param index="0" name="name" type="StringName" /> - <param index="1" name="value" type="Dictionary" /> - <description> - Set a variable's info, using the same format as [method get_variable_info]. - </description> - </method> - </methods> - <signals> - <signal name="node_ports_changed"> - <param index="0" name="id" type="int" /> - <description> - Emitted when the ports of a node are changed. - </description> - </signal> - </signals> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml b/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml deleted file mode 100644 index 0ed66f44e1..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptBasicTypeConstant" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node representing a constant from the base types. - </brief_description> - <description> - A Visual Script node representing a constant from base types, such as [constant Vector3.AXIS_X]. - </description> - <tutorials> - </tutorials> - <members> - <member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type" default="0"> - The type to get the constant from. - </member> - <member name="constant" type="StringName" setter="set_basic_type_constant" getter="get_basic_type_constant"> - The name of the constant to return. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml deleted file mode 100644 index 647b627d25..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml +++ /dev/null @@ -1,221 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptBuiltinFunc" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node used to call built-in functions. - </brief_description> - <description> - A built-in function used inside a [VisualScript]. It is usually a math function or an utility function. - See also [@GDScript], for the same functions in the GDScript language. - </description> - <tutorials> - </tutorials> - <members> - <member name="function" type="int" setter="set_func" getter="get_func" enum="VisualScriptBuiltinFunc.BuiltinFunc" default="0"> - The function to be executed. - </member> - </members> - <constants> - <constant name="MATH_SIN" value="0" enum="BuiltinFunc"> - Returns the sine of the input. - </constant> - <constant name="MATH_COS" value="1" enum="BuiltinFunc"> - Returns the cosine of the input. - </constant> - <constant name="MATH_TAN" value="2" enum="BuiltinFunc"> - Returns the tangent of the input. - </constant> - <constant name="MATH_SINH" value="3" enum="BuiltinFunc"> - Returns the hyperbolic sine of the input. - </constant> - <constant name="MATH_COSH" value="4" enum="BuiltinFunc"> - Returns the hyperbolic cosine of the input. - </constant> - <constant name="MATH_TANH" value="5" enum="BuiltinFunc"> - Returns the hyperbolic tangent of the input. - </constant> - <constant name="MATH_ASIN" value="6" enum="BuiltinFunc"> - Returns the arc sine of the input. - </constant> - <constant name="MATH_ACOS" value="7" enum="BuiltinFunc"> - Returns the arc cosine of the input. - </constant> - <constant name="MATH_ATAN" value="8" enum="BuiltinFunc"> - Returns the arc tangent of the input. - </constant> - <constant name="MATH_ATAN2" value="9" enum="BuiltinFunc"> - Returns the arc tangent of the input, using the signs of both parameters to determine the exact angle. - </constant> - <constant name="MATH_SQRT" value="10" enum="BuiltinFunc"> - Returns the square root of the input. - </constant> - <constant name="MATH_FMOD" value="11" enum="BuiltinFunc"> - Returns the remainder of one input divided by the other, using floating-point numbers. - </constant> - <constant name="MATH_FPOSMOD" value="12" enum="BuiltinFunc"> - Returns the positive remainder of one input divided by the other, using floating-point numbers. - </constant> - <constant name="MATH_FLOOR" value="13" enum="BuiltinFunc"> - Returns the input rounded down. - </constant> - <constant name="MATH_CEIL" value="14" enum="BuiltinFunc"> - Returns the input rounded up. - </constant> - <constant name="MATH_ROUND" value="15" enum="BuiltinFunc"> - Returns the input rounded to the nearest integer. - </constant> - <constant name="MATH_ABS" value="16" enum="BuiltinFunc"> - Returns the absolute value of the input. - </constant> - <constant name="MATH_SIGN" value="17" enum="BuiltinFunc"> - Returns the sign of the input, turning it into 1, -1, or 0. Useful to determine if the input is positive or negative. - </constant> - <constant name="MATH_POW" value="18" enum="BuiltinFunc"> - Returns the input raised to a given power. - </constant> - <constant name="MATH_LOG" value="19" enum="BuiltinFunc"> - Returns the natural logarithm of the input. Note that this is not the typical base-10 logarithm function calculators use. - </constant> - <constant name="MATH_EXP" value="20" enum="BuiltinFunc"> - Returns the mathematical constant [b]e[/b] raised to the specified power of the input. [b]e[/b] has an approximate value of 2.71828. - </constant> - <constant name="MATH_ISNAN" value="21" enum="BuiltinFunc"> - Returns whether the input is NaN (Not a Number) or not. NaN is usually produced by dividing 0 by 0, though other ways exist. - </constant> - <constant name="MATH_ISINF" value="22" enum="BuiltinFunc"> - Returns whether the input is an infinite floating-point number or not. Infinity is usually produced by dividing a number by 0, though other ways exist. - </constant> - <constant name="MATH_EASE" value="23" enum="BuiltinFunc"> - Easing function, based on exponent. 0 is constant, 1 is linear, 0 to 1 is ease-in, 1+ is ease out. Negative values are in-out/out in. - </constant> - <constant name="MATH_STEP_DECIMALS" value="24" enum="BuiltinFunc"> - Returns the number of digit places after the decimal that the first non-zero digit occurs. - </constant> - <constant name="MATH_SNAPPED" value="25" enum="BuiltinFunc"> - Returns the input snapped to a given step. - </constant> - <constant name="MATH_LERP" value="26" enum="BuiltinFunc"> - Returns a number linearly interpolated between the first two inputs, based on the third input. Uses the formula [code]a + (a - b) * t[/code]. - </constant> - <constant name="MATH_CUBIC_INTERPOLATE" value="27" enum="BuiltinFunc"> - </constant> - <constant name="MATH_INVERSE_LERP" value="28" enum="BuiltinFunc"> - </constant> - <constant name="MATH_RANGE_LERP" value="29" enum="BuiltinFunc"> - </constant> - <constant name="MATH_MOVE_TOWARD" value="30" enum="BuiltinFunc"> - Moves the number toward a value, based on the third input. - </constant> - <constant name="MATH_RANDOMIZE" value="31" enum="BuiltinFunc"> - Randomize the seed (or the internal state) of the random number generator. Current implementation reseeds using a number based on time. - </constant> - <constant name="MATH_RANDI" value="32" enum="BuiltinFunc"> - Returns a random 32 bits integer value. To obtain a random value between 0 to N (where N is smaller than 2^32 - 1), you can use it with the remainder function. - </constant> - <constant name="MATH_RANDF" value="33" enum="BuiltinFunc"> - Returns a random floating-point value between 0 and 1. To obtain a random value between 0 to N, you can use it with multiplication. - </constant> - <constant name="MATH_RANDI_RANGE" value="34" enum="BuiltinFunc"> - Returns a random 32-bit integer value between the two inputs. - </constant> - <constant name="MATH_RANDF_RANGE" value="35" enum="BuiltinFunc"> - Returns a random floating-point value between the two inputs. - </constant> - <constant name="MATH_RANDFN" value="36" enum="BuiltinFunc"> - Returns a normally-distributed pseudo-random number, using Box-Muller transform with the specified mean and a standard deviation. This is also called Gaussian distribution. - </constant> - <constant name="MATH_SEED" value="37" enum="BuiltinFunc"> - Set the seed for the random number generator. - </constant> - <constant name="MATH_RANDSEED" value="38" enum="BuiltinFunc"> - Returns a random value from the given seed, along with the new seed. - </constant> - <constant name="MATH_DEG2RAD" value="39" enum="BuiltinFunc"> - Convert the input from degrees to radians. - </constant> - <constant name="MATH_RAD2DEG" value="40" enum="BuiltinFunc"> - Convert the input from radians to degrees. - </constant> - <constant name="MATH_LINEAR2DB" value="41" enum="BuiltinFunc"> - Convert the input from linear volume to decibel volume. - </constant> - <constant name="MATH_DB2LINEAR" value="42" enum="BuiltinFunc"> - Convert the input from decibel volume to linear volume. - </constant> - <constant name="MATH_WRAP" value="43" enum="BuiltinFunc"> - </constant> - <constant name="MATH_WRAPF" value="44" enum="BuiltinFunc"> - </constant> - <constant name="MATH_PINGPONG" value="45" enum="BuiltinFunc"> - Returns the [code]value[/code] wrapped between [code]0[/code] and the [code]length[/code]. If the limit is reached, the next value the function returned is decreased to the [code]0[/code] side or increased to the [code]length[/code] side (like a triangle wave). If [code]length[/code] is less than zero, it becomes positive. - </constant> - <constant name="LOGIC_MAX" value="46" enum="BuiltinFunc"> - Returns the greater of the two numbers, also known as their maximum. - </constant> - <constant name="LOGIC_MIN" value="47" enum="BuiltinFunc"> - Returns the lesser of the two numbers, also known as their minimum. - </constant> - <constant name="LOGIC_CLAMP" value="48" enum="BuiltinFunc"> - Returns the input clamped inside the given range, ensuring the result is never outside it. Equivalent to [code]min(max(input, range_low), range_high)[/code]. - </constant> - <constant name="LOGIC_NEAREST_PO2" value="49" enum="BuiltinFunc"> - Returns the nearest power of 2 to the input. - </constant> - <constant name="OBJ_WEAKREF" value="50" enum="BuiltinFunc"> - Create a [WeakRef] from the input. - </constant> - <constant name="TYPE_CONVERT" value="51" enum="BuiltinFunc"> - Convert between types. - </constant> - <constant name="TYPE_OF" value="52" enum="BuiltinFunc"> - Returns the type of the input as an integer. Check [enum Variant.Type] for the integers that might be returned. - </constant> - <constant name="TYPE_EXISTS" value="53" enum="BuiltinFunc"> - Checks if a type is registered in the [ClassDB]. - </constant> - <constant name="TEXT_CHAR" value="54" enum="BuiltinFunc"> - Returns a character with the given ascii value. - </constant> - <constant name="TEXT_STR" value="55" enum="BuiltinFunc"> - Convert the input to a string. - </constant> - <constant name="TEXT_PRINT" value="56" enum="BuiltinFunc"> - Print the given string to the output window. - </constant> - <constant name="TEXT_PRINTERR" value="57" enum="BuiltinFunc"> - Print the given string to the standard error output. - </constant> - <constant name="TEXT_PRINTRAW" value="58" enum="BuiltinFunc"> - Print the given string to the standard output, without adding a newline. - </constant> - <constant name="TEXT_PRINT_VERBOSE" value="59" enum="BuiltinFunc"> - </constant> - <constant name="VAR_TO_STR" value="60" enum="BuiltinFunc"> - Serialize a [Variant] to a string. - </constant> - <constant name="STR_TO_VAR" value="61" enum="BuiltinFunc"> - Deserialize a [Variant] from a string serialized using [constant VAR_TO_STR]. - </constant> - <constant name="VAR_TO_BYTES" value="62" enum="BuiltinFunc"> - Serialize a [Variant] to a [PackedByteArray]. - </constant> - <constant name="BYTES_TO_VAR" value="63" enum="BuiltinFunc"> - Deserialize a [Variant] from a [PackedByteArray] serialized using [constant VAR_TO_BYTES]. - </constant> - <constant name="MATH_SMOOTHSTEP" value="64" enum="BuiltinFunc"> - Returns a number smoothly interpolated between the first two inputs, based on the third input. Similar to [constant MATH_LERP], but interpolates faster at the beginning and slower at the end. Using Hermite interpolation formula: - [codeblock] - var t = clamp((weight - from) / (to - from), 0.0, 1.0) - return t * t * (3.0 - 2.0 * t) - [/codeblock] - </constant> - <constant name="MATH_POSMOD" value="65" enum="BuiltinFunc"> - </constant> - <constant name="MATH_LERP_ANGLE" value="66" enum="BuiltinFunc"> - </constant> - <constant name="TEXT_ORD" value="67" enum="BuiltinFunc"> - </constant> - <constant name="FUNC_MAX" value="68" enum="BuiltinFunc"> - Represents the size of the [enum BuiltinFunc] enum. - </constant> - </constants> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml deleted file mode 100644 index 2509084f0e..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptClassConstant" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Gets a constant from a given class. - </brief_description> - <description> - This node returns a constant from a given class, such as [constant TYPE_INT]. See the given class' documentation for available constants. - [b]Input Ports:[/b] - none - [b]Output Ports:[/b] - - Data (variant): [code]value[/code] - </description> - <tutorials> - </tutorials> - <members> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> - The constant's parent class. - </member> - <member name="constant" type="StringName" setter="set_class_constant" getter="get_class_constant" default="&"""> - The constant to return. See the given class for its available constants. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptComment.xml b/modules/visual_script/doc_classes/VisualScriptComment.xml deleted file mode 100644 index cf4b57ca19..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptComment.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptComment" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node used to annotate the script. - </brief_description> - <description> - A Visual Script node used to display annotations in the script, so that code may be documented. - Comment nodes can be resized so they encompass a group of nodes. - </description> - <tutorials> - </tutorials> - <members> - <member name="description" type="String" setter="set_description" getter="get_description" default=""""> - The text inside the comment node. - </member> - <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2(150, 150)"> - The comment node's size (in pixels). - </member> - <member name="title" type="String" setter="set_title" getter="get_title" default=""Comment""> - The comment node's title. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptComposeArray.xml b/modules/visual_script/doc_classes/VisualScriptComposeArray.xml deleted file mode 100644 index ea73867c4b..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptComposeArray.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptComposeArray" inherits="VisualScriptLists" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script Node used to create array from a list of items. - </brief_description> - <description> - A Visual Script Node used to compose array from the list of elements provided with custom in-graph UI hard coded in the VisualScript Editor. - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptCondition.xml b/modules/visual_script/doc_classes/VisualScriptCondition.xml deleted file mode 100644 index a29388569f..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptCondition.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptCondition" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node which branches the flow. - </brief_description> - <description> - A Visual Script node that checks a [bool] input port. If [code]true[/code], it will exit via the "true" sequence port. If [code]false[/code], it will exit via the "false" sequence port. After exiting either, it exits via the "done" port. Sequence ports may be left disconnected. - [b]Input Ports:[/b] - - Sequence: [code]if (cond) is[/code] - - Data (boolean): [code]cond[/code] - [b]Output Ports:[/b] - - Sequence: [code]true[/code] - - Sequence: [code]false[/code] - - Sequence: [code]done[/code] - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptConstant.xml b/modules/visual_script/doc_classes/VisualScriptConstant.xml deleted file mode 100644 index 645ede9001..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptConstant.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptConstant" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Gets a contant's value. - </brief_description> - <description> - This node returns a constant's value. - [b]Input Ports:[/b] - none - [b]Output Ports:[/b] - - Data (variant): [code]get[/code] - </description> - <tutorials> - </tutorials> - <members> - <member name="type" type="int" setter="set_constant_type" getter="get_constant_type" enum="Variant.Type" default="0"> - The constant's type. - </member> - <member name="value" type="Variant" setter="set_constant_value" getter="get_constant_value"> - The constant's value. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptConstructor.xml b/modules/visual_script/doc_classes/VisualScriptConstructor.xml deleted file mode 100644 index a003f21ab9..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptConstructor.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptConstructor" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node which calls a base type constructor. - </brief_description> - <description> - A Visual Script node which calls a base type constructor. It can be used for type conversion as well. - </description> - <tutorials> - </tutorials> - <methods> - <method name="get_constructor" qualifiers="const"> - <return type="Dictionary" /> - <description> - </description> - </method> - <method name="get_constructor_type" qualifiers="const"> - <return type="int" enum="Variant.Type" /> - <description> - </description> - </method> - <method name="set_constructor"> - <return type="void" /> - <param index="0" name="constructor" type="Dictionary" /> - <description> - </description> - </method> - <method name="set_constructor_type"> - <return type="void" /> - <param index="0" name="type" type="int" enum="Variant.Type" /> - <description> - </description> - </method> - </methods> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml b/modules/visual_script/doc_classes/VisualScriptCustomNode.xml deleted file mode 100644 index 6e522b2f84..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml +++ /dev/null @@ -1,166 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptCustomNode" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A scripted Visual Script node. - </brief_description> - <description> - A custom Visual Script node which can be scripted in powerful ways. - </description> - <tutorials> - </tutorials> - <methods> - <method name="_get_caption" qualifiers="virtual const"> - <return type="String" /> - <description> - Returns the node's title. - </description> - </method> - <method name="_get_category" qualifiers="virtual const"> - <return type="String" /> - <description> - Returns the node's category. - </description> - </method> - <method name="_get_input_value_port_count" qualifiers="virtual const"> - <return type="int" /> - <description> - Returns the count of input value ports. - </description> - </method> - <method name="_get_input_value_port_hint" qualifiers="virtual const"> - <return type="int" /> - <param index="0" name="input_idx" type="int" /> - <description> - Returns the specified input port's hint. See the [enum @GlobalScope.PropertyHint] hints. - </description> - </method> - <method name="_get_input_value_port_hint_string" qualifiers="virtual const"> - <return type="String" /> - <param index="0" name="input_idx" type="int" /> - <description> - Returns the specified input port's hint string. - </description> - </method> - <method name="_get_input_value_port_name" qualifiers="virtual const"> - <return type="String" /> - <param index="0" name="input_idx" type="int" /> - <description> - Returns the specified input port's name. - </description> - </method> - <method name="_get_input_value_port_type" qualifiers="virtual const"> - <return type="int" /> - <param index="0" name="input_idx" type="int" /> - <description> - Returns the specified input port's type. See the [enum Variant.Type] values. - </description> - </method> - <method name="_get_output_sequence_port_count" qualifiers="virtual const"> - <return type="int" /> - <description> - Returns the amount of output [b]sequence[/b] ports. - </description> - </method> - <method name="_get_output_sequence_port_text" qualifiers="virtual const"> - <return type="String" /> - <param index="0" name="seq_idx" type="int" /> - <description> - Returns the specified [b]sequence[/b] output's name. - </description> - </method> - <method name="_get_output_value_port_count" qualifiers="virtual const"> - <return type="int" /> - <description> - Returns the amount of output value ports. - </description> - </method> - <method name="_get_output_value_port_hint" qualifiers="virtual const"> - <return type="int" /> - <param index="0" name="output_idx" type="int" /> - <description> - Returns the specified output port's hint. See the [enum @GlobalScope.PropertyHint] hints. - </description> - </method> - <method name="_get_output_value_port_hint_string" qualifiers="virtual const"> - <return type="String" /> - <param index="0" name="output_idx" type="int" /> - <description> - Returns the specified output port's hint string. - </description> - </method> - <method name="_get_output_value_port_name" qualifiers="virtual const"> - <return type="String" /> - <param index="0" name="output_idx" type="int" /> - <description> - Returns the specified output port's name. - </description> - </method> - <method name="_get_output_value_port_type" qualifiers="virtual const"> - <return type="int" /> - <param index="0" name="output_idx" type="int" /> - <description> - Returns the specified output port's type. See the [enum Variant.Type] values. - </description> - </method> - <method name="_get_text" qualifiers="virtual const"> - <return type="String" /> - <description> - Returns the custom node's text, which is shown right next to the input [b]sequence[/b] port (if there is none, on the place that is usually taken by it). - </description> - </method> - <method name="_get_working_memory_size" qualifiers="virtual const"> - <return type="int" /> - <description> - Returns the size of the custom node's working memory. See [method _step] for more details. - </description> - </method> - <method name="_has_input_sequence_port" qualifiers="virtual const"> - <return type="bool" /> - <description> - Returns whether the custom node has an input [b]sequence[/b] port. - </description> - </method> - <method name="_step" qualifiers="virtual const"> - <return type="Variant" /> - <param index="0" name="inputs" type="Array" /> - <param index="1" name="outputs" type="Array" /> - <param index="2" name="start_mode" type="int" /> - <param index="3" name="working_mem" type="Array" /> - <description> - Execute the custom node's logic, returning the index of the output sequence port to use or a [String] when there is an error. - The [code]inputs[/code] array contains the values of the input ports. - [code]outputs[/code] is an array whose indices should be set to the respective outputs. - The [code]start_mode[/code] is usually [constant START_MODE_BEGIN_SEQUENCE], unless you have used the [code]STEP_*[/code] constants. - [code]working_mem[/code] is an array which can be used to persist information between runs of the custom node. The size needs to be predefined using [method _get_working_memory_size]. - When returning, you can mask the returned value with one of the [code]STEP_*[/code] constants. - </description> - </method> - </methods> - <constants> - <constant name="START_MODE_BEGIN_SEQUENCE" value="0" enum="StartMode"> - The start mode used the first time when [method _step] is called. - </constant> - <constant name="START_MODE_CONTINUE_SEQUENCE" value="1" enum="StartMode"> - The start mode used when [method _step] is called after coming back from a [constant STEP_PUSH_STACK_BIT]. - </constant> - <constant name="START_MODE_RESUME_YIELD" value="2" enum="StartMode"> - The start mode used when [method _step] is called after resuming from [constant STEP_YIELD_BIT]. - </constant> - <constant name="STEP_PUSH_STACK_BIT" value="16777216"> - Hint used by [method _step] to tell that control should return to it when there is no other node left to execute. - This is used by [VisualScriptCondition] to redirect the sequence to the "Done" port after the [code]true[/code]/[code]false[/code] branch has finished execution. - </constant> - <constant name="STEP_GO_BACK_BIT" value="33554432"> - Hint used by [method _step] to tell that control should return back, either hitting a previous [constant STEP_PUSH_STACK_BIT] or exiting the function. - </constant> - <constant name="STEP_NO_ADVANCE_BIT" value="67108864"> - </constant> - <constant name="STEP_EXIT_FUNCTION_BIT" value="134217728"> - Hint used by [method _step] to tell that control should stop and exit the function. - </constant> - <constant name="STEP_YIELD_BIT" value="268435456"> - Hint used by [method _step] to tell that the function should be yielded. - Using this requires you to have at least one working memory slot, which is used for the [VisualScriptFunctionState]. - </constant> - </constants> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptCustomNodes.xml b/modules/visual_script/doc_classes/VisualScriptCustomNodes.xml deleted file mode 100644 index 48d7975051..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptCustomNodes.xml +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptCustomNodes" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Manages custom nodes for the Visual Script editor. - </brief_description> - <description> - This singleton can be used to manage (i.e., add or remove) custom nodes for the Visual Script editor. - </description> - <tutorials> - </tutorials> - <methods> - <method name="add_custom_node"> - <return type="void" /> - <param index="0" name="name" type="String" /> - <param index="1" name="category" type="String" /> - <param index="2" name="script" type="Script" /> - <description> - Add a custom Visual Script node to the editor. It'll be placed under "Custom Nodes" with the [code]category[/code] as the parameter. - </description> - </method> - <method name="remove_custom_node"> - <return type="void" /> - <param index="0" name="name" type="String" /> - <param index="1" name="category" type="String" /> - <description> - Remove a custom Visual Script node from the editor. Custom nodes already placed on scripts won't be removed. - </description> - </method> - </methods> - <signals> - <signal name="custom_nodes_updated"> - <description> - Emitted when a custom Visual Script node is added or removed. - </description> - </signal> - </signals> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml b/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml deleted file mode 100644 index b544fd9d90..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptDeconstruct" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node which deconstructs a base type instance into its parts. - </brief_description> - <description> - A Visual Script node which deconstructs a base type instance into its parts. - </description> - <tutorials> - </tutorials> - <members> - <member name="type" type="int" setter="set_deconstruct_type" getter="get_deconstruct_type" enum="Variant.Type" default="0"> - The type to deconstruct. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml deleted file mode 100644 index c0cefa0ab7..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptEmitSignal" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Emits a specified signal. - </brief_description> - <description> - Emits a specified signal when it is executed. - [b]Input Ports:[/b] - - Sequence: [code]emit[/code] - [b]Output Ports:[/b] - - Sequence - </description> - <tutorials> - </tutorials> - <members> - <member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="&"""> - The signal to emit. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml b/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml deleted file mode 100644 index f60a048845..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptEngineSingleton" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node returning a singleton from [@GlobalScope]. - </brief_description> - <description> - A Visual Script node returning a singleton from [@GlobalScope]. - </description> - <tutorials> - </tutorials> - <members> - <member name="constant" type="String" setter="set_singleton" getter="get_singleton" default=""""> - The singleton's name. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptExpression.xml b/modules/visual_script/doc_classes/VisualScriptExpression.xml deleted file mode 100644 index 14750e7c8d..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptExpression.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptExpression" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node that can execute a custom expression. - </brief_description> - <description> - A Visual Script node that can execute a custom expression. Values can be provided for the input and the expression result can be retrieved from the output. - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptFunction.xml b/modules/visual_script/doc_classes/VisualScriptFunction.xml deleted file mode 100644 index 74d9f194eb..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptFunction.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptFunction" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node representing a function. - </brief_description> - <description> - [VisualScriptFunction] represents a function header. It is the starting point for the function body and can be used to tweak the function's properties (e.g. RPC mode). - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml deleted file mode 100644 index 543263ff8e..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml +++ /dev/null @@ -1,75 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptFunctionCall" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node for calling a function. - </brief_description> - <description> - [VisualScriptFunctionCall] is created when you add or drag and drop a function onto the Visual Script graph. It allows to tweak parameters of the call, e.g. what object the function is called on. - </description> - <tutorials> - </tutorials> - <members> - <member name="base_script" type="String" setter="set_base_script" getter="get_base_script"> - The script to be used when [member call_mode] is set to [constant CALL_MODE_INSTANCE]. - </member> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> - The base type to be used when [member call_mode] is set to [constant CALL_MODE_INSTANCE]. - </member> - <member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type"> - The type to be used when [member call_mode] is set to [constant CALL_MODE_BASIC_TYPE]. - </member> - <member name="call_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptFunctionCall.CallMode" default="0"> - [code]call_mode[/code] determines the target object on which the method will be called. See [enum CallMode] for options. - </member> - <member name="function" type="StringName" setter="set_function" getter="get_function" default="&"""> - The name of the function to be called. - </member> - <member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path"> - The node path to use when [member call_mode] is set to [constant CALL_MODE_NODE_PATH]. - </member> - <member name="rpc_call_mode" type="int" setter="set_rpc_call_mode" getter="get_rpc_call_mode" enum="VisualScriptFunctionCall.RPCCallMode" default="0"> - The mode for RPC calls. See [method Node.rpc] for more details and [enum RPCCallMode] for available options. - </member> - <member name="singleton" type="StringName" setter="set_singleton" getter="get_singleton"> - The singleton to call the method on. Used when [member call_mode] is set to [constant CALL_MODE_SINGLETON]. - </member> - <member name="use_default_args" type="int" setter="set_use_default_args" getter="get_use_default_args"> - Number of default arguments that will be used when calling the function. Can't be higher than the number of available default arguments in the method's declaration. - </member> - <member name="validate" type="bool" setter="set_validate" getter="get_validate" default="true"> - If [code]false[/code], call errors (e.g. wrong number of arguments) will be ignored. - </member> - </members> - <constants> - <constant name="CALL_MODE_SELF" value="0" enum="CallMode"> - The method will be called on this [Object]. - </constant> - <constant name="CALL_MODE_NODE_PATH" value="1" enum="CallMode"> - The method will be called on the given [Node] in the scene tree. - </constant> - <constant name="CALL_MODE_INSTANCE" value="2" enum="CallMode"> - The method will be called on an instanced node with the given type and script. - </constant> - <constant name="CALL_MODE_BASIC_TYPE" value="3" enum="CallMode"> - The method will be called on a GDScript basic type (e.g. [Vector2]). - </constant> - <constant name="CALL_MODE_SINGLETON" value="4" enum="CallMode"> - The method will be called on a singleton. - </constant> - <constant name="RPC_DISABLED" value="0" enum="RPCCallMode"> - The method will be called locally. - </constant> - <constant name="RPC_RELIABLE" value="1" enum="RPCCallMode"> - The method will be called remotely. - </constant> - <constant name="RPC_UNRELIABLE" value="2" enum="RPCCallMode"> - The method will be called remotely using an unreliable protocol. - </constant> - <constant name="RPC_RELIABLE_TO_ID" value="3" enum="RPCCallMode"> - The method will be called remotely for the given peer. - </constant> - <constant name="RPC_UNRELIABLE_TO_ID" value="4" enum="RPCCallMode"> - The method will be called remotely for the given peer, using an unreliable protocol. - </constant> - </constants> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml deleted file mode 100644 index 03fef9c13b..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptFunctionState" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node representing a function state. - </brief_description> - <description> - [VisualScriptFunctionState] is returned from [VisualScriptYield] and can be used to resume a paused function call. - </description> - <tutorials> - </tutorials> - <methods> - <method name="connect_to_signal"> - <return type="void" /> - <param index="0" name="obj" type="Object" /> - <param index="1" name="signals" type="String" /> - <param index="2" name="args" type="Array" /> - <description> - Connects this [VisualScriptFunctionState] to a signal in the given object to automatically resume when it's emitted. - </description> - </method> - <method name="is_valid" qualifiers="const"> - <return type="bool" /> - <description> - Returns whether the function state is valid. - </description> - </method> - <method name="resume"> - <return type="Variant" /> - <param index="0" name="args" type="Array" default="[]" /> - <description> - Resumes the function to run from the point it was yielded. - </description> - </method> - </methods> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml b/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml deleted file mode 100644 index 42ada99257..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptGlobalConstant" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node returning a constant from [@GlobalScope]. - </brief_description> - <description> - A Visual Script node returning a constant from [@GlobalScope]. - </description> - <tutorials> - </tutorials> - <members> - <member name="constant" type="int" setter="set_global_constant" getter="get_global_constant" default="0"> - The constant to be used. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptIndexGet.xml b/modules/visual_script/doc_classes/VisualScriptIndexGet.xml deleted file mode 100644 index 8828bf9039..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptIndexGet.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptIndexGet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node for getting a value from an array or a dictionary. - </brief_description> - <description> - [VisualScriptIndexGet] will return the value stored in an array or a dictionary under the given index. - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptIndexSet.xml b/modules/visual_script/doc_classes/VisualScriptIndexSet.xml deleted file mode 100644 index 5c81dcd339..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptIndexSet.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptIndexSet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node for setting a value in an array or a dictionary. - </brief_description> - <description> - [VisualScriptIndexSet] will set the value stored in an array or a dictionary under the given index to the provided new value. - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptInputAction.xml b/modules/visual_script/doc_classes/VisualScriptInputAction.xml deleted file mode 100644 index 51c2eaf353..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptInputAction.xml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptInputAction" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node returning a state of an action. - </brief_description> - <description> - [VisualScriptInputAction] can be used to check if an action is pressed or released. - </description> - <tutorials> - </tutorials> - <members> - <member name="action" type="StringName" setter="set_action_name" getter="get_action_name" default="&"""> - Name of the action. - </member> - <member name="mode" type="int" setter="set_action_mode" getter="get_action_mode" enum="VisualScriptInputAction.Mode" default="0"> - State of the action to check. See [enum Mode] for options. - </member> - </members> - <constants> - <constant name="MODE_PRESSED" value="0" enum="Mode"> - [code]True[/code] if action is pressed. - </constant> - <constant name="MODE_RELEASED" value="1" enum="Mode"> - [code]True[/code] if action is released (i.e. not pressed). - </constant> - <constant name="MODE_JUST_PRESSED" value="2" enum="Mode"> - [code]True[/code] on the frame the action was pressed. - </constant> - <constant name="MODE_JUST_RELEASED" value="3" enum="Mode"> - [code]True[/code] on the frame the action was released. - </constant> - </constants> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptIterator.xml b/modules/visual_script/doc_classes/VisualScriptIterator.xml deleted file mode 100644 index ef6846deba..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptIterator.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptIterator" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Steps through items in a given input. - </brief_description> - <description> - This node steps through each item in a given input. Input can be any sequence data type, such as an [Array] or [String]. When each item has been processed, execution passed out the [code]exit[/code] Sequence port. - [b]Input Ports:[/b] - - Sequence: [code]for (elem) in (input)[/code] - - Data (variant): [code]input[/code] - [b]Output Ports:[/b] - - Sequence: [code]each[/code] - - Sequence: [code]exit[/code] - - Data (variant): [code]elem[/code] - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptLists.xml b/modules/visual_script/doc_classes/VisualScriptLists.xml deleted file mode 100644 index 607965bf71..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptLists.xml +++ /dev/null @@ -1,77 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptLists" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script virtual class for in-graph editable nodes. - </brief_description> - <description> - A Visual Script virtual class that defines the shape and the default behavior of the nodes that have to be in-graph editable nodes. - </description> - <tutorials> - </tutorials> - <methods> - <method name="add_input_data_port"> - <return type="void" /> - <param index="0" name="type" type="int" enum="Variant.Type" /> - <param index="1" name="name" type="String" /> - <param index="2" name="index" type="int" /> - <description> - Adds an input port to the Visual Script node. - </description> - </method> - <method name="add_output_data_port"> - <return type="void" /> - <param index="0" name="type" type="int" enum="Variant.Type" /> - <param index="1" name="name" type="String" /> - <param index="2" name="index" type="int" /> - <description> - Adds an output port to the Visual Script node. - </description> - </method> - <method name="remove_input_data_port"> - <return type="void" /> - <param index="0" name="index" type="int" /> - <description> - Removes an input port from the Visual Script node. - </description> - </method> - <method name="remove_output_data_port"> - <return type="void" /> - <param index="0" name="index" type="int" /> - <description> - Removes an output port from the Visual Script node. - </description> - </method> - <method name="set_input_data_port_name"> - <return type="void" /> - <param index="0" name="index" type="int" /> - <param index="1" name="name" type="String" /> - <description> - Sets the name of an input port. - </description> - </method> - <method name="set_input_data_port_type"> - <return type="void" /> - <param index="0" name="index" type="int" /> - <param index="1" name="type" type="int" enum="Variant.Type" /> - <description> - Sets the type of an input port. - </description> - </method> - <method name="set_output_data_port_name"> - <return type="void" /> - <param index="0" name="index" type="int" /> - <param index="1" name="name" type="String" /> - <description> - Sets the name of an output port. - </description> - </method> - <method name="set_output_data_port_type"> - <return type="void" /> - <param index="0" name="index" type="int" /> - <param index="1" name="type" type="int" enum="Variant.Type" /> - <description> - Sets the type of an output port. - </description> - </method> - </methods> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml deleted file mode 100644 index dbf9049f0a..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptLocalVar" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Gets a local variable's value. - </brief_description> - <description> - Returns a local variable's value. "Var Name" must be supplied, with an optional type. - [b]Input Ports:[/b] - none - [b]Output Ports:[/b] - - Data (variant): [code]get[/code] - </description> - <tutorials> - </tutorials> - <members> - <member name="type" type="int" setter="set_var_type" getter="get_var_type" enum="Variant.Type" default="0"> - The local variable's type. - </member> - <member name="var_name" type="StringName" setter="set_var_name" getter="get_var_name" default="&"new_local""> - The local variable's name. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml deleted file mode 100644 index 1ae4e20f97..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptLocalVarSet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Changes a local variable's value. - </brief_description> - <description> - Changes a local variable's value to the given input. The new value is also provided on an output Data port. - [b]Input Ports:[/b] - - Sequence - - Data (variant): [code]set[/code] - [b]Output Ports:[/b] - - Sequence - - Data (variant): [code]get[/code] - </description> - <tutorials> - </tutorials> - <members> - <member name="type" type="int" setter="set_var_type" getter="get_var_type" enum="Variant.Type" default="0"> - The local variable's type. - </member> - <member name="var_name" type="StringName" setter="set_var_name" getter="get_var_name" default="&"new_local""> - The local variable's name. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptMathConstant.xml b/modules/visual_script/doc_classes/VisualScriptMathConstant.xml deleted file mode 100644 index 01c36e763b..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptMathConstant.xml +++ /dev/null @@ -1,49 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptMathConstant" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Commonly used mathematical constants. - </brief_description> - <description> - Provides common math constants, such as Pi, on an output Data port. - [b]Input Ports:[/b] - none - [b]Output Ports:[/b] - - Data (variant): [code]get[/code] - </description> - <tutorials> - </tutorials> - <members> - <member name="constant" type="int" setter="set_math_constant" getter="get_math_constant" enum="VisualScriptMathConstant.MathConstant" default="0"> - The math constant. - </member> - </members> - <constants> - <constant name="MATH_CONSTANT_ONE" value="0" enum="MathConstant"> - Unity: [code]1[/code]. - </constant> - <constant name="MATH_CONSTANT_PI" value="1" enum="MathConstant"> - Pi: [code]3.141593[/code]. - </constant> - <constant name="MATH_CONSTANT_HALF_PI" value="2" enum="MathConstant"> - Pi divided by two: [code]1.570796[/code]. - </constant> - <constant name="MATH_CONSTANT_TAU" value="3" enum="MathConstant"> - Tau: [code]6.283185[/code]. - </constant> - <constant name="MATH_CONSTANT_E" value="4" enum="MathConstant"> - Mathematical constant [code]e[/code], the natural log base: [code]2.718282[/code]. - </constant> - <constant name="MATH_CONSTANT_SQRT2" value="5" enum="MathConstant"> - Square root of two: [code]1.414214[/code]. - </constant> - <constant name="MATH_CONSTANT_INF" value="6" enum="MathConstant"> - Infinity: [code]inf[/code]. - </constant> - <constant name="MATH_CONSTANT_NAN" value="7" enum="MathConstant"> - Not a number: [code]nan[/code]. - </constant> - <constant name="MATH_CONSTANT_MAX" value="8" enum="MathConstant"> - Represents the size of the [enum MathConstant] enum. - </constant> - </constants> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptNode.xml b/modules/visual_script/doc_classes/VisualScriptNode.xml deleted file mode 100644 index 97c4f8ce76..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptNode.xml +++ /dev/null @@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptNode" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A node which is part of a [VisualScript]. - </brief_description> - <description> - A node which is part of a [VisualScript]. Not to be confused with [Node], which is a part of a [SceneTree]. - </description> - <tutorials> - </tutorials> - <methods> - <method name="get_default_input_value" qualifiers="const"> - <return type="Variant" /> - <param index="0" name="port_idx" type="int" /> - <description> - Returns the default value of a given port. The default value is used when nothing is connected to the port. - </description> - </method> - <method name="get_visual_script" qualifiers="const"> - <return type="VisualScript" /> - <description> - Returns the [VisualScript] instance the node is bound to. - </description> - </method> - <method name="ports_changed_notify"> - <return type="void" /> - <description> - Notify that the node's ports have changed. Usually used in conjunction with [VisualScriptCustomNode] . - </description> - </method> - <method name="set_default_input_value"> - <return type="void" /> - <param index="0" name="port_idx" type="int" /> - <param index="1" name="value" type="Variant" /> - <description> - Change the default value of a given port. - </description> - </method> - </methods> - <signals> - <signal name="ports_changed"> - <description> - Emitted when the available input/output ports are changed. - </description> - </signal> - </signals> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptOperator.xml b/modules/visual_script/doc_classes/VisualScriptOperator.xml deleted file mode 100644 index 47ca6ddb90..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptOperator.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptOperator" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node that performs an operation on two values. - </brief_description> - <description> - [b]Input Ports:[/b] - - Data (variant): [code]A[/code] - - Data (variant): [code]B[/code] - [b]Output Ports:[/b] - - Data (variant): [code]result[/code] - </description> - <tutorials> - </tutorials> - <members> - <member name="operator" type="int" setter="set_operator" getter="get_operator" enum="Variant.Operator" default="6"> - The operation to be performed. See [enum Variant.Operator] for available options. - </member> - <member name="type" type="int" setter="set_typed" getter="get_typed" enum="Variant.Type" default="0"> - The type of the values for this operation. See [enum Variant.Type] for available options. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptPreload.xml b/modules/visual_script/doc_classes/VisualScriptPreload.xml deleted file mode 100644 index 146d6cd9c3..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptPreload.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptPreload" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Creates a new [Resource] or loads one from the filesystem. - </brief_description> - <description> - Creates a new [Resource] or loads one from the filesystem. - [b]Input Ports:[/b] - none - [b]Output Ports:[/b] - - Data (object): [code]res[/code] - </description> - <tutorials> - </tutorials> - <members> - <member name="resource" type="Resource" setter="set_preload" getter="get_preload"> - The [Resource] to load. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml deleted file mode 100644 index 77cd6393a9..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptPropertyGet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node returning a value of a property from an [Object]. - </brief_description> - <description> - [VisualScriptPropertyGet] can return a value of any property from the current object or other objects. - </description> - <tutorials> - </tutorials> - <members> - <member name="base_script" type="String" setter="set_base_script" getter="get_base_script"> - The script to be used when [member set_mode] is set to [constant CALL_MODE_INSTANCE]. - </member> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> - The base type to be used when [member set_mode] is set to [constant CALL_MODE_INSTANCE]. - </member> - <member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type"> - The type to be used when [member set_mode] is set to [constant CALL_MODE_BASIC_TYPE]. - </member> - <member name="index" type="StringName" setter="set_index" getter="get_index"> - The indexed name of the property to retrieve. See [method Object.get_indexed] for details. - </member> - <member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path"> - The node path to use when [member set_mode] is set to [constant CALL_MODE_NODE_PATH]. - </member> - <member name="property" type="StringName" setter="set_property" getter="get_property" default="&"""> - The name of the property to retrieve. Changing this will clear [member index]. - </member> - <member name="set_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptPropertyGet.CallMode" default="0"> - [code]set_mode[/code] determines the target object from which the property will be retrieved. See [enum CallMode] for options. - </member> - </members> - <constants> - <constant name="CALL_MODE_SELF" value="0" enum="CallMode"> - The property will be retrieved from this [Object]. - </constant> - <constant name="CALL_MODE_NODE_PATH" value="1" enum="CallMode"> - The property will be retrieved from the given [Node] in the scene tree. - </constant> - <constant name="CALL_MODE_INSTANCE" value="2" enum="CallMode"> - The property will be retrieved from an instanced node with the given type and script. - </constant> - <constant name="CALL_MODE_BASIC_TYPE" value="3" enum="CallMode"> - The property will be retrieved from a GDScript basic type (e.g. [Vector2]). - </constant> - </constants> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml deleted file mode 100644 index 6cffa328c7..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml +++ /dev/null @@ -1,84 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptPropertySet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node that sets a property of an [Object]. - </brief_description> - <description> - [VisualScriptPropertySet] can set the value of any property from the current object or other objects. - </description> - <tutorials> - </tutorials> - <members> - <member name="assign_op" type="int" setter="set_assign_op" getter="get_assign_op" enum="VisualScriptPropertySet.AssignOp" default="0"> - The additional operation to perform when assigning. See [enum AssignOp] for options. - </member> - <member name="base_script" type="String" setter="set_base_script" getter="get_base_script"> - The script to be used when [member set_mode] is set to [constant CALL_MODE_INSTANCE]. - </member> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> - The base type to be used when [member set_mode] is set to [constant CALL_MODE_INSTANCE]. - </member> - <member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type"> - The type to be used when [member set_mode] is set to [constant CALL_MODE_BASIC_TYPE]. - </member> - <member name="index" type="StringName" setter="set_index" getter="get_index"> - The indexed name of the property to set. See [method Object.set_indexed] for details. - </member> - <member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path"> - The node path to use when [member set_mode] is set to [constant CALL_MODE_NODE_PATH]. - </member> - <member name="property" type="StringName" setter="set_property" getter="get_property" default="&"""> - The name of the property to set. Changing this will clear [member index]. - </member> - <member name="set_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptPropertySet.CallMode" default="0"> - [code]set_mode[/code] determines the target object on which the property will be set. See [enum CallMode] for options. - </member> - </members> - <constants> - <constant name="CALL_MODE_SELF" value="0" enum="CallMode"> - The property will be set on this [Object]. - </constant> - <constant name="CALL_MODE_NODE_PATH" value="1" enum="CallMode"> - The property will be set on the given [Node] in the scene tree. - </constant> - <constant name="CALL_MODE_INSTANCE" value="2" enum="CallMode"> - The property will be set on an instanced node with the given type and script. - </constant> - <constant name="CALL_MODE_BASIC_TYPE" value="3" enum="CallMode"> - The property will be set on a GDScript basic type (e.g. [Vector2]). - </constant> - <constant name="ASSIGN_OP_NONE" value="0" enum="AssignOp"> - The property will be assigned regularly. - </constant> - <constant name="ASSIGN_OP_ADD" value="1" enum="AssignOp"> - The value will be added to the property. Equivalent of doing [code]+=[/code]. - </constant> - <constant name="ASSIGN_OP_SUB" value="2" enum="AssignOp"> - The value will be subtracted from the property. Equivalent of doing [code]-=[/code]. - </constant> - <constant name="ASSIGN_OP_MUL" value="3" enum="AssignOp"> - The property will be multiplied by the value. Equivalent of doing [code]*=[/code]. - </constant> - <constant name="ASSIGN_OP_DIV" value="4" enum="AssignOp"> - The property will be divided by the value. Equivalent of doing [code]/=[/code]. - </constant> - <constant name="ASSIGN_OP_MOD" value="5" enum="AssignOp"> - A modulo operation will be performed on the property and the value. Equivalent of doing [code]%=[/code]. - </constant> - <constant name="ASSIGN_OP_SHIFT_LEFT" value="6" enum="AssignOp"> - The property will be binarly shifted to the left by the given value. Equivalent of doing [code]<<[/code]. - </constant> - <constant name="ASSIGN_OP_SHIFT_RIGHT" value="7" enum="AssignOp"> - The property will be binarly shifted to the right by the given value. Equivalent of doing [code]>>[/code]. - </constant> - <constant name="ASSIGN_OP_BIT_AND" value="8" enum="AssignOp"> - A binary [code]AND[/code] operation will be performed on the property. Equivalent of doing [code]&=[/code]. - </constant> - <constant name="ASSIGN_OP_BIT_OR" value="9" enum="AssignOp"> - A binary [code]OR[/code] operation will be performed on the property. Equivalent of doing [code]|=[/code]. - </constant> - <constant name="ASSIGN_OP_BIT_XOR" value="10" enum="AssignOp"> - A binary [code]XOR[/code] operation will be performed on the property. Equivalent of doing [code]^=[/code]. - </constant> - </constants> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptResourcePath.xml b/modules/visual_script/doc_classes/VisualScriptResourcePath.xml deleted file mode 100644 index 6ca8260ade..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptResourcePath.xml +++ /dev/null @@ -1,13 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptResourcePath" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - </brief_description> - <description> - </description> - <tutorials> - </tutorials> - <members> - <member name="path" type="String" setter="set_resource_path" getter="get_resource_path" default=""""> - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptReturn.xml b/modules/visual_script/doc_classes/VisualScriptReturn.xml deleted file mode 100644 index 1d59392782..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptReturn.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptReturn" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Exits a function and returns an optional value. - </brief_description> - <description> - Ends the execution of a function and returns control to the calling function. Optionally, it can return a [Variant] value. - [b]Input Ports:[/b] - - Sequence - - Data (variant): [code]result[/code] (optional) - [b]Output Ports:[/b] - none - </description> - <tutorials> - </tutorials> - <members> - <member name="return_enabled" type="bool" setter="set_enable_return_value" getter="is_return_value_enabled" default="false"> - If [code]true[/code], the [code]return[/code] input port is available. - </member> - <member name="return_type" type="int" setter="set_return_type" getter="get_return_type" enum="Variant.Type" default="0"> - The return value's data type. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptSceneNode.xml b/modules/visual_script/doc_classes/VisualScriptSceneNode.xml deleted file mode 100644 index a769d11d94..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptSceneNode.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSceneNode" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Node reference. - </brief_description> - <description> - A direct reference to a node. - [b]Input Ports:[/b] - none - [b]Output Ports:[/b] - - Data: [code]node[/code] (obj) - </description> - <tutorials> - </tutorials> - <members> - <member name="node_path" type="NodePath" setter="set_node_path" getter="get_node_path" default="NodePath(".")"> - The node's path in the scene tree. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptSceneTree.xml b/modules/visual_script/doc_classes/VisualScriptSceneTree.xml deleted file mode 100644 index 84ab90892f..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptSceneTree.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSceneTree" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node for accessing [SceneTree] methods. - </brief_description> - <description> - A Visual Script node for accessing [SceneTree] methods. - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptSelect.xml b/modules/visual_script/doc_classes/VisualScriptSelect.xml deleted file mode 100644 index 1aa916f779..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptSelect.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSelect" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Chooses between two input values. - </brief_description> - <description> - Chooses between two input values based on a Boolean condition. - [b]Input Ports:[/b] - - Data (boolean): [code]cond[/code] - - Data (variant): [code]a[/code] - - Data (variant): [code]b[/code] - [b]Output Ports:[/b] - - Data (variant): [code]out[/code] - </description> - <tutorials> - </tutorials> - <members> - <member name="type" type="int" setter="set_typed" getter="get_typed" enum="Variant.Type" default="0"> - The input variables' type. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptSelf.xml b/modules/visual_script/doc_classes/VisualScriptSelf.xml deleted file mode 100644 index 8cc59dbccd..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptSelf.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSelf" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Outputs a reference to the current instance. - </brief_description> - <description> - Provides a reference to the node running the visual script. - [b]Input Ports:[/b] - none - [b]Output Ports:[/b] - - Data (object): [code]instance[/code] - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptSequence.xml b/modules/visual_script/doc_classes/VisualScriptSequence.xml deleted file mode 100644 index 9adbc30e0d..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptSequence.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSequence" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Executes a series of Sequence ports. - </brief_description> - <description> - Steps through a series of one or more output Sequence ports. The [code]current[/code] data port outputs the currently executing item. - [b]Input Ports:[/b] - - Sequence: [code]in order[/code] - [b]Output Ports:[/b] - - Sequence: [code]1[/code] - - Sequence: [code]2 - n[/code] (optional) - - Data (int): [code]current[/code] - </description> - <tutorials> - </tutorials> - <members> - <member name="steps" type="int" setter="set_steps" getter="get_steps" default="1"> - The number of steps in the sequence. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptSubCall.xml b/modules/visual_script/doc_classes/VisualScriptSubCall.xml deleted file mode 100644 index 535e89fc82..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptSubCall.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSubCall" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Calls a method called [code]_subcall[/code] in this object. - </brief_description> - <description> - [VisualScriptSubCall] will call method named [code]_subcall[/code] in the current script. It will fail if the method doesn't exist or the provided arguments are wrong. - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptSwitch.xml b/modules/visual_script/doc_classes/VisualScriptSwitch.xml deleted file mode 100644 index 7befe89f50..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptSwitch.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptSwitch" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Branches program flow based on a given input's value. - </brief_description> - <description> - Branches the flow based on an input's value. Use [b]Case Count[/b] in the Inspector to set the number of branches and each comparison's optional type. - [b]Input Ports:[/b] - - Sequence: [code]'input' is[/code] - - Data (variant): [code]=[/code] - - Data (variant): [code]=[/code] (optional) - - Data (variant): [code]input[/code] - [b]Output Ports:[/b] - - Sequence - - Sequence (optional) - - Sequence: [code]done[/code] - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml deleted file mode 100644 index ec84a75601..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptTypeCast" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node that casts the given value to another type. - </brief_description> - <description> - [VisualScriptTypeCast] will perform a type conversion to an [Object]-derived type. - </description> - <tutorials> - </tutorials> - <members> - <member name="base_script" type="String" setter="set_base_script" getter="get_base_script" default=""""> - The target script class to be converted to. If none, only the [member base_type] will be used. - </member> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> - The target type to be converted to. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml deleted file mode 100644 index 8d99b4b9d0..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptVariableGet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Gets a variable's value. - </brief_description> - <description> - Returns a variable's value. "Var Name" must be supplied, with an optional type. - [b]Input Ports:[/b] - none - [b]Output Ports:[/b] - - Data (variant): [code]value[/code] - </description> - <tutorials> - </tutorials> - <members> - <member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="&"""> - The variable's name. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml deleted file mode 100644 index 4f568cc0f6..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptVariableSet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Changes a variable's value. - </brief_description> - <description> - Changes a variable's value to the given input. - [b]Input Ports:[/b] - - Sequence - - Data (variant): [code]set[/code] - [b]Output Ports:[/b] - - Sequence - </description> - <tutorials> - </tutorials> - <members> - <member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="&"""> - The variable's name. - </member> - </members> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptWhile.xml b/modules/visual_script/doc_classes/VisualScriptWhile.xml deleted file mode 100644 index 4e7cccef17..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptWhile.xml +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptWhile" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - Conditional loop. - </brief_description> - <description> - Loops while a condition is [code]true[/code]. Execution continues out the [code]exit[/code] Sequence port when the loop terminates. - [b]Input Ports:[/b] - - Sequence: [code]while(cond)[/code] - - Data (bool): [code]cond[/code] - [b]Output Ports:[/b] - - Sequence: [code]repeat[/code] - - Sequence: [code]exit[/code] - </description> - <tutorials> - </tutorials> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptYield.xml b/modules/visual_script/doc_classes/VisualScriptYield.xml deleted file mode 100644 index ec757a3ac4..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptYield.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptYield" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node used to pause a function execution. - </brief_description> - <description> - [VisualScriptYield] will pause the function call and return [VisualScriptFunctionState], which can be used to resume the function. - </description> - <tutorials> - </tutorials> - <members> - <member name="mode" type="int" setter="set_yield_mode" getter="get_yield_mode" enum="VisualScriptYield.YieldMode" default="1"> - The mode to use for yielding. See [enum YieldMode] for available options. - </member> - <member name="wait_time" type="float" setter="set_wait_time" getter="get_wait_time"> - The time to wait when [member mode] is set to [constant YIELD_WAIT]. - </member> - </members> - <constants> - <constant name="YIELD_FRAME" value="1" enum="YieldMode"> - Yields during an idle frame. - </constant> - <constant name="YIELD_PHYSICS_FRAME" value="2" enum="YieldMode"> - Yields during a physics frame. - </constant> - <constant name="YIELD_WAIT" value="3" enum="YieldMode"> - Yields a function and waits the given time. - </constant> - </constants> -</class> diff --git a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml deleted file mode 100644 index c3f4bc49c5..0000000000 --- a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptYieldSignal" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> - <brief_description> - A Visual Script node yielding for a signal. - </brief_description> - <description> - [VisualScriptYieldSignal] will pause the function execution until the provided signal is emitted. - </description> - <tutorials> - </tutorials> - <members> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> - The base type to be used when [member call_mode] is set to [constant CALL_MODE_INSTANCE]. - </member> - <member name="call_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptYieldSignal.CallMode" default="0"> - [code]call_mode[/code] determines the target object to wait for the signal emission. See [enum CallMode] for options. - </member> - <member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path"> - The node path to use when [member call_mode] is set to [constant CALL_MODE_NODE_PATH]. - </member> - <member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="&"""> - The signal name to be waited for. - </member> - </members> - <constants> - <constant name="CALL_MODE_SELF" value="0" enum="CallMode"> - A signal from this [Object] will be used. - </constant> - <constant name="CALL_MODE_NODE_PATH" value="1" enum="CallMode"> - A signal from the given [Node] in the scene tree will be used. - </constant> - <constant name="CALL_MODE_INSTANCE" value="2" enum="CallMode"> - A signal from an instanced node with the given type will be used. - </constant> - </constants> -</class> diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp deleted file mode 100644 index a5eb09f786..0000000000 --- a/modules/visual_script/editor/visual_script_editor.cpp +++ /dev/null @@ -1,4976 +0,0 @@ -/*************************************************************************/ -/* visual_script_editor.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "visual_script_editor.h" - -#include "../visual_script_expression.h" -#include "../visual_script_flow_control.h" -#include "../visual_script_func_nodes.h" -#include "../visual_script_nodes.h" -#include "core/input/input.h" -#include "core/object/class_db.h" -#include "core/object/script_language.h" -#include "core/os/keyboard.h" -#include "core/variant/variant.h" -#include "editor/editor_node.h" -#include "editor/editor_resource_preview.h" -#include "editor/editor_scale.h" -#include "editor/editor_settings.h" -#include "editor/editor_undo_redo_manager.h" -#include "scene/gui/check_button.h" -#include "scene/gui/graph_edit.h" -#include "scene/gui/separator.h" -#include "scene/gui/view_panner.h" -#include "scene/main/window.h" - -#ifdef TOOLS_ENABLED - -void VisualScriptEditedProperty::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_edited_property", "value"), &VisualScriptEditedProperty::set_edited_property); - ClassDB::bind_method(D_METHOD("get_edited_property"), &VisualScriptEditedProperty::get_edited_property); - - ADD_PROPERTY(PropertyInfo(Variant::NIL, "edited_property", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_edited_property", "get_edited_property"); -} - -void VisualScriptEditedProperty::set_edited_property(Variant p_variant) { - edited_property = p_variant; -} - -Variant VisualScriptEditedProperty::get_edited_property() const { - return edited_property; -} - -///////////////// - -class VisualScriptEditorSignalEdit : public Object { - GDCLASS(VisualScriptEditorSignalEdit, Object); - - StringName sig; - -public: - Ref<EditorUndoRedoManager> undo_redo; - Ref<VisualScript> script; - -protected: - static void _bind_methods() { - ClassDB::bind_method("_sig_changed", &VisualScriptEditorSignalEdit::_sig_changed); - ADD_SIGNAL(MethodInfo("changed")); - } - - void _sig_changed() { - notify_property_list_changed(); - emit_signal(SNAME("changed")); - } - - bool _set(const StringName &p_name, const Variant &p_value) { - if (sig == StringName()) { - return false; - } - - if (p_name == "argument_count") { - int new_argc = p_value; - int argc = script->custom_signal_get_argument_count(sig); - if (argc == new_argc) { - return true; - } - - undo_redo->create_action(TTR("Change Signal Arguments")); - - if (new_argc < argc) { - for (int i = new_argc; i < argc; i++) { - undo_redo->add_do_method(script.ptr(), "custom_signal_remove_argument", sig, new_argc); - undo_redo->add_undo_method(script.ptr(), "custom_signal_add_argument", sig, script->custom_signal_get_argument_name(sig, i), script->custom_signal_get_argument_type(sig, i), -1); - } - } else if (new_argc > argc) { - for (int i = argc; i < new_argc; i++) { - undo_redo->add_do_method(script.ptr(), "custom_signal_add_argument", sig, Variant::NIL, "arg" + itos(i + 1), -1); - undo_redo->add_undo_method(script.ptr(), "custom_signal_remove_argument", sig, argc); - } - } - - undo_redo->add_do_method(this, "_sig_changed"); - undo_redo->add_undo_method(this, "_sig_changed"); - - undo_redo->commit_action(); - - return true; - } - if (String(p_name).begins_with("argument/")) { - int idx = String(p_name).get_slice("/", 1).to_int() - 1; - ERR_FAIL_INDEX_V(idx, script->custom_signal_get_argument_count(sig), false); - String what = String(p_name).get_slice("/", 2); - if (what == "type") { - int old_type = script->custom_signal_get_argument_type(sig, idx); - int new_type = p_value; - undo_redo->create_action(TTR("Change Argument Type")); - undo_redo->add_do_method(script.ptr(), "custom_signal_set_argument_type", sig, idx, new_type); - undo_redo->add_undo_method(script.ptr(), "custom_signal_set_argument_type", sig, idx, old_type); - undo_redo->commit_action(); - - return true; - } - - if (what == "name") { - String old_name = script->custom_signal_get_argument_name(sig, idx); - String new_name = p_value; - undo_redo->create_action(TTR("Change Argument name")); - undo_redo->add_do_method(script.ptr(), "custom_signal_set_argument_name", sig, idx, new_name); - undo_redo->add_undo_method(script.ptr(), "custom_signal_set_argument_name", sig, idx, old_name); - undo_redo->commit_action(); - return true; - } - } - - return false; - } - - bool _get(const StringName &p_name, Variant &r_ret) const { - if (sig == StringName()) { - return false; - } - - if (p_name == "argument_count") { - r_ret = script->custom_signal_get_argument_count(sig); - return true; - } - if (String(p_name).begins_with("argument/")) { - int idx = String(p_name).get_slice("/", 1).to_int() - 1; - ERR_FAIL_INDEX_V(idx, script->custom_signal_get_argument_count(sig), false); - String what = String(p_name).get_slice("/", 2); - if (what == "type") { - r_ret = script->custom_signal_get_argument_type(sig, idx); - return true; - } - if (what == "name") { - r_ret = script->custom_signal_get_argument_name(sig, idx); - return true; - } - } - - return false; - } - void _get_property_list(List<PropertyInfo> *p_list) const { - if (sig == StringName()) { - return; - } - - p_list->push_back(PropertyInfo(Variant::INT, "argument_count", PROPERTY_HINT_RANGE, "0,256")); - String argt = "Variant"; - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - argt += "," + Variant::get_type_name(Variant::Type(i)); - } - - for (int i = 0; i < script->custom_signal_get_argument_count(sig); i++) { - p_list->push_back(PropertyInfo(Variant::INT, "argument/" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt)); - p_list->push_back(PropertyInfo(Variant::STRING, "argument/" + itos(i + 1) + "/name")); - } - } - -public: - void edit(const StringName &p_sig) { - sig = p_sig; - notify_property_list_changed(); - } -}; - -class VisualScriptEditorVariableEdit : public Object { - GDCLASS(VisualScriptEditorVariableEdit, Object); - - StringName var; - -public: - Ref<EditorUndoRedoManager> undo_redo; - Ref<VisualScript> script; - -protected: - static void _bind_methods() { - ClassDB::bind_method("_var_changed", &VisualScriptEditorVariableEdit::_var_changed); - ClassDB::bind_method("_var_value_changed", &VisualScriptEditorVariableEdit::_var_value_changed); - ADD_SIGNAL(MethodInfo("changed")); - } - - void _var_changed() { - notify_property_list_changed(); - emit_signal(SNAME("changed")); - } - void _var_value_changed() { - emit_signal(SNAME("changed")); - } - - bool _set(const StringName &p_name, const Variant &p_value) { - if (var == StringName()) { - return false; - } - - if (String(p_name) == "value") { - undo_redo->create_action(TTR("Set Variable Default Value")); - Variant current = script->get_variable_default_value(var); - undo_redo->add_do_method(script.ptr(), "set_variable_default_value", var, p_value); - undo_redo->add_undo_method(script.ptr(), "set_variable_default_value", var, current); - undo_redo->add_do_method(this, "_var_value_changed"); - undo_redo->add_undo_method(this, "_var_value_changed"); - undo_redo->commit_action(); - return true; - } - - Dictionary d = script->call("get_variable_info", var); - - if (String(p_name) == "type") { - Dictionary dc = d.duplicate(); - dc["type"] = p_value; - undo_redo->create_action(TTR("Set Variable Type")); - undo_redo->add_do_method(script.ptr(), "set_variable_info", var, dc); - undo_redo->add_undo_method(script.ptr(), "set_variable_info", var, d); - - // Setting the default value. - Variant::Type type = (Variant::Type)(int)p_value; - if (type != Variant::NIL) { - Variant default_value; - Callable::CallError ce; - Variant::construct(type, default_value, nullptr, 0, ce); - if (ce.error == Callable::CallError::CALL_OK) { - undo_redo->add_do_method(script.ptr(), "set_variable_default_value", var, default_value); - undo_redo->add_undo_method(script.ptr(), "set_variable_default_value", var, dc["value"]); - } - } - - undo_redo->add_do_method(this, "_var_changed"); - undo_redo->add_undo_method(this, "_var_changed"); - undo_redo->commit_action(); - return true; - } - - if (String(p_name) == "hint") { - Dictionary dc = d.duplicate(); - dc["hint"] = p_value; - undo_redo->create_action(TTR("Set Variable Type")); - undo_redo->add_do_method(script.ptr(), "set_variable_info", var, dc); - undo_redo->add_undo_method(script.ptr(), "set_variable_info", var, d); - undo_redo->add_do_method(this, "_var_changed"); - undo_redo->add_undo_method(this, "_var_changed"); - undo_redo->commit_action(); - return true; - } - - if (String(p_name) == "hint_string") { - Dictionary dc = d.duplicate(); - dc["hint_string"] = p_value; - undo_redo->create_action(TTR("Set Variable Type")); - undo_redo->add_do_method(script.ptr(), "set_variable_info", var, dc); - undo_redo->add_undo_method(script.ptr(), "set_variable_info", var, d); - undo_redo->add_do_method(this, "_var_changed"); - undo_redo->add_undo_method(this, "_var_changed"); - undo_redo->commit_action(); - return true; - } - - if (String(p_name) == "export") { - script->set_variable_export(var, p_value); - InspectorDock::get_inspector_singleton()->update_tree(); - return true; - } - - return false; - } - - bool _get(const StringName &p_name, Variant &r_ret) const { - if (var == StringName()) { - return false; - } - - if (String(p_name) == "value") { - r_ret = script->get_variable_default_value(var); - return true; - } - - PropertyInfo pinfo = script->get_variable_info(var); - - if (String(p_name) == "type") { - r_ret = pinfo.type; - return true; - } - if (String(p_name) == "hint") { - r_ret = pinfo.hint; - return true; - } - if (String(p_name) == "hint_string") { - r_ret = pinfo.hint_string; - return true; - } - - if (String(p_name) == "export") { - r_ret = script->get_variable_export(var); - return true; - } - - return false; - } - void _get_property_list(List<PropertyInfo> *p_list) const { - if (var == StringName()) { - return; - } - - String argt = "Variant"; - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - argt += "," + Variant::get_type_name(Variant::Type(i)); - } - p_list->push_back(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt)); - p_list->push_back(PropertyInfo(script->get_variable_info(var).type, "value", script->get_variable_info(var).hint, script->get_variable_info(var).hint_string, PROPERTY_USAGE_DEFAULT)); - // Update this when PropertyHint changes. - p_list->push_back(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,ExpRange,Enum,ExpEasing,Length,SpriteFrame,KeyAccel,Flags,Layers2dRender,Layers2dPhysics,Layer3dRender,Layer3dPhysics,File,Dir,GlobalFile,GlobalDir,ResourceType,MultilineText,PlaceholderText,ColorNoAlpha,ImageCompressLossy,ImageCompressLossLess,ObjectId,String,NodePathToEditedNode,MethodOfVariantType,MethodOfBaseType,MethodOfInstance,MethodOfScript,PropertyOfVariantType,PropertyOfBaseType,PropertyOfInstance,PropertyOfScript,ObjectTooBig,NodePathValidTypes")); - p_list->push_back(PropertyInfo(Variant::STRING, "hint_string")); - p_list->push_back(PropertyInfo(Variant::BOOL, "export")); - } - -public: - void edit(const StringName &p_var) { - var = p_var; - notify_property_list_changed(); - } -}; - -static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) { - Color color; - if (dark_theme) { - switch (p_type) { - case Variant::NIL: - color = Color(0.41, 0.93, 0.74); - break; - - case Variant::BOOL: - color = Color(0.55, 0.65, 0.94); - break; - case Variant::INT: - color = Color(0.49, 0.78, 0.94); - break; - case Variant::FLOAT: - color = Color(0.38, 0.85, 0.96); - break; - case Variant::STRING: - color = Color(0.42, 0.65, 0.93); - break; - - case Variant::VECTOR2: - color = Color(0.74, 0.57, 0.95); - break; - case Variant::VECTOR2I: - color = Color(0.74, 0.57, 0.95); - break; - case Variant::RECT2: - color = Color(0.95, 0.57, 0.65); - break; - case Variant::RECT2I: - color = Color(0.95, 0.57, 0.65); - break; - case Variant::VECTOR3: - color = Color(0.84, 0.49, 0.93); - break; - case Variant::VECTOR3I: - color = Color(0.84, 0.49, 0.93); - break; - case Variant::VECTOR4: - color = Color(0.84, 0.49, 0.94); - break; - case Variant::VECTOR4I: - color = Color(0.84, 0.49, 0.94); - break; - case Variant::TRANSFORM2D: - color = Color(0.77, 0.93, 0.41); - break; - case Variant::PLANE: - color = Color(0.97, 0.44, 0.44); - break; - case Variant::QUATERNION: - color = Color(0.93, 0.41, 0.64); - break; - case Variant::AABB: - color = Color(0.93, 0.47, 0.57); - break; - case Variant::BASIS: - color = Color(0.89, 0.93, 0.41); - break; - case Variant::TRANSFORM3D: - color = Color(0.96, 0.66, 0.43); - break; - - case Variant::COLOR: - color = Color(0.62, 1.0, 0.44); - break; - case Variant::NODE_PATH: - color = Color(0.41, 0.58, 0.93); - break; - case Variant::RID: - color = Color(0.41, 0.93, 0.6); - break; - case Variant::OBJECT: - color = Color(0.47, 0.95, 0.91); - break; - case Variant::DICTIONARY: - color = Color(0.47, 0.93, 0.69); - break; - - case Variant::ARRAY: - color = Color(0.88, 0.88, 0.88); - break; - case Variant::PACKED_BYTE_ARRAY: - color = Color(0.67, 0.96, 0.78); - break; - case Variant::PACKED_INT32_ARRAY: - color = Color(0.69, 0.86, 0.96); - break; - case Variant::PACKED_FLOAT32_ARRAY: - color = Color(0.59, 0.91, 0.97); - break; - case Variant::PACKED_INT64_ARRAY: - color = Color(0.69, 0.86, 0.96); - break; - case Variant::PACKED_FLOAT64_ARRAY: - color = Color(0.59, 0.91, 0.97); - break; - case Variant::PACKED_STRING_ARRAY: - color = Color(0.62, 0.77, 0.95); - break; - case Variant::PACKED_VECTOR2_ARRAY: - color = Color(0.82, 0.7, 0.96); - break; - case Variant::PACKED_VECTOR3_ARRAY: - color = Color(0.87, 0.61, 0.95); - break; - case Variant::PACKED_COLOR_ARRAY: - color = Color(0.91, 1.0, 0.59); - break; - - default: - color.set_hsv(p_type / float(Variant::VARIANT_MAX), 0.7, 0.7); - } - } else { - switch (p_type) { - case Variant::NIL: - color = Color(0.15, 0.89, 0.63); - break; - - case Variant::BOOL: - color = Color(0.43, 0.56, 0.92); - break; - case Variant::INT: - color = Color(0.31, 0.7, 0.91); - break; - case Variant::FLOAT: - color = Color(0.15, 0.8, 0.94); - break; - case Variant::STRING: - color = Color(0.27, 0.56, 0.91); - break; - - case Variant::VECTOR2: - color = Color(0.68, 0.46, 0.93); - break; - case Variant::VECTOR2I: - color = Color(0.68, 0.46, 0.93); - break; - case Variant::RECT2: - color = Color(0.93, 0.46, 0.56); - break; - case Variant::RECT2I: - color = Color(0.93, 0.46, 0.56); - break; - case Variant::VECTOR3: - color = Color(0.86, 0.42, 0.93); - break; - case Variant::VECTOR3I: - color = Color(0.86, 0.42, 0.93); - break; - case Variant::TRANSFORM2D: - color = Color(0.59, 0.81, 0.1); - break; - case Variant::PLANE: - color = Color(0.97, 0.44, 0.44); - break; - case Variant::QUATERNION: - color = Color(0.93, 0.41, 0.64); - break; - case Variant::AABB: - color = Color(0.93, 0.47, 0.57); - break; - case Variant::BASIS: - color = Color(0.7, 0.73, 0.1); - break; - case Variant::TRANSFORM3D: - color = Color(0.96, 0.56, 0.28); - break; - - case Variant::COLOR: - color = Color(0.24, 0.75, 0.0); - break; - case Variant::NODE_PATH: - color = Color(0.41, 0.58, 0.93); - break; - case Variant::RID: - color = Color(0.17, 0.9, 0.45); - break; - case Variant::OBJECT: - color = Color(0.07, 0.84, 0.76); - break; - case Variant::DICTIONARY: - color = Color(0.34, 0.91, 0.62); - break; - - case Variant::ARRAY: - color = Color(0.45, 0.45, 0.45); - break; - case Variant::PACKED_BYTE_ARRAY: - color = Color(0.38, 0.92, 0.6); - break; - case Variant::PACKED_INT32_ARRAY: - color = Color(0.38, 0.73, 0.92); - break; - case Variant::PACKED_FLOAT32_ARRAY: - color = Color(0.25, 0.83, 0.95); - break; - case Variant::PACKED_INT64_ARRAY: - color = Color(0.38, 0.73, 0.92); - break; - case Variant::PACKED_FLOAT64_ARRAY: - color = Color(0.25, 0.83, 0.95); - break; - case Variant::PACKED_STRING_ARRAY: - color = Color(0.38, 0.62, 0.92); - break; - case Variant::PACKED_VECTOR2_ARRAY: - color = Color(0.62, 0.36, 0.92); - break; - case Variant::PACKED_VECTOR3_ARRAY: - color = Color(0.79, 0.35, 0.92); - break; - case Variant::PACKED_COLOR_ARRAY: - color = Color(0.57, 0.73, 0.0); - break; - - default: - color.set_hsv(p_type / float(Variant::VARIANT_MAX), 0.3, 0.3); - } - } - - return color; -} - -void VisualScriptEditor::_update_graph_connections() { - graph->clear_connections(); - - List<VisualScript::SequenceConnection> sequence_conns; - script->get_sequence_connection_list(&sequence_conns); - - for (const VisualScript::SequenceConnection &E : sequence_conns) { - graph->connect_node(itos(E.from_node), E.from_output, itos(E.to_node), 0); - } - - List<VisualScript::DataConnection> data_conns; - script->get_data_connection_list(&data_conns); - - for (VisualScript::DataConnection &dc : data_conns) { - Ref<VisualScriptNode> from_node = script->get_node(dc.from_node); - Ref<VisualScriptNode> to_node = script->get_node(dc.to_node); - - if (to_node->has_input_sequence_port()) { - dc.to_port++; - } - - dc.from_port += from_node->get_output_sequence_port_count(); - - graph->connect_node(itos(dc.from_node), dc.from_port, itos(dc.to_node), dc.to_port); - } -} - -void VisualScriptEditor::_update_graph(int p_only_id) { - if (updating_graph) { - return; - } - - updating_graph = true; - - //byebye all nodes - if (p_only_id >= 0) { - if (graph->has_node(itos(p_only_id))) { - Node *gid = graph->get_node(itos(p_only_id)); - if (gid) { - memdelete(gid); - } - } - } else { - for (int i = 0; i < graph->get_child_count(); i++) { - if (Object::cast_to<GraphNode>(graph->get_child(i))) { - memdelete(graph->get_child(i)); - i--; - } - } - } - graph->show(); - select_func_text->hide(); - - Ref<Texture2D> type_icons[Variant::VARIANT_MAX] = { - Control::get_theme_icon(SNAME("Variant"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("bool"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("int"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("float"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("String"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Vector2"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Vector2i"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Rect2"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Rect2i"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Vector3"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Vector3i"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Transform2D"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Plane"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Quaternion"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("AABB"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Basis"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Transform3D"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Color"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("StringName"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("NodePath"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("RID"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("MiniObject"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Callable"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Signal"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Dictionary"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Array"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedByteArray"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedInt32Array"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedInt64Array"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedFloat32Array"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedFloat64Array"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedStringArray"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedVector2Array"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedVector3Array"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedColorArray"), SNAME("EditorIcons")) - }; - - // Visual script specific theme for MSDF font. - Ref<Theme> vstheme; - vstheme.instantiate(); - Ref<Font> label_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_msdf", "EditorFonts"); - vstheme->set_font("font", "Label", label_font); - vstheme->set_font("font", "LineEdit", label_font); - vstheme->set_font("font", "Button", label_font); - - Ref<Texture2D> seq_port = Control::get_theme_icon(SNAME("VisualShaderPort"), SNAME("EditorIcons")); - List<int> node_ids; - script->get_node_list(&node_ids); - - List<int> ids; - script->get_node_list(&ids); - - for (int &E : ids) { - if (p_only_id >= 0 && p_only_id != E) { - continue; - } - - Ref<VisualScriptNode> node = script->get_node(E); - Vector2 pos = script->get_node_position(E); - - GraphNode *gnode = memnew(GraphNode); - gnode->set_title(node->get_caption()); - gnode->set_position_offset(pos * EDSCALE); - if (error_line == E) { - gnode->set_overlay(GraphNode::OVERLAY_POSITION); - } else if (node->is_breakpoint()) { - gnode->set_overlay(GraphNode::OVERLAY_BREAKPOINT); - } - - gnode->set_meta("__vnode", node); - gnode->set_name(itos(E)); - gnode->connect("dragged", callable_mp(this, &VisualScriptEditor::_node_moved).bind(E)); - gnode->connect("close_request", callable_mp(this, &VisualScriptEditor::_remove_node).bind(E), CONNECT_DEFERRED); - - { - Ref<VisualScriptFunction> v = node; - if (!v.is_valid()) { - gnode->set_show_close_button(true); - } - } - - bool has_gnode_text = false; - - Ref<VisualScriptLists> nd_list = node; - bool is_vslist = nd_list.is_valid(); - if (is_vslist) { - HBoxContainer *hbnc = memnew(HBoxContainer); - if (nd_list->is_input_port_editable()) { - has_gnode_text = true; - Button *btn = memnew(Button); - btn->set_text(TTR("Add Input Port")); - hbnc->add_child(btn); - btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_input_port).bind(E), CONNECT_DEFERRED); - } - if (nd_list->is_output_port_editable()) { - if (nd_list->is_input_port_editable()) { - hbnc->add_spacer(); - } - has_gnode_text = true; - Button *btn = memnew(Button); - btn->set_text(TTR("Add Output Port")); - hbnc->add_child(btn); - btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_output_port).bind(E), CONNECT_DEFERRED); - } - gnode->add_child(hbnc); - } else if (Object::cast_to<VisualScriptExpression>(node.ptr())) { - has_gnode_text = true; - LineEdit *line_edit = memnew(LineEdit); - line_edit->set_text(node->get_text()); - line_edit->set_expand_to_text_length_enabled(true); - line_edit->add_theme_font_override("font", get_theme_font(SNAME("source"), SNAME("EditorFonts"))); - gnode->add_child(line_edit); - line_edit->connect("text_changed", callable_mp(this, &VisualScriptEditor::_expression_text_changed).bind(E)); - } else { - String text = node->get_text(); - if (!text.is_empty()) { - has_gnode_text = true; - Label *label = memnew(Label); - label->set_text(text); - gnode->add_child(label); - } - } - - if (Object::cast_to<VisualScriptComment>(node.ptr())) { - Ref<VisualScriptComment> vsc = node; - gnode->set_comment(true); - gnode->set_resizable(true); - gnode->set_custom_minimum_size(vsc->get_size() * EDSCALE); - gnode->connect("resize_request", callable_mp(this, &VisualScriptEditor::_comment_node_resized).bind(E)); - } - - if (node_styles.has(node->get_category())) { - Ref<StyleBoxFlat> sbf = node_styles[node->get_category()]; - if (gnode->is_comment()) { - sbf = EditorNode::get_singleton()->get_theme_base()->get_theme()->get_stylebox(SNAME("comment"), SNAME("GraphNode")); - } - - Color c = sbf->get_border_color(); - c = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0, 0.85) : Color(0.0, 0.0, 0.0, 0.85); - Color ic = c; - gnode->add_theme_color_override("title_color", c); - c.a = 1; - gnode->add_theme_color_override("close_color", c); - gnode->add_theme_color_override("resizer_color", ic); - gnode->add_theme_style_override("frame", sbf); - } - - const Color mono_color = get_theme_color(SNAME("mono_color"), SNAME("Editor")); - - int slot_idx = 0; - - bool single_seq_output = node->get_output_sequence_port_count() == 1 && node->get_output_sequence_port_text(0) == String(); - if ((node->has_input_sequence_port() || single_seq_output) || has_gnode_text) { - // IF has_gnode_text is true BUT we have no sequence ports to draw (in here), - // we still draw the disabled default ones to shift up the slots by one, - // so the slots DON'T start with the content text. - - // IF has_gnode_text is false, but we DO want to draw default sequence ports, - // we draw a dummy text to take up the position of the sequence nodes, so all the other ports are still aligned correctly. - if (!has_gnode_text) { - Label *dummy = memnew(Label); - dummy->set_text(" "); - gnode->add_child(dummy); - } - gnode->set_slot(0, node->has_input_sequence_port(), TYPE_SEQUENCE, mono_color, single_seq_output, TYPE_SEQUENCE, mono_color, seq_port, seq_port); - slot_idx++; - } - - int mixed_seq_ports = 0; - - if (!single_seq_output) { - if (node->has_mixed_input_and_sequence_ports()) { - mixed_seq_ports = node->get_output_sequence_port_count(); - } else { - for (int i = 0; i < node->get_output_sequence_port_count(); i++) { - Label *text2 = memnew(Label); - text2->set_text(node->get_output_sequence_port_text(i)); - text2->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT); - gnode->add_child(text2); - gnode->set_slot(slot_idx, false, 0, Color(), true, TYPE_SEQUENCE, mono_color, seq_port, seq_port); - slot_idx++; - } - } - } - - for (int i = 0; i < MAX(node->get_output_value_port_count(), MAX(mixed_seq_ports, node->get_input_value_port_count())); i++) { - bool left_ok = false; - Variant::Type left_type = Variant::NIL; - String left_name; - - if (i < node->get_input_value_port_count()) { - PropertyInfo pi = node->get_input_value_port_info(i); - left_ok = true; - left_type = pi.type; - left_name = pi.name; - } - - bool right_ok = false; - Variant::Type right_type = Variant::NIL; - String right_name; - - if (i >= mixed_seq_ports && i < node->get_output_value_port_count() + mixed_seq_ports) { - PropertyInfo pi = node->get_output_value_port_info(i - mixed_seq_ports); - right_ok = true; - right_type = pi.type; - right_name = pi.name; - } - VBoxContainer *vbc = memnew(VBoxContainer); - HBoxContainer *hbc = memnew(HBoxContainer); - HBoxContainer *hbc2 = memnew(HBoxContainer); - vbc->add_child(hbc); - vbc->add_child(hbc2); - if (left_ok) { - Ref<Texture2D> t; - if (left_type >= 0 && left_type < Variant::VARIANT_MAX) { - t = type_icons[left_type]; - } - if (t.is_valid()) { - TextureRect *tf = memnew(TextureRect); - tf->set_texture(t); - tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); - hbc->add_child(tf); - } - - if (is_vslist) { - if (nd_list->is_input_port_name_editable()) { - LineEdit *name_box = memnew(LineEdit); - hbc->add_child(name_box); - name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0)); - name_box->set_text(left_name); - name_box->set_expand_to_text_length_enabled(true); - name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size).bind(E)); - name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out).bind(name_box, E, i, true)); - } else { - hbc->add_child(memnew(Label(left_name))); - } - - if (nd_list->is_input_port_type_editable()) { - OptionButton *opbtn = memnew(OptionButton); - for (int j = Variant::NIL; j < Variant::VARIANT_MAX; j++) { - opbtn->add_item(Variant::get_type_name(Variant::Type(j))); - } - opbtn->select(left_type); - opbtn->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); - hbc->add_child(opbtn); - opbtn->connect("item_selected", callable_mp(this, &VisualScriptEditor::_change_port_type).bind(E, i, true), CONNECT_DEFERRED); - } - - Button *rmbtn = memnew(Button); - rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); - hbc->add_child(rmbtn); - rmbtn->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_input_port).bind(E, i), CONNECT_DEFERRED); - } else { - hbc->add_child(memnew(Label(left_name))); - } - - if (left_type != Variant::NIL && !script->is_input_value_port_connected(E, i)) { - PropertyInfo pi = node->get_input_value_port_info(i); - Button *button = memnew(Button); - Variant value = node->get_default_input_value(i); - if (value.get_type() != left_type) { - //different type? for now convert - //not the same, reconvert - Callable::CallError ce; - const Variant *existingp = &value; - Variant::construct(left_type, value, &existingp, 1, ce); - } - - if (left_type == Variant::COLOR) { - button->set_custom_minimum_size(Size2(30, 0) * EDSCALE); - button->connect("draw", callable_mp(this, &VisualScriptEditor::_draw_color_over_button).bind(button, value)); - } else if (left_type == Variant::OBJECT && Ref<Resource>(value).is_valid()) { - Ref<Resource> res = value; - Array arr; - arr.push_back(button->get_instance_id()); - arr.push_back(String(value)); - EditorResourcePreview::get_singleton()->queue_edited_resource_preview(res, this, "_button_resource_previewed", arr); - - } else if (pi.type == Variant::INT && pi.hint == PROPERTY_HINT_ENUM) { - bool found = false; - const Vector<String> options = pi.hint_string.split(","); - int64_t current_val = 0; - for (const String &option : options) { - Vector<String> text_split = option.split(":"); - if (text_split.size() != 1) { - current_val = text_split[1].to_int(); - } - if (value.operator int() == current_val) { - button->set_text(text_split[0]); - found = true; - break; - } - current_val += 1; - } - if (!found) { - button->set_text(value); - } - } else if (pi.type == Variant::INT && pi.hint == PROPERTY_HINT_FLAGS) { - Vector<String> value_texts; - const Vector<String> options = pi.hint_string.split(","); - uint32_t v = value; - for (const String &option : options) { - uint32_t current_val; - Vector<String> text_split = option.split(":"); - if (text_split.size() != -1) { - current_val = text_split[1].to_int(); - } else { - current_val = 1 << i; - } - if ((v & current_val) == current_val) { - value_texts.push_back(text_split[0]); - } - } - if (value_texts.size() != 0) { - String value_text = value_texts[0]; - for (const String &text : value_texts) { - value_text += " | " + text; - } - button->set_text(value_text); - } else { - button->set_text(value); - } - } else { - button->set_text(value); - } - button->connect("pressed", callable_mp(this, &VisualScriptEditor::_default_value_edited).bind(button, E, i)); - hbc2->add_child(button); - } - } else { - Control *c = memnew(Control); - c->set_custom_minimum_size(Size2(10, 0) * EDSCALE); - hbc->add_child(c); - } - - hbc->add_spacer(); - hbc2->add_spacer(); - - if (i < mixed_seq_ports) { - Label *text2 = memnew(Label); - text2->set_text(node->get_output_sequence_port_text(i)); - text2->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT); - hbc->add_child(text2); - } - - if (right_ok) { - if (is_vslist) { - Button *rmbtn = memnew(Button); - rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); - hbc->add_child(rmbtn); - rmbtn->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_output_port).bind(E, i), CONNECT_DEFERRED); - - if (nd_list->is_output_port_type_editable()) { - OptionButton *opbtn = memnew(OptionButton); - for (int j = Variant::NIL; j < Variant::VARIANT_MAX; j++) { - opbtn->add_item(Variant::get_type_name(Variant::Type(j))); - } - opbtn->select(right_type); - opbtn->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); - hbc->add_child(opbtn); - opbtn->connect("item_selected", callable_mp(this, &VisualScriptEditor::_change_port_type).bind(E, i, false), CONNECT_DEFERRED); - } - - if (nd_list->is_output_port_name_editable()) { - LineEdit *name_box = memnew(LineEdit); - hbc->add_child(name_box); - name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0)); - name_box->set_text(right_name); - name_box->set_expand_to_text_length_enabled(true); - name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size).bind(E)); - name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out).bind(name_box, E, i, false)); - } else { - hbc->add_child(memnew(Label(right_name))); - } - } else { - hbc->add_child(memnew(Label(right_name))); - } - - Ref<Texture2D> t; - if (right_type >= 0 && right_type < Variant::VARIANT_MAX) { - t = type_icons[right_type]; - } - if (t.is_valid()) { - TextureRect *tf = memnew(TextureRect); - tf->set_texture(t); - tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); - hbc->add_child(tf); - } - } - - gnode->add_child(vbc); - - bool dark_theme = get_theme_constant(SNAME("dark_theme"), SNAME("Editor")); - if (i < mixed_seq_ports) { - gnode->set_slot(slot_idx, left_ok, left_type, _color_from_type(left_type, dark_theme), true, TYPE_SEQUENCE, mono_color, Ref<Texture2D>(), seq_port); - } else { - gnode->set_slot(slot_idx, left_ok, left_type, _color_from_type(left_type, dark_theme), right_ok, right_type, _color_from_type(right_type, dark_theme)); - } - - slot_idx++; - } - graph->add_child(gnode); - gnode->set_theme(vstheme); - if (gnode->is_comment()) { - graph->move_child(gnode, 0); - } - } - - _update_graph_connections(); - - float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity"); - graph->set_minimap_opacity(graph_minimap_opacity); - - float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature"); - graph->set_connection_lines_curvature(graph_lines_curvature); - - // Use default_func instead of default_func for now I think that should be good stop gap solution to ensure not breaking anything. - graph->call_deferred(SNAME("set_scroll_ofs"), script->get_scroll() * EDSCALE); - updating_graph = false; -} - -void VisualScriptEditor::_change_port_type(int p_select, int p_id, int p_port, bool is_input) { - Ref<VisualScriptLists> vsn = script->get_node(p_id); - if (!vsn.is_valid()) { - return; - } - - undo_redo->create_action(TTR("Change Port Type")); - if (is_input) { - undo_redo->add_do_method(vsn.ptr(), "set_input_data_port_type", p_port, Variant::Type(p_select)); - undo_redo->add_undo_method(vsn.ptr(), "set_input_data_port_type", p_port, vsn->get_input_value_port_info(p_port).type); - } else { - undo_redo->add_do_method(vsn.ptr(), "set_output_data_port_type", p_port, Variant::Type(p_select)); - undo_redo->add_undo_method(vsn.ptr(), "set_output_data_port_type", p_port, vsn->get_output_value_port_info(p_port).type); - } - undo_redo->commit_action(); -} - -void VisualScriptEditor::_update_node_size(int p_id) { - Node *node = graph->get_node(itos(p_id)); - if (Object::cast_to<Control>(node)) { - Object::cast_to<Control>(node)->reset_size(); // Shrink if text is smaller. - } -} - -void VisualScriptEditor::_port_name_focus_out(const Node *p_name_box, int p_id, int p_port, bool is_input) { - Ref<VisualScriptLists> vsn = script->get_node(p_id); - if (!vsn.is_valid()) { - return; - } - - String text; - - if (Object::cast_to<LineEdit>(p_name_box)) { - text = Object::cast_to<LineEdit>(p_name_box)->get_text(); - } else { - return; - } - - undo_redo->create_action(TTR("Change Port Name")); - if (is_input) { - undo_redo->add_do_method(vsn.ptr(), "set_input_data_port_name", p_port, text); - undo_redo->add_undo_method(vsn.ptr(), "set_input_data_port_name", p_port, vsn->get_input_value_port_info(p_port).name); - } else { - undo_redo->add_do_method(vsn.ptr(), "set_output_data_port_name", p_port, text); - undo_redo->add_undo_method(vsn.ptr(), "set_output_data_port_name", p_port, vsn->get_output_value_port_info(p_port).name); - } - undo_redo->commit_action(); -} - -void VisualScriptEditor::_update_members() { - ERR_FAIL_COND(!script.is_valid()); - - updating_members = true; - - members->clear(); - TreeItem *root = members->create_item(); - - TreeItem *functions = members->create_item(root); - functions->set_selectable(0, false); - functions->set_text(0, TTR("Functions:")); - functions->add_button(0, Control::get_theme_icon(SNAME("Override"), SNAME("EditorIcons")), 1, false, TTR("Override an existing built-in function.")); - functions->add_button(0, Control::get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), 0, false, TTR("Create a new function.")); - functions->set_custom_color(0, Control::get_theme_color(SNAME("mono_color"), SNAME("Editor"))); - - List<StringName> func_names; - script->get_function_list(&func_names); - func_names.sort_custom<StringName::AlphCompare>(); - for (const StringName &E : func_names) { - TreeItem *ti = members->create_item(functions); - ti->set_text(0, E); - ti->set_selectable(0, true); - ti->set_metadata(0, E); - ti->add_button(0, Control::get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")), 0); - if (selected == E) { - ti->select(0); - } - } - - TreeItem *variables = members->create_item(root); - variables->set_selectable(0, false); - variables->set_text(0, TTR("Variables:")); - variables->add_button(0, Control::get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), -1, false, TTR("Create a new variable.")); - variables->set_custom_color(0, Control::get_theme_color(SNAME("mono_color"), SNAME("Editor"))); - - Ref<Texture2D> type_icons[Variant::VARIANT_MAX] = { - Control::get_theme_icon(SNAME("Variant"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("bool"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("int"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("float"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("String"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Vector2"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Vector2i"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Rect2"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Rect2i"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Vector3"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Vector3i"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Transform2D"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Plane"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Quaternion"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("AABB"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Basis"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Transform3D"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Color"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("StringName"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("NodePath"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("RID"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("MiniObject"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Callable"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Signal"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Dictionary"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("Array"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedByteArray"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedInt32Array"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedInt64Array"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedFloat32Array"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedFloat64Array"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedStringArray"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedVector2Array"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedVector3Array"), SNAME("EditorIcons")), - Control::get_theme_icon(SNAME("PackedColorArray"), SNAME("EditorIcons")) - }; - - List<StringName> var_names; - script->get_variable_list(&var_names); - var_names.sort_custom<StringName::AlphCompare>(); - for (const StringName &E : var_names) { - TreeItem *ti = members->create_item(variables); - - ti->set_text(0, E); - - ti->set_suffix(0, "= " + _sanitized_variant_text(E)); - ti->set_icon(0, type_icons[script->get_variable_info(E).type]); - - ti->set_selectable(0, true); - ti->set_editable(0, true); - ti->set_metadata(0, E); - if (selected == E) { - ti->select(0); - } - } - - TreeItem *_signals = members->create_item(root); - _signals->set_selectable(0, false); - _signals->set_text(0, TTR("Signals:")); - _signals->add_button(0, Control::get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), -1, false, TTR("Create a new signal.")); - _signals->set_custom_color(0, Control::get_theme_color(SNAME("mono_color"), SNAME("Editor"))); - - List<StringName> signal_names; - script->get_custom_signal_list(&signal_names); - for (const StringName &E : signal_names) { - TreeItem *ti = members->create_item(_signals); - ti->set_text(0, E); - ti->set_selectable(0, true); - ti->set_editable(0, true); - ti->set_metadata(0, E); - if (selected == E) { - ti->select(0); - } - } - - String base_type = script->get_instance_base_type(); - String icon_type = base_type; - if (!Control::has_theme_icon(base_type, SNAME("EditorIcons"))) { - icon_type = "Object"; - } - - base_type_select->set_text(base_type); - base_type_select->set_icon(Control::get_theme_icon(icon_type, SNAME("EditorIcons"))); - - updating_members = false; -} - -String VisualScriptEditor::_sanitized_variant_text(const StringName &property_name) { - Variant var = script->get_variable_default_value(property_name); - - if (script->get_variable_info(property_name).type != Variant::NIL) { - Callable::CallError ce; - const Variant *converted = &var; - Variant n; - Variant::construct(script->get_variable_info(property_name).type, n, &converted, 1, ce); - var = n; - } - - return String(var); -} - -void VisualScriptEditor::_member_selected() { - if (updating_members) { - return; - } - - TreeItem *ti = members->get_selected(); - ERR_FAIL_COND(!ti); - - selected = ti->get_metadata(0); - - if (ti->get_parent() == members->get_root()->get_first_child()) { -#ifdef MACOS_ENABLED - bool held_ctrl = Input::get_singleton()->is_key_pressed(Key::META); -#else - bool held_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL); -#endif - if (held_ctrl) { - ERR_FAIL_COND(!script->has_function(selected)); - _center_on_node(script->get_function_node_id(selected)); - } - } -} - -void VisualScriptEditor::_member_edited() { - if (updating_members) { - return; - } - - TreeItem *ti = members->get_edited(); - ERR_FAIL_COND(!ti); - - String name = ti->get_metadata(0); - String new_name = ti->get_text(0); - - if (name == new_name) { - return; - } - - if (!new_name.is_valid_identifier()) { - EditorNode::get_singleton()->show_warning(TTR("Name is not a valid identifier:") + " " + new_name); - updating_members = true; - ti->set_text(0, name); - updating_members = false; - return; - } - - if (script->has_function(new_name) || script->has_variable(new_name) || script->has_custom_signal(new_name)) { - EditorNode::get_singleton()->show_warning(TTR("Name already in use by another func/var/signal:") + " " + new_name); - updating_members = true; - ti->set_text(0, name); - updating_members = false; - return; - } - - TreeItem *root = members->get_root(); - - if (ti->get_parent() == root->get_first_child()) { - selected = new_name; - - int node_id = script->get_function_node_id(name); - Ref<VisualScriptFunction> func; - if (script->has_node(node_id)) { - func = script->get_node(node_id); - } - undo_redo->create_action(TTR("Rename Function")); - undo_redo->add_do_method(script.ptr(), "rename_function", name, new_name); - undo_redo->add_undo_method(script.ptr(), "rename_function", new_name, name); - if (func.is_valid()) { - undo_redo->add_do_method(func.ptr(), "set_name", new_name); - undo_redo->add_undo_method(func.ptr(), "set_name", name); - } - - // Also fix all function calls. - List<int> lst; - script->get_node_list(&lst); - for (int &F : lst) { - Ref<VisualScriptFunctionCall> fncall = script->get_node(F); - if (!fncall.is_valid()) { - continue; - } - if (fncall->get_function() == name) { - undo_redo->add_do_method(fncall.ptr(), "set_function", new_name); - undo_redo->add_undo_method(fncall.ptr(), "set_function", name); - } - } - - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->add_do_method(this, "emit_signal", "edited_script_changed"); - undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed"); - undo_redo->commit_action(); - - return; // Or crash because it will become invalid. - } - - if (ti->get_parent() == root->get_first_child()->get_next()) { - selected = new_name; - undo_redo->create_action(TTR("Rename Variable")); - undo_redo->add_do_method(script.ptr(), "rename_variable", name, new_name); - undo_redo->add_undo_method(script.ptr(), "rename_variable", new_name, name); - - // Also fix all variable setter & getter calls - List<int> lst; - script->get_node_list(&lst); - for (int &P : lst) { - Ref<VisualScriptPropertySet> pset = script->get_node(P); - if (pset.is_valid() && pset->get_property() == name) { - undo_redo->add_do_method(pset.ptr(), "set_property", new_name); - undo_redo->add_undo_method(pset.ptr(), "set_property", name); - } - Ref<VisualScriptPropertyGet> pget = script->get_node(P); - if (pget.is_valid() && pget->get_property() == name) { - undo_redo->add_do_method(pget.ptr(), "set_property", new_name); - undo_redo->add_undo_method(pget.ptr(), "set_property", name); - } - } - - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->add_do_method(this, "emit_signal", "edited_script_changed"); - undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed"); - undo_redo->commit_action(); - - return; // Or crash because it will become invalid. - } - - if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) { - selected = new_name; - undo_redo->create_action(TTR("Rename Signal")); - undo_redo->add_do_method(script.ptr(), "rename_custom_signal", name, new_name); - undo_redo->add_undo_method(script.ptr(), "rename_custom_signal", new_name, name); - - // Also fix all signal emitting nodes - List<int> lst; - script->get_node_list(&lst); - for (int &P : lst) { - Ref<VisualScriptEmitSignal> psig = script->get_node(P); - if (psig.is_valid() && psig->get_signal() == name) { - undo_redo->add_do_method(psig.ptr(), "set_signal", new_name); - undo_redo->add_undo_method(psig.ptr(), "set_signal", name); - } - } - - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->add_do_method(this, "emit_signal", "edited_script_changed"); - undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed"); - undo_redo->commit_action(); - - return; // Or crash because it will become invalid. - } -} - -void VisualScriptEditor::_create_function_dialog() { - function_create_dialog->popup_centered(); - func_name_box->set_text(""); - func_name_box->grab_focus(); - for (int i = 0; i < func_input_vbox->get_child_count(); i++) { - Node *nd = func_input_vbox->get_child(i); - nd->queue_delete(); - } -} - -void VisualScriptEditor::_create_function() { - String name = _validate_name((func_name_box->get_text().is_empty()) ? "new_func" : func_name_box->get_text()); - selected = name; - Vector2 pos = _get_available_pos(); - - Ref<VisualScriptFunction> func_node; - func_node.instantiate(); - func_node->set_name(name); - - for (int i = 0; i < func_input_vbox->get_child_count(); i++) { - OptionButton *opbtn = Object::cast_to<OptionButton>(func_input_vbox->get_child(i)->get_child(3)); - LineEdit *lne = Object::cast_to<LineEdit>(func_input_vbox->get_child(i)->get_child(1)); - if (!opbtn || !lne) { - continue; - } - Variant::Type arg_type = Variant::Type(opbtn->get_selected()); - String arg_name = lne->get_text(); - func_node->add_argument(arg_type, arg_name); - } - - int func_node_id = script->get_available_id(); - - undo_redo->create_action(TTR("Add Function")); - undo_redo->add_do_method(script.ptr(), "add_function", name, func_node_id); - undo_redo->add_undo_method(script.ptr(), "remove_function", name); - undo_redo->add_do_method(script.ptr(), "add_node", func_node_id, func_node, pos); - undo_redo->add_undo_method(script.ptr(), "remove_node", func_node_id); - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->add_do_method(this, "emit_signal", "edited_script_changed"); - undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed"); - undo_redo->commit_action(); - - _update_graph(); -} - -void VisualScriptEditor::_add_node_dialog() { - _generic_search(graph->get_global_position() + Vector2(55, 80), true); -} - -void VisualScriptEditor::_add_func_input() { - HBoxContainer *hbox = memnew(HBoxContainer); - hbox->set_h_size_flags(SIZE_EXPAND_FILL); - - Label *name_label = memnew(Label); - name_label->set_text(TTR("Name:")); - hbox->add_child(name_label); - - LineEdit *name_box = memnew(LineEdit); - name_box->set_h_size_flags(SIZE_EXPAND_FILL); - name_box->set_text("input"); - name_box->connect("focus_entered", callable_mp(this, &VisualScriptEditor::_deselect_input_names)); - hbox->add_child(name_box); - - Label *type_label = memnew(Label); - type_label->set_text(TTR("Type:")); - hbox->add_child(type_label); - - OptionButton *type_box = memnew(OptionButton); - type_box->set_custom_minimum_size(Size2(120 * EDSCALE, 0)); - for (int i = Variant::NIL; i < Variant::VARIANT_MAX; i++) { - type_box->add_item(Variant::get_type_name(Variant::Type(i))); - } - type_box->select(1); - hbox->add_child(type_box); - - Button *delete_button = memnew(Button); - delete_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); - delete_button->set_tooltip(vformat(TTR("Delete input port"))); - hbox->add_child(delete_button); - - for (int i = 0; i < func_input_vbox->get_child_count(); i++) { - LineEdit *line_edit = (LineEdit *)func_input_vbox->get_child(i)->get_child(1); - line_edit->deselect(); - } - - func_input_vbox->add_child(hbox); - hbox->set_meta("id", hbox->get_index()); - - delete_button->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_func_input).bind(hbox)); - - name_box->select_all(); - name_box->grab_focus(); -} - -void VisualScriptEditor::_remove_func_input(Node *p_node) { - func_input_vbox->remove_child(p_node); - p_node->queue_delete(); -} - -void VisualScriptEditor::_deselect_input_names() { - int cn = func_input_vbox->get_child_count(); - for (int i = 0; i < cn; i++) { - LineEdit *lne = Object::cast_to<LineEdit>(func_input_vbox->get_child(i)->get_child(1)); - if (lne) { - lne->deselect(); - } - } -} - -void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_button, MouseButton p_mouse_button) { - if (p_mouse_button != MouseButton::LEFT) { - return; - } - - TreeItem *ti = Object::cast_to<TreeItem>(p_item); - - TreeItem *root = members->get_root(); - - if (ti->get_parent() == root) { - //main buttons - if (ti == root->get_first_child()) { - // Add function, this one uses menu. - - if (p_button == 1) { - // Ensure script base exists otherwise use custom base type. - ERR_FAIL_COND(script.is_null()); - new_virtual_method_select->select_method_from_base_type(script->get_instance_base_type(), true); - return; - } else if (p_button == 0) { - String name = _validate_name("new_function"); - selected = name; - Vector2 pos = _get_available_pos(); - - Ref<VisualScriptFunction> func_node; - func_node.instantiate(); - func_node->set_name(name); - int fn_id = script->get_available_id(); - - undo_redo->create_action(TTR("Add Function")); - undo_redo->add_do_method(script.ptr(), "add_function", name, fn_id); - undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, pos); - undo_redo->add_undo_method(script.ptr(), "remove_function", name); - undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id); - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->add_do_method(this, "emit_signal", "edited_script_changed"); - undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed"); - undo_redo->commit_action(); - - _update_graph(); - } - - return; // Or crash because it will become invalid. - } - - if (ti == root->get_first_child()->get_next()) { - // Add variable. - String name = _validate_name("new_variable"); - selected = name; - - undo_redo->create_action(TTR("Add Variable")); - undo_redo->add_do_method(script.ptr(), "add_variable", name); - undo_redo->add_undo_method(script.ptr(), "remove_variable", name); - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->add_do_method(this, "emit_signal", "edited_script_changed"); - undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed"); - undo_redo->commit_action(); - return; // Or crash because it will become invalid. - } - - if (ti == root->get_first_child()->get_next()->get_next()) { - // Add variable. - String name = _validate_name("new_signal"); - selected = name; - - undo_redo->create_action(TTR("Add Signal")); - undo_redo->add_do_method(script.ptr(), "add_custom_signal", name); - undo_redo->add_undo_method(script.ptr(), "remove_custom_signal", name); - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->add_do_method(this, "emit_signal", "edited_script_changed"); - undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed"); - undo_redo->commit_action(); - return; // Or crash because it will become invalid. - } - } else if (ti->get_parent() == root->get_first_child()) { - selected = ti->get_text(0); - function_name_edit->set_position(get_screen_position() + get_local_mouse_position() - Vector2(60, -10)); - function_name_edit->popup(); - function_name_box->set_text(selected); - function_name_box->select_all(); - function_name_box->grab_focus(); - } -} - -void VisualScriptEditor::_add_input_port(int p_id) { - Ref<VisualScriptLists> vsn = script->get_node(p_id); - if (!vsn.is_valid()) { - return; - } - - updating_graph = true; - - undo_redo->create_action(TTR("Add Input Port"), UndoRedo::MERGE_ENDS); - undo_redo->add_do_method(vsn.ptr(), "add_input_data_port", Variant::NIL, "arg", -1); - undo_redo->add_do_method(this, "_update_graph", p_id); - - undo_redo->add_undo_method(vsn.ptr(), "remove_input_data_port", vsn->get_input_value_port_count()); - undo_redo->add_undo_method(this, "_update_graph", p_id); - - updating_graph = false; - - undo_redo->commit_action(); -} - -void VisualScriptEditor::_add_output_port(int p_id) { - Ref<VisualScriptLists> vsn = script->get_node(p_id); - if (!vsn.is_valid()) { - return; - } - - updating_graph = true; - - undo_redo->create_action(TTR("Add Output Port"), UndoRedo::MERGE_ENDS); - undo_redo->add_do_method(vsn.ptr(), "add_output_data_port", Variant::NIL, "arg", -1); - undo_redo->add_do_method(this, "_update_graph", p_id); - - undo_redo->add_undo_method(vsn.ptr(), "remove_output_data_port", vsn->get_output_value_port_count()); - undo_redo->add_undo_method(this, "_update_graph", p_id); - - updating_graph = false; - - undo_redo->commit_action(); -} - -void VisualScriptEditor::_remove_input_port(int p_id, int p_port) { - Ref<VisualScriptLists> vsn = script->get_node(p_id); - if (!vsn.is_valid()) { - return; - } - - updating_graph = true; - - undo_redo->create_action(TTR("Remove Input Port"), UndoRedo::MERGE_ENDS); - - int conn_from = -1, conn_port = -1; - script->get_input_value_port_connection_source(p_id, p_port, &conn_from, &conn_port); - - if (conn_from != -1) { - undo_redo->add_do_method(script.ptr(), "data_disconnect", conn_from, conn_port, p_id, p_port); - } - - undo_redo->add_do_method(vsn.ptr(), "remove_input_data_port", p_port); - undo_redo->add_do_method(this, "_update_graph", p_id); - - if (conn_from != -1) { - undo_redo->add_undo_method(script.ptr(), "data_connect", conn_from, conn_port, p_id, p_port); - } - - undo_redo->add_undo_method(vsn.ptr(), "add_input_data_port", vsn->get_input_value_port_info(p_port).type, vsn->get_input_value_port_info(p_port).name, p_port); - undo_redo->add_undo_method(this, "_update_graph", p_id); - - updating_graph = false; - - undo_redo->commit_action(); -} - -void VisualScriptEditor::_remove_output_port(int p_id, int p_port) { - Ref<VisualScriptLists> vsn = script->get_node(p_id); - if (!vsn.is_valid()) { - return; - } - - updating_graph = true; - - undo_redo->create_action(TTR("Remove Output Port"), UndoRedo::MERGE_ENDS); - - List<VisualScript::DataConnection> data_connections; - script->get_data_connection_list(&data_connections); - - HashMap<int, RBSet<int>> conn_map; - for (const VisualScript::DataConnection &E : data_connections) { - if (E.from_node == p_id && E.from_port == p_port) { - // Push into the connections map. - if (!conn_map.has(E.to_node)) { - conn_map.insert(E.to_node, RBSet<int>()); - } - conn_map[E.to_node].insert(E.to_port); - } - } - - undo_redo->add_do_method(vsn.ptr(), "remove_output_data_port", p_port); - undo_redo->add_do_method(this, "_update_graph", p_id); - - for (const KeyValue<int, RBSet<int>> &E : conn_map) { - for (const int &F : E.value) { - undo_redo->add_undo_method(script.ptr(), "data_connect", p_id, p_port, E.key, F); - } - } - - undo_redo->add_undo_method(vsn.ptr(), "add_output_data_port", vsn->get_output_value_port_info(p_port).type, vsn->get_output_value_port_info(p_port).name, p_port); - undo_redo->add_undo_method(this, "_update_graph", p_id); - - updating_graph = false; - - undo_redo->commit_action(); -} - -void VisualScriptEditor::_expression_text_changed(const String &p_text, int p_id) { - Ref<VisualScriptExpression> vse = script->get_node(p_id); - if (!vse.is_valid()) { - return; - } - - updating_graph = true; - - undo_redo->create_action(TTR("Change Expression"), UndoRedo::MERGE_ENDS); - undo_redo->add_do_property(vse.ptr(), "expression", p_text); - undo_redo->add_undo_property(vse.ptr(), "expression", vse->get("expression")); - undo_redo->add_do_method(this, "_update_graph", p_id); - undo_redo->add_undo_method(this, "_update_graph", p_id); - undo_redo->commit_action(); - - Node *node = graph->get_node(itos(p_id)); - if (Object::cast_to<Control>(node)) { - Object::cast_to<Control>(node)->reset_size(); // Shrink if text is smaller. - } - - updating_graph = false; -} - -Vector2 VisualScriptEditor::_get_pos_in_graph(Vector2 p_point) const { - Vector2 pos = (graph->get_scroll_ofs() + p_point) / (graph->get_zoom() * EDSCALE); - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - pos = pos.snapped(Vector2(snap, snap)); - } - return pos; -} - -Vector2 VisualScriptEditor::_get_available_pos(bool p_centered, Vector2 p_pos) const { - if (p_centered) { - p_pos = _get_pos_in_graph(graph->get_size() * 0.5); - } - - while (true) { - bool exists = false; - List<int> existing; - script->get_node_list(&existing); - for (int &E : existing) { - Point2 pos = script->get_node_position(E); - if (pos.distance_to(p_pos) < 50) { - p_pos += Vector2(graph->get_snap(), graph->get_snap()); - exists = true; - break; - } - } - if (exists) { - continue; - } - break; - } - - return p_pos; -} - -String VisualScriptEditor::_validate_name(const String &p_name) const { - String valid = p_name; - - int counter = 1; - while (true) { - bool exists = script->has_function(valid) || script->has_variable(valid) || script->has_custom_signal(valid); - - if (exists) { - counter++; - valid = p_name + "_" + itos(counter); - continue; - } - - break; - } - - return valid; -} - -void VisualScriptEditor::_on_nodes_copy() { - clipboard->nodes.clear(); - clipboard->data_connections.clear(); - clipboard->sequence_connections.clear(); - - for (int i = 0; i < graph->get_child_count(); i++) { - GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); - if (gn) { - if (gn->is_selected()) { - int id = gn->get_name().operator String().to_int(); - Ref<VisualScriptNode> node = script->get_node(id); - if (Object::cast_to<VisualScriptFunction>(*node)) { - EditorNode::get_singleton()->show_warning(TTR("Can't copy the function node.")); - return; - } - if (node.is_valid()) { - clipboard->nodes[id] = node->duplicate(true); - clipboard->nodes_positions[id] = script->get_node_position(id); - } - } - } - } - - if (clipboard->nodes.is_empty()) { - return; - } - - List<VisualScript::SequenceConnection> sequence_connections; - script->get_sequence_connection_list(&sequence_connections); - - for (const VisualScript::SequenceConnection &E : sequence_connections) { - if (clipboard->nodes.has(E.from_node) && clipboard->nodes.has(E.to_node)) { - clipboard->sequence_connections.insert(E); - } - } - - List<VisualScript::DataConnection> data_connections; - script->get_data_connection_list(&data_connections); - - for (const VisualScript::DataConnection &E : data_connections) { - if (clipboard->nodes.has(E.from_node) && clipboard->nodes.has(E.to_node)) { - clipboard->data_connections.insert(E); - } - } -} - -void VisualScriptEditor::_on_nodes_paste() { - if (clipboard->nodes.is_empty()) { - EditorNode::get_singleton()->show_warning(TTR("Clipboard is empty!")); - return; - } - - HashMap<int, int> remap; - - undo_redo->create_action(TTR("Paste VisualScript Nodes")); - int idc = script->get_available_id() + 1; - - RBSet<int> to_select; - - RBSet<Vector2> existing_positions; - - { - List<int> nodes; - script->get_node_list(&nodes); - for (int &E : nodes) { - Vector2 pos = script->get_node_position(E).snapped(Vector2(2, 2)); - existing_positions.insert(pos); - } - } - - bool first_paste = true; - Vector2 position_offset = Vector2(0, 0); - - for (KeyValue<int, Ref<VisualScriptNode>> &E : clipboard->nodes) { - Ref<VisualScriptNode> node = E.value->duplicate(); - - int new_id = idc++; - to_select.insert(new_id); - - remap[E.key] = new_id; - - Vector2 paste_pos = clipboard->nodes_positions[E.key]; - - if (first_paste) { - position_offset = _get_pos_in_graph(mouse_up_position - graph->get_global_position()) - paste_pos; - first_paste = false; - } - - paste_pos += position_offset; - - while (existing_positions.has(paste_pos.snapped(Vector2(2, 2)))) { - paste_pos += Vector2(20, 20) * EDSCALE; - } - - undo_redo->add_do_method(script.ptr(), "add_node", new_id, node, paste_pos); - undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); - } - - for (const VisualScript::SequenceConnection &E : clipboard->sequence_connections) { - undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E.from_node], E.from_output, remap[E.to_node]); - undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", remap[E.from_node], E.from_output, remap[E.to_node]); - } - - for (const VisualScript::DataConnection &E : clipboard->data_connections) { - undo_redo->add_do_method(script.ptr(), "data_connect", remap[E.from_node], E.from_port, remap[E.to_node], E.to_port); - undo_redo->add_undo_method(script.ptr(), "data_disconnect", remap[E.from_node], E.from_port, remap[E.to_node], E.to_port); - } - - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - - undo_redo->commit_action(); - - for (int i = 0; i < graph->get_child_count(); i++) { - GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); - if (gn) { - int id = gn->get_name().operator String().to_int(); - gn->set_selected(to_select.has(id)); - } - } -} - -void VisualScriptEditor::_on_nodes_delete() { - // Delete all the selected nodes. - - List<int> to_erase; - - for (int i = 0; i < graph->get_child_count(); i++) { - GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); - if (gn) { - if (gn->is_selected() && gn->is_close_button_visible()) { - to_erase.push_back(gn->get_name().operator String().to_int()); - } - } - } - - if (to_erase.is_empty()) { - return; - } - - undo_redo->create_action(TTR("Remove VisualScript Nodes")); - - for (int &F : to_erase) { - int cr_node = F; - - undo_redo->add_do_method(script.ptr(), "remove_node", cr_node); - undo_redo->add_undo_method(script.ptr(), "add_node", cr_node, script->get_node(cr_node), script->get_node_position(cr_node)); - - List<VisualScript::SequenceConnection> sequence_conns; - script->get_sequence_connection_list(&sequence_conns); - - for (const VisualScript::SequenceConnection &E : sequence_conns) { - if (E.from_node == cr_node || E.to_node == cr_node) { - undo_redo->add_undo_method(script.ptr(), "sequence_connect", E.from_node, E.from_output, E.to_node); - } - } - - List<VisualScript::DataConnection> data_conns; - script->get_data_connection_list(&data_conns); - - for (const VisualScript::DataConnection &E : data_conns) { - if (E.from_node == F || E.to_node == F) { - undo_redo->add_undo_method(script.ptr(), "data_connect", E.from_node, E.from_port, E.to_node, E.to_port); - } - } - } - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - - undo_redo->commit_action(); -} - -void VisualScriptEditor::_on_nodes_duplicate() { - RBSet<int> to_duplicate; - - for (int i = 0; i < graph->get_child_count(); i++) { - GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); - if (gn) { - if (gn->is_selected() && gn->is_close_button_visible()) { - int id = gn->get_name().operator String().to_int(); - to_duplicate.insert(id); - } - } - } - - if (to_duplicate.is_empty()) { - return; - } - - undo_redo->create_action(TTR("Duplicate VisualScript Nodes")); - int idc = script->get_available_id() + 1; - - RBSet<int> to_select; - HashMap<int, int> remap; - - for (const int &F : to_duplicate) { - // Duplicate from the specific function but place it into the default func as it would lack the connections. - Ref<VisualScriptNode> node = script->get_node(F); - - Ref<VisualScriptNode> dupe = node->duplicate(true); - - int new_id = idc++; - remap.insert(F, new_id); - - to_select.insert(new_id); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, dupe, script->get_node_position(F) + Vector2(20, 20)); - undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); - } - - List<VisualScript::SequenceConnection> seqs; - script->get_sequence_connection_list(&seqs); - for (const VisualScript::SequenceConnection &E : seqs) { - if (to_duplicate.has(E.from_node) && to_duplicate.has(E.to_node)) { - undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E.from_node], E.from_output, remap[E.to_node]); - } - } - - List<VisualScript::DataConnection> data; - script->get_data_connection_list(&data); - for (const VisualScript::DataConnection &E : data) { - if (to_duplicate.has(E.from_node) && to_duplicate.has(E.to_node)) { - undo_redo->add_do_method(script.ptr(), "data_connect", remap[E.from_node], E.from_port, remap[E.to_node], E.to_port); - } - } - - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - - undo_redo->commit_action(); - - for (int i = 0; i < graph->get_child_count(); i++) { - GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); - if (gn) { - int id = gn->get_name().operator String().to_int(); - gn->set_selected(to_select.has(id)); - } - } - - if (to_select.size()) { - EditorNode::get_singleton()->push_item(script->get_node(to_select.front()->get()).ptr()); - } -} - -void VisualScriptEditor::_generic_search(Vector2 pos, bool node_centered) { - if (node_centered) { - port_action_pos = graph->get_size() / 2.0f; - } else { - port_action_pos = graph->get_viewport()->get_mouse_position() - graph->get_global_position(); - } - - new_connect_node_select->select_from_visual_script(script, false); // do not reset text -} - -void VisualScriptEditor::input(const Ref<InputEvent> &p_event) { - ERR_FAIL_COND(p_event.is_null()); - - // GUI input for VS Editor Plugin - Ref<InputEventMouseButton> key = p_event; - - if (key.is_valid() && key->is_pressed()) { - mouse_up_position = get_screen_position() + get_local_mouse_position(); - } -} - -void VisualScriptEditor::_graph_gui_input(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseButton> key = p_event; - - if (key.is_valid() && key->is_pressed() && key->get_button_mask() == MouseButton::RIGHT) { - bool is_empty_selection = true; - - for (int i = 0; i < graph->get_child_count(); i++) { - GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); - if (gn && gn->is_selected()) { - is_empty_selection = false; - break; - } - } - if (is_empty_selection && clipboard->nodes.is_empty()) { - _generic_search(); - } else { - popup_menu->set_item_disabled(int(EDIT_CUT_NODES), is_empty_selection); - popup_menu->set_item_disabled(int(EDIT_COPY_NODES), is_empty_selection); - popup_menu->set_item_disabled(int(EDIT_PASTE_NODES), clipboard->nodes.is_empty()); - popup_menu->set_item_disabled(int(EDIT_DELETE_NODES), is_empty_selection); - popup_menu->set_item_disabled(int(EDIT_DUPLICATE_NODES), is_empty_selection); - popup_menu->set_item_disabled(int(EDIT_CLEAR_COPY_BUFFER), clipboard->nodes.is_empty()); - - popup_menu->set_position(mouse_up_position); - popup_menu->popup(); - } - } -} - -void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) { - Ref<InputEventKey> key = p_event; - if (key.is_valid() && key->is_pressed() && !key->is_echo()) { - if (members->has_focus()) { - TreeItem *ti = members->get_selected(); - if (ti) { - TreeItem *root = members->get_root(); - if (ti->get_parent() == root->get_first_child()) { - member_type = MEMBER_FUNCTION; - } - if (ti->get_parent() == root->get_first_child()->get_next()) { - member_type = MEMBER_VARIABLE; - } - if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) { - member_type = MEMBER_SIGNAL; - } - member_name = ti->get_text(0); - } - if (ED_IS_SHORTCUT("ui_graph_delete", p_event)) { - _member_option(MEMBER_REMOVE); - } - if (ED_IS_SHORTCUT("visual_script_editor/edit_member", p_event)) { - _member_option(MEMBER_EDIT); - } - } - } - - Ref<InputEventMouseButton> btn = p_event; - if (btn.is_valid() && btn->is_double_click()) { - TreeItem *ti = members->get_selected(); - if (ti && ti->get_parent() == members->get_root()->get_first_child()) { // to check if it's a function - _center_on_node(script->get_function_node_id(ti->get_metadata(0))); - } - } -} - -void VisualScriptEditor::_rename_function(const String &name, const String &new_name) { - if (!new_name.is_valid_identifier()) { - EditorNode::get_singleton()->show_warning(TTR("Name is not a valid identifier:") + " " + new_name); - return; - } - - if (script->has_function(new_name) || script->has_variable(new_name) || script->has_custom_signal(new_name)) { - EditorNode::get_singleton()->show_warning(TTR("Name already in use by another func/var/signal:") + " " + new_name); - return; - } - - int node_id = script->get_function_node_id(name); - Ref<VisualScriptFunction> func; - if (script->has_node(node_id)) { - func = script->get_node(node_id); - } - undo_redo->create_action(TTR("Rename Function")); - undo_redo->add_do_method(script.ptr(), "rename_function", name, new_name); - undo_redo->add_undo_method(script.ptr(), "rename_function", new_name, name); - if (func.is_valid()) { - undo_redo->add_do_method(func.ptr(), "set_name", new_name); - undo_redo->add_undo_method(func.ptr(), "set_name", name); - } - - // Also fix all function calls. - List<int> lst; - script->get_node_list(&lst); - for (int &F : lst) { - Ref<VisualScriptFunctionCall> fncall = script->get_node(F); - if (!fncall.is_valid()) { - continue; - } - if (fncall->get_function() == name) { - undo_redo->add_do_method(fncall.ptr(), "set_function", new_name); - undo_redo->add_undo_method(fncall.ptr(), "set_function", name); - } - } - - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->add_do_method(this, "emit_signal", "edited_script_changed"); - undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed"); - undo_redo->commit_action(); -} - -void VisualScriptEditor::_fn_name_box_input(const Ref<InputEvent> &p_event) { - if (!function_name_edit->is_visible()) { - return; - } - - Ref<InputEventKey> key = p_event; - if (key.is_valid() && key->is_pressed() && key->get_keycode() == Key::ENTER) { - function_name_edit->hide(); - _on_fn_name_box_confirmed(); - function_name_box->clear(); - } -} - -void VisualScriptEditor::_on_fn_name_box_confirmed() { - _rename_function(selected, function_name_box->get_text()); -} - -Variant VisualScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { - if (p_from == members) { - TreeItem *it = members->get_item_at_position(p_point); - if (!it) { - return Variant(); - } - - String type = it->get_metadata(0); - - if (type.is_empty()) { - return Variant(); - } - - Dictionary dd; - TreeItem *root = members->get_root(); - - if (it->get_parent() == root->get_first_child()) { - dd["type"] = "visual_script_function_drag"; - dd["function"] = type; - } else if (it->get_parent() == root->get_first_child()->get_next()) { - dd["type"] = "visual_script_variable_drag"; - dd["variable"] = type; - } else if (it->get_parent() == root->get_first_child()->get_next()->get_next()) { - dd["type"] = "visual_script_signal_drag"; - dd["signal"] = type; - - } else { - return Variant(); - } - - Label *label = memnew(Label); - label->set_text(it->get_text(0)); - set_drag_preview(label); - return dd; - } - return Variant(); -} - -bool VisualScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { - if (p_from == graph) { - Dictionary d = p_data; - if (d.has("type") && - (String(d["type"]) == "visual_script_node_drag" || - String(d["type"]) == "visual_script_function_drag" || - String(d["type"]) == "visual_script_variable_drag" || - String(d["type"]) == "visual_script_signal_drag" || - String(d["type"]) == "obj_property" || - String(d["type"]) == "resource" || - String(d["type"]) == "files" || - String(d["type"]) == "nodes")) { - if (String(d["type"]) == "obj_property") { -#ifdef MACOS_ENABLED - const_cast<VisualScriptEditor *>(this)->_show_hint(vformat(TTR("Hold %s to drop a Getter. Hold Shift to drop a generic signature."), find_keycode_name(Key::META))); -#else - const_cast<VisualScriptEditor *>(this)->_show_hint(TTR("Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature.")); -#endif - } - - if (String(d["type"]) == "nodes") { -#ifdef MACOS_ENABLED - const_cast<VisualScriptEditor *>(this)->_show_hint(vformat(TTR("Hold %s to drop a simple reference to the node."), find_keycode_name(Key::META))); -#else - const_cast<VisualScriptEditor *>(this)->_show_hint(TTR("Hold Ctrl to drop a simple reference to the node.")); -#endif - } - - if (String(d["type"]) == "visual_script_variable_drag") { -#ifdef MACOS_ENABLED - const_cast<VisualScriptEditor *>(this)->_show_hint(vformat(TTR("Hold %s to drop a Variable Setter."), find_keycode_name(Key::META))); -#else - const_cast<VisualScriptEditor *>(this)->_show_hint(TTR("Hold Ctrl to drop a Variable Setter.")); -#endif - } - - return true; - } - } - - return false; -} - -static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) { - if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene) { - return nullptr; - } - - Ref<Script> scr = p_current_node->get_script(); - - if (scr.is_valid() && scr == script) { - return p_current_node; - } - - for (int i = 0; i < p_current_node->get_child_count(); i++) { - Node *n = _find_script_node(p_edited_scene, p_current_node->get_child(i), script); - if (n) { - return n; - } - } - - return nullptr; -} - -void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { - if (p_from != graph) { - return; - } - - Dictionary d = p_data; - - if (!d.has("type")) { - return; - } - - if (String(d["type"]) == "visual_script_node_drag") { - if (!d.has("node_type") || String(d["node_type"]) == "Null") { - return; - } - - Vector2 pos = _get_pos_in_graph(p_point); - - int new_id = _create_new_node_from_name(d["node_type"], pos); - - Node *node = graph->get_node(itos(new_id)); - if (node) { - graph->set_selected(node); - _node_selected(node); - } - } - - if (String(d["type"]) == "visual_script_variable_drag") { -#ifdef MACOS_ENABLED - bool use_set = Input::get_singleton()->is_key_pressed(Key::META); -#else - bool use_set = Input::get_singleton()->is_key_pressed(Key::CTRL); -#endif - Vector2 pos = _get_pos_in_graph(p_point); - - Ref<VisualScriptNode> vnode; - if (use_set) { - Ref<VisualScriptPropertySet> pset; - pset.instantiate(); - vnode = pset; - } else { - Ref<VisualScriptPropertyGet> pget; - pget.instantiate(); - vnode = pget; - } - - int new_id = script->get_available_id(); - undo_redo->create_action(TTR("Add Node")); - undo_redo->add_do_method(vnode.ptr(), "set_property", d["variable"]); - undo_redo->add_do_method(vnode.ptr(), "set_base_script", script->get_path()); - - undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos); - undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->commit_action(); - - Node *node = graph->get_node(itos(new_id)); - if (node) { - graph->set_selected(node); - _node_selected(node); - } - } - - if (String(d["type"]) == "visual_script_function_drag") { - Vector2 pos = _get_pos_in_graph(p_point); - - Ref<VisualScriptFunctionCall> vnode; - vnode.instantiate(); - vnode->set_call_mode(VisualScriptFunctionCall::CALL_MODE_SELF); - - int new_id = script->get_available_id(); - - undo_redo->create_action(TTR("Add Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos); - undo_redo->add_do_method(vnode.ptr(), "set_base_type", script->get_instance_base_type()); - undo_redo->add_do_method(vnode.ptr(), "set_function", d["function"]); - - undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->commit_action(); - - Node *node = graph->get_node(itos(new_id)); - if (node) { - graph->set_selected(node); - _node_selected(node); - } - } - - if (String(d["type"]) == "visual_script_signal_drag") { - Vector2 pos = _get_pos_in_graph(p_point); - - Ref<VisualScriptEmitSignal> vnode; - vnode.instantiate(); - vnode->set_signal(d["signal"]); - - int new_id = script->get_available_id(); - - undo_redo->create_action(TTR("Add Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos); - undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->commit_action(); - - Node *node = graph->get_node(itos(new_id)); - if (node) { - graph->set_selected(node); - _node_selected(node); - } - } - - if (String(d["type"]) == "resource") { - Vector2 pos = _get_pos_in_graph(p_point); - - Ref<VisualScriptPreload> prnode; - prnode.instantiate(); - prnode->set_preload(d["resource"]); - - int new_id = script->get_available_id(); - - undo_redo->create_action(TTR("Add Preload Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, prnode, pos); - undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->commit_action(); - - Node *node = graph->get_node(itos(new_id)); - if (node) { - graph->set_selected(node); - _node_selected(node); - } - } - - if (String(d["type"]) == "files") { -#ifdef MACOS_ENABLED - bool use_preload = Input::get_singleton()->is_key_pressed(Key::META); -#else - bool use_preload = Input::get_singleton()->is_key_pressed(Key::CTRL); -#endif - Vector2 pos = _get_pos_in_graph(p_point); - - Array files = d["files"]; - - List<int> new_ids; - int new_id = script->get_available_id(); - - if (files.size()) { - undo_redo->create_action(TTR("Add Node(s)")); - - for (int i = 0; i < files.size(); i++) { - Ref<Resource> res = ResourceLoader::load(files[i]); - if (!res.is_valid()) { - continue; - } - Ref<Script> drop_script = ResourceLoader::load(files[i]); - if (drop_script.is_valid() && drop_script->is_tool() && drop_script->get_instance_base_type() == "VisualScriptCustomNode" && !use_preload) { - Ref<VisualScriptCustomNode> vscn; - vscn.instantiate(); - vscn->set_script(drop_script); - - undo_redo->add_do_method(script.ptr(), "add_node", new_id, vscn, pos); - undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); - } else { - Ref<VisualScriptPreload> prnode; - prnode.instantiate(); - prnode->set_preload(res); - - undo_redo->add_do_method(script.ptr(), "add_node", new_id, prnode, pos); - undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); - } - new_ids.push_back(new_id); - new_id++; - pos += Vector2(20, 20); - } - - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->commit_action(); - } - - for (int &E : new_ids) { - Node *node = graph->get_node(itos(E)); - if (node) { - graph->set_selected(node); - _node_selected(node); - } - } - } - - if (String(d["type"]) == "nodes") { - Node *sn = _find_script_node(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root(), script); - - if (!sn) { - EditorNode::get_singleton()->show_warning(vformat(TTR("Can't drop nodes because script '%s' is not used in this scene."), get_name())); - return; - } - -#ifdef MACOS_ENABLED - bool use_node = Input::get_singleton()->is_key_pressed(Key::META); -#else - bool use_node = Input::get_singleton()->is_key_pressed(Key::CTRL); -#endif - - Array nodes = d["nodes"]; - - Vector2 pos = _get_pos_in_graph(p_point); - - undo_redo->create_action(TTR("Add Node(s) From Tree")); - int base_id = script->get_available_id(); - - if (use_node || nodes.size() > 1) { - for (int i = 0; i < nodes.size(); i++) { - NodePath np = nodes[i]; - Node *node = get_node(np); - if (!node) { - continue; - } - - Ref<VisualScriptNode> n; - - Ref<VisualScriptSceneNode> scene_node; - scene_node.instantiate(); - scene_node->set_node_path(sn->get_path_to(node)); - n = scene_node; - - undo_redo->add_do_method(script.ptr(), "add_node", base_id, n, pos); - undo_redo->add_undo_method(script.ptr(), "remove_node", base_id); - - base_id++; - pos += Vector2(25, 25); - } - - } else { - NodePath np = nodes[0]; - Node *node = get_node(np); - drop_position = pos; - drop_node = node; - drop_path = sn->get_path_to(node); - new_connect_node_select->select_from_instance(node, false); - } - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->commit_action(); - } - - if (String(d["type"]) == "obj_property") { - Node *sn = _find_script_node(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root(), script); - - if (!sn && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) { - EditorNode::get_singleton()->show_warning(vformat(TTR("Can't drop properties because script '%s' is not used in this scene.\nDrop holding 'Shift' to just copy the signature."), get_name())); - return; - } - - Object *obj = d["object"]; - - if (!obj) { - return; - } - - Node *node = Object::cast_to<Node>(obj); - Vector2 pos = _get_pos_in_graph(p_point); - -#ifdef MACOS_ENABLED - bool use_get = Input::get_singleton()->is_key_pressed(Key::META); -#else - bool use_get = Input::get_singleton()->is_key_pressed(Key::CTRL); -#endif - - if (!node || Input::get_singleton()->is_key_pressed(Key::SHIFT)) { - if (use_get) { - undo_redo->create_action(TTR("Add Getter Property")); - } else { - undo_redo->create_action(TTR("Add Setter Property")); - } - - int base_id = script->get_available_id(); - - Ref<VisualScriptNode> vnode; - - if (!use_get) { - Ref<VisualScriptPropertySet> pset; - pset.instantiate(); - pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); - pset->set_base_type(obj->get_class()); - vnode = pset; - } else { - Ref<VisualScriptPropertyGet> pget; - pget.instantiate(); - pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); - pget->set_base_type(obj->get_class()); - vnode = pget; - } - - undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, pos); - undo_redo->add_do_method(vnode.ptr(), "set_property", d["property"]); - if (!obj->get_script().is_null()) { - undo_redo->add_do_method(vnode.ptr(), "set_base_script", Ref<Script>(obj->get_script())->get_path()); - } - if (!use_get) { - undo_redo->add_do_method(vnode.ptr(), "set_default_input_value", 0, d["value"]); - } - - undo_redo->add_undo_method(script.ptr(), "remove_node", base_id); - - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->commit_action(); - - } else { - if (use_get) { - undo_redo->create_action(TTR("Add Getter Property")); - } else { - undo_redo->create_action(TTR("Add Setter Property")); - } - - int base_id = script->get_available_id(); - - Ref<VisualScriptNode> vnode; - - if (!use_get) { - Ref<VisualScriptPropertySet> pset; - pset.instantiate(); - if (sn == node) { - pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_SELF); - } else { - pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_NODE_PATH); - pset->set_base_path(sn->get_path_to(node)); - } - vnode = pset; - } else { - Ref<VisualScriptPropertyGet> pget; - pget.instantiate(); - if (sn == node) { - pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_SELF); - } else { - pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_NODE_PATH); - pget->set_base_path(sn->get_path_to(node)); - } - vnode = pget; - } - undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, pos); - undo_redo->add_do_method(vnode.ptr(), "set_property", d["property"]); - if (!obj->get_script().is_null()) { - undo_redo->add_do_method(vnode.ptr(), "set_base_script", Ref<Script>(obj->get_script())->get_path()); - } - if (!use_get) { - undo_redo->add_do_method(vnode.ptr(), "set_default_input_value", 0, d["value"]); - } - - undo_redo->add_undo_method(script.ptr(), "remove_node", base_id); - - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->commit_action(); - } - } -} - -void VisualScriptEditor::_draw_color_over_button(Object *obj, Color p_color) { - Button *button = Object::cast_to<Button>(obj); - if (!button) { - return; - } - - Ref<StyleBox> normal = get_theme_stylebox(SNAME("normal"), SNAME("Button")); - button->draw_rect(Rect2(normal->get_offset(), button->get_size() - normal->get_minimum_size()), p_color); -} - -void VisualScriptEditor::_button_resource_previewed(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud) { - Array ud = p_ud; - ERR_FAIL_COND(ud.size() != 2); - - ObjectID id = ud[0]; - Object *obj = ObjectDB::get_instance(id); - - if (!obj) { - return; - } - - Button *b = Object::cast_to<Button>(obj); - ERR_FAIL_COND(!b); - - if (p_preview.is_null()) { - b->set_text(ud[1]); - } else { - b->set_icon(p_preview); - } -} - -///////////////////////// - -void VisualScriptEditor::apply_code() { -} - -Ref<Resource> VisualScriptEditor::get_edited_resource() const { - return script; -} - -void VisualScriptEditor::set_edited_resource(const Ref<Resource> &p_res) { - ERR_FAIL_COND(script.is_valid()); - ERR_FAIL_COND(p_res.is_null()); - script = p_res; - signal_editor->script = script; - signal_editor->undo_redo = undo_redo; - variable_editor->script = script; - variable_editor->undo_redo = undo_redo; - - script->connect("node_ports_changed", callable_mp(this, &VisualScriptEditor::_node_ports_changed)); - - _update_graph(); - call_deferred(SNAME("_update_members")); -} - -void VisualScriptEditor::enable_editor() { -} - -Vector<String> VisualScriptEditor::get_functions() { - return Vector<String>(); -} - -void VisualScriptEditor::reload_text() { -} - -String VisualScriptEditor::get_name() { - String name; - - name = script->get_path().get_file(); - if (name.is_empty()) { - // This appears for newly created built-in scripts before saving the scene. - name = TTR("[unsaved]"); - } else if (script->is_built_in()) { - const String &script_name = script->get_name(); - if (!script_name.is_empty()) { - // If the built-in script has a custom resource name defined, - // display the built-in script name as follows: `ResourceName (scene_file.tscn)` - name = vformat("%s (%s)", script_name, name.get_slice("::", 0)); - } - } - - if (is_unsaved()) { - name += "(*)"; - } - - return name; -} - -Ref<Texture2D> VisualScriptEditor::get_theme_icon() { - String icon_name = "VisualScript"; - if (script->is_built_in()) { - icon_name += "Internal"; - } - - if (Control::has_theme_icon(icon_name, "EditorIcons")) { - return Control::get_theme_icon(icon_name, SNAME("EditorIcons")); - } - - return Control::get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons")); -} - -bool VisualScriptEditor::is_unsaved() { - bool unsaved = - script->is_edited() || - script->are_subnodes_edited() || - script->get_path().is_empty(); // In memory. - return unsaved; -} - -Variant VisualScriptEditor::get_edit_state() { - Dictionary d; - d["scroll"] = graph->get_scroll_ofs(); - d["zoom"] = graph->get_zoom(); - d["using_snap"] = graph->is_using_snap(); - d["snap"] = graph->get_snap(); - return d; -} - -void VisualScriptEditor::set_edit_state(const Variant &p_state) { - Dictionary d = p_state; - - _update_graph(); - _update_members(); - - if (d.has("scroll")) { - graph->set_scroll_ofs(d["scroll"]); - } - if (d.has("zoom")) { - graph->set_zoom(d["zoom"]); - } - if (d.has("snap")) { - graph->set_snap(d["snap"]); - } - if (d.has("snap_enabled")) { - graph->set_use_snap(d["snap_enabled"]); - } -} - -void VisualScriptEditor::_center_on_node(int p_id) { - Node *n = graph->get_node(itos(p_id)); - GraphNode *gn = Object::cast_to<GraphNode>(n); - - // Clear selection. - for (int i = 0; i < graph->get_child_count(); i++) { - GraphNode *gnd = Object::cast_to<GraphNode>(graph->get_child(i)); - if (gnd) { - gnd->set_selected(false); - } - } - - if (gn) { - gn->set_selected(true); - Vector2 new_scroll = gn->get_position_offset() * graph->get_zoom() - graph->get_size() * 0.5 + gn->get_size() * 0.5; - graph->set_scroll_ofs(new_scroll); - script->set_scroll(new_scroll / EDSCALE); - script->set_edited(true); - } -} - -void VisualScriptEditor::goto_line(int p_line, bool p_with_error) { - p_line += 1; // Add one because script lines begin from 0. - - if (p_with_error) { - error_line = p_line; - } - - if (script->has_node(p_line)) { - _update_graph(); - _update_members(); - - call_deferred(SNAME("call_deferred"), "_center_on_node", p_line); // The editor might be just created and size might not exist yet. - } -} - -void VisualScriptEditor::set_executing_line(int p_line) { - // todo: add a way to show which node is executing right now. -} - -void VisualScriptEditor::clear_executing_line() { - // todo: add a way to show which node is executing right now. -} - -void VisualScriptEditor::trim_trailing_whitespace() { -} - -void VisualScriptEditor::insert_final_newline() { -} - -void VisualScriptEditor::convert_indent_to_spaces() { -} - -void VisualScriptEditor::convert_indent_to_tabs() { -} - -void VisualScriptEditor::ensure_focus() { - graph->grab_focus(); -} - -void VisualScriptEditor::tag_saved_version() { -} - -void VisualScriptEditor::reload(bool p_soft) { - _update_graph(); -} - -Array VisualScriptEditor::get_breakpoints() { - Array breakpoints; - List<StringName> functions; - script->get_function_list(&functions); - for (int i = 0; i < functions.size(); i++) { - List<int> nodes; - script->get_node_list(&nodes); - for (int &F : nodes) { - Ref<VisualScriptNode> vsn = script->get_node(F); - if (vsn->is_breakpoint()) { - breakpoints.push_back(F - 1); // Subtract 1 because breakpoints in text start from zero. - } - } - } - return breakpoints; -} - -void VisualScriptEditor::add_callback(const String &p_function, PackedStringArray p_args) { - if (script->has_function(p_function)) { - _update_members(); - _update_graph(); - _center_on_node(script->get_function_node_id(p_function)); - return; - } - - Ref<VisualScriptFunction> func; - func.instantiate(); - for (int i = 0; i < p_args.size(); i++) { - String name = p_args[i]; - Variant::Type type = Variant::NIL; - - if (name.contains(":")) { - String tt = name.get_slice(":", 1); - name = name.get_slice(":", 0); - for (int j = 0; j < Variant::VARIANT_MAX; j++) { - String tname = Variant::get_type_name(Variant::Type(j)); - if (tname == tt) { - type = Variant::Type(j); - break; - } - } - } - - func->add_argument(type, name); - } - int fn_id = script->get_available_id(); - func->set_name(p_function); - script->add_function(p_function, fn_id); - script->add_node(fn_id, func); - - _update_members(); - _update_graph(); - - _center_on_node(script->get_function_node_id(p_function)); -} - -bool VisualScriptEditor::show_members_overview() { - return false; -} - -void VisualScriptEditor::update_settings() { - _update_graph(); -} - -void VisualScriptEditor::set_debugger_active(bool p_active) { - if (!p_active) { - error_line = -1; - _update_graph(); //clear line break - } -} - -Control *VisualScriptEditor::get_base_editor() const { - return graph; -} - -void VisualScriptEditor::set_tooltip_request_func(const Callable &p_toolip_callback) { -} - -Control *VisualScriptEditor::get_edit_menu() { - return edit_menu; -} - -void VisualScriptEditor::_change_base_type() { - select_base_type->popup_create(true, true, script->get_instance_base_type()); -} - -void VisualScriptEditor::_toggle_tool_script() { - script->set_tool_enabled(!script->is_tool()); -} - -void VisualScriptEditor::clear_edit_menu() { - memdelete(edit_menu); - memdelete(members_section); -} - -void VisualScriptEditor::_change_base_type_callback() { - String bt = select_base_type->get_selected_type(); - - ERR_FAIL_COND(bt.is_empty()); - undo_redo->create_action(TTR("Change Base Type")); - undo_redo->add_do_method(script.ptr(), "set_instance_base_type", bt); - undo_redo->add_undo_method(script.ptr(), "set_instance_base_type", script->get_instance_base_type()); - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->commit_action(); -} - -void VisualScriptEditor::_node_selected(Node *p_node) { - Ref<VisualScriptNode> vnode = p_node->get_meta("__vnode"); - if (vnode.is_null()) { - return; - } - - EditorNode::get_singleton()->push_item(vnode.ptr()); //edit node in inspector -} - -static bool _get_out_slot(const Ref<VisualScriptNode> &p_node, int p_slot, int &r_real_slot, bool &r_sequence) { - if (p_slot < p_node->get_output_sequence_port_count()) { - r_sequence = true; - r_real_slot = p_slot; - - return true; - } - - r_real_slot = p_slot - p_node->get_output_sequence_port_count(); - r_sequence = false; - - return (r_real_slot < p_node->get_output_value_port_count()); -} - -static bool _get_in_slot(const Ref<VisualScriptNode> &p_node, int p_slot, int &r_real_slot, bool &r_sequence) { - if (p_slot == 0 && p_node->has_input_sequence_port()) { - r_sequence = true; - r_real_slot = 0; - return true; - } - - r_real_slot = p_slot - (p_node->has_input_sequence_port() ? 1 : 0); - r_sequence = false; - - return r_real_slot < p_node->get_input_value_port_count(); -} - -void VisualScriptEditor::_begin_node_move() { - undo_redo->create_action(TTR("Move Node(s)")); -} - -void VisualScriptEditor::_end_node_move() { - undo_redo->commit_action(); -} - -void VisualScriptEditor::_move_node(int p_id, const Vector2 &p_to) { - if (!script->has_node(p_id)) { - return; - } - - Node *node = graph->get_node(itos(p_id)); - - if (Object::cast_to<GraphNode>(node)) { - Object::cast_to<GraphNode>(node)->set_position_offset(p_to); - } - - script->set_node_position(p_id, p_to / EDSCALE); -} - -void VisualScriptEditor::_node_moved(Vector2 p_from, Vector2 p_to, int p_id) { - undo_redo->add_do_method(this, "_move_node", p_id, p_to); - undo_redo->add_undo_method(this, "_move_node", p_id, p_from); -} - -void VisualScriptEditor::_remove_node(int p_id) { - undo_redo->create_action(TTR("Remove VisualScript Node")); - - undo_redo->add_do_method(script.ptr(), "remove_node", p_id); - undo_redo->add_undo_method(script.ptr(), "add_node", p_id, script->get_node(p_id), script->get_node_position(p_id)); - - List<VisualScript::SequenceConnection> sequence_conns; - script->get_sequence_connection_list(&sequence_conns); - - for (const VisualScript::SequenceConnection &E : sequence_conns) { - if (E.from_node == p_id || E.to_node == p_id) { - undo_redo->add_undo_method(script.ptr(), "sequence_connect", E.from_node, E.from_output, E.to_node); - } - } - - List<VisualScript::DataConnection> data_conns; - script->get_data_connection_list(&data_conns); - - for (const VisualScript::DataConnection &E : data_conns) { - if (E.from_node == p_id || E.to_node == p_id) { - undo_redo->add_undo_method(script.ptr(), "data_connect", E.from_node, E.from_port, E.to_node, E.to_port); - } - } - - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - - undo_redo->commit_action(); -} - -void VisualScriptEditor::_node_ports_changed(int p_id) { - _update_graph(p_id); -} - -bool VisualScriptEditor::node_has_sequence_connections(int p_id) { - List<VisualScript::SequenceConnection> sequence_conns; - script->get_sequence_connection_list(&sequence_conns); - - for (const VisualScript::SequenceConnection &E : sequence_conns) { - int from = E.from_node; - int to = E.to_node; - - if (to == p_id || from == p_id) { - return true; - } - } - - return false; -} - -void VisualScriptEditor::_graph_connected(const String &p_from, int p_from_slot, const String &p_to, int p_to_slot) { - Ref<VisualScriptNode> from_node = script->get_node(p_from.to_int()); - ERR_FAIL_COND(!from_node.is_valid()); - - bool from_seq; - int from_port; - - if (!_get_out_slot(from_node, p_from_slot, from_port, from_seq)) { - return; //can't connect this, it's invalid - } - - Ref<VisualScriptNode> to_node = script->get_node(p_to.to_int()); - ERR_FAIL_COND(!to_node.is_valid()); - - bool to_seq; - int to_port; - - if (!_get_in_slot(to_node, p_to_slot, to_port, to_seq)) { - return; //can't connect this, it's invalid - } - - ERR_FAIL_COND(from_seq != to_seq); - - // Checking to prevent warnings. - if (from_seq) { - if (script->has_sequence_connection(p_from.to_int(), from_port, p_to.to_int())) { - return; - } - } else if (script->has_data_connection(p_from.to_int(), from_port, p_to.to_int(), to_port)) { - return; - } - - // Preventing connection to itself. - if (p_from.to_int() == p_to.to_int()) { - return; - } - - // Do all the checks here. - StringName func; // This the func where we store the one the nodes at the end of the resolution on having multiple nodes. - - undo_redo->create_action(TTR("Connect Nodes")); - - if (from_seq) { - undo_redo->add_do_method(script.ptr(), "sequence_connect", p_from.to_int(), from_port, p_to.to_int()); - // This undo error on undo after move can't be removed without painful gymnastics - undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", p_from.to_int(), from_port, p_to.to_int()); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - } else { - bool converted = false; - - Ref<VisualScriptOperator> oper = to_node; - if (oper.is_valid() && oper->get_typed() == Variant::NIL) { - // It's an operator Node and if the type is already nil - if (from_node->get_output_value_port_info(from_port).type != Variant::NIL) { - oper->set_typed(from_node->get_output_value_port_info(from_port).type); - } - } - - Ref<VisualScriptOperator> operf = from_node; - if (operf.is_valid() && operf->get_typed() == Variant::NIL) { - // It's an operator Node and if the type is already nil - if (to_node->get_input_value_port_info(to_port).type != Variant::NIL) { - operf->set_typed(to_node->get_input_value_port_info(to_port).type); - } - } - - // Disconnect current, and connect the new one - if (script->is_input_value_port_connected(p_to.to_int(), to_port)) { - if (can_swap && data_disconnect_node == p_to.to_int()) { - int conn_from; - int conn_port; - script->get_input_value_port_connection_source(p_to.to_int(), to_port, &conn_from, &conn_port); - undo_redo->add_do_method(script.ptr(), "data_disconnect", conn_from, conn_port, p_to.to_int(), to_port); - undo_redo->add_do_method(script.ptr(), "data_connect", conn_from, conn_port, data_disconnect_node, data_disconnect_port); - undo_redo->add_undo_method(script.ptr(), "data_disconnect", conn_from, conn_port, data_disconnect_node, data_disconnect_port); - undo_redo->add_undo_method(script.ptr(), "data_connect", conn_from, conn_port, p_to.to_int(), to_port); - can_swap = false; // swapped - } else { - int conn_from; - int conn_port; - script->get_input_value_port_connection_source(p_to.to_int(), to_port, &conn_from, &conn_port); - undo_redo->add_do_method(script.ptr(), "data_disconnect", conn_from, conn_port, p_to.to_int(), to_port); - undo_redo->add_undo_method(script.ptr(), "data_connect", conn_from, conn_port, p_to.to_int(), to_port); - } - } - if (!converted) { - undo_redo->add_do_method(script.ptr(), "data_connect", p_from.to_int(), from_port, p_to.to_int(), to_port); - undo_redo->add_undo_method(script.ptr(), "data_disconnect", p_from.to_int(), from_port, p_to.to_int(), to_port); - - // Update nodes in graph - undo_redo->add_do_method(this, "_update_graph", p_from.to_int()); - undo_redo->add_do_method(this, "_update_graph", p_to.to_int()); - undo_redo->add_undo_method(this, "_update_graph", p_from.to_int()); - undo_redo->add_undo_method(this, "_update_graph", p_to.to_int()); - } else { - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - } - } - - undo_redo->commit_action(); -} - -void VisualScriptEditor::_graph_disconnected(const String &p_from, int p_from_slot, const String &p_to, int p_to_slot) { - Ref<VisualScriptNode> from_node = script->get_node(p_from.to_int()); - ERR_FAIL_COND(!from_node.is_valid()); - - bool from_seq; - int from_port; - - if (!_get_out_slot(from_node, p_from_slot, from_port, from_seq)) { - return; // Can't connect this, it's invalid. - } - - Ref<VisualScriptNode> to_node = script->get_node(p_to.to_int()); - ERR_FAIL_COND(!to_node.is_valid()); - - bool to_seq; - int to_port; - - if (!_get_in_slot(to_node, p_to_slot, to_port, to_seq)) { - return; // Can't connect this, it's invalid. - } - - ERR_FAIL_COND(from_seq != to_seq); - - undo_redo->create_action(TTR("Disconnect Nodes")); - - if (from_seq) { - undo_redo->add_do_method(script.ptr(), "sequence_disconnect", p_from.to_int(), from_port, p_to.to_int()); - undo_redo->add_undo_method(script.ptr(), "sequence_connect", p_from.to_int(), from_port, p_to.to_int()); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - } else { - can_swap = true; - data_disconnect_node = p_to.to_int(); - data_disconnect_port = to_port; - - undo_redo->add_do_method(script.ptr(), "data_disconnect", p_from.to_int(), from_port, p_to.to_int(), to_port); - undo_redo->add_undo_method(script.ptr(), "data_connect", p_from.to_int(), from_port, p_to.to_int(), to_port); - // Update relevant nodes in the graph. - undo_redo->add_do_method(this, "_update_graph", p_from.to_int()); - undo_redo->add_do_method(this, "_update_graph", p_to.to_int()); - undo_redo->add_undo_method(this, "_update_graph", p_from.to_int()); - undo_redo->add_undo_method(this, "_update_graph", p_to.to_int()); - } - - undo_redo->commit_action(); -} - -void VisualScriptEditor::_graph_connect_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_pos) { - Node *node = graph->get_node(p_from); - GraphNode *gn = Object::cast_to<GraphNode>(node); - if (!gn) { - return; - } - - Ref<VisualScriptNode> vsn = script->get_node(p_from.to_int()); - if (!vsn.is_valid()) { - return; - } - if (vsn->get_output_value_port_count() || vsn->get_output_sequence_port_count()) { - port_action_pos = p_release_pos; - } - - if (p_from_slot < vsn->get_output_sequence_port_count()) { - port_action_node = p_from.to_int(); - port_action_output = p_from_slot; - _port_action_menu(CREATE_ACTION); - } else { - port_action_output = p_from_slot - vsn->get_output_sequence_port_count(); - port_action_node = p_from.to_int(); - _port_action_menu(CREATE_CALL_SET_GET); - } -} - -VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_action_node, int p_port_action_output, RBSet<int> &visited_nodes) { - VisualScriptNode::TypeGuess tg; - tg.type = Variant::NIL; - - if (visited_nodes.has(p_port_action_node)) { - return tg; //no loop - } - - visited_nodes.insert(p_port_action_node); - - Ref<VisualScriptNode> node = script->get_node(p_port_action_node); - - if (!node.is_valid() || node->get_output_value_port_count() <= p_port_action_output) { - return tg; - } - - Vector<VisualScriptNode::TypeGuess> in_guesses; - - for (int i = 0; i < node->get_input_value_port_count(); i++) { - PropertyInfo pi = node->get_input_value_port_info(i); - VisualScriptNode::TypeGuess g; - g.type = pi.type; - - if (g.type == Variant::NIL || g.type == Variant::OBJECT) { - // Any or object input, must further guess what this is. - int from_node; - int from_port; - - if (script->get_input_value_port_connection_source(p_port_action_node, i, &from_node, &from_port)) { - g = _guess_output_type(from_node, from_port, visited_nodes); - } else { - Variant defval = node->get_default_input_value(i); - if (defval.get_type() == Variant::OBJECT) { - Object *obj = defval; - - if (obj) { - g.type = Variant::OBJECT; - g.gdclass = obj->get_class(); - g.script = obj->get_script(); - } - } - } - } - - in_guesses.push_back(g); - } - - return node->guess_output_type(in_guesses.ptrw(), p_port_action_output); -} - -void VisualScriptEditor::_port_action_menu(int p_option) { - RBSet<int> vn; - - switch (p_option) { - case CREATE_CALL_SET_GET: { - Ref<VisualScriptFunctionCall> n; - n.instantiate(); - - VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); - - if (tg.gdclass != StringName()) { - n->set_base_type(tg.gdclass); - } else { - n->set_base_type("Object"); - } - String type_string; - String base_script = ""; - if (script->get_node(port_action_node)->get_output_value_port_count() > 0) { - type_string = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string; - VisualScriptFunctionCall *vsfc = Object::cast_to<VisualScriptFunctionCall>(*script->get_node(port_action_node)); - if (vsfc) { - base_script = vsfc->get_base_script(); - } else { - VisualScriptPropertyGet *vspg = Object::cast_to<VisualScriptPropertyGet>(*script->get_node(port_action_node)); - if (vspg) { - base_script = vspg->get_base_script(); - } else { - VisualScriptPropertySet *vsps = Object::cast_to<VisualScriptPropertySet>(*script->get_node(port_action_node)); - if (vsps) { - base_script = vsps->get_base_script(); - } - } - } - } - if (tg.type == Variant::OBJECT) { - if (tg.script.is_valid()) { - new_connect_node_select->select_from_script(tg.script); - } else if (type_string != String()) { - new_connect_node_select->select_from_base_type(type_string, base_script); - } else { - new_connect_node_select->select_from_base_type(n->get_base_type(), base_script); - } - } else if (tg.type == Variant::NIL) { - new_connect_node_select->select_from_base_type("", base_script); - } else { - new_connect_node_select->select_from_basic_type(tg.type); - } - // Ensure that the dialog fits inside the graph. - Vector2 pos = mouse_up_position; - Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size(); - pos.x = pos.x > bounds.x ? bounds.x : pos.x; - pos.y = pos.y > bounds.y ? bounds.y : pos.y; - new_connect_node_select->set_position(pos); - } break; - case CREATE_ACTION: { - VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); - PropertyInfo property_info; - if (script->get_node(port_action_node)->get_output_value_port_count() > 0) { - property_info = script->get_node(port_action_node)->get_output_value_port_info(port_action_output); - } - if (tg.type == Variant::OBJECT) { - if (property_info.type == Variant::OBJECT && !property_info.hint_string.is_empty()) { - new_connect_node_select->select_from_action(property_info.hint_string); - } else { - new_connect_node_select->select_from_action(""); - } - } else if (tg.type == Variant::NIL) { - new_connect_node_select->select_from_action(""); - } else { - new_connect_node_select->select_from_action(Variant::get_type_name(tg.type)); - } - // Ensure that the dialog fits inside the graph. - Vector2 pos = mouse_up_position; - Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size(); - pos.x = pos.x > bounds.x ? bounds.x : pos.x; - pos.y = pos.y > bounds.y ? bounds.y : pos.y; - new_connect_node_select->set_position(pos); - } break; - } -} - -void VisualScriptEditor::connect_data(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode, int new_id) { - undo_redo->create_action(TTR("Connect Node Data")); - VisualScriptReturn *vnode_return = Object::cast_to<VisualScriptReturn>(vnode.ptr()); - if (vnode_return != nullptr && vnode_old->get_output_value_port_count() > 0) { - vnode_return->set_enable_return_value(true); - } - if (vnode_old->get_output_value_port_count() <= 0) { - undo_redo->commit_action(); - return; - } - if (vnode->get_input_value_port_count() <= 0) { - undo_redo->commit_action(); - return; - } - int port = port_action_output; - int value_count = vnode_old->get_output_value_port_count(); - if (port >= value_count) { - port = 0; - } - undo_redo->add_do_method(script.ptr(), "data_connect", port_action_node, port, new_id, 0); - undo_redo->add_undo_method(script.ptr(), "data_disconnect", port_action_node, port, new_id, 0); - undo_redo->commit_action(); -} - -void VisualScriptEditor::_selected_connect_node(const String &p_text, const String &p_category, const bool p_connecting) { -#ifdef MACOS_ENABLED - bool held_ctrl = Input::get_singleton()->is_key_pressed(Key::META); -#else - bool held_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL); -#endif - Vector2 pos = _get_pos_in_graph(port_action_pos); - - RBSet<int> vn; - bool port_node_exists = true; - - if (drop_position != Vector2()) { - pos = drop_position; - } - drop_position = Vector2(); - - Ref<VisualScriptNode> vnode; - Ref<VisualScriptNode> vnode_old; - if (port_node_exists && p_connecting) { - vnode_old = script->get_node(port_action_node); - } - - if (p_category.begins_with("VisualScriptNode")) { - Ref<VisualScriptNode> n = VisualScriptLanguage::singleton->create_node_from_name(p_text); - - if (Object::cast_to<VisualScriptTypeCast>(n.ptr()) && vnode_old.is_valid()) { - Variant::Type type = vnode_old->get_output_value_port_info(port_action_output).type; - String hint_name = vnode_old->get_output_value_port_info(port_action_output).hint_string; - - if (type == Variant::OBJECT) { - Object::cast_to<VisualScriptTypeCast>(n.ptr())->set_base_type(hint_name); - } else if (type == Variant::NIL) { - Object::cast_to<VisualScriptTypeCast>(n.ptr())->set_base_type(""); - } else { - Object::cast_to<VisualScriptTypeCast>(n.ptr())->set_base_type(Variant::get_type_name(type)); - } - } - vnode = n; - } - - if (p_category == String("Class") && !p_connecting) { - Ref<VisualScriptFunctionCall> n; - n.instantiate(); - n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_SINGLETON); - n->set_singleton("ClassDB"); - n->set_function("instantiate"); - // Did not find a way to edit the input port value - vnode = n; - } else if (p_category == String("class_method")) { - Ref<VisualScriptFunctionCall> n; - n.instantiate(); - if (!drop_path.is_empty()) { - if (drop_path == ".") { - n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_SELF); - } else { - n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_NODE_PATH); - n->set_base_path(drop_path); - } - } else { - n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE); - } - if (drop_node) { - n->set_base_type(drop_node->get_class()); - if (drop_node->get_script_instance()) { - n->set_base_script(drop_node->get_script_instance()->get_script()->get_path()); - } - } - vnode = n; - } else if (p_category == String("class_property")) { - Vector<String> property_path = p_text.split(":"); - if (held_ctrl) { - Ref<VisualScriptPropertySet> n; - n.instantiate(); - n->set_property(property_path[1]); - if (!drop_path.is_empty()) { - if (drop_path == ".") { - n->set_call_mode(VisualScriptPropertySet::CALL_MODE_SELF); - } else { - n->set_call_mode(VisualScriptPropertySet::CALL_MODE_NODE_PATH); - n->set_base_path(drop_path); - } - } - if (drop_node) { - n->set_base_type(drop_node->get_class()); - if (drop_node->get_script_instance()) { - n->set_base_script(drop_node->get_script_instance()->get_script()->get_path()); - } - } - vnode = n; - } else { - Ref<VisualScriptPropertyGet> n; - n.instantiate(); - n->set_property(property_path[1]); - if (!drop_path.is_empty()) { - if (drop_path == ".") { - n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_SELF); - } else { - n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_NODE_PATH); - n->set_base_path(drop_path); - } - } - if (drop_node) { - n->set_base_type(drop_node->get_class()); - if (drop_node->get_script_instance()) { - n->set_base_script(drop_node->get_script_instance()->get_script()->get_path()); - } - } - vnode = n; - } - } else if (p_category == String("class_constant")) { - Vector<String> property_path = p_text.split(":"); - if (ClassDB::class_exists(property_path[0])) { - Ref<VisualScriptClassConstant> n; - n.instantiate(); - n->set_base_type(property_path[0]); - n->set_class_constant(property_path[1]); - vnode = n; - } else { - Ref<VisualScriptBasicTypeConstant> n; - n.instantiate(); - if (property_path[0] == "Nil") { - n->set_basic_type(Variant::NIL); - } else if (property_path[0] == "bool") { - n->set_basic_type(Variant::BOOL); - } else if (property_path[0] == "int") { - n->set_basic_type(Variant::INT); - } else if (property_path[0] == "float") { - n->set_basic_type(Variant::FLOAT); - } else if (property_path[0] == "String") { - n->set_basic_type(Variant::STRING); - } else if (property_path[0] == "Vector2") { - n->set_basic_type(Variant::VECTOR2); - } else if (property_path[0] == "Vector2i") { - n->set_basic_type(Variant::VECTOR2I); - } else if (property_path[0] == "Rect2") { - n->set_basic_type(Variant::RECT2); - } else if (property_path[0] == "Rect2i") { - n->set_basic_type(Variant::RECT2I); - } else if (property_path[0] == "Transform2D") { - n->set_basic_type(Variant::TRANSFORM2D); - } else if (property_path[0] == "Vector3") { - n->set_basic_type(Variant::VECTOR3); - } else if (property_path[0] == "Vector3i") { - n->set_basic_type(Variant::VECTOR3I); - } else if (property_path[0] == "Plane") { - n->set_basic_type(Variant::PLANE); - } else if (property_path[0] == "ABB") { - n->set_basic_type(Variant::AABB); - } else if (property_path[0] == "Quaternion") { - n->set_basic_type(Variant::QUATERNION); - } else if (property_path[0] == "Basis") { - n->set_basic_type(Variant::BASIS); - } else if (property_path[0] == "Transform3D") { - n->set_basic_type(Variant::TRANSFORM3D); - } else if (property_path[0] == "Color") { - n->set_basic_type(Variant::COLOR); - } else if (property_path[0] == "RID") { - n->set_basic_type(Variant::RID); - } else if (property_path[0] == "Object") { - n->set_basic_type(Variant::OBJECT); - } else if (property_path[0] == "Callable") { - n->set_basic_type(Variant::CALLABLE); - } else if (property_path[0] == "Signal") { - n->set_basic_type(Variant::SIGNAL); - } else if (property_path[0] == "StringName") { - n->set_basic_type(Variant::STRING_NAME); - } else if (property_path[0] == "NodePath") { - n->set_basic_type(Variant::NODE_PATH); - } else if (property_path[0] == "Dictionary") { - n->set_basic_type(Variant::DICTIONARY); - } else if (property_path[0] == "Array") { - n->set_basic_type(Variant::ARRAY); - } else if (property_path[0] == "PackedByteArray") { - n->set_basic_type(Variant::PACKED_BYTE_ARRAY); - } else if (property_path[0] == "PackedInt32Array") { - n->set_basic_type(Variant::PACKED_INT32_ARRAY); - } else if (property_path[0] == "PackedInt64Array") { - n->set_basic_type(Variant::PACKED_INT64_ARRAY); - } else if (property_path[0] == "PackedFloat32Array") { - n->set_basic_type(Variant::PACKED_FLOAT32_ARRAY); - } else if (property_path[0] == "PackedStringArray") { - n->set_basic_type(Variant::PACKED_STRING_ARRAY); - } else if (property_path[0] == "PackedVector2Array") { - n->set_basic_type(Variant::PACKED_VECTOR2_ARRAY); - } else if (property_path[0] == "PackedVector3Array") { - n->set_basic_type(Variant::PACKED_VECTOR3_ARRAY); - } else if (property_path[0] == "PackedColorArray") { - n->set_basic_type(Variant::PACKED_COLOR_ARRAY); - } - n->set_basic_type_constant(property_path[1]); - vnode = n; - } - - } else if (p_category == String("class_signal")) { - Vector<String> property_path = p_text.split(":"); - ERR_FAIL_COND(!(script->has_custom_signal(property_path[1]) || ClassDB::has_signal(script->get_instance_base_type(), property_path[1]))); - - Ref<VisualScriptEmitSignal> n; - n.instantiate(); - n->set_signal(property_path[1]); - vnode = n; - } - if (vnode == nullptr) { - print_error("Category not handled: " + p_category.quote()); - } - - if (Object::cast_to<VisualScriptFunctionCall>(vnode.ptr()) && p_category != "Class" && p_category != "VisualScriptNode") { - Vector<String> property_path = p_text.split(":"); - String class_of_method = property_path[0]; - String method_name = property_path[1]; - - Ref<VisualScriptFunctionCall> vsfc = vnode; - vsfc->set_function(method_name); - - if (port_node_exists && p_connecting) { - VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); - - if (tg.type == Variant::OBJECT) { - vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE); - vsfc->set_base_type(String("")); - if (tg.gdclass != StringName()) { - vsfc->set_base_type(tg.gdclass); - } else if (script->get_node(port_action_node).is_valid()) { - PropertyHint hint = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint; - String base_type = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string; - - if (!base_type.is_empty() && hint == PROPERTY_HINT_TYPE_STRING) { - vsfc->set_base_type(base_type); - } - if (method_name == "call" || method_name == "call_deferred") { - vsfc->set_function(String("")); - } - } - if (tg.script.is_valid()) { - vsfc->set_base_script(tg.script->get_path()); - } - } else if (tg.type == Variant::NIL) { - vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE); - vsfc->set_base_type(String("")); - } else { - vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE); - vsfc->set_basic_type(tg.type); - } - } - } - - if (port_node_exists && p_connecting) { - if (Object::cast_to<VisualScriptPropertySet>(vnode.ptr())) { - Ref<VisualScriptPropertySet> vsp = vnode; - - VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); - if (tg.type == Variant::OBJECT) { - vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); - vsp->set_base_type(String("")); - if (tg.gdclass != StringName()) { - vsp->set_base_type(tg.gdclass); - - } else if (script->get_node(port_action_node).is_valid()) { - PropertyHint hint = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint; - String base_type = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string; - - if (!base_type.is_empty() && hint == PROPERTY_HINT_TYPE_STRING) { - vsp->set_base_type(base_type); - } - } - if (tg.script.is_valid()) { - vsp->set_base_script(tg.script->get_path()); - } - } else if (tg.type == Variant::NIL) { - vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); - vsp->set_base_type(String("")); - } else { - vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_BASIC_TYPE); - vsp->set_basic_type(tg.type); - } - } - - if (Object::cast_to<VisualScriptPropertyGet>(vnode.ptr())) { - Ref<VisualScriptPropertyGet> vsp = vnode; - - VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); - if (tg.type == Variant::OBJECT) { - vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); - vsp->set_base_type(String("")); - if (tg.gdclass != StringName()) { - vsp->set_base_type(tg.gdclass); - - } else if (script->get_node(port_action_node).is_valid()) { - PropertyHint hint = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint; - String base_type = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string; - if (!base_type.is_empty() && hint == PROPERTY_HINT_TYPE_STRING) { - vsp->set_base_type(base_type); - } - } - if (tg.script.is_valid()) { - vsp->set_base_script(tg.script->get_path()); - } - } else if (tg.type == Variant::NIL) { - vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); - vsp->set_base_type(String("")); - } else { - vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_BASIC_TYPE); - vsp->set_basic_type(tg.type); - } - } - } - if (vnode == nullptr) { - print_error("Not able to create node from category: \"" + p_category + "\" and text \"" + p_text + "\" Not created"); - return; - } - - int new_id = script->get_available_id(); - undo_redo->create_action(TTR("Add Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos); - undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); - undo_redo->add_do_method(this, "_update_graph", new_id); - undo_redo->add_undo_method(this, "_update_graph", new_id); - undo_redo->commit_action(); - - port_action_new_node = new_id; - - String base_script = ""; - String base_type = ""; - if (port_node_exists) { - if (vnode_old.is_valid()) { - if (Object::cast_to<VisualScriptTypeCast>(vnode_old.ptr())) { - base_type = Object::cast_to<VisualScriptTypeCast>(vnode_old.ptr())->get_base_type(); - base_script = Object::cast_to<VisualScriptTypeCast>(vnode_old.ptr())->get_base_script(); - } else if (Object::cast_to<VisualScriptFunctionCall>(vnode_old.ptr())) { - base_type = Object::cast_to<VisualScriptFunctionCall>(vnode_old.ptr())->get_base_type(); - base_script = Object::cast_to<VisualScriptFunctionCall>(vnode_old.ptr())->get_base_script(); - } else if (Object::cast_to<VisualScriptPropertySet>(vnode_old.ptr())) { - base_type = Object::cast_to<VisualScriptPropertySet>(vnode_old.ptr())->get_base_type(); - base_script = Object::cast_to<VisualScriptPropertySet>(vnode_old.ptr())->get_base_script(); - } else if (Object::cast_to<VisualScriptPropertyGet>(vnode_old.ptr())) { - base_type = Object::cast_to<VisualScriptPropertyGet>(vnode_old.ptr())->get_base_type(); - base_script = Object::cast_to<VisualScriptPropertyGet>(vnode_old.ptr())->get_base_script(); - } - } - - Vector<String> property_path = p_text.split(":"); - if (ClassDB::is_parent_class(script->get_instance_base_type(), property_path[0]) || script->get_path().ends_with(property_path[0].unquote())) { - if (!p_connecting) { - base_type = script->get_instance_base_type(); - base_script = script->get_path(); - } - } else { - base_type = property_path[0]; - base_script = ""; - } - - if (drop_node) { - Ref<Script> script = drop_node->get_script(); - if (script != nullptr) { - base_script = script->get_path(); - } - } - - if (vnode_old.is_valid() && p_connecting) { - if (base_type == "") { - base_type = property_path[0]; - } else if (ClassDB::is_parent_class(property_path[0], base_type)) { - base_type = property_path[0]; - } - connect_seq(vnode_old, vnode, port_action_new_node); - connect_data(vnode_old, vnode, port_action_new_node); - } - } - if (Object::cast_to<VisualScriptTypeCast>(vnode.ptr())) { - Object::cast_to<VisualScriptTypeCast>(vnode.ptr())->set_base_type(base_type); - Object::cast_to<VisualScriptTypeCast>(vnode.ptr())->set_base_script(base_script); - } else if (Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())) { - if (base_type_map.has(base_type)) { - Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_basic_type(base_type_map[base_type]); - Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE); - } else { - Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_base_type(base_type); - Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_base_script(base_script); - } - } else if (Object::cast_to<VisualScriptPropertySet>(vnode.ptr())) { - Object::cast_to<VisualScriptPropertySet>(vnode.ptr())->set_base_type(base_type); - Object::cast_to<VisualScriptPropertySet>(vnode.ptr())->set_base_script(base_script); - } else if (Object::cast_to<VisualScriptPropertyGet>(vnode.ptr())) { - Object::cast_to<VisualScriptPropertyGet>(vnode.ptr())->set_base_type(base_type); - Object::cast_to<VisualScriptPropertyGet>(vnode.ptr())->set_base_script(base_script); - } - - drop_path = String(); - drop_node = nullptr; - - _update_graph(port_action_new_node); -} - -void VisualScriptEditor::connect_seq(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode_new, int new_id) { - VisualScriptOperator *vnode_operator = Object::cast_to<VisualScriptOperator>(vnode_new.ptr()); - if (vnode_operator != nullptr && !vnode_operator->has_input_sequence_port()) { - return; - } - VisualScriptConstructor *vnode_constructor = Object::cast_to<VisualScriptConstructor>(vnode_new.ptr()); - if (vnode_constructor != nullptr) { - return; - } - if (vnode_old->get_output_sequence_port_count() <= 0) { - return; - } - if (!vnode_new->has_input_sequence_port()) { - return; - } - - undo_redo->create_action(TTR("Connect Node Sequence")); - int pass_port = -vnode_old->get_output_sequence_port_count() + 1; - int return_port = port_action_output - 1; - if (vnode_old->get_output_value_port_info(port_action_output).name == String("pass") && - !script->get_output_sequence_ports_connected(port_action_node).has(pass_port)) { - undo_redo->add_do_method(script.ptr(), "sequence_connect", port_action_node, pass_port, new_id); - undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", port_action_node, pass_port, new_id); - } else if (vnode_old->get_output_value_port_info(port_action_output).name == String("return") && - !script->get_output_sequence_ports_connected(port_action_node).has(return_port)) { - undo_redo->add_do_method(script.ptr(), "sequence_connect", port_action_node, return_port, new_id); - undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", port_action_node, return_port, new_id); - } else { - for (int port = 0; port < vnode_old->get_output_sequence_port_count(); port++) { - int count = vnode_old->get_output_sequence_port_count(); - if (port_action_output < count && !script->get_output_sequence_ports_connected(port_action_node).has(port_action_output)) { - undo_redo->add_do_method(script.ptr(), "sequence_connect", port_action_node, port_action_output, new_id); - undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", port_action_node, port_action_output, new_id); - break; - } else if (!script->get_output_sequence_ports_connected(port_action_node).has(port)) { - undo_redo->add_do_method(script.ptr(), "sequence_connect", port_action_node, port, new_id); - undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", port_action_node, port, new_id); - break; - } - } - } - - undo_redo->commit_action(); -} - -void VisualScriptEditor::_selected_new_virtual_method(const String &p_text, const String &p_category, const bool p_connecting) { - String name = p_text.substr(p_text.find_char(':') + 1); - if (script->has_function(name)) { - EditorNode::get_singleton()->show_warning(vformat(TTR("Script already has function '%s'"), name)); - return; - } - - MethodInfo minfo; - { - List<MethodInfo> methods; - bool found = false; - ClassDB::get_virtual_methods(script->get_instance_base_type(), &methods); - for (const MethodInfo &E : methods) { - if (E.name == name) { - minfo = E; - found = true; - } - } - - ERR_FAIL_COND(!found); - } - - selected = name; - Ref<VisualScriptFunction> func_node; - func_node.instantiate(); - func_node->set_name(name); - int fn_id = script->get_available_id(); - undo_redo->create_action(TTR("Add Function")); - undo_redo->add_do_method(script.ptr(), "add_function", name, fn_id); - - for (int i = 0; i < minfo.arguments.size(); i++) { - func_node->add_argument(minfo.arguments[i].type, minfo.arguments[i].name, -1, minfo.arguments[i].hint, minfo.arguments[i].hint_string); - } - - Vector2 pos = _get_available_pos(); - - undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, pos); - undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id); - if (minfo.return_val.type != Variant::NIL || minfo.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) { - Ref<VisualScriptReturn> ret_node; - ret_node.instantiate(); - ret_node->set_return_type(minfo.return_val.type); - ret_node->set_enable_return_value(true); - ret_node->set_name(name); - int nid = script->get_available_id() + 1; - undo_redo->add_do_method(script.ptr(), "add_node", nid, ret_node, _get_available_pos(false, pos + Vector2(500, 0))); - undo_redo->add_undo_method(script.ptr(), "remove_node", nid); - } - - undo_redo->add_undo_method(script.ptr(), "remove_function", name); - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - - undo_redo->commit_action(); - - _update_graph(); -} - -void VisualScriptEditor::_cancel_connect_node() { - // Ensure the cancel is done. - port_action_new_node = -1; -} - -int VisualScriptEditor::_create_new_node_from_name(const String &p_text, const Vector2 &p_point) { - Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(p_text); - int new_id = script->get_available_id(); - undo_redo->create_action(TTR("Add Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, p_point); - undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->commit_action(); - return new_id; -} - -void VisualScriptEditor::_default_value_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing) { - Ref<VisualScriptNode> vsn = script->get_node(editing_id); - if (vsn.is_null()) { - return; - } - - undo_redo->create_action(TTR("Change Input Value")); - undo_redo->add_do_method(vsn.ptr(), "set_default_input_value", editing_input, p_value); - undo_redo->add_undo_method(vsn.ptr(), "set_default_input_value", editing_input, vsn->get_default_input_value(editing_input)); - - undo_redo->add_do_method(this, "_update_graph", editing_id); - undo_redo->add_undo_method(this, "_update_graph", editing_id); - undo_redo->commit_action(); -} - -void VisualScriptEditor::_default_value_edited(Node *p_button, int p_id, int p_input_port) { - Ref<VisualScriptNode> vsn = script->get_node(p_id); - if (vsn.is_null()) { - return; - } - - PropertyInfo pinfo = vsn->get_input_value_port_info(p_input_port); - Variant existing = vsn->get_default_input_value(p_input_port); - if (pinfo.type != Variant::NIL && existing.get_type() != pinfo.type) { - Callable::CallError ce; - Variant e = existing; - const Variant *existingp = &e; - Variant::construct(pinfo.type, existing, &existingp, 1, ce); - } - - if (pinfo.type == Variant::NODE_PATH) { - Node *edited_scene = get_tree()->get_edited_scene_root(); - if (edited_scene) { // Fixing an old crash bug ( Visual Script Crashes on editing NodePath with an empty scene open). - Node *script_node = _find_script_node(edited_scene, edited_scene, script); - - if (script_node) { - // Pick a node relative to the script, IF the script exists. - pinfo.hint = PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE; - pinfo.hint_string = script_node->get_path(); - } else { - // Pick a path relative to edited scene. - pinfo.hint = PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE; - pinfo.hint_string = get_tree()->get_edited_scene_root()->get_path(); - } - } - } - - edited_default_property_holder->set_edited_property(existing); - - if (default_property_editor) { - default_property_editor->disconnect("property_changed", callable_mp(this, &VisualScriptEditor::_default_value_changed)); - default_property_editor_popup->remove_child(default_property_editor); - } - - default_property_editor = EditorInspector::instantiate_property_editor(edited_default_property_holder.ptr(), pinfo.type, "edited_property", pinfo.hint, pinfo.hint_string, PROPERTY_USAGE_NONE); - if (default_property_editor) { - default_property_editor->set_object_and_property(edited_default_property_holder.ptr(), "edited_property"); - default_property_editor->update_property(); - default_property_editor->set_name_split_ratio(0); - default_property_editor_popup->add_child(default_property_editor); - - default_property_editor->connect("property_changed", callable_mp(this, &VisualScriptEditor::_default_value_changed)); - - Button *button = Object::cast_to<Button>(p_button); - if (button) { - default_property_editor_popup->set_position(button->get_screen_position() + Vector2(0, button->get_size().height) * graph->get_zoom()); - } - - default_property_editor_popup->reset_size(); - - if (pinfo.hint == PROPERTY_HINT_MULTILINE_TEXT || !button) { - default_property_editor_popup->popup_centered_ratio(); - } else { - default_property_editor_popup->popup(); - } - } - - editing_id = p_id; - editing_input = p_input_port; -} - -void VisualScriptEditor::_show_hint(const String &p_hint) { - hint_text->set_text(p_hint); - hint_text->show(); - hint_text_timer->start(); -} - -void VisualScriptEditor::_hide_timer() { - hint_text->hide(); -} - -void VisualScriptEditor::_toggle_scripts_pressed() { - ScriptEditor::get_singleton()->toggle_scripts_panel(); - update_toggle_scripts_button(); -} - -void VisualScriptEditor::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: - case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { - graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning"))); - graph->set_warped_panning(bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning"))); - graph->set_minimap_opacity(EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity")); - graph->set_connection_lines_curvature(EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature")); - _update_graph(); - } break; - - case NOTIFICATION_READY: { - variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_members)); - variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_graph).bind(-1), CONNECT_DEFERRED); - signal_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_members)); - signal_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_graph).bind(-1), CONNECT_DEFERRED); - [[fallthrough]]; - } - case NOTIFICATION_THEME_CHANGED: { - if (p_what != NOTIFICATION_READY && !is_visible_in_tree()) { - return; - } - - update_toggle_scripts_button(); - - edit_variable_edit->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree"))); - edit_signal_edit->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree"))); - func_input_scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree"))); - - Ref<Theme> tm = EditorNode::get_singleton()->get_theme_base()->get_theme(); - - bool dark_theme = tm->get_constant("dark_theme", "Editor"); - - if (dark_theme) { - node_colors["flow_control"] = Color(0.96, 0.96, 0.96); - node_colors["functions"] = Color(0.96, 0.52, 0.51); - node_colors["data"] = Color(0.5, 0.96, 0.81); - node_colors["operators"] = Color(0.67, 0.59, 0.87); - node_colors["custom"] = Color(0.5, 0.73, 0.96); - node_colors["constants"] = Color(0.96, 0.5, 0.69); - } else { - node_colors["flow_control"] = Color(0.26, 0.26, 0.26); - node_colors["functions"] = Color(0.95, 0.4, 0.38); - node_colors["data"] = Color(0.07, 0.73, 0.51); - node_colors["operators"] = Color(0.51, 0.4, 0.82); - node_colors["custom"] = Color(0.31, 0.63, 0.95); - node_colors["constants"] = Color(0.94, 0.18, 0.49); - } - - for (const KeyValue<StringName, Color> &E : node_colors) { - const Ref<StyleBoxFlat> sb = tm->get_stylebox(SNAME("frame"), SNAME("GraphNode")); - - if (!sb.is_null()) { - Ref<StyleBoxFlat> frame_style = sb->duplicate(); - // Adjust the border color to be close to the GraphNode's background color. - // This keeps the node's title area from being too distracting. - Color color = dark_theme ? E.value.darkened(0.75) : E.value.lightened(0.75); - color.a = 0.9; - frame_style->set_border_color(color); - node_styles[E.key] = frame_style; - } - } - - if (is_visible_in_tree() && script.is_valid()) { - _update_members(); - _update_graph(); - } - } break; - - case NOTIFICATION_VISIBILITY_CHANGED: { - update_toggle_scripts_button(); - members_section->set_visible(is_visible_in_tree()); - } break; - } -} - -void VisualScriptEditor::_graph_ofs_changed(const Vector2 &p_ofs) { - if (updating_graph || !script.is_valid()) { - return; - } - - updating_graph = true; - - script->set_scroll(graph->get_scroll_ofs() / EDSCALE); - script->set_edited(true); - updating_graph = false; -} - -void VisualScriptEditor::_comment_node_resized(const Vector2 &p_new_size, int p_node) { - if (updating_graph) { - return; - } - Ref<VisualScriptComment> vsc = script->get_node(p_node); - if (vsc.is_null()) { - return; - } - - Node *node = graph->get_node(itos(p_node)); - GraphNode *gn = Object::cast_to<GraphNode>(node); - if (!gn) { - return; - } - - Vector2 new_size = p_new_size; - if (graph->is_using_snap()) { - Vector2 snap = Vector2(graph->get_snap(), graph->get_snap()); - Vector2 min_size = (gn->get_minimum_size() + (snap * 0.5)).snapped(snap); - new_size = new_size.snapped(snap).max(min_size); - } - - updating_graph = true; - - graph->set_block_minimum_size_adjust(true); //faster resize - - undo_redo->create_action(TTR("Resize Comment"), UndoRedo::MERGE_ENDS); - undo_redo->add_do_method(vsc.ptr(), "set_size", new_size / EDSCALE); - undo_redo->add_undo_method(vsc.ptr(), "set_size", vsc->get_size()); - undo_redo->commit_action(); - - gn->set_custom_minimum_size(new_size); - gn->reset_size(); - graph->set_block_minimum_size_adjust(false); - updating_graph = false; -} - -void VisualScriptEditor::_menu_option(int p_what) { - switch (p_what) { - case EDIT_ADD_NODE: { - _generic_search(); - } break; - case EDIT_DELETE_NODES: { - _on_nodes_delete(); - } break; - case EDIT_TOGGLE_BREAKPOINT: { - List<String> reselect; - for (int i = 0; i < graph->get_child_count(); i++) { - GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); - if (gn) { - if (gn->is_selected()) { - int id = String(gn->get_name()).to_int(); - Ref<VisualScriptNode> vsn = script->get_node(id); - if (vsn.is_valid()) { - vsn->set_breakpoint(!vsn->is_breakpoint()); - reselect.push_back(gn->get_name()); - } - } - } - } - - _update_graph(); - - for (const String &E : reselect) { - GraphNode *gn = Object::cast_to<GraphNode>(graph->get_node(E)); - gn->set_selected(true); - } - - } break; - case EDIT_FIND_NODE_TYPE: { - _generic_search(); - } break; - case EDIT_COPY_NODES: { - _on_nodes_copy(); - } break; - case EDIT_CUT_NODES: { - _on_nodes_copy(); - _on_nodes_delete(); - } break; - case EDIT_PASTE_NODES: { - _on_nodes_paste(); - } break; - case EDIT_DUPLICATE_NODES: { - _on_nodes_duplicate(); - } break; - case EDIT_CREATE_FUNCTION: { - // Create Function. - HashMap<int, Ref<VisualScriptNode>> nodes; - RBSet<int> selections; - for (int i = 0; i < graph->get_child_count(); i++) { - GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); - if (gn) { - if (gn->is_selected()) { - int id = String(gn->get_name()).to_int(); - Ref<VisualScriptNode> node = script->get_node(id); - if (Object::cast_to<VisualScriptFunction>(*node)) { - EditorNode::get_singleton()->show_warning(TTR("Can't create function with a function node.")); - return; - } - if (node.is_valid()) { - nodes.insert(id, node); - selections.insert(id); - } - } - } - } - - if (nodes.size() == 0) { - return; // nothing to be done if there are no valid nodes selected - } - - RBSet<VisualScript::SequenceConnection> seqmove; - RBSet<VisualScript::DataConnection> datamove; - - RBSet<VisualScript::SequenceConnection> seqext; - RBSet<VisualScript::DataConnection> dataext; - - int start_node = -1; - RBSet<int> end_nodes; - if (nodes.size() == 1) { - Ref<VisualScriptNode> nd = script->get_node(nodes.begin()->key); - if (nd.is_valid() && nd->has_input_sequence_port()) { - start_node = nodes.begin()->key; - } else { - EditorNode::get_singleton()->show_warning(TTR("Select at least one node with sequence port.")); - return; - } - } else { - List<VisualScript::SequenceConnection> seqs; - script->get_sequence_connection_list(&seqs); - - if (seqs.size() == 0) { - // In case there are no sequence connections, - // select the top most node cause that's probably how, - // the user wants to connect the nodes. - int top_nd = -1; - Vector2 top; - for (const KeyValue<int, Ref<VisualScriptNode>> &E : nodes) { - Ref<VisualScriptNode> nd = script->get_node(E.key); - if (nd.is_valid() && nd->has_input_sequence_port()) { - if (top_nd < 0) { - top_nd = E.key; - top = script->get_node_position(top_nd); - } - Vector2 pos = script->get_node_position(E.key); - if (top.y > pos.y) { - top_nd = E.key; - top = pos; - } - } - } - Ref<VisualScriptNode> nd = script->get_node(top_nd); - if (nd.is_valid() && nd->has_input_sequence_port()) { - start_node = top_nd; - } else { - EditorNode::get_singleton()->show_warning(TTR("Select at least one node with sequence port.")); - return; - } - } else { - // Pick the node with input sequence. - RBSet<int> nodes_from; - RBSet<int> nodes_to; - for (const VisualScript::SequenceConnection &E : seqs) { - if (nodes.has(E.from_node) && nodes.has(E.to_node)) { - seqmove.insert(E); - nodes_from.insert(E.from_node); - } else if (nodes.has(E.from_node) && !nodes.has(E.to_node)) { - seqext.insert(E); - } else if (!nodes.has(E.from_node) && nodes.has(E.to_node)) { - if (start_node == -1) { - seqext.insert(E); - start_node = E.to_node; - } else { - EditorNode::get_singleton()->show_warning(TTR("Try to only have one sequence input in selection.")); - return; - } - } - nodes_to.insert(E.to_node); - } - - // To use to add return nodes. - _get_ends(start_node, seqs, selections, end_nodes); - - if (start_node == -1) { - // If we still don't have a start node then, - // run through the nodes and select the first tree node, - // i.e. node without any input sequence but output sequence. - for (const int &E : nodes_from) { - if (!nodes_to.has(E)) { - start_node = E; - } - } - } - } - } - - if (start_node == -1) { - return; // This should not happen, but just in case something goes wrong. - } - - List<Variant::Type> inputs; // input types - List<Pair<int, int>> input_connections; - { - List<VisualScript::DataConnection> dats; - script->get_data_connection_list(&dats); - for (const VisualScript::DataConnection &E : dats) { - if (nodes.has(E.from_node) && nodes.has(E.to_node)) { - datamove.insert(E); - } else if (!nodes.has(E.from_node) && nodes.has(E.to_node)) { - // Add all these as inputs for the Function. - Ref<VisualScriptNode> node = script->get_node(E.to_node); - if (node.is_valid()) { - dataext.insert(E); - PropertyInfo pi = node->get_input_value_port_info(E.to_port); - inputs.push_back(pi.type); - input_connections.push_back(Pair<int, int>(E.to_node, E.to_port)); - } - } else if (nodes.has(E.from_node) && !nodes.has(E.to_node)) { - dataext.insert(E); - } - } - } - int fn_id = script->get_available_id(); - { - String new_fn = _validate_name("new_function"); - - Vector2 pos = _get_available_pos(false, script->get_node_position(start_node) - Vector2(80, 150)); - - Ref<VisualScriptFunction> func_node; - func_node.instantiate(); - func_node->set_name(new_fn); - - undo_redo->create_action(TTR("Create Function")); - - undo_redo->add_do_method(script.ptr(), "add_function", new_fn, fn_id); - undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, pos); - undo_redo->add_undo_method(script.ptr(), "remove_function", new_fn); - undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id); - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->add_do_method(this, "emit_signal", "edited_script_changed"); - undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed"); - // Might make the system more intelligent by checking port from info. - int i = 0; - List<Pair<int, int>>::Element *F = input_connections.front(); - for (List<Variant::Type>::Element *E = inputs.front(); E && F; E = E->next(), F = F->next()) { - func_node->add_argument(E->get(), "arg_" + String::num_int64(i), i); - undo_redo->add_do_method(script.ptr(), "data_connect", fn_id, i, F->get().first, F->get().second); - i++; // increment i - } - // Ensure Preview Selection is of newly created function node. - if (selections.size()) { - EditorNode::get_singleton()->push_item(func_node.ptr()); - } - } - // Move the nodes. - - // Handles reconnection of sequence connections on undo, start here in case of issues. - for (const VisualScript::SequenceConnection &E : seqext) { - undo_redo->add_do_method(script.ptr(), "sequence_disconnect", E.from_node, E.from_output, E.to_node); - undo_redo->add_undo_method(script.ptr(), "sequence_connect", E.from_node, E.from_output, E.to_node); - } - for (const VisualScript::DataConnection &E : dataext) { - undo_redo->add_do_method(script.ptr(), "data_disconnect", E.from_node, E.from_port, E.to_node, E.to_port); - undo_redo->add_undo_method(script.ptr(), "data_connect", E.from_node, E.from_port, E.to_node, E.to_port); - } - - // I don't really think we need support for non sequenced functions at this moment. - undo_redo->add_do_method(script.ptr(), "sequence_connect", fn_id, 0, start_node); - - // Could fail with the new changes, start here when searching for bugs in create function shortcut. - int m = 1; - for (const int &G : end_nodes) { - Ref<VisualScriptReturn> ret_node; - ret_node.instantiate(); - - int ret_id = fn_id + (m++); - selections.insert(ret_id); - Vector2 posi = _get_available_pos(false, script->get_node_position(G) + Vector2(80, -100)); - undo_redo->add_do_method(script.ptr(), "add_node", ret_id, ret_node, posi); - undo_redo->add_undo_method(script.ptr(), "remove_node", ret_id); - - undo_redo->add_do_method(script.ptr(), "sequence_connect", G, 0, ret_id); - // Add data outputs from each of the end_nodes. - Ref<VisualScriptNode> vsn = script->get_node(G); - if (vsn.is_valid() && vsn->get_output_value_port_count() > 0) { - ret_node->set_enable_return_value(true); - // Use the zeroth data port cause that's the likely one that is planned to be used. - ret_node->set_return_type(vsn->get_output_value_port_info(0).type); - undo_redo->add_do_method(script.ptr(), "data_connect", G, 0, ret_id, 0); - } - } - - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - - undo_redo->commit_action(); - - // Make sure all Nodes get marked for selection so that they can be moved together. - selections.insert(fn_id); - for (int k = 0; k < graph->get_child_count(); k++) { - GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(k)); - if (gn) { - int id = gn->get_name().operator String().to_int(); - gn->set_selected(selections.has(id)); - } - } - - } break; - case REFRESH_GRAPH: { - _update_graph(); - } break; - case EDIT_CLEAR_COPY_BUFFER: { - clipboard->nodes.clear(); - clipboard->nodes_positions.clear(); - clipboard->data_connections.clear(); - clipboard->sequence_connections.clear(); - } break; - } -} - -// This is likely going to be very slow and I am not sure if I should keep it, -// but I hope that it will not be a problem considering that we won't be creating functions so frequently, -// and cyclic connections would be a problem but hopefully we won't let them get to this point. -void VisualScriptEditor::_get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const RBSet<int> &p_selected, RBSet<int> &r_end_nodes) { - for (const VisualScript::SequenceConnection &E : p_seqs) { - int from = E.from_node; - int to = E.to_node; - - if (from == p_node && p_selected.has(to)) { - // This is an interior connection move forward to the to node. - _get_ends(to, p_seqs, p_selected, r_end_nodes); - } else if (from == p_node && !p_selected.has(to)) { - r_end_nodes.insert(from); - } - } -} - -void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos, MouseButton p_button) { - if (p_button != MouseButton::RIGHT) { - return; - } - - TreeItem *ti = members->get_selected(); - ERR_FAIL_COND(!ti); - - member_popup->clear(); - member_popup->set_position(members->get_screen_position() + p_pos); - member_popup->reset_size(); - - function_name_edit->set_position(members->get_screen_position() + p_pos); - function_name_edit->reset_size(); - - TreeItem *root = members->get_root(); - - Ref<Texture2D> del_icon = Control::get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")); - - Ref<Texture2D> edit_icon = Control::get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")); - - if (ti->get_parent() == root->get_first_child()) { - member_type = MEMBER_FUNCTION; - member_name = ti->get_text(0); - member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT); - member_popup->add_separator(); - member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE); - member_popup->popup(); - return; - } - - if (ti->get_parent() == root->get_first_child()->get_next()) { - member_type = MEMBER_VARIABLE; - member_name = ti->get_text(0); - member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT); - member_popup->add_separator(); - member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE); - member_popup->popup(); - return; - } - - if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) { - member_type = MEMBER_SIGNAL; - member_name = ti->get_text(0); - member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT); - member_popup->add_separator(); - member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE); - member_popup->popup(); - return; - } -} - -void VisualScriptEditor::_member_option(int p_option) { - switch (member_type) { - case MEMBER_FUNCTION: { - if (p_option == MEMBER_REMOVE) { - // Delete the function. - String name = member_name; - List<String> lst; - int fn_node = script->get_function_node_id(name); - undo_redo->create_action(TTR("Remove Function")); - undo_redo->add_do_method(script.ptr(), "remove_function", name); - undo_redo->add_do_method(script.ptr(), "remove_node", fn_node); - undo_redo->add_undo_method(script.ptr(), "add_function", name, fn_node); - undo_redo->add_undo_method(script.ptr(), "add_node", fn_node, script->get_node(fn_node), script->get_node_position(fn_node)); - List<VisualScript::SequenceConnection> seqcons; - script->get_sequence_connection_list(&seqcons); - for (const VisualScript::SequenceConnection &E : seqcons) { - if (E.from_node == fn_node) { - undo_redo->add_undo_method(script.ptr(), "sequence_connect", fn_node, E.from_output, E.to_node); - } - } - List<VisualScript::DataConnection> datcons; - script->get_data_connection_list(&datcons); - for (const VisualScript::DataConnection &E : datcons) { - if (E.from_node == fn_node) { - undo_redo->add_undo_method(script.ptr(), "data_connect", fn_node, E.from_port, E.to_node, E.to_port); - } - } - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->commit_action(); - } else if (p_option == MEMBER_EDIT) { - selected = members->get_selected()->get_text(0); - function_name_edit->popup(); - function_name_box->set_text(selected); - function_name_box->select_all(); - function_name_box->grab_focus(); - } - } break; - case MEMBER_VARIABLE: { - String name = member_name; - - if (p_option == MEMBER_REMOVE) { - undo_redo->create_action(TTR("Remove Variable")); - undo_redo->add_do_method(script.ptr(), "remove_variable", name); - undo_redo->add_undo_method(script.ptr(), "add_variable", name, script->get_variable_default_value(name)); - undo_redo->add_undo_method(script.ptr(), "set_variable_info", name, script->call("get_variable_info", name)); //return as dict - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->commit_action(); - } else if (p_option == MEMBER_EDIT) { - variable_editor->edit(name); - edit_variable_dialog->set_title(TTR("Editing Variable:") + " " + name); - edit_variable_dialog->popup_centered(Size2(400, 200) * EDSCALE); - } - } break; - case MEMBER_SIGNAL: { - String name = member_name; - - if (p_option == MEMBER_REMOVE) { - undo_redo->create_action(TTR("Remove Signal")); - undo_redo->add_do_method(script.ptr(), "remove_custom_signal", name); - undo_redo->add_undo_method(script.ptr(), "add_custom_signal", name); - - for (int i = 0; i < script->custom_signal_get_argument_count(name); i++) { - undo_redo->add_undo_method(script.ptr(), "custom_signal_add_argument", name, script->custom_signal_get_argument_name(name, i), script->custom_signal_get_argument_type(name, i)); - } - - undo_redo->add_do_method(this, "_update_members"); - undo_redo->add_undo_method(this, "_update_members"); - undo_redo->commit_action(); - } else if (p_option == MEMBER_EDIT) { - signal_editor->edit(name); - edit_signal_dialog->set_title(TTR("Editing Signal:") + " " + name); - edit_signal_dialog->popup_centered(Size2(400, 300) * EDSCALE); - } - } break; - } -} - -void VisualScriptEditor::add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) { -} - -void VisualScriptEditor::set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) { -} - -void VisualScriptEditor::update_toggle_scripts_button() { - if (is_layout_rtl()) { - toggle_scripts_button->set_icon(Control::get_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Forward") : SNAME("Back"), SNAME("EditorIcons"))); - } else { - toggle_scripts_button->set_icon(Control::get_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Back") : SNAME("Forward"), SNAME("EditorIcons"))); - } - toggle_scripts_button->set_tooltip(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text())); -} - -void VisualScriptEditor::_bind_methods() { - ClassDB::bind_method("_move_node", &VisualScriptEditor::_move_node); - ClassDB::bind_method("_update_graph", &VisualScriptEditor::_update_graph, DEFVAL(-1)); - - ClassDB::bind_method("_center_on_node", &VisualScriptEditor::_center_on_node); - ClassDB::bind_method("_button_resource_previewed", &VisualScriptEditor::_button_resource_previewed); - ClassDB::bind_method("_port_action_menu", &VisualScriptEditor::_port_action_menu); - - ClassDB::bind_method("_create_new_node_from_name", &VisualScriptEditor::_create_new_node_from_name); - - ClassDB::bind_method("_get_drag_data_fw", &VisualScriptEditor::get_drag_data_fw); - ClassDB::bind_method("_can_drop_data_fw", &VisualScriptEditor::can_drop_data_fw); - ClassDB::bind_method("_drop_data_fw", &VisualScriptEditor::drop_data_fw); - - ClassDB::bind_method("_update_graph_connections", &VisualScriptEditor::_update_graph_connections); - ClassDB::bind_method("_update_members", &VisualScriptEditor::_update_members); - - ClassDB::bind_method("_generic_search", &VisualScriptEditor::_generic_search); -} - -VisualScriptEditor::VisualScriptEditor() { - if (!clipboard) { - clipboard = memnew(Clipboard); - } - - edit_menu = memnew(MenuButton); - edit_menu->set_shortcut_context(this); - edit_menu->set_text(TTR("Edit")); - edit_menu->set_switch_on_hover(true); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_graph_delete"), EDIT_DELETE_NODES); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/toggle_breakpoint"), EDIT_TOGGLE_BREAKPOINT); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/find_node_type"), EDIT_FIND_NODE_TYPE); - edit_menu->get_popup()->add_separator(); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_copy"), EDIT_COPY_NODES); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_cut"), EDIT_CUT_NODES); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_paste"), EDIT_PASTE_NODES); - edit_menu->get_popup()->add_separator(); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/create_function"), EDIT_CREATE_FUNCTION); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/refresh_nodes"), REFRESH_GRAPH); - edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &VisualScriptEditor::_menu_option)); - - members_section = memnew(VBoxContainer); - // Add but wait until done setting up this. - ScriptEditor::get_singleton()->get_left_list_split()->call_deferred(SNAME("add_child"), members_section); - members_section->set_v_size_flags(SIZE_EXPAND_FILL); - - CheckButton *tool_script_check = memnew(CheckButton); - tool_script_check->set_text(TTR("Make Tool:")); - members_section->add_child(tool_script_check); - tool_script_check->connect("pressed", callable_mp(this, &VisualScriptEditor::_toggle_tool_script)); - - /// Members /// - - members = memnew(Tree); - members_section->add_margin_child(TTR("Members:"), members, true); - members->set_custom_minimum_size(Size2(0, 50 * EDSCALE)); - members->set_hide_root(true); - members->connect("button_clicked", callable_mp(this, &VisualScriptEditor::_member_button)); - members->connect("item_edited", callable_mp(this, &VisualScriptEditor::_member_edited)); - members->connect("cell_selected", callable_mp(this, &VisualScriptEditor::_member_selected), CONNECT_DEFERRED); - members->connect("gui_input", callable_mp(this, &VisualScriptEditor::_members_gui_input)); - members->connect("item_mouse_selected", callable_mp(this, &VisualScriptEditor::_member_rmb_selected)); - members->set_allow_rmb_select(true); - members->set_allow_reselect(true); - members->set_hide_folding(true); - members->set_drag_forwarding(this); - - member_popup = memnew(PopupMenu); - add_child(member_popup); - member_popup->connect("id_pressed", callable_mp(this, &VisualScriptEditor::_member_option)); - - function_name_edit = memnew(AcceptDialog); - function_name_edit->set_title(TTR("Rename Function")); - function_name_box = memnew(LineEdit); - function_name_edit->add_child(function_name_box); - function_name_box->connect("gui_input", callable_mp(this, &VisualScriptEditor::_fn_name_box_input)); - function_name_edit->get_ok_button()->connect("pressed", callable_mp(this, &VisualScriptEditor::_on_fn_name_box_confirmed)); - function_name_box->set_expand_to_text_length_enabled(true); - add_child(function_name_edit); - - /// Actual Graph /// - - graph = memnew(GraphEdit); - add_child(graph); - graph->set_v_size_flags(Control::SIZE_EXPAND_FILL); - graph->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); - graph->set_show_zoom_label(true); - graph->connect("node_selected", callable_mp(this, &VisualScriptEditor::_node_selected)); - graph->connect("begin_node_move", callable_mp(this, &VisualScriptEditor::_begin_node_move)); - graph->connect("end_node_move", callable_mp(this, &VisualScriptEditor::_end_node_move)); - graph->connect("copy_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_copy)); - graph->connect("paste_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_paste)); - graph->connect("delete_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_delete)); - graph->connect("duplicate_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_duplicate)); - graph->connect("gui_input", callable_mp(this, &VisualScriptEditor::_graph_gui_input)); - graph->set_drag_forwarding(this); - float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity"); - graph->set_minimap_opacity(graph_minimap_opacity); - float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature"); - graph->set_connection_lines_curvature(graph_lines_curvature); - graph->hide(); - graph->connect("scroll_offset_changed", callable_mp(this, &VisualScriptEditor::_graph_ofs_changed)); - - status_bar = memnew(HBoxContainer); - add_child(status_bar); - status_bar->set_h_size_flags(SIZE_EXPAND_FILL); - status_bar->set_custom_minimum_size(Size2(0, 24 * EDSCALE)); - - toggle_scripts_button = memnew(Button); - toggle_scripts_button->set_flat(true); - toggle_scripts_button->connect("pressed", callable_mp(this, &VisualScriptEditor::_toggle_scripts_pressed)); - status_bar->add_child(toggle_scripts_button); - - /// Add Buttons to Top Bar/Zoom bar. - HBoxContainer *graph_hbc = graph->get_zoom_hbox(); - - Label *base_lbl = memnew(Label); - base_lbl->set_text(TTR("Change Base Type:") + " "); - graph_hbc->add_child(base_lbl); - - base_type_select = memnew(Button); - base_type_select->connect("pressed", callable_mp(this, &VisualScriptEditor::_change_base_type)); - graph_hbc->add_child(base_type_select); - - Button *add_nds = memnew(Button); - add_nds->set_text(TTR("Add Nodes...")); - graph_hbc->add_child(add_nds); - add_nds->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_node_dialog)); - - Button *fn_btn = memnew(Button); - fn_btn->set_text(TTR("Add Function...")); - graph_hbc->add_child(fn_btn); - fn_btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_create_function_dialog)); - - // Add Function Dialog. - VBoxContainer *function_vb = memnew(VBoxContainer); - function_vb->set_v_size_flags(SIZE_EXPAND_FILL); - function_vb->set_custom_minimum_size(Size2(450, 300) * EDSCALE); - - HBoxContainer *func_name_hbox = memnew(HBoxContainer); - function_vb->add_child(func_name_hbox); - - Label *func_name_label = memnew(Label); - func_name_label->set_text(TTR("Name:")); - func_name_hbox->add_child(func_name_label); - - func_name_box = memnew(LineEdit); - func_name_box->set_h_size_flags(SIZE_EXPAND_FILL); - func_name_box->set_placeholder(TTR("function_name")); - func_name_box->set_text(""); - func_name_box->connect("focus_entered", callable_mp(this, &VisualScriptEditor::_deselect_input_names)); - func_name_hbox->add_child(func_name_box); - - // Add minor setting for function if needed, here! - - function_vb->add_child(memnew(HSeparator)); - - Button *add_input_button = memnew(Button); - add_input_button->set_h_size_flags(SIZE_EXPAND_FILL); - add_input_button->set_text(TTR("Add Input")); - add_input_button->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_func_input)); - function_vb->add_child(add_input_button); - - func_input_scroll = memnew(ScrollContainer); - func_input_scroll->set_v_size_flags(SIZE_EXPAND_FILL); - function_vb->add_child(func_input_scroll); - - func_input_vbox = memnew(VBoxContainer); - func_input_vbox->set_h_size_flags(SIZE_EXPAND_FILL); - func_input_scroll->add_child(func_input_vbox); - - function_create_dialog = memnew(ConfirmationDialog); - function_create_dialog->set_title(TTR("Create Function")); - function_create_dialog->add_child(function_vb); - function_create_dialog->set_ok_button_text(TTR("Create")); - function_create_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VisualScriptEditor::_create_function)); - add_child(function_create_dialog); - - select_func_text = memnew(Label); - select_func_text->set_text(TTR("Select or create a function to edit its graph.")); - select_func_text->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); - select_func_text->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); - select_func_text->set_h_size_flags(SIZE_EXPAND_FILL); - add_child(select_func_text); - - hint_text = memnew(Label); - hint_text->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -100); - hint_text->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0); - hint_text->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0); - hint_text->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); - hint_text->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); - graph->add_child(hint_text); - - hint_text_timer = memnew(Timer); - hint_text_timer->set_wait_time(4); - hint_text_timer->connect("timeout", callable_mp(this, &VisualScriptEditor::_hide_timer)); - add_child(hint_text_timer); - - // Allowed casts (connections). - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - graph->add_valid_connection_type(Variant::NIL, i); - graph->add_valid_connection_type(i, Variant::NIL); - for (int j = 0; j < Variant::VARIANT_MAX; j++) { - if (Variant::can_convert(Variant::Type(i), Variant::Type(j))) { - graph->add_valid_connection_type(i, j); - } - } - - graph->add_valid_right_disconnect_type(i); - } - - graph->add_valid_left_disconnect_type(TYPE_SEQUENCE); - - graph->connect("connection_request", callable_mp(this, &VisualScriptEditor::_graph_connected)); - graph->connect("disconnection_request", callable_mp(this, &VisualScriptEditor::_graph_disconnected)); - graph->connect("connection_to_empty", callable_mp(this, &VisualScriptEditor::_graph_connect_to_empty)); - - edit_signal_dialog = memnew(AcceptDialog); - edit_signal_dialog->set_ok_button_text(TTR("Close")); - add_child(edit_signal_dialog); - - signal_editor = memnew(VisualScriptEditorSignalEdit); - edit_signal_edit = memnew(EditorInspector); - edit_signal_dialog->add_child(edit_signal_edit); - - edit_signal_edit->edit(signal_editor); - - edit_variable_dialog = memnew(AcceptDialog); - edit_variable_dialog->set_ok_button_text(TTR("Close")); - add_child(edit_variable_dialog); - - variable_editor = memnew(VisualScriptEditorVariableEdit); - edit_variable_edit = memnew(EditorInspector); - edit_variable_dialog->add_child(edit_variable_edit); - - edit_variable_edit->edit(variable_editor); - - select_base_type = memnew(CreateDialog); - select_base_type->set_base_type("Object"); // Anything goes. - select_base_type->connect("create", callable_mp(this, &VisualScriptEditor::_change_base_type_callback)); - add_child(select_base_type); - - undo_redo = EditorNode::get_singleton()->get_undo_redo(); - - set_process_input(true); - - default_property_editor_popup = memnew(PopupPanel); - default_property_editor_popup->set_min_size(Size2i(180, 0) * EDSCALE); - add_child(default_property_editor_popup); - - edited_default_property_holder.instantiate(); - - new_connect_node_select = memnew(VisualScriptPropertySelector); - add_child(new_connect_node_select); - new_connect_node_select->connect("selected", callable_mp(this, &VisualScriptEditor::_selected_connect_node)); - new_connect_node_select->get_cancel_button()->connect("pressed", callable_mp(this, &VisualScriptEditor::_cancel_connect_node)); - - new_virtual_method_select = memnew(VisualScriptPropertySelector); - add_child(new_virtual_method_select); - new_virtual_method_select->connect("selected", callable_mp(this, &VisualScriptEditor::_selected_new_virtual_method)); - - popup_menu = memnew(PopupMenu); - add_child(popup_menu); - popup_menu->add_item(TTR("Add Node"), EDIT_ADD_NODE); - popup_menu->add_separator(); - popup_menu->add_item(TTR("Cut"), EDIT_CUT_NODES); - popup_menu->add_item(TTR("Copy"), EDIT_COPY_NODES); - popup_menu->add_item(TTR("Paste"), EDIT_PASTE_NODES); - popup_menu->add_item(TTR("Delete"), EDIT_DELETE_NODES); - popup_menu->add_item(TTR("Duplicate"), EDIT_DUPLICATE_NODES); - popup_menu->add_item(TTR("Clear Copy Buffer"), EDIT_CLEAR_COPY_BUFFER); - popup_menu->connect("id_pressed", callable_mp(this, &VisualScriptEditor::_menu_option)); - - base_type_map.insert("String", Variant::STRING); - base_type_map.insert("Vector2", Variant::VECTOR2); - base_type_map.insert("Vector2i", Variant::VECTOR2I); - base_type_map.insert("Rect2", Variant::RECT2); - base_type_map.insert("Rect2i", Variant::RECT2I); - base_type_map.insert("Vector3", Variant::VECTOR3); - base_type_map.insert("Vector3i", Variant::VECTOR3I); - base_type_map.insert("Vector4", Variant::VECTOR4); - base_type_map.insert("Vector4i", Variant::VECTOR4I); - base_type_map.insert("Transform2D", Variant::TRANSFORM2D); - base_type_map.insert("Plane", Variant::PLANE); - base_type_map.insert("Quaternion", Variant::QUATERNION); - base_type_map.insert("AABB", Variant::AABB); - base_type_map.insert("Basis", Variant::BASIS); - base_type_map.insert("Transform3D", Variant::TRANSFORM3D); - base_type_map.insert("Projection", Variant::PROJECTION); - base_type_map.insert("Color", Variant::COLOR); - base_type_map.insert("NodePath", Variant::NODE_PATH); - base_type_map.insert("RID", Variant::RID); - base_type_map.insert("Callable", Variant::CALLABLE); - base_type_map.insert("Dictionary", Variant::DICTIONARY); - base_type_map.insert("Array", Variant::ARRAY); - base_type_map.insert("PackedByteArray", Variant::PACKED_BYTE_ARRAY); - base_type_map.insert("PackedInt32Array", Variant::PACKED_INT32_ARRAY); - base_type_map.insert("PackedFloat32Array", Variant::PACKED_FLOAT32_ARRAY); - base_type_map.insert("PackedInt64Array", Variant::PACKED_INT64_ARRAY); - base_type_map.insert("PackedFloat64Array", Variant::PACKED_FLOAT64_ARRAY); - base_type_map.insert("PackedStringArray", Variant::PACKED_STRING_ARRAY); - base_type_map.insert("PackedVector2Array", Variant::PACKED_VECTOR2_ARRAY); - base_type_map.insert("PackedVector3Array", Variant::PACKED_VECTOR3_ARRAY); - base_type_map.insert("PackedColorArray", Variant::PACKED_COLOR_ARRAY); -} - -VisualScriptEditor::~VisualScriptEditor() { - undo_redo->clear_history(); // Avoid crashes. - memdelete(signal_editor); - memdelete(variable_editor); -} - -static ScriptEditorBase *create_editor(const Ref<Resource> &p_resource) { - if (Object::cast_to<VisualScript>(*p_resource)) { - return memnew(VisualScriptEditor); - } - - return nullptr; -} - -VisualScriptEditor::Clipboard *VisualScriptEditor::clipboard = nullptr; - -void VisualScriptEditor::free_clipboard() { - if (clipboard) { - memdelete(clipboard); - } -} - -static void register_editor_callback() { - ScriptEditor::register_create_script_editor_function(create_editor); - - ED_SHORTCUT("visual_script_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), Key::F9); - ED_SHORTCUT("visual_script_editor/find_node_type", TTR("Find Node Type"), KeyModifierMask::CMD + Key::F); - ED_SHORTCUT("visual_script_editor/create_function", TTR("Make Function"), KeyModifierMask::CMD + Key::G); - ED_SHORTCUT("visual_script_editor/refresh_nodes", TTR("Refresh Graph"), KeyModifierMask::CMD + Key::R); - ED_SHORTCUT("visual_script_editor/edit_member", TTR("Edit Member"), KeyModifierMask::CMD + Key::E); -} - -void VisualScriptEditor::register_editor() { - // Too early to register stuff here, request a callback. - EditorNode::add_plugin_init_callback(register_editor_callback); -} - -void VisualScriptEditor::validate() { -} - -// VisualScriptCustomNodes - -Ref<VisualScriptNode> VisualScriptCustomNodes::create_node_custom(const String &p_name) { - Ref<VisualScriptCustomNode> node; - node.instantiate(); - node->set_script(singleton->custom_nodes[p_name]); - return node; -} - -VisualScriptCustomNodes *VisualScriptCustomNodes::singleton = nullptr; -HashMap<String, Ref<RefCounted>> VisualScriptCustomNodes::custom_nodes; - -VisualScriptCustomNodes::VisualScriptCustomNodes() { - singleton = this; -} - -VisualScriptCustomNodes::~VisualScriptCustomNodes() { - custom_nodes.clear(); -} - -void VisualScriptCustomNodes::add_custom_node(const String &p_name, const String &p_category, const Ref<Script> &p_script) { - String node_name = "custom/" + p_category + "/" + p_name; - custom_nodes.insert(node_name, p_script); - VisualScriptLanguage::singleton->add_register_func(node_name, &VisualScriptCustomNodes::create_node_custom); - emit_signal(SNAME("custom_nodes_updated")); -} - -void VisualScriptCustomNodes::remove_custom_node(const String &p_name, const String &p_category) { - String node_name = "custom/" + p_category + "/" + p_name; - custom_nodes.erase(node_name); - VisualScriptLanguage::singleton->remove_register_func(node_name); - emit_signal(SNAME("custom_nodes_updated")); -} - -void VisualScriptCustomNodes::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_custom_node", "name", "category", "script"), &VisualScriptCustomNodes::add_custom_node); - ClassDB::bind_method(D_METHOD("remove_custom_node", "name", "category"), &VisualScriptCustomNodes::remove_custom_node); - ADD_SIGNAL(MethodInfo("custom_nodes_updated")); -} - -#endif diff --git a/modules/visual_script/editor/visual_script_editor.h b/modules/visual_script/editor/visual_script_editor.h deleted file mode 100644 index 306f71ecf8..0000000000 --- a/modules/visual_script/editor/visual_script_editor.h +++ /dev/null @@ -1,395 +0,0 @@ -/*************************************************************************/ -/* visual_script_editor.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 VISUAL_SCRIPT_EDITOR_H -#define VISUAL_SCRIPT_EDITOR_H - -#include "../visual_script.h" -#include "editor/create_dialog.h" -#include "editor/plugins/script_editor_plugin.h" -#include "visual_script_property_selector.h" - -class GraphEdit; - -class EditorUndoRedoManager; -class VisualScriptEditorSignalEdit; -class VisualScriptEditorVariableEdit; - -#ifdef TOOLS_ENABLED - -class VisualScriptEditedProperty : public RefCounted { - GDCLASS(VisualScriptEditedProperty, RefCounted); - -private: - Variant edited_property; - -protected: - static void _bind_methods(); - -public: - void set_edited_property(Variant p_variant); - Variant get_edited_property() const; - - VisualScriptEditedProperty() {} -}; - -// TODO: Maybe this class should be refactored. -// See https://github.com/godotengine/godot/issues/51913 -class VisualScriptEditor : public ScriptEditorBase { - GDCLASS(VisualScriptEditor, ScriptEditorBase); - - enum { - TYPE_SEQUENCE = 1000, - INDEX_BASE_SEQUENCE = 1024 - }; - - enum { - EDIT_ADD_NODE, - EDIT_SEPARATOR, // popup menu separator - ignored - EDIT_CUT_NODES, - EDIT_COPY_NODES, - EDIT_PASTE_NODES, - EDIT_DELETE_NODES, - EDIT_DUPLICATE_NODES, - EDIT_CLEAR_COPY_BUFFER, - - EDIT_CREATE_FUNCTION, - EDIT_TOGGLE_BREAKPOINT, - EDIT_FIND_NODE_TYPE, - REFRESH_GRAPH, - }; - - enum PortAction { - CREATE_CALL_SET_GET, - CREATE_ACTION, - }; - - enum MemberAction { - MEMBER_EDIT, - MEMBER_REMOVE - }; - - enum MemberType { - MEMBER_FUNCTION, - MEMBER_VARIABLE, - MEMBER_SIGNAL - }; - - VBoxContainer *members_section = nullptr; - MenuButton *edit_menu = nullptr; - - Ref<VisualScript> script; - - Button *base_type_select = nullptr; - - LineEdit *func_name_box = nullptr; - ScrollContainer *func_input_scroll = nullptr; - VBoxContainer *func_input_vbox = nullptr; - ConfirmationDialog *function_create_dialog = nullptr; - - GraphEdit *graph = nullptr; - HBoxContainer *status_bar = nullptr; - Button *toggle_scripts_button = nullptr; - - VisualScriptEditorSignalEdit *signal_editor = nullptr; - - AcceptDialog *edit_signal_dialog = nullptr; - EditorInspector *edit_signal_edit = nullptr; - - VisualScriptPropertySelector *method_select = nullptr; - VisualScriptPropertySelector *new_connect_node_select = nullptr; - VisualScriptPropertySelector *new_virtual_method_select = nullptr; - - VisualScriptEditorVariableEdit *variable_editor = nullptr; - - AcceptDialog *edit_variable_dialog = nullptr; - EditorInspector *edit_variable_edit = nullptr; - - PopupPanel *default_property_editor_popup = nullptr; - EditorProperty *default_property_editor = nullptr; - Ref<VisualScriptEditedProperty> edited_default_property_holder; - - Ref<EditorUndoRedoManager> undo_redo; - Tree *members = nullptr; - AcceptDialog *function_name_edit = nullptr; - LineEdit *function_name_box = nullptr; - - Label *hint_text = nullptr; - Timer *hint_text_timer = nullptr; - - Label *select_func_text = nullptr; - - bool updating_graph = false; - - void _show_hint(const String &p_hint); - void _hide_timer(); - - CreateDialog *select_base_type = nullptr; - - struct VirtualInMenu { - String name; - Variant::Type ret; - bool ret_variant; - Vector<Pair<Variant::Type, String>> args; - }; - - HashMap<StringName, Color> node_colors; - HashMap<StringName, Ref<StyleBox>> node_styles; - HashMap<StringName, Variant::Type> base_type_map; - - void _update_graph_connections(); - void _update_graph(int p_only_id = -1); - - bool updating_members = false; - - void _update_members(); - String _sanitized_variant_text(const StringName &property_name); - - StringName selected; - - String _validate_name(const String &p_name) const; - - struct Clipboard { - HashMap<int, Ref<VisualScriptNode>> nodes; - HashMap<int, Vector2> nodes_positions; - - RBSet<VisualScript::SequenceConnection> sequence_connections; - RBSet<VisualScript::DataConnection> data_connections; - }; - - static Clipboard *clipboard; - - PopupMenu *popup_menu = nullptr; - PopupMenu *member_popup = nullptr; - MemberType member_type; - String member_name; - - PortAction port_action; - int port_action_node = 0; - int port_action_output = 0; - Vector2 port_action_pos; - int port_action_new_node = 0; - - bool saved_pos_dirty = false; - - Vector2 mouse_up_position; - - void _port_action_menu(int p_option); - - void connect_data(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode, int new_id); - - NodePath drop_path; - Node *drop_node = nullptr; - Vector2 drop_position; - void _selected_connect_node(const String &p_text, const String &p_category, const bool p_connecting = true); - void connect_seq(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode_new, int new_id); - - void _cancel_connect_node(); - int _create_new_node_from_name(const String &p_text, const Vector2 &p_point); - void _selected_new_virtual_method(const String &p_text, const String &p_category, const bool p_connecting); - - int error_line = -1; - - void _node_selected(Node *p_node); - void _center_on_node(int p_id); - - void _node_filter_changed(const String &p_text); - void _change_base_type_callback(); - void _change_base_type(); - void _toggle_tool_script(); - void _member_selected(); - void _member_edited(); - - void _begin_node_move(); - void _end_node_move(); - void _move_node(int p_id, const Vector2 &p_to); - - void _get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const RBSet<int> &p_selected, RBSet<int> &r_end_nodes); - - void _node_moved(Vector2 p_from, Vector2 p_to, int p_id); - void _remove_node(int p_id); - void _graph_connected(const String &p_from, int p_from_slot, const String &p_to, int p_to_slot); - void _graph_disconnected(const String &p_from, int p_from_slot, const String &p_to, int p_to_slot); - void _graph_connect_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_pos); - - void _node_ports_changed(int p_id); - void _node_create(); - - void _update_available_nodes(); - - void _member_button(Object *p_item, int p_column, int p_button, MouseButton p_mouse_button); - - void _expression_text_changed(const String &p_text, int p_id); - void _add_input_port(int p_id); - void _add_output_port(int p_id); - void _remove_input_port(int p_id, int p_port); - void _remove_output_port(int p_id, int p_port); - void _change_port_type(int p_select, int p_id, int p_port, bool is_input); - void _update_node_size(int p_id); - void _port_name_focus_out(const Node *p_name_box, int p_id, int p_port, bool is_input); - - Vector2 _get_pos_in_graph(Vector2 p_point) const; - Vector2 _get_available_pos(bool p_centered = true, Vector2 p_pos = Vector2()) const; - - bool node_has_sequence_connections(int p_id); - - void _generic_search(Vector2 pos = Vector2(), bool node_centered = false); - - virtual void input(const Ref<InputEvent> &p_event) override; - void _graph_gui_input(const Ref<InputEvent> &p_event); - void _members_gui_input(const Ref<InputEvent> &p_event); - void _fn_name_box_input(const Ref<InputEvent> &p_event); - void _on_fn_name_box_confirmed(); - void _rename_function(const String &p_name, const String &p_new_name); - - void _create_function_dialog(); - void _create_function(); - void _add_func_input(); - void _remove_func_input(Node *p_node); - void _deselect_input_names(); - void _add_node_dialog(); - void _node_item_selected(); - void _node_item_unselected(); - - void _on_nodes_copy(); - void _on_nodes_paste(); - void _on_nodes_delete(); - void _on_nodes_duplicate(); - - Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); - bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; - void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); - - int editing_id = 0; - int editing_input = 0; - - bool can_swap = false; - int data_disconnect_node = 0; - int data_disconnect_port = 0; - - void _default_value_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing); - void _default_value_edited(Node *p_button, int p_id, int p_input_port); - - void _menu_option(int p_what); - - void _graph_ofs_changed(const Vector2 &p_ofs); - void _comment_node_resized(const Vector2 &p_new_size, int p_node); - - void _draw_color_over_button(Object *obj, Color p_color); - void _button_resource_previewed(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud); - - VisualScriptNode::TypeGuess _guess_output_type(int p_port_action_node, int p_port_action_output, RBSet<int> &p_visited_nodes); - - void _member_rmb_selected(const Vector2 &p_pos, MouseButton p_button); - void _member_option(int p_option); - - void _toggle_scripts_pressed(); - -protected: - void _notification(int p_what); - static void _bind_methods(); - -public: - virtual void add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) override; - virtual void set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) override; - - virtual void apply_code() override; - virtual Ref<Resource> get_edited_resource() const override; - virtual void set_edited_resource(const Ref<Resource> &p_res) override; - virtual void enable_editor() override; - virtual Vector<String> get_functions() override; - virtual void reload_text() override; - virtual String get_name() override; - virtual Ref<Texture2D> get_theme_icon() override; - virtual bool is_unsaved() override; - virtual Variant get_edit_state() override; - virtual void set_edit_state(const Variant &p_state) override; - virtual void goto_line(int p_line, bool p_with_error = false) override; - virtual void set_executing_line(int p_line) override; - virtual void clear_executing_line() override; - virtual void trim_trailing_whitespace() override; - virtual void insert_final_newline() override; - virtual void convert_indent_to_spaces() override; - virtual void convert_indent_to_tabs() override; - virtual void ensure_focus() override; - virtual void tag_saved_version() override; - virtual void reload(bool p_soft) override; - virtual Array get_breakpoints() override; - virtual void set_breakpoint(int p_line, bool p_enable) override{}; - virtual void clear_breakpoints() override{}; - virtual void add_callback(const String &p_function, PackedStringArray p_args) override; - virtual void update_settings() override; - virtual bool show_members_overview() override; - virtual void set_debugger_active(bool p_active) override; - virtual void set_tooltip_request_func(const Callable &p_toolip_callback) override; - virtual Control *get_edit_menu() override; - virtual void clear_edit_menu() override; - virtual void set_find_replace_bar(FindReplaceBar *p_bar) override { p_bar->hide(); }; // Not needed here. - virtual bool can_lose_focus_on_node_selection() override { return false; } - virtual void validate() override; - - virtual Control *get_base_editor() const override; - - static void register_editor(); - - static void free_clipboard(); - - void update_toggle_scripts_button() override; - - VisualScriptEditor(); - ~VisualScriptEditor(); -}; - -// Singleton -class VisualScriptCustomNodes : public Object { - GDCLASS(VisualScriptCustomNodes, Object); - - friend class VisualScriptLanguage; - -protected: - static void _bind_methods(); - static VisualScriptCustomNodes *singleton; - - static HashMap<String, Ref<RefCounted>> custom_nodes; - static Ref<VisualScriptNode> create_node_custom(const String &p_name); - -public: - static VisualScriptCustomNodes *get_singleton() { return singleton; } - - void add_custom_node(const String &p_name, const String &p_category, const Ref<Script> &p_script); - void remove_custom_node(const String &p_name, const String &p_category); - - VisualScriptCustomNodes(); - ~VisualScriptCustomNodes(); -}; - -#endif - -#endif // VISUAL_SCRIPT_EDITOR_H diff --git a/modules/visual_script/editor/visual_script_property_selector.cpp b/modules/visual_script/editor/visual_script_property_selector.cpp deleted file mode 100644 index 712c89368b..0000000000 --- a/modules/visual_script/editor/visual_script_property_selector.cpp +++ /dev/null @@ -1,1277 +0,0 @@ -/*************************************************************************/ -/* visual_script_property_selector.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "visual_script_property_selector.h" - -#include "../visual_script.h" -#include "../visual_script_builtin_funcs.h" -#include "../visual_script_flow_control.h" -#include "../visual_script_func_nodes.h" -#include "../visual_script_nodes.h" -#include "core/os/keyboard.h" -#include "editor/doc_tools.h" -#include "editor/editor_feature_profile.h" -#include "editor/editor_scale.h" -#include "editor/editor_settings.h" -#include "scene/main/node.h" -#include "scene/main/window.h" - -void VisualScriptPropertySelector::_update_icons() { - search_box->set_right_icon(results_tree->get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); - search_box->set_clear_button_enabled(true); - search_box->add_theme_icon_override("right_icon", results_tree->get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); - - search_visual_script_nodes->set_icon(results_tree->get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons"))); - search_classes->set_icon(results_tree->get_theme_icon(SNAME("Object"), SNAME("EditorIcons"))); - search_methods->set_icon(results_tree->get_theme_icon(SNAME("MemberMethod"), SNAME("EditorIcons"))); - search_operators->set_icon(results_tree->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); - search_signals->set_icon(results_tree->get_theme_icon(SNAME("MemberSignal"), SNAME("EditorIcons"))); - search_constants->set_icon(results_tree->get_theme_icon(SNAME("MemberConstant"), SNAME("EditorIcons"))); - search_properties->set_icon(results_tree->get_theme_icon(SNAME("MemberProperty"), SNAME("EditorIcons"))); - search_theme_items->set_icon(results_tree->get_theme_icon(SNAME("MemberTheme"), SNAME("EditorIcons"))); - - case_sensitive_button->set_icon(results_tree->get_theme_icon(SNAME("MatchCase"), SNAME("EditorIcons"))); - hierarchy_button->set_icon(results_tree->get_theme_icon(SNAME("ClassList"), SNAME("EditorIcons"))); -} - -void VisualScriptPropertySelector::_sbox_input(const Ref<InputEvent> &p_ie) { - Ref<InputEventKey> k = p_ie; - - if (k.is_valid()) { - switch (k->get_keycode()) { - case Key::UP: - case Key::DOWN: - case Key::PAGEUP: - case Key::PAGEDOWN: { - results_tree->gui_input(k); - search_box->accept_event(); - } break; - default: - break; - } - } -} - -void VisualScriptPropertySelector::_update_results_i(int p_int) { - _update_results(); -} - -void VisualScriptPropertySelector::_update_results_s(String p_string) { - _update_results(); -} - -void VisualScriptPropertySelector::_update_results_search_all() { - if (search_classes->is_pressed()) { - scope_combo->select(COMBO_ALL); - } - _update_results(); -} - -void VisualScriptPropertySelector::_update_results() { - _update_icons(); - search_runner = Ref<SearchRunner>(memnew(SearchRunner(this, results_tree))); - set_process(true); -} - -void VisualScriptPropertySelector::_confirmed() { - TreeItem *ti = results_tree->get_selected(); - if (!ti) { - return; - } - emit_signal(SNAME("selected"), ti->get_metadata(0), ti->get_metadata(1), connecting); - set_visible(false); -} - -void VisualScriptPropertySelector::_item_selected() { - help_bit->set_text(results_tree->get_selected()->get_meta("description", "No description available")); -} - -void VisualScriptPropertySelector::_hide_requested() { - _cancel_pressed(); // From AcceptDialog. -} - -void VisualScriptPropertySelector::_notification(int p_what) { - switch (p_what) { - case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { - _update_icons(); - } break; - - case NOTIFICATION_ENTER_TREE: { - connect("confirmed", callable_mp(this, &VisualScriptPropertySelector::_confirmed)); - } break; - - case NOTIFICATION_PROCESS: { - // Update background search. - if (search_runner.is_valid()) { - if (search_runner->work()) { - // Search done. - get_ok_button()->set_disabled(!results_tree->get_selected()); - - search_runner = Ref<SearchRunner>(); - set_process(false); - } - } else { - // if one is valid - set_process(false); - } - } break; - } -} - -void VisualScriptPropertySelector::select_method_from_base_type(const String &p_base, const bool p_virtuals_only, const bool p_connecting, bool clear_text) { - set_title(TTR("Select method from base type")); - base_type = p_base; - base_script = ""; - type = Variant::NIL; - connecting = p_connecting; - - if (clear_text) { - if (p_virtuals_only) { - search_box->set_text("._"); // show all _methods - search_box->set_caret_column(2); - } else { - search_box->set_text("."); // show all methods - search_box->set_caret_column(1); - } - } - - search_visual_script_nodes->set_pressed(false); - search_classes->set_pressed(false); - search_methods->set_pressed(true); - search_operators->set_pressed(false); - search_signals->set_pressed(false); - search_constants->set_pressed(false); - search_properties->set_pressed(false); - search_theme_items->set_pressed(false); - - scope_combo->select(COMBO_BASE); - - results_tree->clear(); - show_window(.5f); - search_box->grab_focus(); - - _update_results(); -} - -void VisualScriptPropertySelector::select_from_base_type(const String &p_base, const String &p_base_script, bool p_virtuals_only, const bool p_connecting, bool clear_text) { - set_title(TTR("Select from base type")); - base_type = p_base; - base_script = p_base_script.trim_prefix("res://").quote(); // filepath to EditorHelp::get_doc_data().name - type = Variant::NIL; - connecting = p_connecting; - - if (clear_text) { - if (p_virtuals_only) { - search_box->set_text("_"); - } else { - search_box->set_text(" "); - } - } - search_box->select_all(); - - search_visual_script_nodes->set_pressed(false); - search_classes->set_pressed(false); - search_methods->set_pressed(true); - search_operators->set_pressed(false); - search_signals->set_pressed(true); - search_constants->set_pressed(false); - search_properties->set_pressed(true); - search_theme_items->set_pressed(false); - - scope_combo->select(COMBO_RELATED); - - results_tree->clear(); - show_window(.5f); - search_box->grab_focus(); - _update_results(); -} - -void VisualScriptPropertySelector::select_from_script(const Ref<Script> &p_script, const bool p_connecting, bool clear_text) { - set_title(TTR("Select from script")); - ERR_FAIL_COND(p_script.is_null()); - - base_type = p_script->get_instance_base_type(); - base_script = p_script->get_path().trim_prefix("res://").quote(); // filepath to EditorHelp::get_doc_data().name - type = Variant::NIL; - script = p_script->get_instance_id(); - connecting = p_connecting; - - if (clear_text) { - search_box->set_text(""); - } - search_box->select_all(); - - search_visual_script_nodes->set_pressed(false); - search_classes->set_pressed(true); - search_methods->set_pressed(true); - search_operators->set_pressed(true); - search_signals->set_pressed(true); - search_constants->set_pressed(true); - search_properties->set_pressed(true); - search_theme_items->set_pressed(false); - - scope_combo->select(COMBO_BASE); - - results_tree->clear(); - show_window(.5f); - search_box->grab_focus(); - _update_results(); -} - -void VisualScriptPropertySelector::select_from_basic_type(Variant::Type p_type, const bool p_connecting, bool clear_text) { - set_title(TTR("Select from basic type")); - ERR_FAIL_COND(p_type == Variant::NIL); - base_type = Variant::get_type_name(p_type); - base_script = ""; - type = p_type; - connecting = p_connecting; - - if (clear_text) { - search_box->set_text(" "); - } - search_box->select_all(); - - search_visual_script_nodes->set_pressed(false); - search_classes->set_pressed(false); - search_methods->set_pressed(true); - search_operators->set_pressed(true); - search_signals->set_pressed(false); - search_constants->set_pressed(true); - search_properties->set_pressed(true); - search_theme_items->set_pressed(false); - - scope_combo->select(COMBO_BASE); - - results_tree->clear(); - show_window(.5f); - search_box->grab_focus(); - - _update_results(); -} - -void VisualScriptPropertySelector::select_from_action(const String &p_type, const bool p_connecting, bool clear_text) { - set_title(TTR("Select from action")); - base_type = p_type; - base_script = ""; - type = Variant::NIL; - connecting = p_connecting; - - if (clear_text) { - search_box->set_text(""); - } - search_box->select_all(); - - search_visual_script_nodes->set_pressed(true); - search_classes->set_pressed(false); - search_methods->set_pressed(false); - search_operators->set_pressed(false); - search_signals->set_pressed(false); - search_constants->set_pressed(false); - search_properties->set_pressed(false); - search_theme_items->set_pressed(false); - - scope_combo->select(COMBO_RELATED); - - results_tree->clear(); - show_window(.5f); - search_box->grab_focus(); - _update_results(); -} - -void VisualScriptPropertySelector::select_from_instance(Object *p_instance, const bool p_connecting, bool clear_text) { - set_title(TTR("Select from instance")); - base_type = p_instance->get_class(); - - const Ref<Script> &p_script = p_instance->get_script(); - if (p_script == nullptr) { - base_script = ""; - } else { - base_script = p_script->get_path().trim_prefix("res://").quote(); // filepath to EditorHelp::get_doc_data().name - } - - type = Variant::NIL; - connecting = p_connecting; - - if (clear_text) { - search_box->set_text(" "); - } - search_box->select_all(); - - search_visual_script_nodes->set_pressed(false); - search_classes->set_pressed(false); - search_methods->set_pressed(true); - search_operators->set_pressed(false); - search_signals->set_pressed(true); - search_constants->set_pressed(true); - search_properties->set_pressed(true); - search_theme_items->set_pressed(false); - - scope_combo->select(COMBO_BASE); - - results_tree->clear(); - show_window(.5f); - search_box->grab_focus(); - _update_results(); -} - -void VisualScriptPropertySelector::select_from_visual_script(const Ref<Script> &p_script, bool clear_text) { - set_title(TTR("Select from visual script")); - base_type = p_script->get_instance_base_type(); - if (p_script == nullptr) { - base_script = ""; - } else { - base_script = p_script->get_path().trim_prefix("res://").quote(); // filepath to EditorHelp::get_doc_data().name - } - type = Variant::NIL; - connecting = false; - - if (clear_text) { - search_box->set_text(" "); - } - search_box->select_all(); - - search_visual_script_nodes->set_pressed(true); - search_classes->set_pressed(false); - search_methods->set_pressed(true); - search_operators->set_pressed(false); - search_signals->set_pressed(true); - search_constants->set_pressed(true); - search_properties->set_pressed(true); - search_theme_items->set_pressed(false); - - scope_combo->select(COMBO_BASE); - - results_tree->clear(); - show_window(.5f); - search_box->grab_focus(); - _update_results(); -} - -void VisualScriptPropertySelector::show_window(float p_screen_ratio) { - popup_centered_ratio(p_screen_ratio); -} - -void VisualScriptPropertySelector::_bind_methods() { - ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "category"), PropertyInfo(Variant::BOOL, "connecting"))); -} - -VisualScriptPropertySelector::VisualScriptPropertySelector() { - vbox = memnew(VBoxContainer); - add_child(vbox); - - HBoxContainer *hbox = memnew(HBoxContainer); - hbox->set_alignment(hbox->ALIGNMENT_CENTER); - vbox->add_child(hbox); - - case_sensitive_button = memnew(Button); - case_sensitive_button->set_flat(true); - case_sensitive_button->set_tooltip(TTR("Case Sensitive")); - case_sensitive_button->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); - case_sensitive_button->set_toggle_mode(true); - case_sensitive_button->set_focus_mode(Control::FOCUS_NONE); - hbox->add_child(case_sensitive_button); - - hierarchy_button = memnew(Button); - hierarchy_button->set_flat(true); - hierarchy_button->set_tooltip(TTR("Show Hierarchy")); - hierarchy_button->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); - hierarchy_button->set_toggle_mode(true); - hierarchy_button->set_pressed(true); - hierarchy_button->set_focus_mode(Control::FOCUS_NONE); - hbox->add_child(hierarchy_button); - - hbox->add_child(memnew(VSeparator)); - - search_visual_script_nodes = memnew(Button); - search_visual_script_nodes->set_flat(true); - search_visual_script_nodes->set_tooltip(TTR("Search Visual Script Nodes")); - search_visual_script_nodes->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); - search_visual_script_nodes->set_toggle_mode(true); - search_visual_script_nodes->set_pressed(true); - search_visual_script_nodes->set_focus_mode(Control::FOCUS_NONE); - hbox->add_child(search_visual_script_nodes); - - search_classes = memnew(Button); - search_classes->set_flat(true); - search_classes->set_tooltip(TTR("Search Classes")); - search_classes->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results_search_all)); - search_classes->set_toggle_mode(true); - search_classes->set_pressed(true); - search_classes->set_focus_mode(Control::FOCUS_NONE); - hbox->add_child(search_classes); - - search_operators = memnew(Button); - search_operators->set_flat(true); - search_operators->set_tooltip(TTR("Search Operators")); - search_operators->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); - search_operators->set_toggle_mode(true); - search_operators->set_pressed(true); - search_operators->set_focus_mode(Control::FOCUS_NONE); - hbox->add_child(search_operators); - - hbox->add_child(memnew(VSeparator)); - - search_methods = memnew(Button); - search_methods->set_flat(true); - search_methods->set_tooltip(TTR("Search Methods")); - search_methods->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); - search_methods->set_toggle_mode(true); - search_methods->set_pressed(true); - search_methods->set_focus_mode(Control::FOCUS_NONE); - hbox->add_child(search_methods); - - search_signals = memnew(Button); - search_signals->set_flat(true); - search_signals->set_tooltip(TTR("Search Signals")); - search_signals->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); - search_signals->set_toggle_mode(true); - search_signals->set_pressed(true); - search_signals->set_focus_mode(Control::FOCUS_NONE); - hbox->add_child(search_signals); - - search_constants = memnew(Button); - search_constants->set_flat(true); - search_constants->set_tooltip(TTR("Search Constants")); - search_constants->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); - search_constants->set_toggle_mode(true); - search_constants->set_pressed(true); - search_constants->set_focus_mode(Control::FOCUS_NONE); - hbox->add_child(search_constants); - - search_properties = memnew(Button); - search_properties->set_flat(true); - search_properties->set_tooltip(TTR("Search Properties")); - search_properties->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); - search_properties->set_toggle_mode(true); - search_properties->set_pressed(true); - search_properties->set_focus_mode(Control::FOCUS_NONE); - hbox->add_child(search_properties); - - search_theme_items = memnew(Button); - search_theme_items->set_flat(true); - search_theme_items->set_tooltip(TTR("Search Theme Items")); - search_theme_items->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results)); - search_theme_items->set_toggle_mode(true); - search_theme_items->set_pressed(true); - search_theme_items->set_focus_mode(Control::FOCUS_NONE); - hbox->add_child(search_theme_items); - - scope_combo = memnew(OptionButton); - scope_combo->set_custom_minimum_size(Size2(200, 0) * EDSCALE); - scope_combo->set_tooltip(TTR("Select the search limits")); - scope_combo->set_stretch_ratio(0); // Fixed width. - scope_combo->add_item(TTR("Search Related"), SCOPE_RELATED); - scope_combo->add_separator(); - scope_combo->add_item(TTR("Search Base"), SCOPE_BASE); - scope_combo->add_item(TTR("Search Inheriters"), SCOPE_INHERITERS); - scope_combo->add_item(TTR("Search Unrelated"), SCOPE_UNRELATED); - scope_combo->add_item(TTR("Search All"), SCOPE_ALL); - scope_combo->connect("item_selected", callable_mp(this, &VisualScriptPropertySelector::_update_results_i)); - hbox->add_child(scope_combo); - - search_box = memnew(LineEdit); - search_box->set_tooltip(TTR("Enter \" \" to show all filtered options\nEnter \".\" to show all filtered methods, operators and constructors\nUse CTRL_KEY to drop property setters")); - search_box->set_custom_minimum_size(Size2(200, 0) * EDSCALE); - search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); - search_box->connect("text_changed", callable_mp(this, &VisualScriptPropertySelector::_update_results_s)); - search_box->connect("gui_input", callable_mp(this, &VisualScriptPropertySelector::_sbox_input)); - register_text_enter(search_box); - vbox->add_child(search_box); - - results_tree = memnew(Tree); - results_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); - results_tree->set_hide_root(true); - results_tree->set_hide_folding(false); - results_tree->set_columns(2); - results_tree->set_column_title(0, TTR("Name")); - results_tree->set_column_clip_content(0, true); - results_tree->set_column_title(1, TTR("Member Type")); - results_tree->set_column_expand(1, false); - results_tree->set_column_custom_minimum_width(1, 150 * EDSCALE); - results_tree->set_column_clip_content(1, true); - results_tree->set_custom_minimum_size(Size2(0, 100) * EDSCALE); - results_tree->set_select_mode(Tree::SELECT_ROW); - results_tree->connect("item_activated", callable_mp(this, &VisualScriptPropertySelector::_confirmed)); - results_tree->connect("item_selected", callable_mp(this, &VisualScriptPropertySelector::_item_selected)); - vbox->add_child(results_tree); - - ScrollContainer *scroller = memnew(ScrollContainer); - scroller->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED); - scroller->set_v_size_flags(Control::SIZE_EXPAND_FILL); - scroller->set_custom_minimum_size(Size2(600, 400) * EDSCALE); - vbox->add_child(scroller); - - help_bit = memnew(EditorHelpBit); - help_bit->set_h_size_flags(Control::SIZE_EXPAND_FILL); - help_bit->set_v_size_flags(Control::SIZE_EXPAND_FILL); - scroller->add_child(help_bit); - - help_bit->connect("request_hide", callable_mp(this, &VisualScriptPropertySelector::_hide_requested)); - set_ok_button_text(TTR("Open")); - get_ok_button()->set_disabled(true); - set_hide_on_ok(false); -} - -bool VisualScriptPropertySelector::SearchRunner::_is_class_disabled_by_feature_profile(const StringName &p_class) { - Ref<EditorFeatureProfile> profile = EditorFeatureProfileManager::get_singleton()->get_current_profile(); - if (profile.is_null()) { - return false; - } - - StringName class_name = p_class; - while (class_name != StringName()) { - if (!ClassDB::class_exists(class_name)) { - return false; - } - - if (profile->is_class_disabled(class_name)) { - return true; - } - class_name = ClassDB::get_parent_class(class_name); - } - - return false; -} - -bool VisualScriptPropertySelector::SearchRunner::_is_class_disabled_by_scope(const StringName &p_class) { - bool is_base_script = false; - if (p_class == selector_ui->base_script) { - is_base_script = true; - } - bool is_base = false; - if (selector_ui->base_type == p_class) { - is_base = true; - } - bool is_parent = false; - if ((ClassDB::is_parent_class(selector_ui->base_type, p_class)) && !is_base) { - is_parent = true; - } - - bool is_inheriter = false; - List<StringName> inheriters; - ClassDB::get_inheriters_from_class(selector_ui->base_type, &inheriters); - if (inheriters.find(p_class)) { - is_inheriter = true; - } - - if (scope_flags & SCOPE_BASE) { - if (is_base_script || is_base || is_parent) { - return false; - } - } - if (scope_flags & SCOPE_INHERITERS) { - if (is_base_script || is_base || is_inheriter) { - return false; - } - } - // if (scope_flags & SCOPE_RELATED) { - // /* code */ - // } - if (scope_flags & SCOPE_UNRELATED) { - if (!is_base_script && !is_base && !is_inheriter) { - return false; - } - } - return true; -} - -bool VisualScriptPropertySelector::SearchRunner::_slice() { - bool phase_done = false; - switch (phase) { - case PHASE_INIT: - phase_done = _phase_init(); - break; - case PHASE_MATCH_CLASSES_INIT: - phase_done = _phase_match_classes_init(); - break; - case PHASE_NODE_CLASSES_INIT: - phase_done = _phase_node_classes_init(); - break; - case PHASE_NODE_CLASSES_BUILD: - phase_done = _phase_node_classes_build(); - break; - case PHASE_MATCH_CLASSES: - phase_done = _phase_match_classes(); - break; - case PHASE_CLASS_ITEMS_INIT: - phase_done = _phase_class_items_init(); - break; - case PHASE_CLASS_ITEMS: - phase_done = _phase_class_items(); - break; - case PHASE_MEMBER_ITEMS_INIT: - phase_done = _phase_member_items_init(); - break; - case PHASE_MEMBER_ITEMS: - phase_done = _phase_member_items(); - break; - case PHASE_SELECT_MATCH: - phase_done = _phase_select_match(); - break; - case PHASE_MAX: - return true; - default: - WARN_PRINT("Invalid or unhandled phase in EditorHelpSearch::Runner, aborting search."); - return true; - }; - - if (phase_done) { - phase++; - } - return false; -} - -bool VisualScriptPropertySelector::SearchRunner::_phase_init() { - search_flags = 0; // selector_ui->filter_combo->get_selected_id(); - if (selector_ui->search_visual_script_nodes->is_pressed()) { - search_flags |= SEARCH_VISUAL_SCRIPT_NODES; - } - if (selector_ui->search_classes->is_pressed()) { - search_flags |= SEARCH_CLASSES; - } - // if (selector_ui->search_constructors->is_pressed()) { - search_flags |= SEARCH_CONSTRUCTORS; - // } - if (selector_ui->search_methods->is_pressed()) { - search_flags |= SEARCH_METHODS; - } - if (selector_ui->search_operators->is_pressed()) { - search_flags |= SEARCH_OPERATORS; - } - if (selector_ui->search_signals->is_pressed()) { - search_flags |= SEARCH_SIGNALS; - } - if (selector_ui->search_constants->is_pressed()) { - search_flags |= SEARCH_CONSTANTS; - } - if (selector_ui->search_properties->is_pressed()) { - search_flags |= SEARCH_PROPERTIES; - } - if (selector_ui->search_theme_items->is_pressed()) { - search_flags |= SEARCH_THEME_ITEMS; - } - if (selector_ui->case_sensitive_button->is_pressed()) { - search_flags |= SEARCH_CASE_SENSITIVE; - } - if (selector_ui->hierarchy_button->is_pressed()) { - search_flags |= SEARCH_SHOW_HIERARCHY; - } - scope_flags = selector_ui->scope_combo->get_selected_id(); - - return true; -} - -bool VisualScriptPropertySelector::SearchRunner::_phase_match_classes_init() { - combined_docs = EditorHelp::get_doc_data()->class_list; - matches.clear(); - matched_item = nullptr; - match_highest_score = 0; - - if ( - (selector_ui->base_script.unquote() != "") && - (selector_ui->base_script.unquote() != ".") && - !combined_docs.has(selector_ui->base_script)) { - String file_path = "res://" + selector_ui->base_script.unquote(); // EditorHelp::get_doc_data().name to filepath - Ref<Script> script; - script = ResourceLoader::load(file_path); - if (!script.is_null()) { - DocData::ClassDoc class_doc = DocData::ClassDoc(); - - class_doc.name = selector_ui->base_script; - - class_doc.inherits = script->get_instance_base_type(); - class_doc.brief_description = ".vs files not supported by EditorHelp::get_doc_data()"; - class_doc.description = ""; - - Object *obj = ObjectDB::get_instance(script->get_instance_id()); - if (Object::cast_to<Script>(obj)) { - List<MethodInfo> methods; - Object::cast_to<Script>(obj)->get_script_method_list(&methods); - for (List<MethodInfo>::Element *M = methods.front(); M; M = M->next()) { - class_doc.methods.push_back(_get_method_doc(M->get())); - } - - List<MethodInfo> signals; - Object::cast_to<Script>(obj)->get_script_signal_list(&signals); - for (List<MethodInfo>::Element *S = signals.front(); S; S = S->next()) { - class_doc.signals.push_back(_get_method_doc(S->get())); - } - - List<PropertyInfo> properties; - Object::cast_to<Script>(obj)->get_script_property_list(&properties); - for (List<PropertyInfo>::Element *P = properties.front(); P; P = P->next()) { - DocData::PropertyDoc pd = DocData::PropertyDoc(); - pd.name = P->get().name; - pd.type = Variant::get_type_name(P->get().type); - class_doc.properties.push_back(pd); - } - } - combined_docs.insert(class_doc.name, class_doc); - } - } - iterator_doc = combined_docs.begin(); - return true; -} - -bool VisualScriptPropertySelector::SearchRunner::_phase_node_classes_init() { - VisualScriptLanguage::singleton->get_registered_node_names(&vs_nodes); - _add_class_doc("functions", "", ""); - _add_class_doc("operators", "", ""); - return true; -} - -bool VisualScriptPropertySelector::SearchRunner::_phase_node_classes_build() { - if (vs_nodes.is_empty()) { - return true; - } - String registered_node_name = vs_nodes[0]; - vs_nodes.pop_front(); - - Vector<String> path = registered_node_name.split("/"); - if (path[0] == "constants") { - _add_class_doc(registered_node_name, "", "constants"); - } else if (path[0] == "custom") { - _add_class_doc(registered_node_name, "", "custom"); - } else if (path[0] == "data") { - _add_class_doc(registered_node_name, "", "data"); - } else if (path[0] == "flow_control") { - _add_class_doc(registered_node_name, "", "flow_control"); - } else if (path[0] == "functions") { - if (path[1] == "built_in") { - _add_class_doc(registered_node_name, "functions", "built_in"); - } else if (path[1] == "by_type") { - // No action is required. - // Using function references from ClassDB to remove confusion for users. - } else if (path[1] == "constructors") { - _add_class_doc(registered_node_name, "", "constructors"); - } else if (path[1] == "deconstruct") { - _add_class_doc(registered_node_name, "", "deconstruct"); - } else if (path[1] == "wait") { - _add_class_doc(registered_node_name, "functions", "yield"); - } else { - _add_class_doc(registered_node_name, "functions", ""); - } - } else if (path[0] == "index") { - _add_class_doc(registered_node_name, "", "index"); - } else if (path[0] == "operators") { - if (path[1] == "bitwise") { - _add_class_doc(registered_node_name, "operators", "bitwise"); - } else if (path[1] == "compare") { - _add_class_doc(registered_node_name, "operators", "compare"); - } else if (path[1] == "logic") { - _add_class_doc(registered_node_name, "operators", "logic"); - } else if (path[1] == "math") { - _add_class_doc(registered_node_name, "operators", "math"); - } else { - _add_class_doc(registered_node_name, "operators", ""); - } - } - return false; -} - -bool VisualScriptPropertySelector::SearchRunner::_phase_match_classes() { - DocData::ClassDoc &class_doc = iterator_doc->value; - if ( - (!_is_class_disabled_by_feature_profile(class_doc.name) && !_is_class_disabled_by_scope(class_doc.name)) || - _match_visual_script(class_doc)) { - if (class_doc.inherits == "VisualScriptCustomNode") { - class_doc.script_path = "res://" + class_doc.name.unquote(); - Ref<Script> script = ResourceLoader::load(class_doc.script_path); - Ref<VisualScriptCustomNode> vsn; - vsn.instantiate(); - vsn->set_script(script); - class_doc.name = vsn->get_caption(); - if (combined_docs.has(vsn->get_category())) { - class_doc.inherits = vsn->get_category(); - } else if (combined_docs.has("VisualScriptNode/" + vsn->get_category())) { - class_doc.inherits = "VisualScriptNode/" + vsn->get_category(); - } else if (combined_docs.has("VisualScriptCustomNode/" + vsn->get_category())) { - class_doc.inherits = "VisualScriptCustomNode/" + vsn->get_category(); - } else { - class_doc.inherits = ""; - } - class_doc.category = "VisualScriptCustomNode/" + vsn->get_category(); - class_doc.brief_description = ""; - class_doc.constructors.clear(); - class_doc.methods.clear(); - class_doc.operators.clear(); - class_doc.signals.clear(); - class_doc.constants.clear(); - class_doc.enums.clear(); - class_doc.properties.clear(); - class_doc.theme_properties.clear(); - } - - matches[class_doc.name] = ClassMatch(); - ClassMatch &match = matches[class_doc.name]; - - match.category = class_doc.category; - match.doc = &class_doc; - // Match class name. - if (search_flags & SEARCH_CLASSES || _match_visual_script(class_doc)) { - if (term == "") { - match.name = !_match_is_hidden(class_doc); - } else { - match.name = _match_string(term, class_doc.name); - } - // match.name = term == "" || _match_string(term, class_doc.name); - } - - // Match members if the term is long enough. - if (term.length() >= 0) { - if (search_flags & SEARCH_CONSTRUCTORS) { - for (int i = 0; i < class_doc.constructors.size(); i++) { - String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.constructors[i].name : class_doc.constructors[i].name.to_lower(); - if (method_name.find(term) > -1 || - term == " " || - (term.begins_with(".") && method_name.begins_with(term.substr(1))) || - (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) || - (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) { - match.constructors.push_back(const_cast<DocData::MethodDoc *>(&class_doc.constructors[i])); - } - } - } - if (search_flags & SEARCH_METHODS) { - for (int i = 0; i < class_doc.methods.size(); i++) { - String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.methods[i].name : class_doc.methods[i].name.to_lower(); - if (method_name.find(term) > -1 || - term == " " || - (term.begins_with(".") && method_name.begins_with(term.substr(1))) || - (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) || - (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) { - match.methods.push_back(const_cast<DocData::MethodDoc *>(&class_doc.methods[i])); - } - } - } - if (search_flags & SEARCH_OPERATORS) { - for (int i = 0; i < class_doc.operators.size(); i++) { - String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.operators[i].name : class_doc.operators[i].name.to_lower(); - if (method_name.find(term) > -1 || - term == " " || - (term.begins_with(".") && method_name.begins_with(term.substr(1))) || - (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) || - (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) { - match.operators.push_back(const_cast<DocData::MethodDoc *>(&class_doc.operators[i])); - } - } - } - if (search_flags & SEARCH_SIGNALS) { - for (int i = 0; i < class_doc.signals.size(); i++) { - if (_match_string(term, class_doc.signals[i].name) || - term == " ") { - match.signals.push_back(const_cast<DocData::MethodDoc *>(&class_doc.signals[i])); - } - } - } - if (search_flags & SEARCH_CONSTANTS) { - for (int i = 0; i < class_doc.constants.size(); i++) { - if (_match_string(term, class_doc.constants[i].name) || - term == " ") { - match.constants.push_back(const_cast<DocData::ConstantDoc *>(&class_doc.constants[i])); - } - } - } - if (search_flags & SEARCH_PROPERTIES) { - for (int i = 0; i < class_doc.properties.size(); i++) { - if (_match_string(term, class_doc.properties[i].name) || - term == " " || - _match_string(term, class_doc.properties[i].getter) || - _match_string(term, class_doc.properties[i].setter)) { - match.properties.push_back(const_cast<DocData::PropertyDoc *>(&class_doc.properties[i])); - } - } - } - if (search_flags & SEARCH_THEME_ITEMS) { - for (int i = 0; i < class_doc.theme_properties.size(); i++) { - if (_match_string(term, class_doc.theme_properties[i].name) || - term == " ") { - match.theme_properties.push_back(const_cast<DocData::ThemeItemDoc *>(&class_doc.theme_properties[i])); - } - } - } - } - } - - ++iterator_doc; - return !iterator_doc; -} - -bool VisualScriptPropertySelector::SearchRunner::_phase_class_items_init() { - results_tree->clear(); - iterator_match = matches.begin(); - - root_item = results_tree->create_item(); - class_items.clear(); - - return true; -} - -bool VisualScriptPropertySelector::SearchRunner::_phase_class_items() { - if (!iterator_match) { - return true; - } - - ClassMatch &match = iterator_match->value; - - if (search_flags & SEARCH_SHOW_HIERARCHY) { - if (match.required()) { - _create_class_hierarchy(match); - } - } else { - if (match.name) { - _create_class_item(root_item, match.doc, true); - } - } - - ++iterator_match; - return !iterator_match; -} - -bool VisualScriptPropertySelector::SearchRunner::_phase_member_items_init() { - iterator_match = matches.begin(); - - return true; -} - -bool VisualScriptPropertySelector::SearchRunner::_phase_member_items() { - if (!iterator_match) { - return true; - } - - ClassMatch &match = iterator_match->value; - - TreeItem *parent = (search_flags & SEARCH_SHOW_HIERARCHY) ? class_items[match.doc->name] : root_item; - bool constructor_created = false; - for (int i = 0; i < match.methods.size(); i++) { - String text = match.methods[i]->name; - if (!constructor_created) { - if (match.doc->name == match.methods[i]->name) { - text += " " + TTR("(constructors)"); - constructor_created = true; - } - } else { - if (match.doc->name == match.methods[i]->name) { - continue; - } - } - _create_method_item(parent, match.doc, text, match.methods[i]); - } - for (int i = 0; i < match.signals.size(); i++) { - _create_signal_item(parent, match.doc, match.signals[i]); - } - for (int i = 0; i < match.constants.size(); i++) { - _create_constant_item(parent, match.doc, match.constants[i]); - } - for (int i = 0; i < match.properties.size(); i++) { - _create_property_item(parent, match.doc, match.properties[i]); - } - for (int i = 0; i < match.theme_properties.size(); i++) { - _create_theme_property_item(parent, match.doc, match.theme_properties[i]); - } - - ++iterator_match; - return !iterator_match; -} - -bool VisualScriptPropertySelector::SearchRunner::_phase_select_match() { - if (matched_item) { - matched_item->select(0); - } - return true; -} - -bool VisualScriptPropertySelector::SearchRunner::_match_string(const String &p_term, const String &p_string) const { - if (search_flags & SEARCH_CASE_SENSITIVE) { - return p_string.find(p_term) > -1; - } else { - return p_string.findn(p_term) > -1; - } -} - -bool VisualScriptPropertySelector::SearchRunner::_match_visual_script(DocData::ClassDoc &class_doc) { - if (class_doc.category.ends_with("_class")) { - if (class_doc.category.begins_with("VisualScript") && search_flags & SEARCH_CLASSES) { - if (matches.has(class_doc.inherits)) { - return true; - } - } - return false; - } - if (class_doc.category.begins_with("VisualScript") && search_flags & SEARCH_VISUAL_SCRIPT_NODES) { - return true; - } - if (class_doc.name.begins_with("operators") && search_flags & SEARCH_OPERATORS) { - return true; - } - if (class_doc.category.begins_with("VisualScriptNode/deconstruct")) { - if (class_doc.name.find(selector_ui->base_type, 0) > -1) { - return true; - } - } - - return false; -} - -bool VisualScriptPropertySelector::SearchRunner::_match_is_hidden(DocData::ClassDoc &class_doc) { - if (class_doc.category.begins_with("VisualScript")) { - if (class_doc.name.begins_with("flow_control")) { - return false; - } else if (class_doc.name.begins_with("operators")) { - return !(search_flags & SEARCH_OPERATORS); - } else if (class_doc.name.begins_with("functions/built_in/print")) { - return false; - } - return true; - } - return false; -} - -void VisualScriptPropertySelector::SearchRunner::_match_item(TreeItem *p_item, const String &p_text) { - float inverse_length = 1.f / float(p_text.length()); - - // Favor types where search term is a substring close to the start of the type. - float w = 0.5f; - int pos = p_text.findn(term); - float score = (pos > -1) ? 1.0f - w * MIN(1, 3 * pos * inverse_length) : MAX(0.f, .9f - w); - - // Favor shorter items: they resemble the search term more. - w = 0.1f; - score *= (1 - w) + w * (term.length() * inverse_length); - - if (match_highest_score == 0 || score > match_highest_score) { - matched_item = p_item; - match_highest_score = score; - } -} - -void VisualScriptPropertySelector::SearchRunner::_add_class_doc(String class_name, String inherits, String category) { - DocData::ClassDoc class_doc = DocData::ClassDoc(); - class_doc.name = class_name; - class_doc.inherits = inherits; - class_doc.category = "VisualScriptNode/" + category; - class_doc.brief_description = category; - combined_docs.insert(class_doc.name, class_doc); -} - -DocData::MethodDoc VisualScriptPropertySelector::SearchRunner::_get_method_doc(MethodInfo method_info) { - DocData::MethodDoc method_doc = DocData::MethodDoc(); - method_doc.name = method_info.name; - method_doc.return_type = Variant::get_type_name(method_info.return_val.type); - method_doc.description = "No description available"; - for (List<PropertyInfo>::Element *P = method_info.arguments.front(); P; P = P->next()) { - DocData::ArgumentDoc argument_doc = DocData::ArgumentDoc(); - argument_doc.name = P->get().name; - argument_doc.type = Variant::get_type_name(P->get().type); - method_doc.arguments.push_back(argument_doc); - } - return method_doc; -} - -TreeItem *VisualScriptPropertySelector::SearchRunner::_create_class_hierarchy(const ClassMatch &p_match) { - if (class_items.has(p_match.doc->name)) { - return class_items[p_match.doc->name]; - } - - // Ensure parent nodes are created first. - TreeItem *parent = root_item; - if (p_match.doc->inherits != "") { - if (class_items.has(p_match.doc->inherits)) { - parent = class_items[p_match.doc->inherits]; - } else if (matches.has(p_match.doc->inherits)) { - ClassMatch &base_match = matches[p_match.doc->inherits]; - parent = _create_class_hierarchy(base_match); - } - } - - TreeItem *class_item = _create_class_item(parent, p_match.doc, !p_match.name); - class_items[p_match.doc->name] = class_item; - return class_item; -} - -TreeItem *VisualScriptPropertySelector::SearchRunner::_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray) { - Ref<Texture2D> icon = empty_icon; - String text_0 = p_doc->name; - String text_1 = "Class"; - - String what = "Class"; - String details = p_doc->name; - if (p_doc->category.begins_with("VisualScriptCustomNode/")) { - Vector<String> path = p_doc->name.split("/"); - icon = ui_service->get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons")); - text_0 = path[path.size() - 1]; - text_1 = "VisualScriptCustomNode"; - what = "VisualScriptCustomNode"; - details = "CustomNode"; - } else if (p_doc->category.begins_with("VisualScriptNode/")) { - Vector<String> path = p_doc->name.split("/"); - icon = ui_service->get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons")); - text_0 = path[path.size() - 1]; - if (p_doc->category.begins_with("VisualScriptNode/deconstruct")) { - text_0 = "deconstruct " + text_0; - } - text_1 = "VisualScriptNode"; - what = "VisualScriptNode"; - details = p_doc->name; - - if (path.size() == 1) { - if (path[0] == "functions" || path[0] == "operators") { - text_1 = "VisualScript"; - p_gray = true; - what = "no_result"; - details = ""; - } - } - - } else { - if (p_doc->name.is_quoted()) { - text_0 = p_doc->name.unquote().get_file(); - if (ui_service->has_theme_icon(p_doc->inherits, "EditorIcons")) { - icon = ui_service->get_theme_icon(p_doc->inherits, "EditorIcons"); - } - } else if (ui_service->has_theme_icon(p_doc->name, "EditorIcons")) { - icon = ui_service->get_theme_icon(p_doc->name, "EditorIcons"); - } else if (ClassDB::class_exists(p_doc->name) && ClassDB::is_parent_class(p_doc->name, "Object")) { - icon = ui_service->get_theme_icon(SNAME("Object"), SNAME("EditorIcons")); - } - } - String tooltip = p_doc->brief_description.strip_edges(); - - TreeItem *item = results_tree->create_item(p_parent); - item->set_icon(0, icon); - item->set_text(0, text_0); - item->set_text(1, TTR(text_1)); - item->set_tooltip(0, tooltip); - item->set_tooltip(1, tooltip); - item->set_metadata(0, details); - item->set_metadata(1, what); - if (p_gray) { - item->set_custom_color(0, disabled_color); - item->set_custom_color(1, disabled_color); - } - - _match_item(item, p_doc->name); - - return item; -} - -TreeItem *VisualScriptPropertySelector::SearchRunner::_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc) { - String tooltip = p_doc->return_type + " " + p_class_doc->name + "." + p_doc->name + "("; - for (int i = 0; i < p_doc->arguments.size(); i++) { - const DocData::ArgumentDoc &arg = p_doc->arguments[i]; - tooltip += arg.type + " " + arg.name; - if (arg.default_value != "") { - tooltip += " = " + arg.default_value; - } - if (i < p_doc->arguments.size() - 1) { - tooltip += ", "; - } - } - tooltip += ")"; - return _create_member_item(p_parent, p_class_doc->name, "MemberMethod", p_doc->name, p_text, TTRC("Method"), "method", tooltip, p_doc->description); -} - -TreeItem *VisualScriptPropertySelector::SearchRunner::_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) { - String tooltip = p_doc->return_type + " " + p_class_doc->name + "." + p_doc->name + "("; - for (int i = 0; i < p_doc->arguments.size(); i++) { - const DocData::ArgumentDoc &arg = p_doc->arguments[i]; - tooltip += arg.type + " " + arg.name; - if (arg.default_value != "") { - tooltip += " = " + arg.default_value; - } - if (i < p_doc->arguments.size() - 1) { - tooltip += ", "; - } - } - tooltip += ")"; - return _create_member_item(p_parent, p_class_doc->name, "MemberSignal", p_doc->name, p_doc->name, TTRC("Signal"), "signal", tooltip, p_doc->description); -} - -TreeItem *VisualScriptPropertySelector::SearchRunner::_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc) { - String tooltip = p_class_doc->name + "." + p_doc->name; - return _create_member_item(p_parent, p_class_doc->name, "MemberConstant", p_doc->name, p_doc->name, TTRC("Constant"), "constant", tooltip, p_doc->description); -} - -TreeItem *VisualScriptPropertySelector::SearchRunner::_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc) { - String tooltip = p_doc->type + " " + p_class_doc->name + "." + p_doc->name; - tooltip += "\n " + p_class_doc->name + "." + p_doc->setter + "(value) setter"; - tooltip += "\n " + p_class_doc->name + "." + p_doc->getter + "() getter"; - return _create_member_item(p_parent, p_class_doc->name, "MemberProperty", p_doc->name, p_doc->name, TTRC("Property"), "property", tooltip, p_doc->description); -} - -TreeItem *VisualScriptPropertySelector::SearchRunner::_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ThemeItemDoc *p_doc) { - String tooltip = p_doc->type + " " + p_class_doc->name + "." + p_doc->name; - return _create_member_item(p_parent, p_class_doc->name, "MemberTheme", p_doc->name, p_doc->name, TTRC("Theme Property"), "theme_item", tooltip, p_doc->description); -} - -TreeItem *VisualScriptPropertySelector::SearchRunner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_description) { - Ref<Texture2D> icon; - String text; - if (search_flags & SEARCH_SHOW_HIERARCHY) { - icon = ui_service->get_theme_icon(p_icon, SNAME("EditorIcons")); - text = p_text; - } else { - icon = ui_service->get_theme_icon(p_icon, SNAME("EditorIcons")); - text = p_class_name + "." + p_text; - } - - TreeItem *item = results_tree->create_item(p_parent); - item->set_icon(0, icon); - item->set_text(0, text); - item->set_text(1, TTRGET(p_type)); - item->set_tooltip(0, p_tooltip); - item->set_tooltip(1, p_tooltip); - item->set_metadata(0, p_class_name + ":" + p_name); - item->set_metadata(1, "class_" + p_metatype); - item->set_meta("description", p_description); - - _match_item(item, p_name); - - return item; -} - -bool VisualScriptPropertySelector::SearchRunner::work(uint64_t slot) { - // Return true when the search has been completed, otherwise false. - const uint64_t until = OS::get_singleton()->get_ticks_usec() + slot; - while (!_slice()) { - if (OS::get_singleton()->get_ticks_usec() > until) { - return false; - } - } - return true; -} - -VisualScriptPropertySelector::SearchRunner::SearchRunner(VisualScriptPropertySelector *p_selector_ui, Tree *p_results_tree) : - selector_ui(p_selector_ui), - ui_service(p_selector_ui->vbox), - results_tree(p_results_tree), - term(p_selector_ui->search_box->get_text()), - empty_icon(ui_service->get_theme_icon(SNAME("ArrowRight"), SNAME("EditorIcons"))), - disabled_color(ui_service->get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"))) { -} diff --git a/modules/visual_script/editor/visual_script_property_selector.h b/modules/visual_script/editor/visual_script_property_selector.h deleted file mode 100644 index 4de626467e..0000000000 --- a/modules/visual_script/editor/visual_script_property_selector.h +++ /dev/null @@ -1,229 +0,0 @@ -/*************************************************************************/ -/* visual_script_property_selector.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 VISUAL_SCRIPT_PROPERTY_SELECTOR_H -#define VISUAL_SCRIPT_PROPERTY_SELECTOR_H - -#include "../visual_script.h" -#include "editor/editor_help.h" -#include "scene/gui/rich_text_label.h" -#include "scene/gui/tree.h" - -class VisualScriptPropertySelector : public ConfirmationDialog { - GDCLASS(VisualScriptPropertySelector, ConfirmationDialog); - - enum SearchFlags { - SEARCH_CLASSES = 1 << 0, - SEARCH_CONSTRUCTORS = 1 << 1, - SEARCH_METHODS = 1 << 2, - SEARCH_OPERATORS = 1 << 3, - SEARCH_SIGNALS = 1 << 4, - SEARCH_CONSTANTS = 1 << 5, - SEARCH_PROPERTIES = 1 << 6, - SEARCH_THEME_ITEMS = 1 << 7, - SEARCH_VISUAL_SCRIPT_NODES = 1 << 8, - SEARCH_ALL = SEARCH_CLASSES | SEARCH_CONSTRUCTORS | SEARCH_METHODS | SEARCH_OPERATORS | SEARCH_SIGNALS | SEARCH_CONSTANTS | SEARCH_PROPERTIES | SEARCH_THEME_ITEMS, - SEARCH_CASE_SENSITIVE = 1 << 29, - SEARCH_SHOW_HIERARCHY = 1 << 30, - }; - - enum ScopeFlags { - SCOPE_BASE = 1 << 0, - SCOPE_INHERITERS = 1 << 1, - SCOPE_UNRELATED = 1 << 2, - SCOPE_RELATED = SCOPE_BASE | SCOPE_INHERITERS, - SCOPE_ALL = SCOPE_BASE | SCOPE_INHERITERS | SCOPE_UNRELATED - }; - - enum ScopeCombo { - COMBO_RELATED, - COMBO_SEPARATOR, - COMBO_BASE, - COMBO_INHERITERS, - COMBO_UNRELATED, - COMBO_ALL, - }; - - LineEdit *search_box = nullptr; - - Button *case_sensitive_button = nullptr; - Button *hierarchy_button = nullptr; - - Button *search_visual_script_nodes = nullptr; - Button *search_classes = nullptr; - Button *search_operators = nullptr; - - Button *search_methods = nullptr; - Button *search_signals = nullptr; - Button *search_constants = nullptr; - Button *search_properties = nullptr; - Button *search_theme_items = nullptr; - - OptionButton *scope_combo = nullptr; - Tree *results_tree = nullptr; - - class SearchRunner; - Ref<SearchRunner> search_runner; - - void _update_icons(); - - void _sbox_input(const Ref<InputEvent> &p_ie); - void _update_results_i(int p_int); - void _update_results_s(String p_string); - void _update_results_search_all(); - void _update_results(); - - void _confirmed(); - void _item_selected(); - void _hide_requested(); - - EditorHelpBit *help_bit = nullptr; - - bool properties = false; - bool visual_script_generic = false; - bool connecting = false; - String selected; - Variant::Type type; - String base_type; - String base_script; - ObjectID script; - Object *instance = nullptr; - bool virtuals_only = false; - VBoxContainer *vbox = nullptr; - -protected: - void _notification(int p_what); - static void _bind_methods(); - -public: - void select_method_from_base_type(const String &p_base, const bool p_virtuals_only = false, const bool p_connecting = true, bool clear_text = true); - void select_from_base_type(const String &p_base, const String &p_base_script = "", bool p_virtuals_only = false, const bool p_connecting = true, bool clear_text = true); - void select_from_script(const Ref<Script> &p_script, const bool p_connecting = true, bool clear_text = true); - void select_from_basic_type(Variant::Type p_type, const bool p_connecting = true, bool clear_text = true); - void select_from_action(const String &p_type, const bool p_connecting = true, bool clear_text = true); - void select_from_instance(Object *p_instance, const bool p_connecting = true, bool clear_text = true); - void select_from_visual_script(const Ref<Script> &p_script, bool clear_text = true); - - void show_window(float p_screen_ratio); - - VisualScriptPropertySelector(); -}; - -class VisualScriptPropertySelector::SearchRunner : public RefCounted { - enum Phase { - PHASE_INIT, - PHASE_MATCH_CLASSES_INIT, - PHASE_NODE_CLASSES_INIT, - PHASE_NODE_CLASSES_BUILD, - PHASE_MATCH_CLASSES, - PHASE_CLASS_ITEMS_INIT, - PHASE_CLASS_ITEMS, - PHASE_MEMBER_ITEMS_INIT, - PHASE_MEMBER_ITEMS, - PHASE_SELECT_MATCH, - PHASE_MAX - }; - int phase = 0; - - struct ClassMatch { - DocData::ClassDoc *doc; - bool name = false; - String category = ""; - Vector<DocData::MethodDoc *> constructors; - Vector<DocData::MethodDoc *> methods; - Vector<DocData::MethodDoc *> operators; - Vector<DocData::MethodDoc *> signals; - Vector<DocData::ConstantDoc *> constants; - Vector<DocData::PropertyDoc *> properties; - Vector<DocData::ThemeItemDoc *> theme_properties; - - bool required() { - return name || methods.size() || signals.size() || constants.size() || properties.size() || theme_properties.size(); - } - }; - - VisualScriptPropertySelector *selector_ui = nullptr; - Control *ui_service = nullptr; - Tree *results_tree = nullptr; - String term; - int search_flags = 0; - int scope_flags = 0; - - Ref<Texture2D> empty_icon; - Color disabled_color; - - HashMap<String, DocData::ClassDoc>::Iterator iterator_doc; - HashMap<String, ClassMatch> matches; - HashMap<String, ClassMatch>::Iterator iterator_match; - TreeItem *root_item = nullptr; - HashMap<String, TreeItem *> class_items; - TreeItem *matched_item = nullptr; - float match_highest_score = 0; - - HashMap<String, DocData::ClassDoc> combined_docs; - List<String> vs_nodes; - - bool _is_class_disabled_by_feature_profile(const StringName &p_class); - bool _is_class_disabled_by_scope(const StringName &p_class); - - bool _slice(); - bool _phase_init(); - bool _phase_match_classes_init(); - bool _phase_node_classes_init(); - bool _phase_node_classes_build(); - bool _phase_match_classes(); - bool _phase_class_items_init(); - bool _phase_class_items(); - bool _phase_member_items_init(); - bool _phase_member_items(); - bool _phase_select_match(); - - bool _match_string(const String &p_term, const String &p_string) const; - bool _match_visual_script(DocData::ClassDoc &class_doc); - bool _match_is_hidden(DocData::ClassDoc &class_doc); - void _match_item(TreeItem *p_item, const String &p_text); - void _add_class_doc(String class_name, String inherits, String category); - DocData::MethodDoc _get_method_doc(MethodInfo method_info); - TreeItem *_create_class_hierarchy(const ClassMatch &p_match); - TreeItem *_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray); - TreeItem *_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc); - TreeItem *_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc); - TreeItem *_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc); - TreeItem *_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc); - TreeItem *_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ThemeItemDoc *p_doc); - TreeItem *_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_description); - -public: - bool work(uint64_t slot = 100000); - - SearchRunner(VisualScriptPropertySelector *p_selector_ui, Tree *p_results_tree); -}; - -#endif // VISUAL_SCRIPT_PROPERTY_SELECTOR_H diff --git a/modules/visual_script/icons/VisualScript.svg b/modules/visual_script/icons/VisualScript.svg deleted file mode 100644 index bc698247c9..0000000000 --- a/modules/visual_script/icons/VisualScript.svg +++ /dev/null @@ -1 +0,0 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><ellipse cx="3" cy="1039.4" fill="#e0e0e0"/><path d="m7 1-.56445 2.2578a5 5 0 0 0 -.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -.28516.68555l-2.2539.5625v2h5.2715a2 2 0 0 1 -.27148-1 2 2 0 0 1 2-2 2 2 0 0 1 2 2 2 2 0 0 1 -.26953 1h5.2695v-2l-2.2578-.56445a5 5 0 0 0 -.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -.68555-.28516l-.5625-2.2539h-2zm-4 9v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4zm8 0a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2z" fill="#e0e0e0" transform="translate(0 1036.4)"/></g></svg> diff --git a/modules/visual_script/icons/VisualScriptInternal.svg b/modules/visual_script/icons/VisualScriptInternal.svg deleted file mode 100644 index 8ab39ad929..0000000000 --- a/modules/visual_script/icons/VisualScriptInternal.svg +++ /dev/null @@ -1 +0,0 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="3" cy="3.000024" fill="#e0e0e0" r="0"/><path d="m11 10a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2z" fill="#e0e0e0"/><path d="m3 10v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4z" fill="#e0e0e0"/><path d="m7 1-.56445 2.2578a5 5 0 0 0 -.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -.28516.68555l-2.2539.5625v2h5.2715a2 2 0 0 1 -.27148-1 2 2 0 0 1 2-2 2 2 0 0 1 2 2 2 2 0 0 1 -.26953 1h5.2695v-2l-2.2578-.56445a5 5 0 0 0 -.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -.68555-.28516l-.5625-2.2539h-2z" fill="none" stroke="#e0e0e0"/></svg> diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp deleted file mode 100644 index 04a7442d0a..0000000000 --- a/modules/visual_script/register_types.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/*************************************************************************/ -/* register_types.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "register_types.h" - -#include "core/config/engine.h" -#include "core/io/resource_loader.h" -#include "visual_script.h" -#include "visual_script_builtin_funcs.h" -#include "visual_script_expression.h" -#include "visual_script_flow_control.h" -#include "visual_script_func_nodes.h" -#include "visual_script_nodes.h" -#include "visual_script_yield_nodes.h" - -VisualScriptLanguage *visual_script_language = nullptr; - -#ifdef TOOLS_ENABLED -#include "editor/visual_script_editor.h" -static VisualScriptCustomNodes *vs_custom_nodes_singleton = nullptr; -#endif - -void initialize_visual_script_module(ModuleInitializationLevel p_level) { - if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) { - visual_script_language = memnew(VisualScriptLanguage); - //script_language_gd->init(); - ScriptServer::register_language(visual_script_language); - - GDREGISTER_CLASS(VisualScript); - GDREGISTER_ABSTRACT_CLASS(VisualScriptNode); - GDREGISTER_CLASS(VisualScriptFunctionState); - GDREGISTER_CLASS(VisualScriptFunction); - GDREGISTER_ABSTRACT_CLASS(VisualScriptLists); - GDREGISTER_CLASS(VisualScriptComposeArray); - GDREGISTER_CLASS(VisualScriptOperator); - GDREGISTER_CLASS(VisualScriptVariableSet); - GDREGISTER_CLASS(VisualScriptVariableGet); - GDREGISTER_CLASS(VisualScriptConstant); - GDREGISTER_CLASS(VisualScriptIndexGet); - GDREGISTER_CLASS(VisualScriptIndexSet); - GDREGISTER_CLASS(VisualScriptGlobalConstant); - GDREGISTER_CLASS(VisualScriptClassConstant); - GDREGISTER_CLASS(VisualScriptMathConstant); - GDREGISTER_CLASS(VisualScriptBasicTypeConstant); - GDREGISTER_CLASS(VisualScriptEngineSingleton); - GDREGISTER_CLASS(VisualScriptSceneNode); - GDREGISTER_CLASS(VisualScriptSceneTree); - GDREGISTER_CLASS(VisualScriptResourcePath); - GDREGISTER_CLASS(VisualScriptSelf); - GDREGISTER_CLASS(VisualScriptCustomNode); - GDREGISTER_CLASS(VisualScriptSubCall); - GDREGISTER_CLASS(VisualScriptComment); - GDREGISTER_CLASS(VisualScriptConstructor); - GDREGISTER_CLASS(VisualScriptLocalVar); - GDREGISTER_CLASS(VisualScriptLocalVarSet); - GDREGISTER_CLASS(VisualScriptInputAction); - GDREGISTER_CLASS(VisualScriptDeconstruct); - GDREGISTER_CLASS(VisualScriptPreload); - GDREGISTER_CLASS(VisualScriptTypeCast); - - GDREGISTER_CLASS(VisualScriptFunctionCall); - GDREGISTER_CLASS(VisualScriptPropertySet); - GDREGISTER_CLASS(VisualScriptPropertyGet); - //ClassDB::register_type<VisualScriptScriptCall>(); - GDREGISTER_CLASS(VisualScriptEmitSignal); - - GDREGISTER_CLASS(VisualScriptReturn); - GDREGISTER_CLASS(VisualScriptCondition); - GDREGISTER_CLASS(VisualScriptWhile); - GDREGISTER_CLASS(VisualScriptIterator); - GDREGISTER_CLASS(VisualScriptSequence); - //GDREGISTER_CLASS(VisualScriptInputFilter); - GDREGISTER_CLASS(VisualScriptSwitch); - GDREGISTER_CLASS(VisualScriptSelect); - - GDREGISTER_CLASS(VisualScriptYield); - GDREGISTER_CLASS(VisualScriptYieldSignal); - - GDREGISTER_CLASS(VisualScriptBuiltinFunc); - - GDREGISTER_CLASS(VisualScriptExpression); - - register_visual_script_nodes(); - register_visual_script_func_nodes(); - register_visual_script_builtin_func_node(); - register_visual_script_flow_control_nodes(); - register_visual_script_yield_nodes(); - register_visual_script_expression_node(); - } - -#ifdef TOOLS_ENABLED - if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) { - ClassDB::set_current_api(ClassDB::API_EDITOR); - GDREGISTER_CLASS(VisualScriptCustomNodes); - ClassDB::set_current_api(ClassDB::API_CORE); - vs_custom_nodes_singleton = memnew(VisualScriptCustomNodes); - Engine::get_singleton()->add_singleton(Engine::Singleton("VisualScriptCustomNodes", VisualScriptCustomNodes::get_singleton())); - - VisualScriptEditor::register_editor(); - } -#endif -} - -void uninitialize_visual_script_module(ModuleInitializationLevel p_level) { - if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) { - unregister_visual_script_nodes(); - - ScriptServer::unregister_language(visual_script_language); - - if (visual_script_language) { - memdelete(visual_script_language); - } - } - -#ifdef TOOLS_ENABLED - if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) { - VisualScriptEditor::free_clipboard(); - if (vs_custom_nodes_singleton) { - memdelete(vs_custom_nodes_singleton); - } - } -#endif -} diff --git a/modules/visual_script/register_types.h b/modules/visual_script/register_types.h deleted file mode 100644 index 90f84de11c..0000000000 --- a/modules/visual_script/register_types.h +++ /dev/null @@ -1,39 +0,0 @@ -/*************************************************************************/ -/* register_types.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 VISUAL_SCRIPT_REGISTER_TYPES_H -#define VISUAL_SCRIPT_REGISTER_TYPES_H - -#include "modules/register_module_types.h" - -void initialize_visual_script_module(ModuleInitializationLevel p_level); -void uninitialize_visual_script_module(ModuleInitializationLevel p_level); - -#endif // VISUAL_SCRIPT_REGISTER_TYPES_H diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp deleted file mode 100644 index 73249371cd..0000000000 --- a/modules/visual_script/visual_script.cpp +++ /dev/null @@ -1,2506 +0,0 @@ -/*************************************************************************/ -/* visual_script.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "visual_script.h" - -#include "core/config/project_settings.h" -#include "core/core_string_names.h" -#include "core/os/os.h" -#include "scene/main/node.h" -#include "visual_script_nodes.h" - -// Used by editor, this is not really saved. -void VisualScriptNode::set_breakpoint(bool p_breakpoint) { - breakpoint = p_breakpoint; -} - -bool VisualScriptNode::is_breakpoint() const { - return breakpoint; -} - -void VisualScriptNode::ports_changed_notify() { - emit_signal(SNAME("ports_changed")); -} - -void VisualScriptNode::set_default_input_value(int p_port, const Variant &p_value) { - ERR_FAIL_INDEX(p_port, default_input_values.size()); - - default_input_values[p_port] = p_value; - -#ifdef TOOLS_ENABLED - if (script_used.is_valid()) { - script_used->set_edited(true); - } -#endif -} - -Variant VisualScriptNode::get_default_input_value(int p_port) const { - ERR_FAIL_INDEX_V(p_port, default_input_values.size(), Variant()); - return default_input_values[p_port]; -} - -void VisualScriptNode::_set_default_input_values(Array p_values) { - default_input_values = p_values; -} - -void VisualScriptNode::validate_input_default_values() { - default_input_values.resize(MAX(default_input_values.size(), get_input_value_port_count())); //let it grow as big as possible, we don't want to lose values on resize - - // Actually validate on save. - for (int i = 0; i < get_input_value_port_count(); i++) { - Variant::Type expected = get_input_value_port_info(i).type; - - if (expected == Variant::NIL || expected == default_input_values[i].get_type()) { - continue; - } else { - // Not the same, reconvert. - Callable::CallError ce; - Variant existing = default_input_values[i]; - const Variant *existingp = &existing; - Variant::construct(expected, default_input_values[i], &existingp, 1, ce); - if (ce.error != Callable::CallError::CALL_OK) { - //could not convert? force.. - Variant::construct(expected, default_input_values[i], nullptr, 0, ce); - } - } - } -} - -Array VisualScriptNode::_get_default_input_values() const { - // Validate on save, since on load there is little info about this. - Array values = default_input_values; - values.resize(get_input_value_port_count()); - - return values; -} - -String VisualScriptNode::get_text() const { - return ""; -} - -void VisualScriptNode::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_visual_script"), &VisualScriptNode::get_visual_script); - ClassDB::bind_method(D_METHOD("set_default_input_value", "port_idx", "value"), &VisualScriptNode::set_default_input_value); - ClassDB::bind_method(D_METHOD("get_default_input_value", "port_idx"), &VisualScriptNode::get_default_input_value); - ClassDB::bind_method(D_METHOD("ports_changed_notify"), &VisualScriptNode::ports_changed_notify); - ClassDB::bind_method(D_METHOD("_set_default_input_values", "values"), &VisualScriptNode::_set_default_input_values); - ClassDB::bind_method(D_METHOD("_get_default_input_values"), &VisualScriptNode::_get_default_input_values); - - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_default_input_values", "_get_default_input_values"); - ADD_SIGNAL(MethodInfo("ports_changed")); -} - -VisualScriptNode::TypeGuess VisualScriptNode::guess_output_type(TypeGuess *p_inputs, int p_output) const { - ERR_FAIL_COND_V(get_output_value_port_count() <= p_output, TypeGuess()); - - PropertyInfo pinfo = get_output_value_port_info(p_output); - - TypeGuess tg; - - tg.type = pinfo.type; - if (pinfo.hint == PROPERTY_HINT_RESOURCE_TYPE) { - tg.gdclass = pinfo.hint_string; - } - - return tg; -} - -Ref<VisualScript> VisualScriptNode::get_visual_script() const { - return script_used; -} - -VisualScriptNode::VisualScriptNode() { -} - -//////////////// - -///////////////////// - -VisualScriptNodeInstance::VisualScriptNodeInstance() { -} - -VisualScriptNodeInstance::~VisualScriptNodeInstance() { - if (sequence_outputs) { - memdelete_arr(sequence_outputs); - } - - if (input_ports) { - memdelete_arr(input_ports); - } - - if (output_ports) { - memdelete_arr(output_ports); - } -} - -void VisualScript::add_function(const StringName &p_name, int p_func_node_id) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(!String(p_name).is_valid_identifier()); - ERR_FAIL_COND(functions.has(p_name)); - ERR_FAIL_COND(variables.has(p_name)); - ERR_FAIL_COND(custom_signals.has(p_name)); - - functions[p_name] = Function(); - functions[p_name].func_id = p_func_node_id; -} - -bool VisualScript::has_function(const StringName &p_name) const { - return functions.has(p_name); -} - -void VisualScript::remove_function(const StringName &p_name) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(!functions.has(p_name)); - - // Let the editor handle the node removal. - functions.erase(p_name); -} - -void VisualScript::rename_function(const StringName &p_name, const StringName &p_new_name) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(!functions.has(p_name)); - if (p_new_name == p_name) { - return; - } - - ERR_FAIL_COND(!String(p_new_name).is_valid_identifier()); - - ERR_FAIL_COND(functions.has(p_new_name)); - ERR_FAIL_COND(variables.has(p_new_name)); - ERR_FAIL_COND(custom_signals.has(p_new_name)); - - functions[p_new_name] = functions[p_name]; - functions.erase(p_name); -} - -void VisualScript::set_scroll(const Vector2 &p_scroll) { - scroll = p_scroll; -} - -Vector2 VisualScript::get_scroll() const { - return scroll; -} - -void VisualScript::get_function_list(List<StringName> *r_functions) const { - for (const KeyValue<StringName, Function> &E : functions) { - r_functions->push_back(E.key); - } -} - -int VisualScript::get_function_node_id(const StringName &p_name) const { - ERR_FAIL_COND_V(!functions.has(p_name), -1); - - return functions[p_name].func_id; -} - -void VisualScript::_node_ports_changed(int p_id) { - Ref<VisualScriptNode> vsn = nodes[p_id].node; - - vsn->validate_input_default_values(); - - // Must revalidate all the functions. - - { - List<SequenceConnection> to_remove; - - for (const SequenceConnection &E : sequence_connections) { - if (E.from_node == p_id && E.from_output >= vsn->get_output_sequence_port_count()) { - to_remove.push_back(E); - } - if (E.to_node == p_id && !vsn->has_input_sequence_port()) { - to_remove.push_back(E); - } - } - - while (to_remove.size()) { - sequence_connections.erase(to_remove.front()->get()); - to_remove.pop_front(); - } - } - - { - List<DataConnection> to_remove; - - for (const DataConnection &E : data_connections) { - if (E.from_node == p_id && E.from_port >= vsn->get_output_value_port_count()) { - to_remove.push_back(E); - } - if (E.to_node == p_id && E.to_port >= vsn->get_input_value_port_count()) { - to_remove.push_back(E); - } - } - - while (to_remove.size()) { - data_connections.erase(to_remove.front()->get()); - to_remove.pop_front(); - } - } - -#ifdef TOOLS_ENABLED - set_edited(true); // Something changed, let's set as edited. - emit_signal(SNAME("node_ports_changed"), p_id); -#endif -} - -void VisualScript::add_node(int p_id, const Ref<VisualScriptNode> &p_node, const Point2 &p_pos) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(nodes.has(p_id)); // ID can exist only one in script. - ERR_FAIL_COND(p_node.is_null()); - - NodeData nd; - nd.node = p_node; - nd.pos = p_pos; - - Ref<VisualScriptNode> vsn = p_node; - vsn->connect("ports_changed", callable_mp(this, &VisualScript::_node_ports_changed).bind(p_id)); - vsn->script_used = Ref<VisualScript>(this); - vsn->validate_input_default_values(); // Validate when fully loaded. - - nodes[p_id] = nd; -} - -void VisualScript::remove_node(int p_id) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(!nodes.has(p_id)); - { - List<SequenceConnection> to_remove; - - for (const SequenceConnection &E : sequence_connections) { - if (E.from_node == p_id || E.to_node == p_id) { - to_remove.push_back(E); - } - } - - while (to_remove.size()) { - sequence_connections.erase(to_remove.front()->get()); - to_remove.pop_front(); - } - } - - { - List<DataConnection> to_remove; - - for (const DataConnection &E : data_connections) { - if (E.from_node == p_id || E.to_node == p_id) { - to_remove.push_back(E); - } - } - - while (to_remove.size()) { - data_connections.erase(to_remove.front()->get()); - to_remove.pop_front(); - } - } - - nodes[p_id].node->disconnect("ports_changed", callable_mp(this, &VisualScript::_node_ports_changed)); - nodes[p_id].node->script_used.unref(); - - nodes.erase(p_id); -} - -bool VisualScript::has_node(int p_id) const { - return nodes.has(p_id); -} - -Ref<VisualScriptNode> VisualScript::get_node(int p_id) const { - ERR_FAIL_COND_V(!nodes.has(p_id), Ref<VisualScriptNode>()); - - return nodes[p_id].node; -} - -void VisualScript::set_node_position(int p_id, const Point2 &p_pos) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(!nodes.has(p_id)); - nodes[p_id].pos = p_pos; -} - -Point2 VisualScript::get_node_position(int p_id) const { - ERR_FAIL_COND_V(!nodes.has(p_id), Point2()); - return nodes[p_id].pos; -} - -void VisualScript::get_node_list(List<int> *r_nodes) const { - for (const KeyValue<int, NodeData> &E : nodes) { - r_nodes->push_back(E.key); - } -} - -void VisualScript::sequence_connect(int p_from_node, int p_from_output, int p_to_node) { - ERR_FAIL_COND(instances.size()); - - SequenceConnection sc; - sc.from_node = p_from_node; - sc.from_output = p_from_output; - sc.to_node = p_to_node; - ERR_FAIL_COND(sequence_connections.has(sc)); - - sequence_connections.insert(sc); -} - -void VisualScript::sequence_disconnect(int p_from_node, int p_from_output, int p_to_node) { - SequenceConnection sc; - sc.from_node = p_from_node; - sc.from_output = p_from_output; - sc.to_node = p_to_node; - ERR_FAIL_COND(!sequence_connections.has(sc)); - - sequence_connections.erase(sc); -} - -bool VisualScript::has_sequence_connection(int p_from_node, int p_from_output, int p_to_node) const { - SequenceConnection sc; - sc.from_node = p_from_node; - sc.from_output = p_from_output; - sc.to_node = p_to_node; - - return sequence_connections.has(sc); -} - -void VisualScript::get_sequence_connection_list(List<SequenceConnection> *r_connection) const { - for (const SequenceConnection &E : sequence_connections) { - r_connection->push_back(E); - } -} - -void VisualScript::data_connect(int p_from_node, int p_from_port, int p_to_node, int p_to_port) { - ERR_FAIL_COND(instances.size()); - - DataConnection dc; - dc.from_node = p_from_node; - dc.from_port = p_from_port; - dc.to_node = p_to_node; - dc.to_port = p_to_port; - - ERR_FAIL_COND(data_connections.has(dc)); - - data_connections.insert(dc); -} - -void VisualScript::data_disconnect(int p_from_node, int p_from_port, int p_to_node, int p_to_port) { - DataConnection dc; - dc.from_node = p_from_node; - dc.from_port = p_from_port; - dc.to_node = p_to_node; - dc.to_port = p_to_port; - - ERR_FAIL_COND(!data_connections.has(dc)); - - data_connections.erase(dc); -} - -bool VisualScript::has_data_connection(int p_from_node, int p_from_port, int p_to_node, int p_to_port) const { - DataConnection dc; - dc.from_node = p_from_node; - dc.from_port = p_from_port; - dc.to_node = p_to_node; - dc.to_port = p_to_port; - - return data_connections.has(dc); -} - -bool VisualScript::is_input_value_port_connected(int p_node, int p_port) const { - for (const DataConnection &E : data_connections) { - if (E.to_node == p_node && E.to_port == p_port) { - return true; - } - } - return false; -} - -bool VisualScript::get_input_value_port_connection_source(int p_node, int p_port, int *r_node, int *r_port) const { - for (const DataConnection &E : data_connections) { - if (E.to_node == p_node && E.to_port == p_port) { - *r_node = E.from_node; - *r_port = E.from_port; - return true; - } - } - return false; -} - -void VisualScript::get_data_connection_list(List<DataConnection> *r_connection) const { - for (const DataConnection &E : data_connections) { - r_connection->push_back(E); - } -} - -void VisualScript::set_tool_enabled(bool p_enabled) { - is_tool_script = p_enabled; -} - -void VisualScript::add_variable(const StringName &p_name, const Variant &p_default_value, bool p_export) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(!String(p_name).is_valid_identifier()); - ERR_FAIL_COND(variables.has(p_name)); - - Variable v; - v.default_value = p_default_value; - v.info.type = p_default_value.get_type(); - v.info.name = p_name; - v.info.hint = PROPERTY_HINT_NONE; - v._export = p_export; - - variables[p_name] = v; - -#ifdef TOOLS_ENABLED - _update_placeholders(); -#endif -} - -bool VisualScript::has_variable(const StringName &p_name) const { - return variables.has(p_name); -} - -void VisualScript::remove_variable(const StringName &p_name) { - ERR_FAIL_COND(!variables.has(p_name)); - variables.erase(p_name); - -#ifdef TOOLS_ENABLED - _update_placeholders(); -#endif -} - -void VisualScript::set_variable_default_value(const StringName &p_name, const Variant &p_value) { - ERR_FAIL_COND(!variables.has(p_name)); - - variables[p_name].default_value = p_value; - -#ifdef TOOLS_ENABLED - _update_placeholders(); -#endif -} - -Variant VisualScript::get_variable_default_value(const StringName &p_name) const { - ERR_FAIL_COND_V(!variables.has(p_name), Variant()); - return variables[p_name].default_value; -} - -void VisualScript::set_variable_info(const StringName &p_name, const PropertyInfo &p_info) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(!variables.has(p_name)); - variables[p_name].info = p_info; - variables[p_name].info.name = p_name; - -#ifdef TOOLS_ENABLED - _update_placeholders(); -#endif -} - -PropertyInfo VisualScript::get_variable_info(const StringName &p_name) const { - ERR_FAIL_COND_V(!variables.has(p_name), PropertyInfo()); - return variables[p_name].info; -} - -void VisualScript::set_variable_export(const StringName &p_name, bool p_export) { - ERR_FAIL_COND(!variables.has(p_name)); - - variables[p_name]._export = p_export; -#ifdef TOOLS_ENABLED - _update_placeholders(); -#endif -} - -bool VisualScript::get_variable_export(const StringName &p_name) const { - ERR_FAIL_COND_V(!variables.has(p_name), false); - return variables[p_name]._export; -} - -void VisualScript::_set_variable_info(const StringName &p_name, const Dictionary &p_info) { - PropertyInfo pinfo; - if (p_info.has("type")) { - pinfo.type = Variant::Type(int(p_info["type"])); - } - if (p_info.has("name")) { - pinfo.name = p_info["name"]; - } - if (p_info.has("hint")) { - pinfo.hint = PropertyHint(int(p_info["hint"])); - } - if (p_info.has("hint_string")) { - pinfo.hint_string = p_info["hint_string"]; - } - if (p_info.has("usage")) { - pinfo.usage = p_info["usage"]; - } - - set_variable_info(p_name, pinfo); -} - -Dictionary VisualScript::_get_variable_info(const StringName &p_name) const { - PropertyInfo pinfo = get_variable_info(p_name); - Dictionary d; - d["type"] = pinfo.type; - d["name"] = pinfo.name; - d["hint"] = pinfo.hint; - d["hint_string"] = pinfo.hint_string; - d["usage"] = pinfo.usage; - - return d; -} - -void VisualScript::get_variable_list(List<StringName> *r_variables) const { - for (const KeyValue<StringName, Variable> &E : variables) { - r_variables->push_back(E.key); - } -} - -void VisualScript::set_instance_base_type(const StringName &p_type) { - ERR_FAIL_COND(instances.size()); - base_type = p_type; -} - -void VisualScript::rename_variable(const StringName &p_name, const StringName &p_new_name) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(!variables.has(p_name)); - if (p_new_name == p_name) { - return; - } - - ERR_FAIL_COND(!String(p_new_name).is_valid_identifier()); - - ERR_FAIL_COND(functions.has(p_new_name)); - ERR_FAIL_COND(variables.has(p_new_name)); - ERR_FAIL_COND(custom_signals.has(p_new_name)); - - variables[p_new_name] = variables[p_name]; - variables.erase(p_name); - List<int> ids; - get_node_list(&ids); - for (int &E : ids) { - Ref<VisualScriptVariableGet> nodeget = get_node(E); - if (nodeget.is_valid()) { - if (nodeget->get_variable() == p_name) { - nodeget->set_variable(p_new_name); - } - } else { - Ref<VisualScriptVariableSet> nodeset = get_node(E); - if (nodeset.is_valid()) { - if (nodeset->get_variable() == p_name) { - nodeset->set_variable(p_new_name); - } - } - } - } -} - -void VisualScript::add_custom_signal(const StringName &p_name) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(!String(p_name).is_valid_identifier()); - ERR_FAIL_COND(custom_signals.has(p_name)); - - custom_signals[p_name] = Vector<Argument>(); -} - -bool VisualScript::has_custom_signal(const StringName &p_name) const { - return custom_signals.has(p_name); -} - -void VisualScript::custom_signal_add_argument(const StringName &p_func, Variant::Type p_type, const String &p_name, int p_index) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(!custom_signals.has(p_func)); - Argument arg; - arg.type = p_type; - arg.name = p_name; - if (p_index < 0) { - custom_signals[p_func].push_back(arg); - } else { - custom_signals[p_func].insert(0, arg); - } -} - -void VisualScript::custom_signal_set_argument_type(const StringName &p_func, int p_argidx, Variant::Type p_type) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(!custom_signals.has(p_func)); - ERR_FAIL_INDEX(p_argidx, custom_signals[p_func].size()); - custom_signals[p_func].write[p_argidx].type = p_type; -} - -Variant::Type VisualScript::custom_signal_get_argument_type(const StringName &p_func, int p_argidx) const { - ERR_FAIL_COND_V(!custom_signals.has(p_func), Variant::NIL); - ERR_FAIL_INDEX_V(p_argidx, custom_signals[p_func].size(), Variant::NIL); - return custom_signals[p_func][p_argidx].type; -} - -void VisualScript::custom_signal_set_argument_name(const StringName &p_func, int p_argidx, const String &p_name) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(!custom_signals.has(p_func)); - ERR_FAIL_INDEX(p_argidx, custom_signals[p_func].size()); - custom_signals[p_func].write[p_argidx].name = p_name; -} - -String VisualScript::custom_signal_get_argument_name(const StringName &p_func, int p_argidx) const { - ERR_FAIL_COND_V(!custom_signals.has(p_func), String()); - ERR_FAIL_INDEX_V(p_argidx, custom_signals[p_func].size(), String()); - return custom_signals[p_func][p_argidx].name; -} - -void VisualScript::custom_signal_remove_argument(const StringName &p_func, int p_argidx) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(!custom_signals.has(p_func)); - ERR_FAIL_INDEX(p_argidx, custom_signals[p_func].size()); - custom_signals[p_func].remove_at(p_argidx); -} - -int VisualScript::custom_signal_get_argument_count(const StringName &p_func) const { - ERR_FAIL_COND_V(!custom_signals.has(p_func), 0); - return custom_signals[p_func].size(); -} - -void VisualScript::custom_signal_swap_argument(const StringName &p_func, int p_argidx, int p_with_argidx) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(!custom_signals.has(p_func)); - ERR_FAIL_INDEX(p_argidx, custom_signals[p_func].size()); - ERR_FAIL_INDEX(p_with_argidx, custom_signals[p_func].size()); - - SWAP(custom_signals[p_func].write[p_argidx], custom_signals[p_func].write[p_with_argidx]); -} - -void VisualScript::remove_custom_signal(const StringName &p_name) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(!custom_signals.has(p_name)); - custom_signals.erase(p_name); -} - -void VisualScript::rename_custom_signal(const StringName &p_name, const StringName &p_new_name) { - ERR_FAIL_COND(instances.size()); - ERR_FAIL_COND(!custom_signals.has(p_name)); - if (p_new_name == p_name) { - return; - } - - ERR_FAIL_COND(!String(p_new_name).is_valid_identifier()); - - ERR_FAIL_COND(functions.has(p_new_name)); - ERR_FAIL_COND(variables.has(p_new_name)); - ERR_FAIL_COND(custom_signals.has(p_new_name)); - - custom_signals[p_new_name] = custom_signals[p_name]; - custom_signals.erase(p_name); -} - -void VisualScript::get_custom_signal_list(List<StringName> *r_custom_signals) const { - for (const KeyValue<StringName, Vector<Argument>> &E : custom_signals) { - r_custom_signals->push_back(E.key); - } - - r_custom_signals->sort_custom<StringName::AlphCompare>(); -} - -int VisualScript::get_available_id() const { - // This is infinitely increasing, - // so one might want to implement a better solution, - // if the there is a case for huge number of nodes to be added to visual script. - - int max = -1; - for (const KeyValue<int, NodeData> &E : nodes) { - if (E.key > max) { - max = E.key; - } - } - return (max + 1); -} - -///////////////////////////////// - -bool VisualScript::can_instantiate() const { - return true; // ScriptServer::is_scripting_enabled(); -} - -StringName VisualScript::get_instance_base_type() const { - return base_type; -} - -Ref<Script> VisualScript::get_base_script() const { - return Ref<Script>(); // No inheritance in visual script. -} - -#ifdef TOOLS_ENABLED -void VisualScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { - placeholders.erase(p_placeholder); -} - -void VisualScript::_update_placeholders() { - if (placeholders.size() == 0) { - return; // No bother if no placeholders. - } - List<PropertyInfo> pinfo; - HashMap<StringName, Variant> values; - - for (const KeyValue<StringName, Variable> &E : variables) { - if (!variables[E.key]._export) { - continue; - } - - PropertyInfo p = variables[E.key].info; - p.name = String(E.key); - pinfo.push_back(p); - values[p.name] = variables[E.key].default_value; - } - - for (PlaceHolderScriptInstance *E : placeholders) { - E->update(pinfo, values); - } -} - -#endif - -ScriptInstance *VisualScript::instance_create(Object *p_this) { -#ifdef TOOLS_ENABLED - - if (!ScriptServer::is_scripting_enabled() && !is_tool_script) { - PlaceHolderScriptInstance *sins = memnew(PlaceHolderScriptInstance(VisualScriptLanguage::singleton, Ref<Script>((Script *)this), p_this)); - placeholders.insert(sins); - - List<PropertyInfo> pinfo; - HashMap<StringName, Variant> values; - - for (const KeyValue<StringName, Variable> &E : variables) { - if (!variables[E.key]._export) { - continue; - } - - PropertyInfo p = variables[E.key].info; - p.name = String(E.key); - pinfo.push_back(p); - values[p.name] = variables[E.key].default_value; - } - sins->update(pinfo, values); - - return sins; - } -#endif - - VisualScriptInstance *instance = memnew(VisualScriptInstance); - instance->create(Ref<VisualScript>(this), p_this); - - { - MutexLock lock(VisualScriptLanguage::singleton->lock); - - instances[p_this] = instance; - } - - return instance; -} - -bool VisualScript::instance_has(const Object *p_this) const { - return instances.has((Object *)p_this); -} - -bool VisualScript::has_source_code() const { - return false; -} - -String VisualScript::get_source_code() const { - return String(); -} - -void VisualScript::set_source_code(const String &p_code) { -} - -Error VisualScript::reload(bool p_keep_state) { - return OK; -} - -bool VisualScript::is_tool() const { - return is_tool_script; -} - -bool VisualScript::is_valid() const { - return true; // Always valid. -} - -ScriptLanguage *VisualScript::get_language() const { - return VisualScriptLanguage::singleton; -} - -bool VisualScript::has_script_signal(const StringName &p_signal) const { - return custom_signals.has(p_signal); -} - -void VisualScript::get_script_signal_list(List<MethodInfo> *r_signals) const { - for (const KeyValue<StringName, Vector<Argument>> &E : custom_signals) { - MethodInfo mi; - mi.name = E.key; - for (int i = 0; i < E.value.size(); i++) { - PropertyInfo arg; - arg.type = E.value[i].type; - arg.name = E.value[i].name; - mi.arguments.push_back(arg); - } - - r_signals->push_back(mi); - } -} - -bool VisualScript::get_property_default_value(const StringName &p_property, Variant &r_value) const { - if (!variables.has(p_property)) { - return false; - } - - r_value = variables[p_property].default_value; - return true; -} - -void VisualScript::get_script_method_list(List<MethodInfo> *p_list) const { - for (const KeyValue<StringName, Function> &E : functions) { - MethodInfo mi; - mi.name = E.key; - if (functions[E.key].func_id >= 0) { - Ref<VisualScriptFunction> func = nodes[functions[E.key].func_id].node; - if (func.is_valid()) { - for (int i = 0; i < func->get_argument_count(); i++) { - PropertyInfo arg; - arg.name = func->get_argument_name(i); - arg.type = func->get_argument_type(i); - mi.arguments.push_back(arg); - } - - p_list->push_back(mi); - } - } - } -} - -bool VisualScript::has_method(const StringName &p_method) const { - return functions.has(p_method); -} - -MethodInfo VisualScript::get_method_info(const StringName &p_method) const { - const Function funct = functions[p_method]; - if (funct.func_id == -1) { - return MethodInfo(); - } - - MethodInfo mi; - mi.name = p_method; - if (funct.func_id >= 0) { - Ref<VisualScriptFunction> func = nodes[funct.func_id].node; - if (func.is_valid()) { - for (int i = 0; i < func->get_argument_count(); i++) { - PropertyInfo arg; - arg.name = func->get_argument_name(i); - arg.type = func->get_argument_type(i); - mi.arguments.push_back(arg); - } - - if (!func->is_sequenced()) { - mi.flags |= METHOD_FLAG_CONST; - } - } - } - - return mi; -} - -void VisualScript::get_script_property_list(List<PropertyInfo> *p_list) const { - List<StringName> vars; - get_variable_list(&vars); - - for (const StringName &E : vars) { - if (!variables[E]._export) { - continue; - } - PropertyInfo pi = variables[E].info; - pi.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; - p_list->push_back(pi); - } -} - -int VisualScript::get_member_line(const StringName &p_member) const { - return functions[p_member].func_id; // will be -1 if not found -} - -#ifdef TOOLS_ENABLED -bool VisualScript::are_subnodes_edited() const { - for (const KeyValue<int, NodeData> &F : nodes) { - if (F.value.node->is_edited()) { - return true; - } - } - return false; -} -#endif - -const Variant VisualScript::get_rpc_config() const { - return rpc_functions; -} - -void VisualScript::_set_data(const Dictionary &p_data) { - Dictionary d = p_data; - if (d.has("base_type")) { - base_type = d["base_type"]; - } - - variables.clear(); - Array vars = d["variables"]; - for (int i = 0; i < vars.size(); i++) { - Dictionary v = vars[i]; - StringName name = v["name"]; - add_variable(name); - _set_variable_info(name, v); - set_variable_default_value(name, v["default_value"]); - set_variable_export(name, v.has("export") && bool(v["export"])); - } - - custom_signals.clear(); - Array sigs = d["signals"]; - for (int i = 0; i < sigs.size(); i++) { - Dictionary cs = sigs[i]; - add_custom_signal(cs["name"]); - - Array args = cs["arguments"]; - for (int j = 0; j < args.size(); j += 2) { - custom_signal_add_argument(cs["name"], Variant::Type(int(args[j + 1])), args[j]); - } - } - - Array funcs = d["functions"]; - functions.clear(); - - for (int i = 0; i < funcs.size(); i++) { - Dictionary func = funcs[i]; - add_function(func["name"], func["function_id"]); - } - { - Array nodes = d["nodes"]; - for (int i = 0; i < nodes.size(); i += 3) { - add_node(nodes[i], nodes[i + 2], nodes[i + 1]); - } - - Array sequence_connections = d["sequence_connections"]; - for (int j = 0; j < sequence_connections.size(); j += 3) { - sequence_connect(sequence_connections[j + 0], sequence_connections[j + 1], sequence_connections[j + 2]); - } - - Array data_connections = d["data_connections"]; - for (int j = 0; j < data_connections.size(); j += 4) { - data_connect(data_connections[j + 0], data_connections[j + 1], data_connections[j + 2], data_connections[j + 3]); - } - } - is_tool_script = d["is_tool_script"]; - scroll = d["scroll"]; - - // Takes all the rpc methods. - rpc_functions.clear(); - for (const KeyValue<StringName, Function> &E : functions) { - if (E.value.func_id >= 0 && nodes.has(E.value.func_id)) { - Ref<VisualScriptFunction> vsf = nodes[E.value.func_id].node; - if (!vsf.is_valid() || vsf->get_rpc_mode() == MultiplayerAPI::RPC_MODE_DISABLED) { - continue; - } - Dictionary nd; - nd["rpc_mode"] = vsf->get_rpc_mode(); - nd["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_RELIABLE; // TODO - nd["call_local"] = false; // TODO - rpc_functions[E.key] = nd; - } - } -} - -Dictionary VisualScript::_get_data() const { - Dictionary d; - d["base_type"] = base_type; - - Array vars; - for (const KeyValue<StringName, Variable> &E : variables) { - Dictionary var = _get_variable_info(E.key); - var["name"] = E.key; // Make sure it's the right one. - var["default_value"] = E.value.default_value; - var["export"] = E.value._export; - vars.push_back(var); - } - d["variables"] = vars; - - Array sigs; - for (const KeyValue<StringName, Vector<Argument>> &E : custom_signals) { - Dictionary cs; - cs["name"] = E.key; - Array args; - for (int i = 0; i < E.value.size(); i++) { - args.push_back(E.value[i].name); - args.push_back(E.value[i].type); - } - cs["arguments"] = args; - - sigs.push_back(cs); - } - - d["signals"] = sigs; - - Array funcs; - for (const KeyValue<StringName, Function> &E : functions) { - Dictionary func; - func["name"] = E.key; - func["function_id"] = E.value.func_id; - funcs.push_back(func); - } - d["functions"] = funcs; - - Array nds; - for (const KeyValue<int, NodeData> &F : nodes) { - nds.push_back(F.key); - nds.push_back(F.value.pos); - nds.push_back(F.value.node); - } - d["nodes"] = nds; - - Array seqconns; - for (const SequenceConnection &F : sequence_connections) { - seqconns.push_back(F.from_node); - seqconns.push_back(F.from_output); - seqconns.push_back(F.to_node); - } - d["sequence_connections"] = seqconns; - - Array dataconns; - for (const DataConnection &F : data_connections) { - dataconns.push_back(F.from_node); - dataconns.push_back(F.from_port); - dataconns.push_back(F.to_node); - dataconns.push_back(F.to_port); - } - d["data_connections"] = dataconns; - - d["is_tool_script"] = is_tool_script; - d["scroll"] = scroll; - - return d; -} - -void VisualScript::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_function", "name", "func_node_id"), &VisualScript::add_function); - ClassDB::bind_method(D_METHOD("has_function", "name"), &VisualScript::has_function); - ClassDB::bind_method(D_METHOD("remove_function", "name"), &VisualScript::remove_function); - ClassDB::bind_method(D_METHOD("rename_function", "name", "new_name"), &VisualScript::rename_function); - ClassDB::bind_method(D_METHOD("set_scroll", "offset"), &VisualScript::set_scroll); - ClassDB::bind_method(D_METHOD("get_scroll"), &VisualScript::get_scroll); - - ClassDB::bind_method(D_METHOD("add_node", "id", "node", "position"), &VisualScript::add_node, DEFVAL(Point2())); - ClassDB::bind_method(D_METHOD("remove_node", "id"), &VisualScript::remove_node); - ClassDB::bind_method(D_METHOD("get_function_node_id", "name"), &VisualScript::get_function_node_id); - - ClassDB::bind_method(D_METHOD("get_node", "id"), &VisualScript::get_node); - ClassDB::bind_method(D_METHOD("has_node", "id"), &VisualScript::has_node); - ClassDB::bind_method(D_METHOD("set_node_position", "id", "position"), &VisualScript::set_node_position); - ClassDB::bind_method(D_METHOD("get_node_position", "id"), &VisualScript::get_node_position); - - ClassDB::bind_method(D_METHOD("sequence_connect", "from_node", "from_output", "to_node"), &VisualScript::sequence_connect); - ClassDB::bind_method(D_METHOD("sequence_disconnect", "from_node", "from_output", "to_node"), &VisualScript::sequence_disconnect); - ClassDB::bind_method(D_METHOD("has_sequence_connection", "from_node", "from_output", "to_node"), &VisualScript::has_sequence_connection); - - ClassDB::bind_method(D_METHOD("data_connect", "from_node", "from_port", "to_node", "to_port"), &VisualScript::data_connect); - ClassDB::bind_method(D_METHOD("data_disconnect", "from_node", "from_port", "to_node", "to_port"), &VisualScript::data_disconnect); - ClassDB::bind_method(D_METHOD("has_data_connection", "from_node", "from_port", "to_node", "to_port"), &VisualScript::has_data_connection); - - ClassDB::bind_method(D_METHOD("add_variable", "name", "default_value", "export"), &VisualScript::add_variable, DEFVAL(Variant()), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("has_variable", "name"), &VisualScript::has_variable); - ClassDB::bind_method(D_METHOD("remove_variable", "name"), &VisualScript::remove_variable); - ClassDB::bind_method(D_METHOD("set_variable_default_value", "name", "value"), &VisualScript::set_variable_default_value); - ClassDB::bind_method(D_METHOD("get_variable_default_value", "name"), &VisualScript::get_variable_default_value); - ClassDB::bind_method(D_METHOD("set_variable_info", "name", "value"), &VisualScript::_set_variable_info); - ClassDB::bind_method(D_METHOD("get_variable_info", "name"), &VisualScript::_get_variable_info); - ClassDB::bind_method(D_METHOD("set_variable_export", "name", "enable"), &VisualScript::set_variable_export); - ClassDB::bind_method(D_METHOD("get_variable_export", "name"), &VisualScript::get_variable_export); - ClassDB::bind_method(D_METHOD("rename_variable", "name", "new_name"), &VisualScript::rename_variable); - - ClassDB::bind_method(D_METHOD("add_custom_signal", "name"), &VisualScript::add_custom_signal); - ClassDB::bind_method(D_METHOD("has_custom_signal", "name"), &VisualScript::has_custom_signal); - ClassDB::bind_method(D_METHOD("custom_signal_add_argument", "name", "type", "argname", "index"), &VisualScript::custom_signal_add_argument, DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("custom_signal_set_argument_type", "name", "argidx", "type"), &VisualScript::custom_signal_set_argument_type); - ClassDB::bind_method(D_METHOD("custom_signal_get_argument_type", "name", "argidx"), &VisualScript::custom_signal_get_argument_type); - ClassDB::bind_method(D_METHOD("custom_signal_set_argument_name", "name", "argidx", "argname"), &VisualScript::custom_signal_set_argument_name); - ClassDB::bind_method(D_METHOD("custom_signal_get_argument_name", "name", "argidx"), &VisualScript::custom_signal_get_argument_name); - ClassDB::bind_method(D_METHOD("custom_signal_remove_argument", "name", "argidx"), &VisualScript::custom_signal_remove_argument); - ClassDB::bind_method(D_METHOD("custom_signal_get_argument_count", "name"), &VisualScript::custom_signal_get_argument_count); - ClassDB::bind_method(D_METHOD("custom_signal_swap_argument", "name", "argidx", "withidx"), &VisualScript::custom_signal_swap_argument); - ClassDB::bind_method(D_METHOD("remove_custom_signal", "name"), &VisualScript::remove_custom_signal); - ClassDB::bind_method(D_METHOD("rename_custom_signal", "name", "new_name"), &VisualScript::rename_custom_signal); - - ClassDB::bind_method(D_METHOD("set_instance_base_type", "type"), &VisualScript::set_instance_base_type); - - ClassDB::bind_method(D_METHOD("_set_data", "data"), &VisualScript::_set_data); - ClassDB::bind_method(D_METHOD("_get_data"), &VisualScript::_get_data); - - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); - - ADD_SIGNAL(MethodInfo("node_ports_changed", PropertyInfo(Variant::INT, "id"))); -} - -VisualScript::VisualScript() { - base_type = "Object"; - is_tool_script = false; -} - -bool VisualScript::inherits_script(const Ref<Script> &p_script) const { - return this == p_script.ptr(); // There is no inheritance in visual scripts, so this is enough. -} - -RBSet<int> VisualScript::get_output_sequence_ports_connected(int from_node) { - List<VisualScript::SequenceConnection> *sc = memnew(List<VisualScript::SequenceConnection>); - get_sequence_connection_list(sc); - RBSet<int> connected; - for (List<VisualScript::SequenceConnection>::Element *E = sc->front(); E; E = E->next()) { - if (E->get().from_node == from_node) { - connected.insert(E->get().from_output); - } - } - memdelete(sc); - return connected; -} - -VisualScript::~VisualScript() { - // Remove all nodes and stuff that hold data refs. - for (const KeyValue<int, NodeData> &E : nodes) { - remove_node(E.key); - } -} - -//////////////////////////////////////////// - -bool VisualScriptInstance::set(const StringName &p_name, const Variant &p_value) { - HashMap<StringName, Variant>::Iterator E = variables.find(p_name); - if (!E) { - return false; - } - - E->value = p_value; - - return true; -} - -bool VisualScriptInstance::get(const StringName &p_name, Variant &r_ret) const { - HashMap<StringName, Variant>::ConstIterator E = variables.find(p_name); - if (!E) { - return false; - } - - r_ret = E->value; - return true; -} - -void VisualScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const { -#ifdef TOOLS_ENABLED - p_properties->push_back(script->get_class_category()); -#endif // TOOLS_ENABLED - - for (const KeyValue<StringName, VisualScript::Variable> &E : script->variables) { - if (!E.value._export) { - continue; - } - PropertyInfo p = E.value.info; - p.name = String(E.key); - p.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; - p_properties->push_back(p); - } -} - -Variant::Type VisualScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const { - if (!script->variables.has(p_name)) { - if (r_is_valid) { - *r_is_valid = false; - } - ERR_FAIL_V(Variant::NIL); - } - - if (r_is_valid) { - *r_is_valid = true; - } - - return script->variables[p_name].info.type; -} - -void VisualScriptInstance::get_method_list(List<MethodInfo> *p_list) const { - for (const KeyValue<StringName, VisualScript::Function> &E : script->functions) { - MethodInfo mi; - mi.name = E.key; - if (E.value.func_id >= 0 && script->nodes.has(E.value.func_id)) { - Ref<VisualScriptFunction> vsf = script->nodes[E.value.func_id].node; - if (vsf.is_valid()) { - for (int i = 0; i < vsf->get_argument_count(); i++) { - PropertyInfo arg; - arg.name = vsf->get_argument_name(i); - arg.type = vsf->get_argument_type(i); - - mi.arguments.push_back(arg); - } - - if (!vsf->is_sequenced()) { // Assumed constant if not sequenced. - mi.flags |= METHOD_FLAG_CONST; - } - } - } - p_list->push_back(mi); - } -} - -bool VisualScriptInstance::has_method(const StringName &p_method) const { - return script->functions.has(p_method); -} - -//#define VSDEBUG(m_text) print_line(m_text) -#define VSDEBUG(m_text) - -void VisualScriptInstance::_dependency_step(VisualScriptNodeInstance *node, int p_pass, int *pass_stack, const Variant **input_args, Variant **output_args, Variant *variant_stack, Callable::CallError &r_error, String &error_str, VisualScriptNodeInstance **r_error_node) { - ERR_FAIL_COND(node->pass_idx == -1); - - if (pass_stack[node->pass_idx] == p_pass) { - return; - } - - pass_stack[node->pass_idx] = p_pass; - - if (!node->dependencies.is_empty()) { - int dc = node->dependencies.size(); - VisualScriptNodeInstance **deps = node->dependencies.ptrw(); - - for (int i = 0; i < dc; i++) { - _dependency_step(deps[i], p_pass, pass_stack, input_args, output_args, variant_stack, r_error, error_str, r_error_node); - if (r_error.error != Callable::CallError::CALL_OK) { - return; - } - } - } - - for (int i = 0; i < node->input_port_count; i++) { - int index = node->input_ports[i] & VisualScriptNodeInstance::INPUT_MASK; - - if (node->input_ports[i] & VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT) { - // Is a default value (unassigned input port). - input_args[i] = &default_values[index]; - } else { - // Regular temporary in stack. - input_args[i] = &variant_stack[index]; - } - } - for (int i = 0; i < node->output_port_count; i++) { - output_args[i] = &variant_stack[node->output_ports[i]]; - } - - Variant *working_mem = node->working_mem_idx >= 0 ? &variant_stack[node->working_mem_idx] : (Variant *)nullptr; - - node->step(input_args, output_args, VisualScriptNodeInstance::START_MODE_BEGIN_SEQUENCE, working_mem, r_error, error_str); - // Ignore return. - if (r_error.error != Callable::CallError::CALL_OK) { - *r_error_node = node; - } -} - -Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p_stack, int p_stack_size, VisualScriptNodeInstance *p_node, int p_flow_stack_pos, int p_pass, bool p_resuming_yield, Callable::CallError &r_error) { - HashMap<StringName, Function>::Iterator F = functions.find(p_method); - ERR_FAIL_COND_V(!F, Variant()); - Function *f = &F->value; - - // This call goes separate, so it can be yielded and suspended. - Variant *variant_stack = (Variant *)p_stack; - bool *sequence_bits = (bool *)(variant_stack + f->max_stack); - const Variant **input_args = (const Variant **)(sequence_bits + f->node_count); - Variant **output_args = (Variant **)(input_args + max_input_args); - int flow_max = f->flow_stack_size; - int *flow_stack = flow_max ? (int *)(output_args + max_output_args) : (int *)nullptr; - int *pass_stack = flow_stack ? (int *)(flow_stack + flow_max) : (int *)nullptr; - - String error_str; - - VisualScriptNodeInstance *node = p_node; - bool error = false; - int current_node_id = f->node; - Variant return_value; - Variant *working_mem = nullptr; - - int flow_stack_pos = p_flow_stack_pos; - -#ifdef DEBUG_ENABLED - if (EngineDebugger::is_active()) { - VisualScriptLanguage::singleton->enter_function(this, &p_method, variant_stack, &working_mem, ¤t_node_id); - } -#endif - - while (true) { - p_pass++; // Increment pass. - current_node_id = node->get_id(); - - VSDEBUG("==========AT NODE: " + itos(current_node_id) + " base: " + node->get_base_node()->get_class_name()); - VSDEBUG("AT STACK POS: " + itos(flow_stack_pos)); - - // Setup working mem. - working_mem = node->working_mem_idx >= 0 ? &variant_stack[node->working_mem_idx] : (Variant *)nullptr; - - VSDEBUG("WORKING MEM: " + itos(node->working_mem_idx)); - - if (current_node_id == f->node) { - // If function node, set up function arguments from beginning of stack. - - for (int i = 0; i < f->argument_count; i++) { - input_args[i] = &variant_stack[i]; - } - } else { - // Run dependencies first. - - if (!node->dependencies.is_empty()) { - int dc = node->dependencies.size(); - VisualScriptNodeInstance **deps = node->dependencies.ptrw(); - - for (int i = 0; i < dc; i++) { - _dependency_step(deps[i], p_pass, pass_stack, input_args, output_args, variant_stack, r_error, error_str, &node); - if (r_error.error != Callable::CallError::CALL_OK) { - error = true; - current_node_id = node->id; - break; - } - } - } - - if (!error) { - // Setup input pointers normally. - VSDEBUG("INPUT PORTS: " + itos(node->input_port_count)); - - for (int i = 0; i < node->input_port_count; i++) { - int index = node->input_ports[i] & VisualScriptNodeInstance::INPUT_MASK; - - if (node->input_ports[i] & VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT) { - // Is a default value (unassigned input port). - input_args[i] = &default_values[index]; - VSDEBUG("\tPORT " + itos(i) + " DEFAULT VAL"); - } else { - // Regular temporary in stack. - input_args[i] = &variant_stack[index]; - VSDEBUG("PORT " + itos(i) + " AT STACK " + itos(index)); - } - } - } - } - - if (error) { - break; - } - - // Setup output pointers. - - VSDEBUG("OUTPUT PORTS: " + itos(node->output_port_count)); - for (int i = 0; i < node->output_port_count; i++) { - output_args[i] = &variant_stack[node->output_ports[i]]; - VSDEBUG("PORT " + itos(i) + " AT STACK " + itos(node->output_ports[i])); - } - - // Do step. - - VisualScriptNodeInstance::StartMode start_mode; - { - if (p_resuming_yield) { - start_mode = VisualScriptNodeInstance::START_MODE_RESUME_YIELD; - p_resuming_yield = false; // Should resume only the first time. - } else if (flow_stack && (flow_stack[flow_stack_pos] & VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT)) { - // If there is a push bit, it means we are continuing a sequence. - start_mode = VisualScriptNodeInstance::START_MODE_CONTINUE_SEQUENCE; - } else { - start_mode = VisualScriptNodeInstance::START_MODE_BEGIN_SEQUENCE; - } - } - - VSDEBUG("STEP - STARTSEQ: " + itos(start_mode)); - - int ret = node->step(input_args, output_args, start_mode, working_mem, r_error, error_str); - - if (r_error.error != Callable::CallError::CALL_OK) { - // Use error from step. - error = true; - break; - } - - if (ret & VisualScriptNodeInstance::STEP_YIELD_BIT) { - // Yielded! - if (node->get_working_memory_size() == 0) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - error_str = RTR("A node yielded without working memory, please read the docs on how to yield properly!"); - error = true; - break; - - } else { - Ref<VisualScriptFunctionState> state = *working_mem; - if (!state.is_valid()) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - error_str = RTR("Node yielded, but did not return a function state in the first working memory."); - error = true; - break; - } - - // Step 1, capture all state. - state->instance_id = get_owner_ptr()->get_instance_id(); - state->script_id = get_script()->get_instance_id(); - state->instance = this; - state->function = p_method; - state->working_mem_index = node->working_mem_idx; - state->variant_stack_size = f->max_stack; - state->node = node; - state->flow_stack_pos = flow_stack_pos; - state->stack.resize(p_stack_size); - state->pass = p_pass; - memcpy(state->stack.ptrw(), p_stack, p_stack_size); - // Step 2, run away, return directly. - r_error.error = Callable::CallError::CALL_OK; - -#ifdef DEBUG_ENABLED - // Will re-enter later, so exiting. - if (EngineDebugger::is_active()) { - VisualScriptLanguage::singleton->exit_function(); - } -#endif - - return state; - } - } - -#ifdef DEBUG_ENABLED - if (EngineDebugger::is_active()) { - // line - bool do_break = false; - - if (EngineDebugger::get_script_debugger()->get_lines_left() > 0) { - if (EngineDebugger::get_script_debugger()->get_depth() <= 0) { - EngineDebugger::get_script_debugger()->set_lines_left(EngineDebugger::get_script_debugger()->get_lines_left() - 1); - } - if (EngineDebugger::get_script_debugger()->get_lines_left() <= 0) { - do_break = true; - } - } - - if (EngineDebugger::get_script_debugger()->is_breakpoint(current_node_id, source)) { - do_break = true; - } - - if (do_break) { - VisualScriptLanguage::singleton->debug_break("Breakpoint", true); - } - - EngineDebugger::get_singleton()->line_poll(); - } -#endif - int output = ret & VisualScriptNodeInstance::STEP_MASK; - - VSDEBUG("STEP RETURN: " + itos(ret)); - - if (ret & VisualScriptNodeInstance::STEP_EXIT_FUNCTION_BIT) { - if (node->get_working_memory_size() == 0) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - error_str = RTR("Return value must be assigned to first element of node working memory! Fix your node please."); - error = true; - } else { - // Assign from working memory, first element. - return_value = *working_mem; - } - - VSDEBUG("EXITING FUNCTION - VALUE " + String(return_value)); - break; // Exit function requested, bye - } - - VisualScriptNodeInstance *next = nullptr; // Next node. - - if ((ret == output || ret & VisualScriptNodeInstance::STEP_FLAG_PUSH_STACK_BIT) && node->sequence_output_count) { - // If no exit bit was set, and has sequence outputs, guess next node. - if (output >= node->sequence_output_count) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - error_str = RTR("Node returned an invalid sequence output:") + " " + itos(output); - error = true; - break; - } - - next = node->sequence_outputs[output]; - VSDEBUG("GOT NEXT NODE - " + (next ? itos(next->get_id()) : "Null")); - } - - if (flow_stack) { - // Update flow stack pos (may have changed). - flow_stack[flow_stack_pos] = current_node_id; - - // Add stack push bit if requested. - if (ret & VisualScriptNodeInstance::STEP_FLAG_PUSH_STACK_BIT) { - flow_stack[flow_stack_pos] |= VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT; - sequence_bits[node->sequence_index] = true; // Remember sequence bit. - VSDEBUG("NEXT SEQ - FLAG BIT"); - } else { - sequence_bits[node->sequence_index] = false; // Forget sequence bit. - VSDEBUG("NEXT SEQ - NORMAL"); - } - - if (ret & VisualScriptNodeInstance::STEP_FLAG_GO_BACK_BIT) { - // Go back request. - - if (flow_stack_pos > 0) { - flow_stack_pos--; - node = instances[flow_stack[flow_stack_pos] & VisualScriptNodeInstance::FLOW_STACK_MASK]; - VSDEBUG("NEXT IS GO BACK"); - } else { - VSDEBUG("NEXT IS GO BACK, BUT NO NEXT SO EXIT"); - break; // Simply exit without value or error. - } - } else if (next) { - if (sequence_bits[next->sequence_index]) { - // What happened here is that we are entering a node that is in the middle of doing a sequence (pushed stack) from the front - // because each node has a working memory, we can't really do a sub-sequence - // as a result, the sequence will be restarted and the stack will roll back to find where this node - // started the sequence. - - bool found = false; - - for (int i = flow_stack_pos; i >= 0; i--) { - if ((flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_MASK) == next->get_id()) { - flow_stack_pos = i; // Roll back and remove bit. - flow_stack[i] = next->get_id(); - sequence_bits[next->sequence_index] = false; - found = true; - } - } - - if (!found) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - error_str = RTR("Found sequence bit but not the node in the stack (please report)."); - error = true; - break; - } - - node = next; - VSDEBUG("RE-ENTERED A LOOP, RETURNED STACK POS TO - " + itos(flow_stack_pos)); - - } else { - // Check for stack overflow. - if (flow_stack_pos + 1 >= flow_max) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - error_str = vformat(RTR("Stack overflow (stack size: %s). Check for infinite recursion in your script."), output); - error = true; - break; - } - - node = next; - - flow_stack_pos++; - flow_stack[flow_stack_pos] = node->get_id(); - - VSDEBUG("INCREASE FLOW STACK"); - } - - } else { - // No next node, try to go back in stack to pushed bit. - - bool found = false; - - for (int i = flow_stack_pos; i >= 0; i--) { - VSDEBUG("FS " + itos(i) + " - " + itos(flow_stack[i])); - if (flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT) { - node = instances[flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_MASK]; - flow_stack_pos = i; - found = true; - break; - } - } - - if (!found) { - VSDEBUG("NO NEXT NODE, NO GO BACK, EXITING"); - break; // Done, couldn't find a push stack bit. - } - - VSDEBUG("NO NEXT NODE, GO BACK TO: " + itos(flow_stack_pos)); - } - } else { - node = next; // Stackless mode, simply assign next node. - } - } - - if (error) { - // Error - // Function, file, line, error, explanation. - String err_file = script->get_path(); - String err_func = p_method; - int err_line = current_node_id; // Not a line but it works as one. - - if (node && (r_error.error != Callable::CallError::CALL_ERROR_INVALID_METHOD || error_str.is_empty())) { - if (!error_str.is_empty()) { - error_str += " "; - } - - if (r_error.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) { - int errorarg = r_error.argument; - error_str += "Cannot convert argument " + itos(errorarg + 1) + " to " + Variant::get_type_name(Variant::Type(r_error.expected)) + "."; - } else if (r_error.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) { - error_str += "Expected " + itos(r_error.argument) + " arguments."; - } else if (r_error.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) { - error_str += "Expected " + itos(r_error.argument) + " arguments."; - } else if (r_error.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) { - error_str += "Invalid Call."; - } else if (r_error.error == Callable::CallError::CALL_ERROR_METHOD_NOT_CONST) { - error_str += "Method not const in a const instance."; - } else if (r_error.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) { - error_str += "Base Instance is null"; - } - } - - //if (!GDScriptLanguage::get_singleton()->debug_break(err_text,false)) { - // debugger break did not happen - - if (!VisualScriptLanguage::singleton->debug_break(error_str, false)) { - _err_print_error(err_func.utf8().get_data(), err_file.utf8().get_data(), err_line, error_str.utf8().get_data(), false, ERR_HANDLER_SCRIPT); - } - - //} - } else { - //return_value= - } - -#ifdef DEBUG_ENABLED - if (EngineDebugger::is_active()) { - VisualScriptLanguage::singleton->exit_function(); - } -#endif - - // Clean up variant stack. - for (int i = 0; i < f->max_stack; i++) { - variant_stack[i].~Variant(); - } - - return return_value; -} - -Variant VisualScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - r_error.error = Callable::CallError::CALL_OK; //ok by default - - HashMap<StringName, Function>::Iterator F = functions.find(p_method); - if (!F) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - return Variant(); - } - - VSDEBUG("CALLING: " + String(p_method)); - - Function *f = &F->value; - - int total_stack_size = 0; - - total_stack_size += f->max_stack * sizeof(Variant); //variants - total_stack_size += f->node_count * sizeof(bool); - total_stack_size += (max_input_args + max_output_args) * sizeof(Variant *); //arguments - total_stack_size += f->flow_stack_size * sizeof(int); //flow - total_stack_size += f->pass_stack_size * sizeof(int); - - VSDEBUG("STACK SIZE: " + itos(total_stack_size)); - VSDEBUG("STACK VARIANTS: : " + itos(f->max_stack)); - VSDEBUG("SEQBITS: : " + itos(f->node_count)); - VSDEBUG("MAX INPUT: " + itos(max_input_args)); - VSDEBUG("MAX OUTPUT: " + itos(max_output_args)); - VSDEBUG("FLOW STACK SIZE: " + itos(f->flow_stack_size)); - VSDEBUG("PASS STACK SIZE: " + itos(f->pass_stack_size)); - - void *stack = alloca(total_stack_size); - - Variant *variant_stack = (Variant *)stack; - bool *sequence_bits = (bool *)(variant_stack + f->max_stack); - const Variant **input_args = (const Variant **)(sequence_bits + f->node_count); - Variant **output_args = (Variant **)(input_args + max_input_args); - int flow_max = f->flow_stack_size; - int *flow_stack = flow_max ? (int *)(output_args + max_output_args) : (int *)nullptr; - int *pass_stack = flow_stack ? (int *)(flow_stack + flow_max) : (int *)nullptr; - - for (int i = 0; i < f->node_count; i++) { - sequence_bits[i] = false; // All starts as false. - } - - memset(pass_stack, 0, f->pass_stack_size * sizeof(int)); - - HashMap<int, VisualScriptNodeInstance *>::Iterator E = instances.find(f->node); - if (!E) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - - ERR_FAIL_V_MSG(Variant(), "No VisualScriptFunction node in function."); - } - - VisualScriptNodeInstance *node = E->value; - - if (flow_stack) { - flow_stack[0] = node->get_id(); - } - - VSDEBUG("ARGUMENTS: " + itos(f->argument_count) = " RECEIVED: " + itos(p_argcount)); - - if (p_argcount < f->argument_count) { - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = node->get_input_port_count(); - - return Variant(); - } - - if (p_argcount > f->argument_count) { - r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.argument = node->get_input_port_count(); - - return Variant(); - } - - // Allocate variant stack. - for (int i = 0; i < f->max_stack; i++) { - memnew_placement(&variant_stack[i], Variant); - } - - // Allocate function arguments (must be copied for yield to work properly). - for (int i = 0; i < p_argcount; i++) { - variant_stack[i] = *p_args[i]; - } - - return _call_internal(p_method, stack, total_stack_size, node, 0, 0, false, r_error); -} - -void VisualScriptInstance::notification(int p_notification) { - // Do nothing as this is called using virtual. - - Variant what = p_notification; - const Variant *whatp = &what; - Callable::CallError ce; - callp(VisualScriptLanguage::singleton->notification, &whatp, 1, ce); // Do as call. -} - -String VisualScriptInstance::to_string(bool *r_valid) { - if (has_method(CoreStringNames::get_singleton()->_to_string)) { - Callable::CallError ce; - Variant ret = callp(CoreStringNames::get_singleton()->_to_string, nullptr, 0, ce); - if (ce.error == Callable::CallError::CALL_OK) { - if (ret.get_type() != Variant::STRING) { - if (r_valid) { - *r_valid = false; - } - ERR_FAIL_V_MSG(String(), "Wrong type for " + CoreStringNames::get_singleton()->_to_string + ", must be a String."); - } - if (r_valid) { - *r_valid = true; - } - return ret.operator String(); - } - } - if (r_valid) { - *r_valid = false; - } - return String(); -} - -Ref<Script> VisualScriptInstance::get_script() const { - return script; -} - -const Variant VisualScriptInstance::get_rpc_config() const { - return script->get_rpc_config(); -} - -void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_owner) { - script = p_script; - owner = p_owner; - source = p_script->get_path(); - - max_input_args = 0; - max_output_args = 0; - - // Setup variables. - { - for (const KeyValue<StringName, VisualScript::Variable> &E : script->variables) { - variables[E.key] = E.value.default_value; - } - } - - // Setup functions from sequence trees. - { - for (const KeyValue<StringName, VisualScript::Function> &E : script->functions) { - const VisualScript::Function &vsfn = E.value; - Function function; - function.node = vsfn.func_id; - function.max_stack = 0; - function.flow_stack_size = 0; - function.pass_stack_size = 0; - function.node_count = 0; - - HashMap<StringName, int> local_var_indices; - - if (function.node < 0) { - VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No start node in function: " + String(E.key)); - ERR_CONTINUE(function.node < 0); - } - - { - Ref<VisualScriptFunction> func_node = script->get_node(vsfn.func_id); - - if (func_node.is_null()) { - VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No VisualScriptFunction typed start node in function: " + String(E.key)); - } - - ERR_CONTINUE(!func_node.is_valid()); - - function.argument_count = func_node->get_argument_count(); - function.max_stack += function.argument_count; - function.flow_stack_size = func_node->is_stack_less() ? 0 : func_node->get_stack_size(); - max_input_args = MAX(max_input_args, function.argument_count); - } - // Function nodes graphs. - RBSet<VisualScript::SequenceConnection> seqconns; - RBSet<VisualScript::DataConnection> dataconns; - RBSet<int> node_ids; - node_ids.insert(function.node); - { - List<int> nd_queue; - nd_queue.push_back(function.node); - while (!nd_queue.is_empty()) { - for (const VisualScript::SequenceConnection &F : script->sequence_connections) { - if (nd_queue.front()->get() == F.from_node && !node_ids.has(F.to_node)) { - nd_queue.push_back(F.to_node); - node_ids.insert(F.to_node); - } - if (nd_queue.front()->get() == F.from_node && !seqconns.has(F)) { - seqconns.insert(F); - } - } - nd_queue.pop_front(); - } - HashMap<int, HashMap<int, Pair<int, int>>> dc_lut; // :: to -> to_port -> (from, from_port) - for (const VisualScript::DataConnection &F : script->data_connections) { - dc_lut[F.to_node][F.to_port] = Pair<int, int>(F.from_node, F.from_port); - } - for (const int &F : node_ids) { - nd_queue.push_back(F); - } - List<int> dc_keys; - while (!nd_queue.is_empty()) { - int ky = nd_queue.front()->get(); - for (const KeyValue<int, Pair<int, int>> &F : dc_lut[ky]) { - VisualScript::DataConnection dc; - dc.from_node = F.value.first; - dc.from_port = F.value.second; - dc.to_node = ky; - dc.to_port = F.key; - dataconns.insert(dc); - nd_queue.push_back(dc.from_node); - node_ids.insert(dc.from_node); - } - dc_keys.clear(); // Necessary as get_key_list does a push_back not a set. - nd_queue.pop_front(); - } - } - - //Multiple passes are required to set up this complex thing.. - //First create the nodes. - for (const int &F : node_ids) { - Ref<VisualScriptNode> node = script->nodes[F].node; - - VisualScriptNodeInstance *instance = node->instantiate(this); // Create instance. - ERR_FAIL_COND(!instance); - - instance->base = node.ptr(); - - instance->id = F; - instance->input_port_count = node->get_input_value_port_count(); - instance->input_ports = nullptr; - instance->output_port_count = node->get_output_value_port_count(); - instance->output_ports = nullptr; - instance->sequence_output_count = node->get_output_sequence_port_count(); - instance->sequence_index = function.node_count++; - instance->sequence_outputs = nullptr; - instance->pass_idx = -1; - - if (instance->input_port_count) { - instance->input_ports = memnew_arr(int, instance->input_port_count); - for (int i = 0; i < instance->input_port_count; i++) { - instance->input_ports[i] = -1; // If not assigned, will become default value. - } - } - - if (instance->output_port_count) { - instance->output_ports = memnew_arr(int, instance->output_port_count); - for (int i = 0; i < instance->output_port_count; i++) { - instance->output_ports[i] = -1; // If not assigned, will output to trash. - } - } - - if (instance->sequence_output_count) { - instance->sequence_outputs = memnew_arr(VisualScriptNodeInstance *, instance->sequence_output_count); - for (int i = 0; i < instance->sequence_output_count; i++) { - instance->sequence_outputs[i] = nullptr; // If it remains null, flow ends here. - } - } - - if (Object::cast_to<VisualScriptLocalVar>(node.ptr()) || Object::cast_to<VisualScriptLocalVarSet>(*node)) { - // Working memory is shared only for this node, for the same variables. - Ref<VisualScriptLocalVar> vslv = node; - - StringName var_name; - - if (Object::cast_to<VisualScriptLocalVar>(*node)) { - var_name = String(Object::cast_to<VisualScriptLocalVar>(*node)->get_var_name()).strip_edges(); - } else { - var_name = String(Object::cast_to<VisualScriptLocalVarSet>(*node)->get_var_name()).strip_edges(); - } - - if (!local_var_indices.has(var_name)) { - local_var_indices[var_name] = function.max_stack; - function.max_stack++; - } - - instance->working_mem_idx = local_var_indices[var_name]; - - } else if (instance->get_working_memory_size()) { - instance->working_mem_idx = function.max_stack; - function.max_stack += instance->get_working_memory_size(); - } else { - instance->working_mem_idx = -1; //no working mem - } - - max_input_args = MAX(max_input_args, instance->input_port_count); - max_output_args = MAX(max_output_args, instance->output_port_count); - - instances[F] = instance; - } - - function.trash_pos = function.max_stack++; // create pos for trash - - // Second pass, do data connections. - for (const VisualScript::DataConnection &F : dataconns) { - VisualScript::DataConnection dc = F; - ERR_CONTINUE(!instances.has(dc.from_node)); - VisualScriptNodeInstance *from = instances[dc.from_node]; - ERR_CONTINUE(!instances.has(dc.to_node)); - VisualScriptNodeInstance *to = instances[dc.to_node]; - ERR_CONTINUE(dc.from_port >= from->output_port_count); - ERR_CONTINUE(dc.to_port >= to->input_port_count); - - if (from->output_ports[dc.from_port] == -1) { - int stack_pos = function.max_stack++; - from->output_ports[dc.from_port] = stack_pos; - } - - if (from->get_sequence_output_count() == 0 && to->dependencies.find(from) == -1) { - // If the node we are reading from has no output sequence, we must call step() before reading from it. - if (from->pass_idx == -1) { - from->pass_idx = function.pass_stack_size; - function.pass_stack_size++; - } - to->dependencies.push_back(from); - } - - to->input_ports[dc.to_port] = from->output_ports[dc.from_port]; // Read from wherever the stack is. - } - - // Third pass, do sequence connections. - for (const VisualScript::SequenceConnection &F : seqconns) { - VisualScript::SequenceConnection sc = F; - ERR_CONTINUE(!instances.has(sc.from_node)); - VisualScriptNodeInstance *from = instances[sc.from_node]; - ERR_CONTINUE(!instances.has(sc.to_node)); - VisualScriptNodeInstance *to = instances[sc.to_node]; - ERR_CONTINUE(sc.from_output >= from->sequence_output_count); - - from->sequence_outputs[sc.from_output] = to; - } - - //fourth pass: - // 1) unassigned input ports to default values - // 2) connect unassigned output ports to trash - for (const int &F : node_ids) { - ERR_CONTINUE(!instances.has(F)); - - Ref<VisualScriptNode> node = script->nodes[F].node; - VisualScriptNodeInstance *instance = instances[F]; - - // Connect to default values. - for (int i = 0; i < instance->input_port_count; i++) { - if (instance->input_ports[i] == -1) { - // Unassigned, connect to default val. - instance->input_ports[i] = default_values.size() | VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT; - default_values.push_back(node->get_default_input_value(i)); - } - } - - // Connect to trash. - for (int i = 0; i < instance->output_port_count; i++) { - if (instance->output_ports[i] == -1) { - instance->output_ports[i] = function.trash_pos; //trash is same for all - } - } - } - - functions[E.key] = function; - } - } -} - -ScriptLanguage *VisualScriptInstance::get_language() { - return VisualScriptLanguage::singleton; -} - -VisualScriptInstance::VisualScriptInstance() { -} - -VisualScriptInstance::~VisualScriptInstance() { - { - MutexLock lock(VisualScriptLanguage::singleton->lock); - - script->instances.erase(owner); - } - - for (const KeyValue<int, VisualScriptNodeInstance *> &E : instances) { - memdelete(E.value); - } -} - -///////////////////////////////////////////// - -///////////////////// - -Variant VisualScriptFunctionState::_signal_callback(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - ERR_FAIL_COND_V(function == StringName(), Variant()); - -#ifdef DEBUG_ENABLED - - ERR_FAIL_COND_V_MSG(instance_id.is_valid() && !ObjectDB::get_instance(instance_id), Variant(), "Resumed after yield, but class instance is gone."); - ERR_FAIL_COND_V_MSG(script_id.is_valid() && !ObjectDB::get_instance(script_id), Variant(), "Resumed after yield, but script is gone."); - -#endif - - r_error.error = Callable::CallError::CALL_OK; - - Array args; - - if (p_argcount == 0) { - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = 1; - return Variant(); - } else if (p_argcount == 1) { - //noooneee, reserved for me, me and only me. - } else { - for (int i = 0; i < p_argcount - 1; i++) { - args.push_back(*p_args[i]); - } - } - - Ref<VisualScriptFunctionState> self = *p_args[p_argcount - 1]; //hi, I'm myself, needed this to remain alive. - - if (self.is_null()) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = p_argcount - 1; - r_error.expected = Variant::OBJECT; - return Variant(); - } - - r_error.error = Callable::CallError::CALL_OK; - - Variant *working_mem = ((Variant *)stack.ptr()) + working_mem_index; - - *working_mem = args; // Arguments go to working mem. - - Variant ret = instance->_call_internal(function, stack.ptrw(), stack.size(), node, flow_stack_pos, pass, true, r_error); - function = StringName(); //invalidate - return ret; -} - -void VisualScriptFunctionState::connect_to_signal(Object *p_obj, const String &p_signal, Array p_binds) { - ERR_FAIL_NULL(p_obj); - Vector<Variant> binds; - for (int i = 0; i < p_binds.size(); i++) { - binds.push_back(p_binds[i]); - } - binds.push_back(Ref<VisualScriptFunctionState>(this)); //add myself on the back to avoid dying from unreferencing - - Vector<const Variant *> bind_ptrs; - bind_ptrs.resize(p_binds.size()); - for (int i = 0; i < bind_ptrs.size(); i++) { - bind_ptrs.write[i] = &binds.write[i]; - } - - p_obj->connect(p_signal, Callable(this, "_signal_callback").bindp((const Variant **)bind_ptrs.ptr(), bind_ptrs.size()), CONNECT_ONESHOT); -} - -bool VisualScriptFunctionState::is_valid() const { - return function != StringName(); -} - -Variant VisualScriptFunctionState::resume(Array p_args) { - ERR_FAIL_COND_V(function == StringName(), Variant()); -#ifdef DEBUG_ENABLED - - ERR_FAIL_COND_V_MSG(instance_id.is_valid() && !ObjectDB::get_instance(instance_id), Variant(), "Resumed after yield, but class instance is gone."); - ERR_FAIL_COND_V_MSG(script_id.is_valid() && !ObjectDB::get_instance(script_id), Variant(), "Resumed after yield, but script is gone."); - -#endif - - Callable::CallError r_error; - r_error.error = Callable::CallError::CALL_OK; - - Variant *working_mem = ((Variant *)stack.ptr()) + working_mem_index; - - *working_mem = p_args; // Arguments go to working mem. - - Variant ret = instance->_call_internal(function, stack.ptrw(), stack.size(), node, flow_stack_pos, pass, true, r_error); - function = StringName(); //invalidate - return ret; -} - -void VisualScriptFunctionState::_bind_methods() { - ClassDB::bind_method(D_METHOD("connect_to_signal", "obj", "signals", "args"), &VisualScriptFunctionState::connect_to_signal); - ClassDB::bind_method(D_METHOD("resume", "args"), &VisualScriptFunctionState::resume, DEFVAL(Array())); - ClassDB::bind_method(D_METHOD("is_valid"), &VisualScriptFunctionState::is_valid); - ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &VisualScriptFunctionState::_signal_callback, MethodInfo("_signal_callback")); -} - -VisualScriptFunctionState::VisualScriptFunctionState() { -} - -VisualScriptFunctionState::~VisualScriptFunctionState() { - if (function != StringName()) { - Variant *s = ((Variant *)stack.ptr()); - for (int i = 0; i < variant_stack_size; i++) { - s[i].~Variant(); - } - } -} - -/////////////////////////////////////////////// - -String VisualScriptLanguage::get_name() const { - return "VisualScript"; -} - -/* LANGUAGE FUNCTIONS */ -void VisualScriptLanguage::init() { -} - -String VisualScriptLanguage::get_type() const { - return "VisualScript"; -} - -String VisualScriptLanguage::get_extension() const { - return "vs"; -} - -Error VisualScriptLanguage::execute_file(const String &p_path) { - return OK; -} - -void VisualScriptLanguage::finish() { -} - -/* EDITOR FUNCTIONS */ -void VisualScriptLanguage::get_reserved_words(List<String> *p_words) const { -} - -bool VisualScriptLanguage::is_control_flow_keyword(String p_keyword) const { - return false; -} - -void VisualScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const { -} - -void VisualScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { -} - -bool VisualScriptLanguage::is_using_templates() { - return false; -} - -Ref<Script> VisualScriptLanguage::make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const { - Ref<VisualScript> script; - script.instantiate(); - script->set_instance_base_type(p_base_class_name); - return script; -} - -bool VisualScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, HashSet<int> *r_safe_lines) const { - return false; -} - -Script *VisualScriptLanguage::create_script() const { - return memnew(VisualScript); -} - -bool VisualScriptLanguage::has_named_classes() const { - return false; -} - -bool VisualScriptLanguage::supports_builtin_mode() const { - return true; -} - -int VisualScriptLanguage::find_function(const String &p_function, const String &p_code) const { - return -1; -} - -String VisualScriptLanguage::make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const { - return String(); -} - -void VisualScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_to_line) const { -} - -void VisualScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) { -} - -/* DEBUGGER FUNCTIONS */ - -bool VisualScriptLanguage::debug_break_parse(const String &p_file, int p_node, const String &p_error) { - // Break because of parse error. - - if (EngineDebugger::is_active() && Thread::get_caller_id() == Thread::get_main_id()) { - _debug_parse_err_node = p_node; - _debug_parse_err_file = p_file; - _debug_error = p_error; - EngineDebugger::get_script_debugger()->debug(this, false, true); - return true; - } else { - return false; - } -} - -bool VisualScriptLanguage::debug_break(const String &p_error, bool p_allow_continue) { - if (EngineDebugger::is_active() && Thread::get_caller_id() == Thread::get_main_id()) { - _debug_parse_err_node = -1; - _debug_parse_err_file = ""; - _debug_error = p_error; - EngineDebugger::get_script_debugger()->debug(this, p_allow_continue, true); - return true; - } else { - return false; - } -} - -String VisualScriptLanguage::debug_get_error() const { - return _debug_error; -} - -int VisualScriptLanguage::debug_get_stack_level_count() const { - if (_debug_parse_err_node >= 0) { - return 1; - } - - return _debug_call_stack_pos; -} - -int VisualScriptLanguage::debug_get_stack_level_line(int p_level) const { - if (_debug_parse_err_node >= 0) { - return _debug_parse_err_node; - } - - ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, -1); - - int l = _debug_call_stack_pos - p_level - 1; - - return *(_call_stack[l].current_id); -} - -String VisualScriptLanguage::debug_get_stack_level_function(int p_level) const { - if (_debug_parse_err_node >= 0) { - return ""; - } - - ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, ""); - int l = _debug_call_stack_pos - p_level - 1; - return *_call_stack[l].function; -} - -String VisualScriptLanguage::debug_get_stack_level_source(int p_level) const { - if (_debug_parse_err_node >= 0) { - return _debug_parse_err_file; - } - - ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, ""); - int l = _debug_call_stack_pos - p_level - 1; - return _call_stack[l].instance->get_script_ptr()->get_path(); -} - -void VisualScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { - if (_debug_parse_err_node >= 0) { - return; - } - - ERR_FAIL_INDEX(p_level, _debug_call_stack_pos); - - int l = _debug_call_stack_pos - p_level - 1; - const StringName *f = _call_stack[l].function; - - ERR_FAIL_COND(!_call_stack[l].instance->functions.has(*f)); - - VisualScriptNodeInstance *node = _call_stack[l].instance->instances[*_call_stack[l].current_id]; - ERR_FAIL_COND(!node); - - p_locals->push_back("node_name"); - p_values->push_back(node->get_base_node()->get_text()); - - for (int i = 0; i < node->input_port_count; i++) { - String name = node->get_base_node()->get_input_value_port_info(i).name; - if (name.is_empty()) { - name = "in_" + itos(i); - } - - p_locals->push_back("input/" + name); - - //value is trickier - - int in_from = node->input_ports[i]; - int in_value = in_from & VisualScriptNodeInstance::INPUT_MASK; - - if (in_from & VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT) { - p_values->push_back(_call_stack[l].instance->default_values[in_value]); - } else { - p_values->push_back(_call_stack[l].stack[in_value]); - } - } - - for (int i = 0; i < node->output_port_count; i++) { - String name = node->get_base_node()->get_output_value_port_info(i).name; - if (name.is_empty()) { - name = "out_" + itos(i); - } - - p_locals->push_back("output/" + name); - - //value is trickier - - int in_from = node->output_ports[i]; - p_values->push_back(_call_stack[l].stack[in_from]); - } - - for (int i = 0; i < node->get_working_memory_size(); i++) { - p_locals->push_back("working_mem/mem_" + itos(i)); - p_values->push_back((*_call_stack[l].work_mem)[i]); - } -} - -void VisualScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { - if (_debug_parse_err_node >= 0) { - return; - } - - ERR_FAIL_INDEX(p_level, _debug_call_stack_pos); - int l = _debug_call_stack_pos - p_level - 1; - - Ref<VisualScript> vs = _call_stack[l].instance->get_script(); - if (vs.is_null()) { - return; - } - - List<StringName> vars; - vs->get_variable_list(&vars); - for (const StringName &E : vars) { - Variant v; - if (_call_stack[l].instance->get_variable(E, &v)) { - p_members->push_back("variables/" + E); - p_values->push_back(v); - } - } -} - -void VisualScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { - // No globals are really reachable in gdscript. -} - -String VisualScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { - return ""; -} - -void VisualScriptLanguage::reload_all_scripts() { -} - -void VisualScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) { -} - -/* LOADER FUNCTIONS */ - -void VisualScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("vs"); -} - -void VisualScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const { -} - -void VisualScriptLanguage::get_public_constants(List<Pair<String, Variant>> *p_constants) const { -} - -void VisualScriptLanguage::get_public_annotations(List<MethodInfo> *p_annotations) const { -} - -void VisualScriptLanguage::profiling_start() { -} - -void VisualScriptLanguage::profiling_stop() { -} - -int VisualScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) { - return 0; -} - -int VisualScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) { - return 0; -} - -VisualScriptLanguage *VisualScriptLanguage::singleton = nullptr; - -void VisualScriptLanguage::add_register_func(const String &p_name, VisualScriptNodeRegisterFunc p_func) { - ERR_FAIL_COND(register_funcs.has(p_name)); - register_funcs[p_name] = p_func; -} - -void VisualScriptLanguage::remove_register_func(const String &p_name) { - ERR_FAIL_COND(!register_funcs.has(p_name)); - register_funcs.erase(p_name); -} - -Ref<VisualScriptNode> VisualScriptLanguage::create_node_from_name(const String &p_name) { - ERR_FAIL_COND_V(!register_funcs.has(p_name), Ref<VisualScriptNode>()); - - return register_funcs[p_name](p_name); -} - -void VisualScriptLanguage::get_registered_node_names(List<String> *r_names) { - for (const KeyValue<String, VisualScriptNodeRegisterFunc> &E : register_funcs) { - r_names->push_back(E.key); - } -} - -VisualScriptLanguage::VisualScriptLanguage() { - singleton = this; - - int dmcs = GLOBAL_DEF("debug/settings/visual_script/max_call_stack", 1024); - ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/visual_script/max_call_stack", PropertyInfo(Variant::INT, "debug/settings/visual_script/max_call_stack", PROPERTY_HINT_RANGE, "1024,4096,1,or_greater")); //minimum is 1024 - - if (EngineDebugger::is_active()) { - // Debugging enabled! - _debug_max_call_stack = dmcs; - _call_stack = memnew_arr(CallLevel, _debug_max_call_stack + 1); - - } else { - _debug_max_call_stack = 0; - _call_stack = nullptr; - } -} - -VisualScriptLanguage::~VisualScriptLanguage() { - if (_call_stack) { - memdelete_arr(_call_stack); - } - singleton = nullptr; -} diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h deleted file mode 100644 index d3a90d53fb..0000000000 --- a/modules/visual_script/visual_script.h +++ /dev/null @@ -1,630 +0,0 @@ -/*************************************************************************/ -/* visual_script.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 VISUAL_SCRIPT_H -#define VISUAL_SCRIPT_H - -#include "core/debugger/engine_debugger.h" -#include "core/debugger/script_debugger.h" -#include "core/doc_data.h" -#include "core/object/script_language.h" -#include "core/os/thread.h" -#include "core/templates/rb_set.h" - -class VisualScriptInstance; -class VisualScriptNodeInstance; -class VisualScript; - -class VisualScriptNode : public Resource { - GDCLASS(VisualScriptNode, Resource); - - friend class VisualScript; - - Ref<VisualScript> script_used; - - Array default_input_values; - bool breakpoint = false; - - void _set_default_input_values(Array p_values); - Array _get_default_input_values() const; - - void validate_input_default_values(); - -protected: - void ports_changed_notify(); - static void _bind_methods(); - -public: - Ref<VisualScript> get_visual_script() const; - - virtual int get_output_sequence_port_count() const = 0; - virtual bool has_input_sequence_port() const = 0; - - virtual String get_output_sequence_port_text(int p_port) const = 0; - - virtual bool has_mixed_input_and_sequence_ports() const { return false; } - - virtual int get_input_value_port_count() const = 0; - virtual int get_output_value_port_count() const = 0; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const = 0; - virtual PropertyInfo get_output_value_port_info(int p_idx) const = 0; - - void set_default_input_value(int p_port, const Variant &p_value); - Variant get_default_input_value(int p_port) const; - - virtual String get_caption() const = 0; - virtual String get_text() const; - virtual String get_category() const = 0; - - // Used by editor, this is not really saved. - void set_breakpoint(bool p_breakpoint); - bool is_breakpoint() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) = 0; - - struct TypeGuess { - Variant::Type type = Variant::NIL; - StringName gdclass; - Ref<Script> script; - }; - - virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const; - - VisualScriptNode(); -}; - -class VisualScriptNodeInstance { - friend class VisualScriptInstance; - friend class VisualScriptLanguage; // For debugger. - - enum { // Input argument addressing. - INPUT_SHIFT = 1 << 24, - INPUT_MASK = INPUT_SHIFT - 1, - INPUT_DEFAULT_VALUE_BIT = INPUT_SHIFT, // from unassigned input port, using default value (edited by user) - }; - - int id = 0; - int sequence_index = 0; - VisualScriptNodeInstance **sequence_outputs = nullptr; - int sequence_output_count = 0; - Vector<VisualScriptNodeInstance *> dependencies; - int *input_ports = nullptr; - int input_port_count = 0; - int *output_ports = nullptr; - int output_port_count = 0; - int working_mem_idx = 0; - int pass_idx = 0; - - VisualScriptNode *base = nullptr; - -public: - enum StartMode { - START_MODE_BEGIN_SEQUENCE, - START_MODE_CONTINUE_SEQUENCE, - START_MODE_RESUME_YIELD - }; - - enum { - STEP_SHIFT = 1 << 24, - STEP_MASK = STEP_SHIFT - 1, - STEP_FLAG_PUSH_STACK_BIT = STEP_SHIFT, // push bit to stack - STEP_FLAG_GO_BACK_BIT = STEP_SHIFT << 1, // go back to previous node - STEP_NO_ADVANCE_BIT = STEP_SHIFT << 2, // do not advance past this node - STEP_EXIT_FUNCTION_BIT = STEP_SHIFT << 3, // return from function - STEP_YIELD_BIT = STEP_SHIFT << 4, // yield (will find VisualScriptFunctionState state in first working memory) - - FLOW_STACK_PUSHED_BIT = 1 << 30, // in flow stack, means bit was pushed (must go back here if end of sequence) - FLOW_STACK_MASK = FLOW_STACK_PUSHED_BIT - 1 - - }; - - _FORCE_INLINE_ int get_input_port_count() const { return input_port_count; } - _FORCE_INLINE_ int get_output_port_count() const { return output_port_count; } - _FORCE_INLINE_ int get_sequence_output_count() const { return sequence_output_count; } - - _FORCE_INLINE_ int get_id() const { return id; } - - virtual int get_working_memory_size() const { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) = 0; // Do a step, return which sequence port to go out. - - Ref<VisualScriptNode> get_base_node() { return Ref<VisualScriptNode>(base); } - - VisualScriptNodeInstance(); - virtual ~VisualScriptNodeInstance(); -}; - -class VisualScript : public Script { - GDCLASS(VisualScript, Script); - - RES_BASE_EXTENSION("vs"); - -public: - struct SequenceConnection { - union { - struct { - uint64_t from_node : 24; - uint64_t from_output : 16; - uint64_t to_node : 24; - }; - uint64_t id = 0; - }; - - bool operator<(const SequenceConnection &p_connection) const { - return id < p_connection.id; - } - }; - - struct DataConnection { - union { - struct { - uint64_t from_node : 24; - uint64_t from_port : 8; - uint64_t to_node : 24; - uint64_t to_port : 8; - }; - uint64_t id = 0; - }; - - bool operator<(const DataConnection &p_connection) const { - return id < p_connection.id; - } - }; - -private: - friend class VisualScriptInstance; - - StringName base_type; - struct Argument { - String name; - Variant::Type type = Variant::Type::NIL; - }; - - struct NodeData { - Point2 pos; - Ref<VisualScriptNode> node; - }; - - HashMap<int, NodeData> nodes; // Can be a sparse map. - - RBSet<SequenceConnection> sequence_connections; - RBSet<DataConnection> data_connections; - - Vector2 scroll; - - struct Function { - int func_id; - Function() { func_id = -1; } - }; - - struct Variable { - PropertyInfo info; - Variant default_value; - bool _export = false; - // Add getter & setter options here. - }; - - HashMap<StringName, Function> functions; - HashMap<StringName, Variable> variables; - HashMap<StringName, Vector<Argument>> custom_signals; - Dictionary rpc_functions; - - HashMap<Object *, VisualScriptInstance *> instances; - - bool is_tool_script; - -#ifdef TOOLS_ENABLED - RBSet<PlaceHolderScriptInstance *> placeholders; - // void _update_placeholder(PlaceHolderScriptInstance *p_placeholder); - virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override; - void _update_placeholders(); -#endif - - void _set_variable_info(const StringName &p_name, const Dictionary &p_info); - Dictionary _get_variable_info(const StringName &p_name) const; - - void _set_data(const Dictionary &p_data); - Dictionary _get_data() const; - -protected: - void _node_ports_changed(int p_id); - static void _bind_methods(); - -public: - bool inherits_script(const Ref<Script> &p_script) const override; - - void set_scroll(const Vector2 &p_scroll); - Vector2 get_scroll() const; - - void add_function(const StringName &p_name, int p_func_node_id); - bool has_function(const StringName &p_name) const; - void remove_function(const StringName &p_name); - void rename_function(const StringName &p_name, const StringName &p_new_name); - void get_function_list(List<StringName> *r_functions) const; - int get_function_node_id(const StringName &p_name) const; - void set_tool_enabled(bool p_enabled); - - void add_node(int p_id, const Ref<VisualScriptNode> &p_node, const Point2 &p_pos = Point2()); - void remove_node(int p_id); - bool has_node(int p_id) const; - Ref<VisualScriptNode> get_node(int p_id) const; - void set_node_position(int p_id, const Point2 &p_pos); - Point2 get_node_position(int p_id) const; - void get_node_list(List<int> *r_nodes) const; - - void sequence_connect(int p_from_node, int p_from_output, int p_to_node); - void sequence_disconnect(int p_from_node, int p_from_output, int p_to_node); - bool has_sequence_connection(int p_from_node, int p_from_output, int p_to_node) const; - void get_sequence_connection_list(List<SequenceConnection> *r_connection) const; - RBSet<int> get_output_sequence_ports_connected(int from_node); - - void data_connect(int p_from_node, int p_from_port, int p_to_node, int p_to_port); - void data_disconnect(int p_from_node, int p_from_port, int p_to_node, int p_to_port); - bool has_data_connection(int p_from_node, int p_from_port, int p_to_node, int p_to_port) const; - void get_data_connection_list(List<DataConnection> *r_connection) const; - - bool is_input_value_port_connected(int p_node, int p_port) const; - bool get_input_value_port_connection_source(int p_node, int p_port, int *r_node, int *r_port) const; - - void add_variable(const StringName &p_name, const Variant &p_default_value = Variant(), bool p_export = false); - bool has_variable(const StringName &p_name) const; - void remove_variable(const StringName &p_name); - void set_variable_default_value(const StringName &p_name, const Variant &p_value); - Variant get_variable_default_value(const StringName &p_name) const; - void set_variable_info(const StringName &p_name, const PropertyInfo &p_info); - PropertyInfo get_variable_info(const StringName &p_name) const; - void set_variable_export(const StringName &p_name, bool p_export); - bool get_variable_export(const StringName &p_name) const; - void get_variable_list(List<StringName> *r_variables) const; - void rename_variable(const StringName &p_name, const StringName &p_new_name); - - void add_custom_signal(const StringName &p_name); - bool has_custom_signal(const StringName &p_name) const; - void custom_signal_add_argument(const StringName &p_func, Variant::Type p_type, const String &p_name, int p_index = -1); - void custom_signal_set_argument_type(const StringName &p_func, int p_argidx, Variant::Type p_type); - Variant::Type custom_signal_get_argument_type(const StringName &p_func, int p_argidx) const; - void custom_signal_set_argument_name(const StringName &p_func, int p_argidx, const String &p_name); - String custom_signal_get_argument_name(const StringName &p_func, int p_argidx) const; - void custom_signal_remove_argument(const StringName &p_func, int p_argidx); - int custom_signal_get_argument_count(const StringName &p_func) const; - void custom_signal_swap_argument(const StringName &p_func, int p_argidx, int p_with_argidx); - void remove_custom_signal(const StringName &p_name); - void rename_custom_signal(const StringName &p_name, const StringName &p_new_name); - RBSet<int> get_output_sequence_ports_connected(const String &edited_func, int from_node); - - void get_custom_signal_list(List<StringName> *r_custom_signals) const; - - int get_available_id() const; - - void set_instance_base_type(const StringName &p_type); - - virtual bool can_instantiate() const override; - - virtual Ref<Script> get_base_script() const override; - virtual StringName get_instance_base_type() const override; - virtual ScriptInstance *instance_create(Object *p_this) override; - virtual bool instance_has(const Object *p_this) const override; - - virtual bool has_source_code() const override; - virtual String get_source_code() const override; - virtual void set_source_code(const String &p_code) override; - virtual Error reload(bool p_keep_state = false) override; - -#ifdef TOOLS_ENABLED - virtual Vector<DocData::ClassDoc> get_documentation() const override { - Vector<DocData::ClassDoc> docs; - return docs; - } -#endif // TOOLS_ENABLED - - virtual bool is_tool() const override; - virtual bool is_valid() const override; - - virtual ScriptLanguage *get_language() const override; - - virtual bool has_script_signal(const StringName &p_signal) const override; - virtual void get_script_signal_list(List<MethodInfo> *r_signals) const override; - - virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const override; - virtual void get_script_method_list(List<MethodInfo> *p_list) const override; - - virtual bool has_method(const StringName &p_method) const override; - virtual MethodInfo get_method_info(const StringName &p_method) const override; - - virtual void get_script_property_list(List<PropertyInfo> *p_list) const override; - - virtual int get_member_line(const StringName &p_member) const override; - - virtual const Variant get_rpc_config() const override; - -#ifdef TOOLS_ENABLED - virtual bool are_subnodes_edited() const; -#endif - - VisualScript(); - ~VisualScript(); -}; - -class VisualScriptInstance : public ScriptInstance { - Object *owner = nullptr; - Ref<VisualScript> script; - - HashMap<StringName, Variant> variables; // Using variable path, not script. - HashMap<int, VisualScriptNodeInstance *> instances; - - struct Function { - int node = 0; - int max_stack = 0; - int trash_pos = 0; - int flow_stack_size = 0; - int pass_stack_size = 0; - int node_count = 0; - int argument_count = 0; - }; - - HashMap<StringName, Function> functions; - - Vector<Variant> default_values; - int max_input_args = 0; - int max_output_args = 0; - - StringName source; - - void _dependency_step(VisualScriptNodeInstance *node, int p_pass, int *pass_stack, const Variant **input_args, Variant **output_args, Variant *variant_stack, Callable::CallError &r_error, String &error_str, VisualScriptNodeInstance **r_error_node); - Variant _call_internal(const StringName &p_method, void *p_stack, int p_stack_size, VisualScriptNodeInstance *p_node, int p_flow_stack_pos, int p_pass, bool p_resuming_yield, Callable::CallError &r_error); - - friend class VisualScriptFunctionState; // For yield. - friend class VisualScriptLanguage; // For debugger. -public: - virtual bool set(const StringName &p_name, const Variant &p_value); - virtual bool get(const StringName &p_name, Variant &r_ret) const; - virtual void get_property_list(List<PropertyInfo> *p_properties) const; - virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const; - - virtual bool property_can_revert(const StringName &p_name) const { return false; }; - virtual bool property_get_revert(const StringName &p_name, Variant &r_ret) const { return false; }; - - virtual void get_method_list(List<MethodInfo> *p_list) const; - virtual bool has_method(const StringName &p_method) const; - virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); - virtual void notification(int p_notification); - String to_string(bool *r_valid); - - bool set_variable(const StringName &p_variable, const Variant &p_value) { - HashMap<StringName, Variant>::Iterator E = variables.find(p_variable); - if (!E) { - return false; - } - - E->value = p_value; - return true; - } - - bool get_variable(const StringName &p_variable, Variant *r_variable) const { - HashMap<StringName, Variant>::ConstIterator E = variables.find(p_variable); - if (!E) { - return false; - } - - *r_variable = E->value; - return true; - } - - virtual Ref<Script> get_script() const; - - _FORCE_INLINE_ VisualScript *get_script_ptr() { return script.ptr(); } - _FORCE_INLINE_ Object *get_owner_ptr() { return owner; } - - void create(const Ref<VisualScript> &p_script, Object *p_owner); - - virtual ScriptLanguage *get_language(); - - virtual const Variant get_rpc_config() const; - - VisualScriptInstance(); - ~VisualScriptInstance(); -}; - -class VisualScriptFunctionState : public RefCounted { - GDCLASS(VisualScriptFunctionState, RefCounted); - friend class VisualScriptInstance; - - ObjectID instance_id; - ObjectID script_id; - VisualScriptInstance *instance = nullptr; - StringName function; - Vector<uint8_t> stack; - int working_mem_index = 0; - int variant_stack_size = 0; - VisualScriptNodeInstance *node = nullptr; - int flow_stack_pos = 0; - int pass = 0; - - Variant _signal_callback(const Variant **p_args, int p_argcount, Callable::CallError &r_error); - -protected: - static void _bind_methods(); - -public: - void connect_to_signal(Object *p_obj, const String &p_signal, Array p_binds); - bool is_valid() const; - Variant resume(Array p_args); - VisualScriptFunctionState(); - ~VisualScriptFunctionState(); -}; - -typedef Ref<VisualScriptNode> (*VisualScriptNodeRegisterFunc)(const String &p_type); - -class VisualScriptLanguage : public ScriptLanguage { - HashMap<String, VisualScriptNodeRegisterFunc> register_funcs; - - struct CallLevel { - Variant *stack = nullptr; - Variant **work_mem = nullptr; - const StringName *function = nullptr; - VisualScriptInstance *instance = nullptr; - int *current_id = nullptr; - }; - - int _debug_parse_err_node = -1; - String _debug_parse_err_file = ""; - String _debug_error; - int _debug_call_stack_pos = 0; - int _debug_max_call_stack; - CallLevel *_call_stack = nullptr; - -public: - StringName notification = "_notification"; - StringName _get_output_port_unsequenced; - StringName _step = "_step"; - StringName _subcall = "_subcall"; - - static VisualScriptLanguage *singleton; - - Mutex lock; - - bool debug_break(const String &p_error, bool p_allow_continue = true); - bool debug_break_parse(const String &p_file, int p_node, const String &p_error); - - _FORCE_INLINE_ void enter_function(VisualScriptInstance *p_instance, const StringName *p_function, Variant *p_stack, Variant **p_work_mem, int *current_id) { - if (Thread::get_main_id() != Thread::get_caller_id()) { - return; // No support for other threads than main for now. - } - - if (EngineDebugger::get_script_debugger()->get_lines_left() > 0 && EngineDebugger::get_script_debugger()->get_depth() >= 0) { - EngineDebugger::get_script_debugger()->set_depth(EngineDebugger::get_script_debugger()->get_depth() + 1); - } - - if (_debug_call_stack_pos >= _debug_max_call_stack) { - // Stack overflow. - _debug_error = vformat("Stack overflow (stack size: %s). Check for infinite recursion in your script.", _debug_max_call_stack); - EngineDebugger::get_script_debugger()->debug(this); - return; - } - - _call_stack[_debug_call_stack_pos].stack = p_stack; - _call_stack[_debug_call_stack_pos].instance = p_instance; - _call_stack[_debug_call_stack_pos].function = p_function; - _call_stack[_debug_call_stack_pos].work_mem = p_work_mem; - _call_stack[_debug_call_stack_pos].current_id = current_id; - _debug_call_stack_pos++; - } - - _FORCE_INLINE_ void exit_function() { - if (Thread::get_main_id() != Thread::get_caller_id()) { - return; // No support for other threads than main for now. - } - - if (EngineDebugger::get_script_debugger()->get_lines_left() > 0 && EngineDebugger::get_script_debugger()->get_depth() >= 0) { - EngineDebugger::get_script_debugger()->set_depth(EngineDebugger::get_script_debugger()->get_depth() - 1); - } - - if (_debug_call_stack_pos == 0) { - _debug_error = "Stack underflow (engine bug), please report."; - EngineDebugger::get_script_debugger()->debug(this); - return; - } - - _debug_call_stack_pos--; - } - - ////////////////////////////////////// - - virtual String get_name() const override; - - /* LANGUAGE FUNCTIONS */ - virtual void init() override; - virtual String get_type() const override; - virtual String get_extension() const override; - virtual Error execute_file(const String &p_path) override; - virtual void finish() override; - - /* EDITOR FUNCTIONS */ - virtual void get_reserved_words(List<String> *p_words) const override; - virtual bool is_control_flow_keyword(String p_keyword) const override; - virtual void get_comment_delimiters(List<String> *p_delimiters) const override; - virtual void get_string_delimiters(List<String> *p_delimiters) const override; - virtual bool is_using_templates() override; - virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override; - virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const override; - virtual Script *create_script() const override; - virtual bool has_named_classes() const override; - virtual bool supports_builtin_mode() const override; - virtual int find_function(const String &p_function, const String &p_code) const override; - virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const override; - virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const override; - virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) override; - - /* DEBUGGER FUNCTIONS */ - - virtual String debug_get_error() const override; - virtual int debug_get_stack_level_count() const override; - virtual int debug_get_stack_level_line(int p_level) const override; - virtual String debug_get_stack_level_function(int p_level) const override; - virtual String debug_get_stack_level_source(int p_level) const override; - virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override; - virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override; - virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override; - virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1) override; - - virtual void reload_all_scripts() override; - virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) override; - /* LOADER FUNCTIONS */ - - virtual void get_recognized_extensions(List<String> *p_extensions) const override; - virtual void get_public_functions(List<MethodInfo> *p_functions) const override; - virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const override; - virtual void get_public_annotations(List<MethodInfo> *p_annotations) const override; - - virtual void profiling_start() override; - virtual void profiling_stop() override; - - virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) override; - virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) override; - - void add_register_func(const String &p_name, VisualScriptNodeRegisterFunc p_func); - void remove_register_func(const String &p_name); - Ref<VisualScriptNode> create_node_from_name(const String &p_name); - void get_registered_node_names(List<String> *r_names); - - VisualScriptLanguage(); - ~VisualScriptLanguage(); -}; - -// Aid for registering. -template <class T> -static Ref<VisualScriptNode> create_node_generic(const String &p_name) { - Ref<T> node; - node.instantiate(); - return node; -} - -#endif // VISUAL_SCRIPT_H diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp deleted file mode 100644 index 44e792869d..0000000000 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ /dev/null @@ -1,1380 +0,0 @@ -/*************************************************************************/ -/* visual_script_builtin_funcs.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "visual_script_builtin_funcs.h" - -#include "core/io/marshalls.h" -#include "core/math/math_funcs.h" -#include "core/object/class_db.h" -#include "core/object/ref_counted.h" -#include "core/os/os.h" -#include "core/variant/variant_parser.h" - -const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX] = { - "sin", - "cos", - "tan", - "sinh", - "cosh", - "tanh", - "asin", - "acos", - "atan", - "atan2", - "sqrt", - "fmod", - "fposmod", - "floor", - "ceil", - "round", - "abs", - "sign", - "pow", - "log", - "exp", - "is_nan", - "is_inf", - "ease", - "step_decimals", - "snapped", - "lerp", - "cubic_interpolate", - "inverse_lerp", - "range_lerp", - "move_toward", - "randomize", - "randi", - "randf", - "randi_range", - "randf_range", - "randfn", - "seed", - "rand_seed", - "deg2rad", - "rad2deg", - "linear2db", - "db2linear", - "wrapi", - "wrapf", - "pingpong", - "max", - "min", - "clamp", - "nearest_po2", - "weakref", - "convert", - "typeof", - "type_exists", - "char", - "str", - "print", - "printerr", - "printraw", - "print_verbose", - "var2str", - "str2var", - "var2bytes", - "bytes2var", - "smoothstep", - "posmod", - "lerp_angle", - "ord", -}; - -VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::find_function(const String &p_string) { - for (int i = 0; i < FUNC_MAX; i++) { - if (p_string == func_name[i]) { - return BuiltinFunc(i); - } - } - - return FUNC_MAX; -} - -String VisualScriptBuiltinFunc::get_func_name(BuiltinFunc p_func) { - ERR_FAIL_INDEX_V(p_func, FUNC_MAX, String()); - return func_name[p_func]; -} - -int VisualScriptBuiltinFunc::get_output_sequence_port_count() const { - return has_input_sequence_port() ? 1 : 0; -} - -bool VisualScriptBuiltinFunc::has_input_sequence_port() const { - switch (func) { - case MATH_RANDOMIZE: - case TEXT_PRINT: - case TEXT_PRINTERR: - case TEXT_PRINTRAW: - case TEXT_PRINT_VERBOSE: - case MATH_SEED: - return true; - default: - return false; - } -} - -int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) { - switch (p_func) { - case MATH_RANDOMIZE: - case MATH_RANDI: - case MATH_RANDF: - return 0; - case MATH_SIN: - case MATH_COS: - case MATH_TAN: - case MATH_SINH: - case MATH_COSH: - case MATH_TANH: - case MATH_ASIN: - case MATH_ACOS: - case MATH_ATAN: - case MATH_SQRT: - case MATH_FLOOR: - case MATH_CEIL: - case MATH_ROUND: - case MATH_ABS: - case MATH_SIGN: - case MATH_LOG: - case MATH_EXP: - case MATH_ISNAN: - case MATH_ISINF: - case MATH_STEP_DECIMALS: - case MATH_SEED: - case MATH_RANDSEED: - case MATH_DEG2RAD: - case MATH_RAD2DEG: - case MATH_LINEAR2DB: - case MATH_DB2LINEAR: - case LOGIC_NEAREST_PO2: - case OBJ_WEAKREF: - case TYPE_OF: - case TEXT_CHAR: - case TEXT_ORD: - case TEXT_STR: - case TEXT_PRINT: - case TEXT_PRINTERR: - case TEXT_PRINTRAW: - case TEXT_PRINT_VERBOSE: - case VAR_TO_STR: - case STR_TO_VAR: - case TYPE_EXISTS: - return 1; - case VAR_TO_BYTES: - case BYTES_TO_VAR: - case MATH_ATAN2: - case MATH_FMOD: - case MATH_FPOSMOD: - case MATH_POSMOD: - case MATH_PINGPONG: - case MATH_POW: - case MATH_EASE: - case MATH_SNAPPED: - case MATH_RANDI_RANGE: - case MATH_RANDF_RANGE: - case MATH_RANDFN: - case LOGIC_MAX: - case LOGIC_MIN: - case TYPE_CONVERT: - return 2; - case MATH_LERP: - case MATH_LERP_ANGLE: - case MATH_INVERSE_LERP: - case MATH_SMOOTHSTEP: - case MATH_MOVE_TOWARD: - case MATH_WRAP: - case MATH_WRAPF: - case LOGIC_CLAMP: - return 3; - case MATH_CUBIC_INTERPOLATE: - case MATH_RANGE_LERP: - return 5; - case FUNC_MAX: { - } - } - return 0; -} - -int VisualScriptBuiltinFunc::get_input_value_port_count() const { - return get_func_argument_count(func); -} - -int VisualScriptBuiltinFunc::get_output_value_port_count() const { - switch (func) { - case MATH_RANDOMIZE: - case TEXT_PRINT: - case TEXT_PRINTERR: - case TEXT_PRINTRAW: - case TEXT_PRINT_VERBOSE: - case MATH_SEED: - return 0; - case MATH_RANDSEED: - return 2; - default: - return 1; - } - - return 1; -} - -String VisualScriptBuiltinFunc::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const { - switch (func) { - case MATH_SIN: - case MATH_COS: - case MATH_TAN: - case MATH_SINH: - case MATH_COSH: - case MATH_TANH: - case MATH_ASIN: - case MATH_ACOS: - case MATH_ATAN: - case MATH_SQRT: - case MATH_FLOOR: - case MATH_CEIL: - case MATH_ROUND: - case MATH_ABS: - case MATH_SIGN: - case MATH_LOG: - case MATH_EXP: - case MATH_ISNAN: - case MATH_ISINF: { - return PropertyInfo(Variant::FLOAT, "s"); - } break; - case MATH_ATAN2: { - if (p_idx == 0) { - return PropertyInfo(Variant::FLOAT, "y"); - } else { - return PropertyInfo(Variant::FLOAT, "x"); - } - } break; - case MATH_FMOD: - case MATH_FPOSMOD: - case LOGIC_MAX: - case LOGIC_MIN: { - if (p_idx == 0) { - return PropertyInfo(Variant::FLOAT, "a"); - } else { - return PropertyInfo(Variant::FLOAT, "b"); - } - } break; - case MATH_POSMOD: { - if (p_idx == 0) { - return PropertyInfo(Variant::INT, "a"); - } else { - return PropertyInfo(Variant::INT, "b"); - } - } break; - case MATH_POW: { - if (p_idx == 0) { - return PropertyInfo(Variant::FLOAT, "base"); - } else { - return PropertyInfo(Variant::FLOAT, "exp"); - } - } break; - case MATH_EASE: { - if (p_idx == 0) { - return PropertyInfo(Variant::FLOAT, "s"); - } else { - return PropertyInfo(Variant::FLOAT, "curve"); - } - } break; - case MATH_STEP_DECIMALS: { - return PropertyInfo(Variant::FLOAT, "step"); - } break; - case MATH_SNAPPED: { - if (p_idx == 0) { - return PropertyInfo(Variant::FLOAT, "s"); - } else { - return PropertyInfo(Variant::FLOAT, "steps"); - } - } break; - case MATH_LERP: - case MATH_LERP_ANGLE: - case MATH_INVERSE_LERP: - case MATH_SMOOTHSTEP: { - if (p_idx == 0) { - return PropertyInfo(Variant::FLOAT, "from"); - } else if (p_idx == 1) { - return PropertyInfo(Variant::FLOAT, "to"); - } else { - return PropertyInfo(Variant::FLOAT, "weight"); - } - } break; - case MATH_CUBIC_INTERPOLATE: { - if (p_idx == 0) { - return PropertyInfo(Variant::FLOAT, "from"); - } else if (p_idx == 1) { - return PropertyInfo(Variant::FLOAT, "to"); - } else if (p_idx == 2) { - return PropertyInfo(Variant::FLOAT, "pre"); - } else if (p_idx == 3) { - return PropertyInfo(Variant::FLOAT, "post"); - } else { - return PropertyInfo(Variant::FLOAT, "weight"); - } - } break; - case MATH_RANGE_LERP: { - if (p_idx == 0) { - return PropertyInfo(Variant::FLOAT, "value"); - } else if (p_idx == 1) { - return PropertyInfo(Variant::FLOAT, "istart"); - } else if (p_idx == 2) { - return PropertyInfo(Variant::FLOAT, "istop"); - } else if (p_idx == 3) { - return PropertyInfo(Variant::FLOAT, "ostart"); - } else { - return PropertyInfo(Variant::FLOAT, "ostop"); - } - } break; - case MATH_MOVE_TOWARD: { - if (p_idx == 0) { - return PropertyInfo(Variant::FLOAT, "from"); - } else if (p_idx == 1) { - return PropertyInfo(Variant::FLOAT, "to"); - } else { - return PropertyInfo(Variant::FLOAT, "delta"); - } - } break; - case MATH_RANDOMIZE: - case MATH_RANDI: - case MATH_RANDF: { - } break; - case MATH_RANDI_RANGE: { - if (p_idx == 0) { - return PropertyInfo(Variant::INT, "from"); - } else { - return PropertyInfo(Variant::INT, "to"); - } - } break; - case MATH_RANDF_RANGE: { - if (p_idx == 0) { - return PropertyInfo(Variant::FLOAT, "from"); - } else { - return PropertyInfo(Variant::FLOAT, "to"); - } - } break; - case MATH_RANDFN: { - if (p_idx == 0) { - return PropertyInfo(Variant::FLOAT, "mean"); - } else { - return PropertyInfo(Variant::FLOAT, "deviation"); - } - } break; - case MATH_SEED: - case MATH_RANDSEED: { - return PropertyInfo(Variant::INT, "seed"); - } break; - case MATH_DEG2RAD: { - return PropertyInfo(Variant::FLOAT, "deg"); - } break; - case MATH_RAD2DEG: { - return PropertyInfo(Variant::FLOAT, "rad"); - } break; - case MATH_LINEAR2DB: { - return PropertyInfo(Variant::FLOAT, "nrg"); - } break; - case MATH_DB2LINEAR: { - return PropertyInfo(Variant::FLOAT, "db"); - } break; - case MATH_PINGPONG: { - if (p_idx == 0) { - return PropertyInfo(Variant::FLOAT, "value"); - } else { - return PropertyInfo(Variant::FLOAT, "length"); - } - } break; - case MATH_WRAP: { - if (p_idx == 0) { - return PropertyInfo(Variant::INT, "value"); - } else if (p_idx == 1) { - return PropertyInfo(Variant::INT, "min"); - } else { - return PropertyInfo(Variant::INT, "max"); - } - } break; - case MATH_WRAPF: - case LOGIC_CLAMP: { - if (p_idx == 0) { - return PropertyInfo(Variant::FLOAT, "value"); - } else if (p_idx == 1) { - return PropertyInfo(Variant::FLOAT, "min"); - } else { - return PropertyInfo(Variant::FLOAT, "max"); - } - } break; - case LOGIC_NEAREST_PO2: { - return PropertyInfo(Variant::INT, "value"); - } break; - case OBJ_WEAKREF: { - return PropertyInfo(Variant::OBJECT, "source"); - } break; - case TYPE_CONVERT: { - if (p_idx == 0) { - return PropertyInfo(Variant::NIL, "what"); - } else { - return PropertyInfo(Variant::STRING, "type"); - } - } break; - case TYPE_OF: { - return PropertyInfo(Variant::NIL, "what"); - } break; - case TYPE_EXISTS: { - return PropertyInfo(Variant::STRING, "type"); - } break; - case TEXT_ORD: { - return PropertyInfo(Variant::STRING, "character"); - } break; - case TEXT_CHAR: { - return PropertyInfo(Variant::INT, "ascii"); - } break; - case TEXT_STR: - case TEXT_PRINT: - case TEXT_PRINTERR: - case TEXT_PRINTRAW: - case TEXT_PRINT_VERBOSE: { - return PropertyInfo(Variant::NIL, "value"); - } break; - case STR_TO_VAR: { - return PropertyInfo(Variant::STRING, "string"); - } break; - case VAR_TO_STR: - case VAR_TO_BYTES: { - if (p_idx == 0) { - return PropertyInfo(Variant::NIL, "var"); - } else { - return PropertyInfo(Variant::BOOL, "full_objects"); - } - - } break; - case BYTES_TO_VAR: { - if (p_idx == 0) { - return PropertyInfo(Variant::PACKED_BYTE_ARRAY, "bytes"); - } else { - return PropertyInfo(Variant::BOOL, "allow_objects"); - } - } break; - case FUNC_MAX: { - } - } - - return PropertyInfo(); -} - -PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) const { - Variant::Type t = Variant::NIL; - switch (func) { - case MATH_SIN: - case MATH_COS: - case MATH_TAN: - case MATH_SINH: - case MATH_COSH: - case MATH_TANH: - case MATH_ASIN: - case MATH_ACOS: - case MATH_ATAN: - case MATH_ATAN2: - case MATH_SQRT: - case MATH_FMOD: - case MATH_FPOSMOD: - case MATH_FLOOR: - case MATH_CEIL: { - t = Variant::FLOAT; - } break; - case MATH_POSMOD: { - t = Variant::INT; - } break; - case MATH_ROUND: { - t = Variant::FLOAT; - } break; - case MATH_ABS: { - t = Variant::NIL; - } break; - case MATH_SIGN: { - t = Variant::NIL; - } break; - case MATH_POW: - case MATH_LOG: - case MATH_EXP: { - t = Variant::FLOAT; - } break; - case MATH_ISNAN: - case MATH_ISINF: { - t = Variant::BOOL; - } break; - case MATH_EASE: { - t = Variant::FLOAT; - } break; - case MATH_STEP_DECIMALS: { - t = Variant::INT; - } break; - case MATH_SNAPPED: - case MATH_LERP: - case MATH_CUBIC_INTERPOLATE: - case MATH_LERP_ANGLE: - case MATH_INVERSE_LERP: - case MATH_RANGE_LERP: - case MATH_SMOOTHSTEP: - case MATH_MOVE_TOWARD: - case MATH_RANDOMIZE: { - } break; - case MATH_RANDI: { - t = Variant::INT; - } break; - case MATH_RANDF: - case MATH_RANDFN: - case MATH_RANDF_RANGE: { - t = Variant::FLOAT; - } break; - case MATH_RANDI_RANGE: { - t = Variant::INT; - } break; - case MATH_SEED: { - } break; - case MATH_RANDSEED: { - if (p_idx == 0) { - return PropertyInfo(Variant::INT, "rnd"); - } else { - return PropertyInfo(Variant::INT, "seed"); - } - } break; - case MATH_DEG2RAD: - case MATH_RAD2DEG: - case MATH_LINEAR2DB: - case MATH_WRAPF: - case MATH_PINGPONG: - case MATH_DB2LINEAR: { - t = Variant::FLOAT; - } break; - case MATH_WRAP: { - t = Variant::INT; - } break; - case LOGIC_MAX: - case LOGIC_MIN: - case LOGIC_CLAMP: { - } break; - - case LOGIC_NEAREST_PO2: { - t = Variant::NIL; - } break; - case OBJ_WEAKREF: { - t = Variant::OBJECT; - - } break; - case TYPE_CONVERT: { - } break; - case TEXT_ORD: - case TYPE_OF: { - t = Variant::INT; - - } break; - case TYPE_EXISTS: { - t = Variant::BOOL; - - } break; - case TEXT_CHAR: - case TEXT_STR: { - t = Variant::STRING; - - } break; - case TEXT_PRINT: { - } break; - case TEXT_PRINTERR: { - } break; - case TEXT_PRINTRAW: { - } break; - case TEXT_PRINT_VERBOSE: { - } break; - case VAR_TO_STR: { - t = Variant::STRING; - } break; - case STR_TO_VAR: { - } break; - case VAR_TO_BYTES: { - if (p_idx == 0) { - t = Variant::PACKED_BYTE_ARRAY; - } else { - t = Variant::BOOL; - } - - } break; - case BYTES_TO_VAR: { - if (p_idx == 1) { - t = Variant::BOOL; - } - } break; - case FUNC_MAX: { - } - } - - return PropertyInfo(t, ""); -} - -/* -String VisualScriptBuiltinFunc::get_caption() const { - return "BuiltinFunc"; -} - -*/ - -String VisualScriptBuiltinFunc::get_caption() const { - return func_name[func]; -} - -void VisualScriptBuiltinFunc::set_func(BuiltinFunc p_which) { - ERR_FAIL_INDEX(p_which, FUNC_MAX); - func = p_which; - notify_property_list_changed(); - ports_changed_notify(); -} - -VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::get_func() { - return func; -} - -#define VALIDATE_ARG_NUM(m_arg) \ - if (!p_inputs[m_arg]->is_num()) { \ - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \ - r_error.argument = m_arg; \ - r_error.expected = Variant::FLOAT; \ - return; \ - } - -void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return, Callable::CallError &r_error, String &r_error_str) { - switch (p_func) { - case VisualScriptBuiltinFunc::MATH_SIN: { - VALIDATE_ARG_NUM(0); - *r_return = Math::sin((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_COS: { - VALIDATE_ARG_NUM(0); - *r_return = Math::cos((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_TAN: { - VALIDATE_ARG_NUM(0); - *r_return = Math::tan((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_SINH: { - VALIDATE_ARG_NUM(0); - *r_return = Math::sinh((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_COSH: { - VALIDATE_ARG_NUM(0); - *r_return = Math::cosh((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_TANH: { - VALIDATE_ARG_NUM(0); - *r_return = Math::tanh((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ASIN: { - VALIDATE_ARG_NUM(0); - *r_return = Math::asin((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ACOS: { - VALIDATE_ARG_NUM(0); - *r_return = Math::acos((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ATAN: { - VALIDATE_ARG_NUM(0); - *r_return = Math::atan((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ATAN2: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *r_return = Math::atan2((double)*p_inputs[0], (double)*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_SQRT: { - VALIDATE_ARG_NUM(0); - *r_return = Math::sqrt((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_FMOD: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *r_return = Math::fmod((double)*p_inputs[0], (double)*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_FPOSMOD: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *r_return = Math::fposmod((double)*p_inputs[0], (double)*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_POSMOD: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *r_return = Math::posmod((int64_t)*p_inputs[0], (int64_t)*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_FLOOR: { - VALIDATE_ARG_NUM(0); - *r_return = Math::floor((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_CEIL: { - VALIDATE_ARG_NUM(0); - *r_return = Math::ceil((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ROUND: { - VALIDATE_ARG_NUM(0); - *r_return = Math::round((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ABS: { - if (p_inputs[0]->get_type() == Variant::INT) { - int64_t i = *p_inputs[0]; - *r_return = ABS(i); - } else if (p_inputs[0]->get_type() == Variant::FLOAT) { - real_t r = *p_inputs[0]; - *r_return = Math::abs(r); - } else { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::FLOAT; - } - } break; - case VisualScriptBuiltinFunc::MATH_SIGN: { - if (p_inputs[0]->get_type() == Variant::INT) { - int64_t i = *p_inputs[0]; - *r_return = i < 0 ? -1 : (i > 0 ? +1 : 0); - } else if (p_inputs[0]->get_type() == Variant::FLOAT) { - real_t r = *p_inputs[0]; - *r_return = r < 0.0 ? -1.0 : (r > 0.0 ? +1.0 : 0.0); - } else { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::FLOAT; - } - } break; - case VisualScriptBuiltinFunc::MATH_POW: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *r_return = Math::pow((double)*p_inputs[0], (double)*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_LOG: { - VALIDATE_ARG_NUM(0); - *r_return = Math::log((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_EXP: { - VALIDATE_ARG_NUM(0); - *r_return = Math::exp((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ISNAN: { - VALIDATE_ARG_NUM(0); - *r_return = Math::is_nan((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ISINF: { - VALIDATE_ARG_NUM(0); - *r_return = Math::is_inf((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_EASE: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *r_return = Math::ease((double)*p_inputs[0], (double)*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_STEP_DECIMALS: { - VALIDATE_ARG_NUM(0); - *r_return = Math::step_decimals((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_SNAPPED: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *r_return = Math::snapped((double)*p_inputs[0], (double)*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_LERP: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - *r_return = Math::lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); - } break; - case VisualScriptBuiltinFunc::MATH_CUBIC_INTERPOLATE: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - VALIDATE_ARG_NUM(3); - VALIDATE_ARG_NUM(4); - *r_return = Math::cubic_interpolate((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]); - } break; - case VisualScriptBuiltinFunc::MATH_LERP_ANGLE: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - *r_return = Math::lerp_angle((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); - } break; - case VisualScriptBuiltinFunc::MATH_INVERSE_LERP: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - *r_return = Math::inverse_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); - } break; - case VisualScriptBuiltinFunc::MATH_RANGE_LERP: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - VALIDATE_ARG_NUM(3); - VALIDATE_ARG_NUM(4); - *r_return = Math::range_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]); - } break; - case VisualScriptBuiltinFunc::MATH_SMOOTHSTEP: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - *r_return = Math::smoothstep((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); - } break; - case VisualScriptBuiltinFunc::MATH_MOVE_TOWARD: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - *r_return = Math::move_toward((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); - } break; - case VisualScriptBuiltinFunc::MATH_RANDOMIZE: { - Math::randomize(); - - } break; - case VisualScriptBuiltinFunc::MATH_RANDI: { - *r_return = Math::rand(); - } break; - case VisualScriptBuiltinFunc::MATH_RANDF: { - *r_return = Math::randf(); - } break; - case VisualScriptBuiltinFunc::MATH_RANDI_RANGE: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *r_return = Math::random((int)*p_inputs[0], (int)*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_RANDF_RANGE: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *r_return = Math::random((double)*p_inputs[0], (double)*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_RANDFN: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *r_return = Math::randfn((double)*p_inputs[0], (double)*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_SEED: { - VALIDATE_ARG_NUM(0); - uint64_t seed = *p_inputs[0]; - Math::seed(seed); - - } break; - case VisualScriptBuiltinFunc::MATH_RANDSEED: { - VALIDATE_ARG_NUM(0); - uint64_t seed = *p_inputs[0]; - int ret = Math::rand_from_seed(&seed); - Array reta; - reta.push_back(ret); - reta.push_back(seed); - *r_return = reta; - - } break; - case VisualScriptBuiltinFunc::MATH_DEG2RAD: { - VALIDATE_ARG_NUM(0); - *r_return = Math::deg2rad((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_RAD2DEG: { - VALIDATE_ARG_NUM(0); - *r_return = Math::rad2deg((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_LINEAR2DB: { - VALIDATE_ARG_NUM(0); - *r_return = Math::linear2db((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_DB2LINEAR: { - VALIDATE_ARG_NUM(0); - *r_return = Math::db2linear((double)*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_PINGPONG: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *r_return = Math::pingpong((double)*p_inputs[0], (double)*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_WRAP: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - *r_return = Math::wrapi((int64_t)*p_inputs[0], (int64_t)*p_inputs[1], (int64_t)*p_inputs[2]); - } break; - case VisualScriptBuiltinFunc::MATH_WRAPF: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - *r_return = Math::wrapf((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); - } break; - case VisualScriptBuiltinFunc::LOGIC_MAX: { - if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT) { - int64_t a = *p_inputs[0]; - int64_t b = *p_inputs[1]; - *r_return = MAX(a, b); - } else { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - - real_t a = *p_inputs[0]; - real_t b = *p_inputs[1]; - - *r_return = MAX(a, b); - } - - } break; - case VisualScriptBuiltinFunc::LOGIC_MIN: { - if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT) { - int64_t a = *p_inputs[0]; - int64_t b = *p_inputs[1]; - *r_return = MIN(a, b); - } else { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - - real_t a = *p_inputs[0]; - real_t b = *p_inputs[1]; - - *r_return = MIN(a, b); - } - } break; - case VisualScriptBuiltinFunc::LOGIC_CLAMP: { - if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT && p_inputs[2]->get_type() == Variant::INT) { - int64_t a = *p_inputs[0]; - int64_t b = *p_inputs[1]; - int64_t c = *p_inputs[2]; - *r_return = CLAMP(a, b, c); - } else { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - - real_t a = *p_inputs[0]; - real_t b = *p_inputs[1]; - real_t c = *p_inputs[2]; - - *r_return = CLAMP(a, b, c); - } - } break; - case VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2: { - VALIDATE_ARG_NUM(0); - int64_t num = *p_inputs[0]; - *r_return = next_power_of_2(num); - } break; - case VisualScriptBuiltinFunc::OBJ_WEAKREF: { - if (p_inputs[0]->get_type() != Variant::OBJECT) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::OBJECT; - - return; - } - - if (p_inputs[0]->is_ref_counted()) { - Ref<RefCounted> r = *p_inputs[0]; - if (!r.is_valid()) { - return; - } - - Ref<WeakRef> wref = memnew(WeakRef); - wref->set_ref(r); - *r_return = wref; - } else { - Object *obj = *p_inputs[0]; - if (!obj) { - return; - } - Ref<WeakRef> wref = memnew(WeakRef); - wref->set_obj(obj); - *r_return = wref; - } - - } break; - case VisualScriptBuiltinFunc::TYPE_CONVERT: { - VALIDATE_ARG_NUM(1); - int type = *p_inputs[1]; - if (type < 0 || type >= Variant::VARIANT_MAX) { - r_error_str = RTR("Invalid type argument to convert(), use TYPE_* constants."); - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::INT; - return; - - } else { - Variant::construct(Variant::Type(type), *r_return, p_inputs, 1, r_error); - } - } break; - case VisualScriptBuiltinFunc::TYPE_OF: { - *r_return = p_inputs[0]->get_type(); - - } break; - case VisualScriptBuiltinFunc::TYPE_EXISTS: { - *r_return = ClassDB::class_exists(*p_inputs[0]); - - } break; - case VisualScriptBuiltinFunc::TEXT_CHAR: { - char32_t result[2] = { *p_inputs[0], 0 }; - - *r_return = String(result); - - } break; - case VisualScriptBuiltinFunc::TEXT_ORD: { - if (p_inputs[0]->get_type() != Variant::STRING) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::STRING; - - return; - } - - String str = p_inputs[0]->operator String(); - - if (str.length() != 1) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::STRING; - *r_return = "Expected a string of length 1 (a character)."; - - return; - } - - *r_return = str.get(0); - - } break; - case VisualScriptBuiltinFunc::TEXT_STR: { - String str = *p_inputs[0]; - - *r_return = str; - - } break; - case VisualScriptBuiltinFunc::TEXT_PRINT: { - String str = *p_inputs[0]; - print_line(str); - - } break; - - case VisualScriptBuiltinFunc::TEXT_PRINTERR: { - String str = *p_inputs[0]; - print_error(str); - - } break; - case VisualScriptBuiltinFunc::TEXT_PRINTRAW: { - String str = *p_inputs[0]; - OS::get_singleton()->print("%s", str.utf8().get_data()); - - } break; - case VisualScriptBuiltinFunc::TEXT_PRINT_VERBOSE: { - String str = *p_inputs[0]; - print_verbose(str); - } break; - case VisualScriptBuiltinFunc::VAR_TO_STR: { - String vars; - VariantWriter::write_to_string(*p_inputs[0], vars); - *r_return = vars; - } break; - case VisualScriptBuiltinFunc::STR_TO_VAR: { - if (p_inputs[0]->get_type() != Variant::STRING) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::STRING; - - return; - } - - VariantParser::StreamString ss; - ss.s = *p_inputs[0]; - - String errs; - int line; - Error err = VariantParser::parse(&ss, *r_return, errs, line); - - if (err != OK) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::STRING; - *r_return = "Parse error at line " + itos(line) + ": " + errs; - return; - } - - } break; - case VisualScriptBuiltinFunc::VAR_TO_BYTES: { - if (p_inputs[1]->get_type() != Variant::BOOL) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 1; - r_error.expected = Variant::BOOL; - return; - } - PackedByteArray barr; - int len; - bool full_objects = *p_inputs[1]; - Error err = encode_variant(*p_inputs[0], nullptr, len, full_objects); - if (err) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::NIL; - r_error_str = "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."; - return; - } - - barr.resize(len); - { - uint8_t *w = barr.ptrw(); - encode_variant(*p_inputs[0], w, len, full_objects); - } - *r_return = barr; - } break; - case VisualScriptBuiltinFunc::BYTES_TO_VAR: { - if (p_inputs[0]->get_type() != Variant::PACKED_BYTE_ARRAY) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::PACKED_BYTE_ARRAY; - return; - } - if (p_inputs[1]->get_type() != Variant::BOOL) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 1; - r_error.expected = Variant::BOOL; - return; - } - - PackedByteArray varr = *p_inputs[0]; - bool allow_objects = *p_inputs[1]; - Variant ret; - { - const uint8_t *r = varr.ptr(); - Error err = decode_variant(ret, r, varr.size(), nullptr, allow_objects); - if (err != OK) { - r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format."); - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::PACKED_BYTE_ARRAY; - return; - } - } - - *r_return = ret; - - } break; - default: { - } - } -} - -class VisualScriptNodeInstanceBuiltinFunc : public VisualScriptNodeInstance { -public: - VisualScriptBuiltinFunc *node = nullptr; - VisualScriptInstance *instance = nullptr; - - VisualScriptBuiltinFunc::BuiltinFunc func; - - //virtual int get_working_memory_size() const override { return 0; } - //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } - //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - VisualScriptBuiltinFunc::exec_func(func, p_inputs, p_outputs[0], r_error, r_error_str); - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptBuiltinFunc::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceBuiltinFunc *instance = memnew(VisualScriptNodeInstanceBuiltinFunc); - instance->node = this; - instance->instance = p_instance; - instance->func = func; - return instance; -} - -void VisualScriptBuiltinFunc::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_func", "which"), &VisualScriptBuiltinFunc::set_func); - ClassDB::bind_method(D_METHOD("get_func"), &VisualScriptBuiltinFunc::get_func); - - String cc; - - for (int i = 0; i < FUNC_MAX; i++) { - if (i > 0) { - cc += ","; - } - cc += func_name[i]; - } - ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, cc), "set_func", "get_func"); - - BIND_ENUM_CONSTANT(MATH_SIN); - BIND_ENUM_CONSTANT(MATH_COS); - BIND_ENUM_CONSTANT(MATH_TAN); - BIND_ENUM_CONSTANT(MATH_SINH); - BIND_ENUM_CONSTANT(MATH_COSH); - BIND_ENUM_CONSTANT(MATH_TANH); - BIND_ENUM_CONSTANT(MATH_ASIN); - BIND_ENUM_CONSTANT(MATH_ACOS); - BIND_ENUM_CONSTANT(MATH_ATAN); - BIND_ENUM_CONSTANT(MATH_ATAN2); - BIND_ENUM_CONSTANT(MATH_SQRT); - BIND_ENUM_CONSTANT(MATH_FMOD); - BIND_ENUM_CONSTANT(MATH_FPOSMOD); - BIND_ENUM_CONSTANT(MATH_FLOOR); - BIND_ENUM_CONSTANT(MATH_CEIL); - BIND_ENUM_CONSTANT(MATH_ROUND); - BIND_ENUM_CONSTANT(MATH_ABS); - BIND_ENUM_CONSTANT(MATH_SIGN); - BIND_ENUM_CONSTANT(MATH_POW); - BIND_ENUM_CONSTANT(MATH_LOG); - BIND_ENUM_CONSTANT(MATH_EXP); - BIND_ENUM_CONSTANT(MATH_ISNAN); - BIND_ENUM_CONSTANT(MATH_ISINF); - BIND_ENUM_CONSTANT(MATH_EASE); - BIND_ENUM_CONSTANT(MATH_STEP_DECIMALS); - BIND_ENUM_CONSTANT(MATH_SNAPPED); - BIND_ENUM_CONSTANT(MATH_LERP); - BIND_ENUM_CONSTANT(MATH_CUBIC_INTERPOLATE); - BIND_ENUM_CONSTANT(MATH_INVERSE_LERP); - BIND_ENUM_CONSTANT(MATH_RANGE_LERP); - BIND_ENUM_CONSTANT(MATH_MOVE_TOWARD); - BIND_ENUM_CONSTANT(MATH_RANDOMIZE); - BIND_ENUM_CONSTANT(MATH_RANDI); - BIND_ENUM_CONSTANT(MATH_RANDF); - BIND_ENUM_CONSTANT(MATH_RANDI_RANGE); - BIND_ENUM_CONSTANT(MATH_RANDF_RANGE); - BIND_ENUM_CONSTANT(MATH_RANDFN); - BIND_ENUM_CONSTANT(MATH_SEED); - BIND_ENUM_CONSTANT(MATH_RANDSEED); - BIND_ENUM_CONSTANT(MATH_DEG2RAD); - BIND_ENUM_CONSTANT(MATH_RAD2DEG); - BIND_ENUM_CONSTANT(MATH_LINEAR2DB); - BIND_ENUM_CONSTANT(MATH_DB2LINEAR); - BIND_ENUM_CONSTANT(MATH_WRAP); - BIND_ENUM_CONSTANT(MATH_WRAPF); - BIND_ENUM_CONSTANT(MATH_PINGPONG); - BIND_ENUM_CONSTANT(LOGIC_MAX); - BIND_ENUM_CONSTANT(LOGIC_MIN); - BIND_ENUM_CONSTANT(LOGIC_CLAMP); - BIND_ENUM_CONSTANT(LOGIC_NEAREST_PO2); - BIND_ENUM_CONSTANT(OBJ_WEAKREF); - BIND_ENUM_CONSTANT(TYPE_CONVERT); - BIND_ENUM_CONSTANT(TYPE_OF); - BIND_ENUM_CONSTANT(TYPE_EXISTS); - BIND_ENUM_CONSTANT(TEXT_CHAR); - BIND_ENUM_CONSTANT(TEXT_STR); - BIND_ENUM_CONSTANT(TEXT_PRINT); - BIND_ENUM_CONSTANT(TEXT_PRINTERR); - BIND_ENUM_CONSTANT(TEXT_PRINTRAW); - BIND_ENUM_CONSTANT(TEXT_PRINT_VERBOSE); - BIND_ENUM_CONSTANT(VAR_TO_STR); - BIND_ENUM_CONSTANT(STR_TO_VAR); - BIND_ENUM_CONSTANT(VAR_TO_BYTES); - BIND_ENUM_CONSTANT(BYTES_TO_VAR); - BIND_ENUM_CONSTANT(MATH_SMOOTHSTEP); - BIND_ENUM_CONSTANT(MATH_POSMOD); - BIND_ENUM_CONSTANT(MATH_LERP_ANGLE); - BIND_ENUM_CONSTANT(TEXT_ORD); - BIND_ENUM_CONSTANT(FUNC_MAX); -} - -VisualScriptBuiltinFunc::VisualScriptBuiltinFunc(VisualScriptBuiltinFunc::BuiltinFunc func) { - this->func = func; -} - -VisualScriptBuiltinFunc::VisualScriptBuiltinFunc() { - func = MATH_SIN; -} - -template <VisualScriptBuiltinFunc::BuiltinFunc func> -static Ref<VisualScriptNode> create_builtin_func_node(const String &p_name) { - Ref<VisualScriptBuiltinFunc> node = memnew(VisualScriptBuiltinFunc(func)); - return node; -} - -void register_visual_script_builtin_func_node() { - VisualScriptLanguage::singleton->add_register_func("functions/built_in/sin", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SIN>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/cos", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_COS>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/tan", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_TAN>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/sinh", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SINH>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/cosh", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_COSH>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/tanh", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_TANH>); - - VisualScriptLanguage::singleton->add_register_func("functions/built_in/asin", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ASIN>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/acos", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ACOS>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/atan", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ATAN>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/atan2", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ATAN2>); - - VisualScriptLanguage::singleton->add_register_func("functions/built_in/sqrt", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SQRT>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/fmod", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FMOD>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/fposmod", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FPOSMOD>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/posmod", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_POSMOD>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/floor", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FLOOR>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/ceil", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_CEIL>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/round", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ROUND>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/abs", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ABS>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/sign", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SIGN>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/pow", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_POW>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/log", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LOG>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/exp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_EXP>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/isnan", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ISNAN>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/isinf", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ISINF>); - - VisualScriptLanguage::singleton->add_register_func("functions/built_in/ease", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_EASE>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/step_decimals", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_STEP_DECIMALS>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/snapped", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SNAPPED>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/cubic_interpolate", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_CUBIC_INTERPOLATE>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/lerp_angle", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP_ANGLE>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/inverse_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_INVERSE_LERP>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/range_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANGE_LERP>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/smoothstep", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SMOOTHSTEP>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/move_toward", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_MOVE_TOWARD>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/randomize", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOMIZE>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/randi", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDI>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/randf", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDF>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/randi_range", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDI_RANGE>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/randf_range", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDF_RANGE>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/randfn", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDFN>); - - VisualScriptLanguage::singleton->add_register_func("functions/built_in/seed", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SEED>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/randseed", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDSEED>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/deg2rad", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DEG2RAD>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/rad2deg", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAD2DEG>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/linear2db", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LINEAR2DB>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/db2linear", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DB2LINEAR>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/wrapi", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_WRAP>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/wrapf", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_WRAPF>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/pingpong", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_PINGPONG>); - - VisualScriptLanguage::singleton->add_register_func("functions/built_in/max", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MAX>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/min", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MIN>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/clamp", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_CLAMP>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/nearest_po2", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2>); - - VisualScriptLanguage::singleton->add_register_func("functions/built_in/weakref", create_builtin_func_node<VisualScriptBuiltinFunc::OBJ_WEAKREF>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/convert", create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_CONVERT>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/typeof", create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_OF>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/type_exists", create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_EXISTS>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/char", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_CHAR>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/ord", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_ORD>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/str", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_STR>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/print", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINT>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/printerr", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTERR>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/printraw", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTRAW>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/print_verbose", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINT_VERBOSE>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/var2str", create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_STR>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/str2var", create_builtin_func_node<VisualScriptBuiltinFunc::STR_TO_VAR>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/var2bytes", create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_BYTES>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/bytes2var", create_builtin_func_node<VisualScriptBuiltinFunc::BYTES_TO_VAR>); -} diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h deleted file mode 100644 index 18935b9995..0000000000 --- a/modules/visual_script/visual_script_builtin_funcs.h +++ /dev/null @@ -1,153 +0,0 @@ -/*************************************************************************/ -/* visual_script_builtin_funcs.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 VISUAL_SCRIPT_BUILTIN_FUNCS_H -#define VISUAL_SCRIPT_BUILTIN_FUNCS_H - -#include "visual_script.h" - -class VisualScriptBuiltinFunc : public VisualScriptNode { - GDCLASS(VisualScriptBuiltinFunc, VisualScriptNode); - -public: - enum BuiltinFunc { - MATH_SIN, - MATH_COS, - MATH_TAN, - MATH_SINH, - MATH_COSH, - MATH_TANH, - MATH_ASIN, - MATH_ACOS, - MATH_ATAN, - MATH_ATAN2, - MATH_SQRT, - MATH_FMOD, - MATH_FPOSMOD, - MATH_FLOOR, - MATH_CEIL, - MATH_ROUND, - MATH_ABS, - MATH_SIGN, - MATH_POW, - MATH_LOG, - MATH_EXP, - MATH_ISNAN, - MATH_ISINF, - MATH_EASE, - MATH_STEP_DECIMALS, - MATH_SNAPPED, - MATH_LERP, - MATH_CUBIC_INTERPOLATE, - MATH_INVERSE_LERP, - MATH_RANGE_LERP, - MATH_MOVE_TOWARD, - MATH_RANDOMIZE, - MATH_RANDI, - MATH_RANDF, - MATH_RANDI_RANGE, - MATH_RANDF_RANGE, - MATH_RANDFN, - MATH_SEED, - MATH_RANDSEED, - MATH_DEG2RAD, - MATH_RAD2DEG, - MATH_LINEAR2DB, - MATH_DB2LINEAR, - MATH_WRAP, - MATH_WRAPF, - MATH_PINGPONG, - LOGIC_MAX, - LOGIC_MIN, - LOGIC_CLAMP, - LOGIC_NEAREST_PO2, - OBJ_WEAKREF, - TYPE_CONVERT, - TYPE_OF, - TYPE_EXISTS, - TEXT_CHAR, - TEXT_STR, - TEXT_PRINT, - TEXT_PRINTERR, - TEXT_PRINTRAW, - TEXT_PRINT_VERBOSE, - VAR_TO_STR, - STR_TO_VAR, - VAR_TO_BYTES, - BYTES_TO_VAR, - MATH_SMOOTHSTEP, - MATH_POSMOD, - MATH_LERP_ANGLE, - TEXT_ORD, - FUNC_MAX - }; - - static int get_func_argument_count(BuiltinFunc p_func); - static String get_func_name(BuiltinFunc p_func); - static void exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return, Callable::CallError &r_error, String &r_error_str); - static BuiltinFunc find_function(const String &p_string); - -private: - static const char *func_name[FUNC_MAX]; - BuiltinFunc func; - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - //virtual String get_text() const; - virtual String get_category() const override { return "functions"; } - - void set_func(BuiltinFunc p_which); - BuiltinFunc get_func(); - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptBuiltinFunc(VisualScriptBuiltinFunc::BuiltinFunc func); - VisualScriptBuiltinFunc(); -}; - -VARIANT_ENUM_CAST(VisualScriptBuiltinFunc::BuiltinFunc) - -void register_visual_script_builtin_func_node(); - -#endif // VISUAL_SCRIPT_BUILTIN_FUNCS_H diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp deleted file mode 100644 index e0f6436094..0000000000 --- a/modules/visual_script/visual_script_expression.cpp +++ /dev/null @@ -1,1570 +0,0 @@ -/*************************************************************************/ -/* visual_script_expression.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "visual_script_expression.h" - -bool VisualScriptExpression::_set(const StringName &p_name, const Variant &p_value) { - if (String(p_name) == "expression") { - expression = p_value; - expression_dirty = true; - ports_changed_notify(); - return true; - } - - if (String(p_name) == "out_type") { - output_type = Variant::Type(int(p_value)); - expression_dirty = true; - ports_changed_notify(); - return true; - } - if (String(p_name) == "sequenced") { - sequenced = p_value; - ports_changed_notify(); - return true; - } - - if (String(p_name) == "input_count") { - int from = inputs.size(); - inputs.resize(int(p_value)); - for (int i = from; i < inputs.size(); i++) { - inputs.write[i].name = String::chr('a' + i); - if (from == 0) { - inputs.write[i].type = output_type; - } else { - inputs.write[i].type = inputs[from - 1].type; - } - } - expression_dirty = true; - ports_changed_notify(); - notify_property_list_changed(); - return true; - } - - if (String(p_name).begins_with("input_")) { - int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int(); - ERR_FAIL_INDEX_V(idx, inputs.size(), false); - - String what = String(p_name).get_slice("/", 1); - - if (what == "type") { - inputs.write[idx].type = Variant::Type(int(p_value)); - } else if (what == "name") { - inputs.write[idx].name = p_value; - } else { - return false; - } - - expression_dirty = true; - ports_changed_notify(); - return true; - } - - return false; -} - -bool VisualScriptExpression::_get(const StringName &p_name, Variant &r_ret) const { - if (String(p_name) == "expression") { - r_ret = expression; - return true; - } - - if (String(p_name) == "out_type") { - r_ret = output_type; - return true; - } - - if (String(p_name) == "sequenced") { - r_ret = sequenced; - return true; - } - - if (String(p_name) == "input_count") { - r_ret = inputs.size(); - return true; - } - - if (String(p_name).begins_with("input_")) { - int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int(); - ERR_FAIL_INDEX_V(idx, inputs.size(), false); - - String what = String(p_name).get_slice("/", 1); - - if (what == "type") { - r_ret = inputs[idx].type; - } else if (what == "name") { - r_ret = inputs[idx].name; - } else { - return false; - } - - return true; - } - - return false; -} - -void VisualScriptExpression::_get_property_list(List<PropertyInfo> *p_list) const { - String argt = "Any"; - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - argt += "," + Variant::get_type_name(Variant::Type(i)); - } - - p_list->push_back(PropertyInfo(Variant::STRING, "expression", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR)); - p_list->push_back(PropertyInfo(Variant::INT, "out_type", PROPERTY_HINT_ENUM, argt)); - p_list->push_back(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1")); - p_list->push_back(PropertyInfo(Variant::BOOL, "sequenced")); - - for (int i = 0; i < inputs.size(); i++) { - p_list->push_back(PropertyInfo(Variant::INT, "input_" + itos(i) + "/type", PROPERTY_HINT_ENUM, argt)); - p_list->push_back(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name")); - } -} - -int VisualScriptExpression::get_output_sequence_port_count() const { - return sequenced ? 1 : 0; -} - -bool VisualScriptExpression::has_input_sequence_port() const { - return sequenced; -} - -String VisualScriptExpression::get_output_sequence_port_text(int p_port) const { - return String(); -} - -int VisualScriptExpression::get_input_value_port_count() const { - return inputs.size(); -} - -int VisualScriptExpression::get_output_value_port_count() const { - return 1; -} - -PropertyInfo VisualScriptExpression::get_input_value_port_info(int p_idx) const { - return PropertyInfo(inputs[p_idx].type, inputs[p_idx].name); -} - -PropertyInfo VisualScriptExpression::get_output_value_port_info(int p_idx) const { - return PropertyInfo(output_type, "result"); -} - -String VisualScriptExpression::get_caption() const { - return RTR("Expression"); -} - -String VisualScriptExpression::get_text() const { - return expression; -} - -Error VisualScriptExpression::_get_token(Token &r_token) { - while (true) { -#define GET_CHAR() (str_ofs >= expression.length() ? 0 : expression[str_ofs++]) - - char32_t cchar = GET_CHAR(); - if (cchar == 0) { - r_token.type = TK_EOF; - return OK; - } - - switch (cchar) { - case 0: { - r_token.type = TK_EOF; - return OK; - } break; - case '{': { - r_token.type = TK_CURLY_BRACKET_OPEN; - return OK; - }; - case '}': { - r_token.type = TK_CURLY_BRACKET_CLOSE; - return OK; - }; - case '[': { - r_token.type = TK_BRACKET_OPEN; - return OK; - }; - case ']': { - r_token.type = TK_BRACKET_CLOSE; - return OK; - }; - case '(': { - r_token.type = TK_PARENTHESIS_OPEN; - return OK; - }; - case ')': { - r_token.type = TK_PARENTHESIS_CLOSE; - return OK; - }; - case ',': { - r_token.type = TK_COMMA; - return OK; - }; - case ':': { - r_token.type = TK_COLON; - return OK; - }; - case '.': { - r_token.type = TK_PERIOD; - return OK; - }; - case '=': { - cchar = GET_CHAR(); - if (cchar == '=') { - r_token.type = TK_OP_EQUAL; - } else { - _set_error("Expected '='"); - r_token.type = TK_ERROR; - return ERR_PARSE_ERROR; - } - return OK; - }; - case '!': { - if (expression[str_ofs] == '=') { - r_token.type = TK_OP_NOT_EQUAL; - str_ofs++; - } else { - r_token.type = TK_OP_NOT; - } - return OK; - }; - case '>': { - if (expression[str_ofs] == '=') { - r_token.type = TK_OP_GREATER_EQUAL; - str_ofs++; - } else if (expression[str_ofs] == '>') { - r_token.type = TK_OP_SHIFT_RIGHT; - str_ofs++; - } else { - r_token.type = TK_OP_GREATER; - } - return OK; - }; - case '<': { - if (expression[str_ofs] == '=') { - r_token.type = TK_OP_LESS_EQUAL; - str_ofs++; - } else if (expression[str_ofs] == '<') { - r_token.type = TK_OP_SHIFT_LEFT; - str_ofs++; - } else { - r_token.type = TK_OP_LESS; - } - return OK; - }; - case '+': { - r_token.type = TK_OP_ADD; - return OK; - }; - case '-': { - r_token.type = TK_OP_SUB; - return OK; - }; - case '/': { - r_token.type = TK_OP_DIV; - return OK; - }; - case '*': { - r_token.type = TK_OP_MUL; - return OK; - }; - case '%': { - r_token.type = TK_OP_MOD; - return OK; - }; - case '&': { - if (expression[str_ofs] == '&') { - r_token.type = TK_OP_AND; - str_ofs++; - } else { - r_token.type = TK_OP_BIT_AND; - } - return OK; - }; - case '|': { - if (expression[str_ofs] == '|') { - r_token.type = TK_OP_OR; - str_ofs++; - } else { - r_token.type = TK_OP_BIT_OR; - } - return OK; - }; - case '^': { - r_token.type = TK_OP_BIT_XOR; - - return OK; - }; - case '~': { - r_token.type = TK_OP_BIT_INVERT; - - return OK; - }; - case '"': { - String str; - char32_t prev = 0; - while (true) { - char32_t ch = GET_CHAR(); - - if (ch == 0) { - _set_error("Unterminated String"); - r_token.type = TK_ERROR; - return ERR_PARSE_ERROR; - } else if (ch == '"') { - break; - } else if (ch == '\\') { - //escaped characters... - - char32_t next = GET_CHAR(); - if (next == 0) { - _set_error("Unterminated String"); - r_token.type = TK_ERROR; - return ERR_PARSE_ERROR; - } - char32_t res = 0; - - switch (next) { - case 'b': - res = 8; - break; - case 't': - res = 9; - break; - case 'n': - res = 10; - break; - case 'f': - res = 12; - break; - case 'r': - res = 13; - break; - case 'U': - case 'u': { - // Hexadecimal sequence. - int hex_len = (next == 'U') ? 6 : 4; - for (int j = 0; j < hex_len; j++) { - char32_t c = GET_CHAR(); - - if (c == 0) { - _set_error("Unterminated String"); - r_token.type = TK_ERROR; - return ERR_PARSE_ERROR; - } - if (!is_hex_digit(c)) { - _set_error("Malformed hex constant in string"); - r_token.type = TK_ERROR; - return ERR_PARSE_ERROR; - } - char32_t v; - if (is_digit(c)) { - v = c - '0'; - } else if (c >= 'a' && c <= 'f') { - v = c - 'a'; - v += 10; - } else if (c >= 'A' && c <= 'F') { - v = c - 'A'; - v += 10; - } else { - ERR_PRINT("Bug parsing hex constant."); - v = 0; - } - - res <<= 4; - res |= v; - } - - } break; - default: { - res = next; - } break; - } - - // Parse UTF-16 pair. - if ((res & 0xfffffc00) == 0xd800) { - if (prev == 0) { - prev = res; - continue; - } else { - _set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate"); - r_token.type = TK_ERROR; - return ERR_PARSE_ERROR; - } - } else if ((res & 0xfffffc00) == 0xdc00) { - if (prev == 0) { - _set_error("Invalid UTF-16 sequence in string, unpaired trail surrogate"); - r_token.type = TK_ERROR; - return ERR_PARSE_ERROR; - } else { - res = (prev << 10UL) + res - ((0xd800 << 10UL) + 0xdc00 - 0x10000); - prev = 0; - } - } - if (prev != 0) { - _set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate"); - r_token.type = TK_ERROR; - return ERR_PARSE_ERROR; - } - str += res; - } else { - if (prev != 0) { - _set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate"); - r_token.type = TK_ERROR; - return ERR_PARSE_ERROR; - } - str += ch; - } - } - if (prev != 0) { - _set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate"); - r_token.type = TK_ERROR; - return ERR_PARSE_ERROR; - } - - r_token.type = TK_CONSTANT; - r_token.value = str; - return OK; - - } break; - default: { - if (cchar <= 32) { - break; - } - - if (is_digit(cchar)) { - //a number - - String num; -#define READING_SIGN 0 -#define READING_INT 1 -#define READING_DEC 2 -#define READING_EXP 3 -#define READING_DONE 4 - int reading = READING_INT; - - char32_t c = cchar; - bool exp_sign = false; - bool exp_beg = false; - bool is_float = false; - - while (true) { - switch (reading) { - case READING_INT: { - if (is_digit(c)) { - //pass - } else if (c == '.') { - reading = READING_DEC; - is_float = true; - } else if (c == 'e') { - reading = READING_EXP; - } else { - reading = READING_DONE; - } - - } break; - case READING_DEC: { - if (is_digit(c)) { - } else if (c == 'e') { - reading = READING_EXP; - - } else { - reading = READING_DONE; - } - - } break; - case READING_EXP: { - if (is_digit(c)) { - exp_beg = true; - - } else if ((c == '-' || c == '+') && !exp_sign && !exp_beg) { - if (c == '-') { - is_float = true; - } - exp_sign = true; - - } else { - reading = READING_DONE; - } - } break; - } - - if (reading == READING_DONE) { - break; - } - num += String::chr(c); - c = GET_CHAR(); - } - - str_ofs--; - - r_token.type = TK_CONSTANT; - - if (is_float) { - r_token.value = num.to_float(); - } else { - r_token.value = num.to_int(); - } - return OK; - - } else if (is_ascii_char(cchar) || cchar == '_') { - String id; - bool first = true; - - while (is_ascii_char(cchar) || cchar == '_' || (!first && is_digit(cchar))) { - id += String::chr(cchar); - cchar = GET_CHAR(); - first = false; - } - - str_ofs--; //go back one - - if (id == "in") { - r_token.type = TK_OP_IN; - } else if (id == "null") { - r_token.type = TK_CONSTANT; - r_token.value = Variant(); - } else if (id == "true") { - r_token.type = TK_CONSTANT; - r_token.value = true; - } else if (id == "false") { - r_token.type = TK_CONSTANT; - r_token.value = false; - } else if (id == "PI") { - r_token.type = TK_CONSTANT; - r_token.value = Math_PI; - } else if (id == "TAU") { - r_token.type = TK_CONSTANT; - r_token.value = Math_TAU; - } else if (id == "INF") { - r_token.type = TK_CONSTANT; - r_token.value = INFINITY; - } else if (id == "NAN") { - r_token.type = TK_CONSTANT; - r_token.value = NAN; - } else if (id == "not") { - r_token.type = TK_OP_NOT; - } else if (id == "or") { - r_token.type = TK_OP_OR; - } else if (id == "and") { - r_token.type = TK_OP_AND; - } else if (id == "self") { - r_token.type = TK_SELF; - } else { - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - if (id == Variant::get_type_name(Variant::Type(i))) { - r_token.type = TK_BASIC_TYPE; - r_token.value = i; - return OK; - } - } - - VisualScriptBuiltinFunc::BuiltinFunc bifunc = VisualScriptBuiltinFunc::find_function(id); - if (bifunc != VisualScriptBuiltinFunc::FUNC_MAX) { - r_token.type = TK_BUILTIN_FUNC; - r_token.value = bifunc; - return OK; - } - - r_token.type = TK_IDENTIFIER; - r_token.value = id; - } - - return OK; - } else { - _set_error("Unexpected character."); - r_token.type = TK_ERROR; - return ERR_PARSE_ERROR; - } - } - } - } - - r_token.type = TK_ERROR; - return ERR_PARSE_ERROR; -} - -const char *VisualScriptExpression::token_name[TK_MAX] = { - "CURLY BRACKET OPEN", - "CURLY BRACKET CLOSE", - "BRACKET OPEN", - "BRACKET CLOSE", - "PARENTHESIS OPEN", - "PARENTHESIS CLOSE", - "IDENTIFIER", - "BUILTIN FUNC", - "SELF", - "CONSTANT", - "BASIC TYPE", - "COLON", - "COMMA", - "PERIOD", - "OP IN", - "OP EQUAL", - "OP NOT EQUAL", - "OP LESS", - "OP LESS EQUAL", - "OP GREATER", - "OP GREATER EQUAL", - "OP AND", - "OP OR", - "OP NOT", - "OP ADD", - "OP SUB", - "OP MUL", - "OP DIV", - "OP MOD", - "OP SHIFT LEFT", - "OP SHIFT RIGHT", - "OP BIT AND", - "OP BIT OR", - "OP BIT XOR", - "OP BIT INVERT", - "EOF", - "ERROR" -}; - -VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() { - Vector<Expression> expression; - - while (true) { - //keep appending stuff to expression - ENode *expr = nullptr; - - Token tk; - _get_token(tk); - if (error_set) { - return nullptr; - } - - switch (tk.type) { - case TK_CURLY_BRACKET_OPEN: { - //a dictionary - DictionaryNode *dn = alloc_node<DictionaryNode>(); - - while (true) { - int cofs = str_ofs; - _get_token(tk); - if (tk.type == TK_CURLY_BRACKET_CLOSE) { - break; - } - str_ofs = cofs; //revert - //parse an expression - ENode *expr2 = _parse_expression(); - if (!expr2) { - return nullptr; - } - dn->dict.push_back(expr2); - - _get_token(tk); - if (tk.type != TK_COLON) { - _set_error("Expected ':'"); - return nullptr; - } - - expr2 = _parse_expression(); - if (!expr2) { - return nullptr; - } - - dn->dict.push_back(expr2); - - cofs = str_ofs; - _get_token(tk); - if (tk.type == TK_COMMA) { - //all good - } else if (tk.type == TK_CURLY_BRACKET_CLOSE) { - str_ofs = cofs; - } else { - _set_error("Expected ',' or '}'"); - } - } - - expr = dn; - } break; - case TK_BRACKET_OPEN: { - //an array - - ArrayNode *an = alloc_node<ArrayNode>(); - - while (true) { - int cofs = str_ofs; - _get_token(tk); - if (tk.type == TK_BRACKET_CLOSE) { - break; - } - str_ofs = cofs; //revert - //parse an expression - ENode *expr2 = _parse_expression(); - if (!expr2) { - return nullptr; - } - an->array.push_back(expr2); - - cofs = str_ofs; - _get_token(tk); - if (tk.type == TK_COMMA) { - //all good - } else if (tk.type == TK_BRACKET_CLOSE) { - str_ofs = cofs; - } else { - _set_error("Expected ',' or ']'"); - } - } - - expr = an; - } break; - case TK_PARENTHESIS_OPEN: { - //a suexpression - ENode *e = _parse_expression(); - if (error_set) { - return nullptr; - } - _get_token(tk); - if (tk.type != TK_PARENTHESIS_CLOSE) { - _set_error("Expected ')'"); - return nullptr; - } - - expr = e; - - } break; - case TK_IDENTIFIER: { - String what = tk.value; - int index = -1; - for (int i = 0; i < inputs.size(); i++) { - if (what == inputs[i].name) { - index = i; - break; - } - } - - if (index != -1) { - InputNode *input = alloc_node<InputNode>(); - input->index = index; - expr = input; - } else { - _set_error("Invalid input identifier '" + what + "'. For script variables, use self (locals are for inputs)." + what); - return nullptr; - } - } break; - case TK_SELF: { - SelfNode *self = alloc_node<SelfNode>(); - expr = self; - } break; - case TK_CONSTANT: { - ConstantNode *constant = alloc_node<ConstantNode>(); - constant->value = tk.value; - expr = constant; - } break; - case TK_BASIC_TYPE: { - //constructor.. - - Variant::Type bt = Variant::Type(int(tk.value)); - _get_token(tk); - if (tk.type != TK_PARENTHESIS_OPEN) { - _set_error("Expected '('"); - return nullptr; - } - - ConstructorNode *constructor = alloc_node<ConstructorNode>(); - constructor->data_type = bt; - - while (true) { - int cofs = str_ofs; - _get_token(tk); - if (tk.type == TK_PARENTHESIS_CLOSE) { - break; - } - str_ofs = cofs; //revert - //parse an expression - ENode *expr2 = _parse_expression(); - if (!expr2) { - return nullptr; - } - - constructor->arguments.push_back(expr2); - - cofs = str_ofs; - _get_token(tk); - if (tk.type == TK_COMMA) { - //all good - } else if (tk.type == TK_PARENTHESIS_CLOSE) { - str_ofs = cofs; - } else { - _set_error("Expected ',' or ')'"); - } - } - - expr = constructor; - - } break; - case TK_BUILTIN_FUNC: { - //builtin function - - _get_token(tk); - if (tk.type != TK_PARENTHESIS_OPEN) { - _set_error("Expected '('"); - return nullptr; - } - - BuiltinFuncNode *bifunc = alloc_node<BuiltinFuncNode>(); - bifunc->func = VisualScriptBuiltinFunc::BuiltinFunc(int(tk.value)); - - while (true) { - int cofs = str_ofs; - _get_token(tk); - if (tk.type == TK_PARENTHESIS_CLOSE) { - break; - } - str_ofs = cofs; //revert - //parse an expression - ENode *expr2 = _parse_expression(); - if (!expr2) { - return nullptr; - } - - bifunc->arguments.push_back(expr2); - - cofs = str_ofs; - _get_token(tk); - if (tk.type == TK_COMMA) { - //all good - } else if (tk.type == TK_PARENTHESIS_CLOSE) { - str_ofs = cofs; - } else { - _set_error("Expected ',' or ')'"); - } - } - - int expected_args = VisualScriptBuiltinFunc::get_func_argument_count(bifunc->func); - if (bifunc->arguments.size() != expected_args) { - _set_error("Builtin func '" + VisualScriptBuiltinFunc::get_func_name(bifunc->func) + "' expects " + itos(expected_args) + " arguments."); - } - - expr = bifunc; - - } break; - case TK_OP_SUB: { - Expression e; - e.is_op = true; - e.op = Variant::OP_NEGATE; - expression.push_back(e); - continue; - } break; - case TK_OP_NOT: { - Expression e; - e.is_op = true; - e.op = Variant::OP_NOT; - expression.push_back(e); - continue; - } break; - - default: { - _set_error("Expected expression."); - return nullptr; - } break; - } - - //before going to operators, must check indexing! - - while (true) { - int cofs2 = str_ofs; - _get_token(tk); - if (error_set) { - return nullptr; - } - - bool done = false; - - switch (tk.type) { - case TK_BRACKET_OPEN: { - //value indexing - - IndexNode *index = alloc_node<IndexNode>(); - index->base = expr; - - ENode *what = _parse_expression(); - if (!what) { - return nullptr; - } - - index->index = what; - - _get_token(tk); - if (tk.type != TK_BRACKET_CLOSE) { - _set_error("Expected ']' at end of index."); - return nullptr; - } - expr = index; - - } break; - case TK_PERIOD: { - //named indexing or function call - _get_token(tk); - if (tk.type != TK_IDENTIFIER) { - _set_error("Expected identifier after '.'"); - return nullptr; - } - - StringName identifier = tk.value; - - int cofs = str_ofs; - _get_token(tk); - if (tk.type == TK_PARENTHESIS_OPEN) { - //function call - CallNode *func_call = alloc_node<CallNode>(); - func_call->method = identifier; - func_call->base = expr; - - while (true) { - int cofs3 = str_ofs; - _get_token(tk); - if (tk.type == TK_PARENTHESIS_CLOSE) { - break; - } - str_ofs = cofs3; //revert - //parse an expression - ENode *expr2 = _parse_expression(); - if (!expr2) { - return nullptr; - } - - func_call->arguments.push_back(expr2); - - cofs3 = str_ofs; - _get_token(tk); - if (tk.type == TK_COMMA) { - //all good - } else if (tk.type == TK_PARENTHESIS_CLOSE) { - str_ofs = cofs3; - } else { - _set_error("Expected ',' or ')'"); - } - } - - expr = func_call; - } else { - //named indexing - str_ofs = cofs; - - NamedIndexNode *index = alloc_node<NamedIndexNode>(); - index->base = expr; - index->name = identifier; - expr = index; - } - - } break; - default: { - str_ofs = cofs2; - done = true; - } break; - } - - if (done) { - break; - } - } - - //push expression - { - Expression e; - e.is_op = false; - e.node = expr; - expression.push_back(e); - } - - //ok finally look for an operator - - int cofs = str_ofs; - _get_token(tk); - if (error_set) { - return nullptr; - } - - Variant::Operator op = Variant::OP_MAX; - - switch (tk.type) { - case TK_OP_IN: - op = Variant::OP_IN; - break; - case TK_OP_EQUAL: - op = Variant::OP_EQUAL; - break; - case TK_OP_NOT_EQUAL: - op = Variant::OP_NOT_EQUAL; - break; - case TK_OP_LESS: - op = Variant::OP_LESS; - break; - case TK_OP_LESS_EQUAL: - op = Variant::OP_LESS_EQUAL; - break; - case TK_OP_GREATER: - op = Variant::OP_GREATER; - break; - case TK_OP_GREATER_EQUAL: - op = Variant::OP_GREATER_EQUAL; - break; - case TK_OP_AND: - op = Variant::OP_AND; - break; - case TK_OP_OR: - op = Variant::OP_OR; - break; - case TK_OP_NOT: - op = Variant::OP_NOT; - break; - case TK_OP_ADD: - op = Variant::OP_ADD; - break; - case TK_OP_SUB: - op = Variant::OP_SUBTRACT; - break; - case TK_OP_MUL: - op = Variant::OP_MULTIPLY; - break; - case TK_OP_DIV: - op = Variant::OP_DIVIDE; - break; - case TK_OP_MOD: - op = Variant::OP_MODULE; - break; - case TK_OP_SHIFT_LEFT: - op = Variant::OP_SHIFT_LEFT; - break; - case TK_OP_SHIFT_RIGHT: - op = Variant::OP_SHIFT_RIGHT; - break; - case TK_OP_BIT_AND: - op = Variant::OP_BIT_AND; - break; - case TK_OP_BIT_OR: - op = Variant::OP_BIT_OR; - break; - case TK_OP_BIT_XOR: - op = Variant::OP_BIT_XOR; - break; - case TK_OP_BIT_INVERT: - op = Variant::OP_BIT_NEGATE; - break; - default: { - }; - } - - if (op == Variant::OP_MAX) { //stop appending stuff - str_ofs = cofs; - break; - } - - //push operator and go on - { - Expression e; - e.is_op = true; - e.op = op; - expression.push_back(e); - } - } - - /* Reduce the set of expressions and place them in an operator tree, respecting precedence */ - - while (expression.size() > 1) { - int next_op = -1; - int min_priority = 0xFFFFF; - bool is_unary = false; - - for (int i = 0; i < expression.size(); i++) { - if (!expression[i].is_op) { - continue; - } - - int priority; - - bool unary = false; - - switch (expression[i].op) { - case Variant::OP_BIT_NEGATE: - priority = 0; - unary = true; - break; - case Variant::OP_NEGATE: - priority = 1; - unary = true; - break; - - case Variant::OP_MULTIPLY: - priority = 2; - break; - case Variant::OP_DIVIDE: - priority = 2; - break; - case Variant::OP_MODULE: - priority = 2; - break; - - case Variant::OP_ADD: - priority = 3; - break; - case Variant::OP_SUBTRACT: - priority = 3; - break; - - case Variant::OP_SHIFT_LEFT: - priority = 4; - break; - case Variant::OP_SHIFT_RIGHT: - priority = 4; - break; - - case Variant::OP_BIT_AND: - priority = 5; - break; - case Variant::OP_BIT_XOR: - priority = 6; - break; - case Variant::OP_BIT_OR: - priority = 7; - break; - - case Variant::OP_LESS: - priority = 8; - break; - case Variant::OP_LESS_EQUAL: - priority = 8; - break; - case Variant::OP_GREATER: - priority = 8; - break; - case Variant::OP_GREATER_EQUAL: - priority = 8; - break; - - case Variant::OP_EQUAL: - priority = 8; - break; - case Variant::OP_NOT_EQUAL: - priority = 8; - break; - - case Variant::OP_IN: - priority = 10; - break; - - case Variant::OP_NOT: - priority = 11; - unary = true; - break; - case Variant::OP_AND: - priority = 12; - break; - case Variant::OP_OR: - priority = 13; - break; - - default: { - _set_error("Parser bug, invalid operator in expression: " + itos(expression[i].op)); - return nullptr; - } - } - - if (priority < min_priority) { - // < is used for left to right (default) - // <= is used for right to left - - next_op = i; - min_priority = priority; - is_unary = unary; - } - } - - if (next_op == -1) { - _set_error("Yet another parser bug...."); - ERR_FAIL_V(nullptr); - } - - // OK! create operator.. - if (is_unary) { - int expr_pos = next_op; - while (expression[expr_pos].is_op) { - expr_pos++; - if (expr_pos == expression.size()) { - //can happen.. - _set_error("Unexpected end of expression..."); - return nullptr; - } - } - - //consecutively do unary operators - for (int i = expr_pos - 1; i >= next_op; i--) { - OperatorNode *op = alloc_node<OperatorNode>(); - op->op = expression[i].op; - op->nodes[0] = expression[i + 1].node; - op->nodes[1] = nullptr; - expression.write[i].is_op = false; - expression.write[i].node = op; - expression.remove_at(i + 1); - } - - } else { - if (next_op < 1 || next_op >= (expression.size() - 1)) { - _set_error("Parser bug..."); - ERR_FAIL_V(nullptr); - } - - OperatorNode *op = alloc_node<OperatorNode>(); - op->op = expression[next_op].op; - - if (expression[next_op - 1].is_op) { - _set_error("Parser bug..."); - ERR_FAIL_V(nullptr); - } - - if (expression[next_op + 1].is_op) { - // this is not invalid and can really appear - // but it becomes invalid anyway because no binary op - // can be followed by a unary op in a valid combination, - // due to how precedence works, unaries will always disappear first - - _set_error("Unexpected two consecutive operators."); - return nullptr; - } - - op->nodes[0] = expression[next_op - 1].node; //expression goes as left - op->nodes[1] = expression[next_op + 1].node; //next expression goes as right - - //replace all 3 nodes by this operator and make it an expression - expression.write[next_op - 1].node = op; - expression.remove_at(next_op); - expression.remove_at(next_op); - } - } - - return expression[0].node; -} - -bool VisualScriptExpression::_compile_expression() { - if (!expression_dirty) { - return error_set; - } - - if (nodes) { - memdelete(nodes); - nodes = nullptr; - root = nullptr; - } - - error_str = String(); - error_set = false; - str_ofs = 0; - - root = _parse_expression(); - - if (error_set) { - root = nullptr; - if (nodes) { - memdelete(nodes); - } - nodes = nullptr; - return true; - } - - expression_dirty = false; - return false; -} - -class VisualScriptNodeInstanceExpression : public VisualScriptNodeInstance { -public: - VisualScriptInstance *instance = nullptr; - VisualScriptExpression *expression = nullptr; - - //virtual int get_working_memory_size() const override { return 0; } - //execute by parsing the tree directly - virtual bool _execute(const Variant **p_inputs, VisualScriptExpression::ENode *p_node, Variant &r_ret, String &r_error_str, Callable::CallError &ce) { - switch (p_node->type) { - case VisualScriptExpression::ENode::TYPE_INPUT: { - const VisualScriptExpression::InputNode *in = static_cast<const VisualScriptExpression::InputNode *>(p_node); - r_ret = *p_inputs[in->index]; - } break; - case VisualScriptExpression::ENode::TYPE_CONSTANT: { - const VisualScriptExpression::ConstantNode *c = static_cast<const VisualScriptExpression::ConstantNode *>(p_node); - r_ret = c->value; - - } break; - case VisualScriptExpression::ENode::TYPE_SELF: { - r_ret = instance->get_owner_ptr(); - } break; - case VisualScriptExpression::ENode::TYPE_OPERATOR: { - const VisualScriptExpression::OperatorNode *op = static_cast<const VisualScriptExpression::OperatorNode *>(p_node); - - Variant a; - bool ret = _execute(p_inputs, op->nodes[0], a, r_error_str, ce); - if (ret) { - return true; - } - - Variant b; - - if (op->nodes[1]) { - ret = _execute(p_inputs, op->nodes[1], b, r_error_str, ce); - if (ret) { - return true; - } - } - - bool valid = true; - Variant::evaluate(op->op, a, b, r_ret, valid); - if (!valid) { - r_error_str = "Invalid operands to operator " + Variant::get_operator_name(op->op) + ": " + Variant::get_type_name(a.get_type()) + " and " + Variant::get_type_name(b.get_type()) + "."; - return true; - } - - } break; - case VisualScriptExpression::ENode::TYPE_INDEX: { - const VisualScriptExpression::IndexNode *index = static_cast<const VisualScriptExpression::IndexNode *>(p_node); - - Variant base; - bool ret = _execute(p_inputs, index->base, base, r_error_str, ce); - if (ret) { - return true; - } - - Variant idx; - - ret = _execute(p_inputs, index->index, idx, r_error_str, ce); - if (ret) { - return true; - } - - bool valid; - r_ret = base.get(idx, &valid); - if (!valid) { - r_error_str = "Invalid index of type " + Variant::get_type_name(idx.get_type()) + " for base of type " + Variant::get_type_name(base.get_type()) + "."; - return true; - } - - } break; - case VisualScriptExpression::ENode::TYPE_NAMED_INDEX: { - const VisualScriptExpression::NamedIndexNode *index = static_cast<const VisualScriptExpression::NamedIndexNode *>(p_node); - - Variant base; - bool ret = _execute(p_inputs, index->base, base, r_error_str, ce); - if (ret) { - return true; - } - - bool valid; - r_ret = base.get_named(index->name, valid); - if (!valid) { - r_error_str = "Invalid index '" + String(index->name) + "' for base of type " + Variant::get_type_name(base.get_type()) + "."; - return true; - } - - } break; - case VisualScriptExpression::ENode::TYPE_ARRAY: { - const VisualScriptExpression::ArrayNode *array = static_cast<const VisualScriptExpression::ArrayNode *>(p_node); - - Array arr; - arr.resize(array->array.size()); - for (int i = 0; i < array->array.size(); i++) { - Variant value; - bool ret = _execute(p_inputs, array->array[i], value, r_error_str, ce); - if (ret) { - return true; - } - arr[i] = value; - } - - r_ret = arr; - - } break; - case VisualScriptExpression::ENode::TYPE_DICTIONARY: { - const VisualScriptExpression::DictionaryNode *dictionary = static_cast<const VisualScriptExpression::DictionaryNode *>(p_node); - - Dictionary d; - for (int i = 0; i < dictionary->dict.size(); i += 2) { - Variant key; - bool ret = _execute(p_inputs, dictionary->dict[i + 0], key, r_error_str, ce); - if (ret) { - return true; - } - - Variant value; - ret = _execute(p_inputs, dictionary->dict[i + 1], value, r_error_str, ce); - if (ret) { - return true; - } - - d[key] = value; - } - - r_ret = d; - } break; - case VisualScriptExpression::ENode::TYPE_CONSTRUCTOR: { - const VisualScriptExpression::ConstructorNode *constructor = static_cast<const VisualScriptExpression::ConstructorNode *>(p_node); - - Vector<Variant> arr; - Vector<const Variant *> argp; - arr.resize(constructor->arguments.size()); - argp.resize(constructor->arguments.size()); - - for (int i = 0; i < constructor->arguments.size(); i++) { - Variant value; - bool ret = _execute(p_inputs, constructor->arguments[i], value, r_error_str, ce); - if (ret) { - return true; - } - arr.write[i] = value; - argp.write[i] = &arr[i]; - } - - Variant::construct(constructor->data_type, r_ret, (const Variant **)argp.ptr(), argp.size(), ce); - - if (ce.error != Callable::CallError::CALL_OK) { - r_error_str = "Invalid arguments to construct '" + Variant::get_type_name(constructor->data_type) + "'."; - return true; - } - - } break; - case VisualScriptExpression::ENode::TYPE_BUILTIN_FUNC: { - const VisualScriptExpression::BuiltinFuncNode *bifunc = static_cast<const VisualScriptExpression::BuiltinFuncNode *>(p_node); - - Vector<Variant> arr; - Vector<const Variant *> argp; - arr.resize(bifunc->arguments.size()); - argp.resize(bifunc->arguments.size()); - - for (int i = 0; i < bifunc->arguments.size(); i++) { - Variant value; - bool ret = _execute(p_inputs, bifunc->arguments[i], value, r_error_str, ce); - if (ret) { - return true; - } - arr.write[i] = value; - argp.write[i] = &arr[i]; - } - - VisualScriptBuiltinFunc::exec_func(bifunc->func, (const Variant **)argp.ptr(), &r_ret, ce, r_error_str); - - if (ce.error != Callable::CallError::CALL_OK) { - r_error_str = "Builtin Call Failed. " + r_error_str; - return true; - } - - } break; - case VisualScriptExpression::ENode::TYPE_CALL: { - const VisualScriptExpression::CallNode *call = static_cast<const VisualScriptExpression::CallNode *>(p_node); - - Variant base; - bool ret = _execute(p_inputs, call->base, base, r_error_str, ce); - if (ret) { - return true; - } - - Vector<Variant> arr; - Vector<const Variant *> argp; - arr.resize(call->arguments.size()); - argp.resize(call->arguments.size()); - - for (int i = 0; i < call->arguments.size(); i++) { - Variant value; - bool ret2 = _execute(p_inputs, call->arguments[i], value, r_error_str, ce); - if (ret2) { - return true; - } - arr.write[i] = value; - argp.write[i] = &arr[i]; - } - - base.callp(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce); - - if (ce.error != Callable::CallError::CALL_OK) { - r_error_str = "On call to '" + String(call->method) + "':"; - return true; - } - - } break; - } - return false; - } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - if (!expression->root || expression->error_set) { - r_error_str = expression->error_str; - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - return 0; - } - - bool error = _execute(p_inputs, expression->root, *p_outputs[0], r_error_str, r_error); - if (error && r_error.error == Callable::CallError::CALL_OK) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - } - -#ifdef DEBUG_ENABLED - if (!error && expression->output_type != Variant::NIL && !Variant::can_convert_strict(p_outputs[0]->get_type(), expression->output_type)) { - r_error_str += "Can't convert expression result from " + Variant::get_type_name(p_outputs[0]->get_type()) + " to " + Variant::get_type_name(expression->output_type) + "."; - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - } -#endif - - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptExpression::instantiate(VisualScriptInstance *p_instance) { - _compile_expression(); - VisualScriptNodeInstanceExpression *instance = memnew(VisualScriptNodeInstanceExpression); - instance->instance = p_instance; - instance->expression = this; - return instance; -} - -void VisualScriptExpression::reset_state() { - if (nodes) { - memdelete(nodes); - nodes = nullptr; - root = nullptr; - } - - error_str = String(); - error_set = false; - str_ofs = 0; - inputs.clear(); -} - -VisualScriptExpression::VisualScriptExpression() { -} - -VisualScriptExpression::~VisualScriptExpression() { - if (nodes) { - memdelete(nodes); - } -} - -void register_visual_script_expression_node() { - VisualScriptLanguage::singleton->add_register_func("operators/expression", create_node_generic<VisualScriptExpression>); -} diff --git a/modules/visual_script/visual_script_expression.h b/modules/visual_script/visual_script_expression.h deleted file mode 100644 index 7e10f98f36..0000000000 --- a/modules/visual_script/visual_script_expression.h +++ /dev/null @@ -1,284 +0,0 @@ -/*************************************************************************/ -/* visual_script_expression.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 VISUAL_SCRIPT_EXPRESSION_H -#define VISUAL_SCRIPT_EXPRESSION_H - -#include "visual_script.h" -#include "visual_script_builtin_funcs.h" - -class VisualScriptExpression : public VisualScriptNode { - GDCLASS(VisualScriptExpression, VisualScriptNode); - friend class VisualScriptNodeInstanceExpression; - - struct Input { - Variant::Type type = Variant::NIL; - String name; - }; - - Vector<Input> inputs; - Variant::Type output_type = Variant::NIL; - - String expression; - - bool sequenced = false; - int str_ofs = 0; - bool expression_dirty = true; - - bool _compile_expression(); - - enum TokenType { - TK_CURLY_BRACKET_OPEN, - TK_CURLY_BRACKET_CLOSE, - TK_BRACKET_OPEN, - TK_BRACKET_CLOSE, - TK_PARENTHESIS_OPEN, - TK_PARENTHESIS_CLOSE, - TK_IDENTIFIER, - TK_BUILTIN_FUNC, - TK_SELF, - TK_CONSTANT, - TK_BASIC_TYPE, - TK_COLON, - TK_COMMA, - TK_PERIOD, - TK_OP_IN, - TK_OP_EQUAL, - TK_OP_NOT_EQUAL, - TK_OP_LESS, - TK_OP_LESS_EQUAL, - TK_OP_GREATER, - TK_OP_GREATER_EQUAL, - TK_OP_AND, - TK_OP_OR, - TK_OP_NOT, - TK_OP_ADD, - TK_OP_SUB, - TK_OP_MUL, - TK_OP_DIV, - TK_OP_MOD, - TK_OP_SHIFT_LEFT, - TK_OP_SHIFT_RIGHT, - TK_OP_BIT_AND, - TK_OP_BIT_OR, - TK_OP_BIT_XOR, - TK_OP_BIT_INVERT, - TK_EOF, - TK_ERROR, - TK_MAX - }; - - static const char *token_name[TK_MAX]; - struct Token { - TokenType type; - Variant value; - }; - - void _set_error(const String &p_err) { - if (error_set) { - return; - } - error_str = p_err; - error_set = true; - } - - Error _get_token(Token &r_token); - - String error_str; - bool error_set = true; - - struct ENode { - enum Type { - TYPE_INPUT, - TYPE_CONSTANT, - TYPE_SELF, - TYPE_OPERATOR, - TYPE_INDEX, - TYPE_NAMED_INDEX, - TYPE_ARRAY, - TYPE_DICTIONARY, - TYPE_CONSTRUCTOR, - TYPE_BUILTIN_FUNC, - TYPE_CALL - }; - - ENode *next = nullptr; - - Type type = Type::TYPE_SELF; - - virtual ~ENode() { - if (next) { - memdelete(next); - } - } - }; - - struct Expression { - bool is_op = false; - union { - Variant::Operator op; - ENode *node = nullptr; - }; - }; - - ENode *_parse_expression(); - - struct InputNode : public ENode { - int index = 0; - InputNode() { - type = TYPE_INPUT; - } - }; - - struct ConstantNode : public ENode { - Variant value; - ConstantNode() { - type = TYPE_CONSTANT; - } - }; - - struct OperatorNode : public ENode { - Variant::Operator op = Variant::Operator::OP_ADD; - - ENode *nodes[2] = { nullptr, nullptr }; - - OperatorNode() { - type = TYPE_OPERATOR; - } - }; - - struct SelfNode : public ENode { - SelfNode() { - type = TYPE_SELF; - } - }; - - struct IndexNode : public ENode { - ENode *base = nullptr; - ENode *index = nullptr; - - IndexNode() { - type = TYPE_INDEX; - } - }; - - struct NamedIndexNode : public ENode { - ENode *base = nullptr; - StringName name; - - NamedIndexNode() { - type = TYPE_NAMED_INDEX; - } - }; - - struct ConstructorNode : public ENode { - Variant::Type data_type = Variant::Type::NIL; - Vector<ENode *> arguments; - - ConstructorNode() { - type = TYPE_CONSTRUCTOR; - } - }; - - struct CallNode : public ENode { - ENode *base = nullptr; - StringName method; - Vector<ENode *> arguments; - - CallNode() { - type = TYPE_CALL; - } - }; - - struct ArrayNode : public ENode { - Vector<ENode *> array; - ArrayNode() { - type = TYPE_ARRAY; - } - }; - - struct DictionaryNode : public ENode { - Vector<ENode *> dict; - DictionaryNode() { - type = TYPE_DICTIONARY; - } - }; - - struct BuiltinFuncNode : public ENode { - VisualScriptBuiltinFunc::BuiltinFunc func = VisualScriptBuiltinFunc::BuiltinFunc::BYTES_TO_VAR; - Vector<ENode *> arguments; - BuiltinFuncNode() { - type = TYPE_BUILTIN_FUNC; - } - }; - - template <class T> - T *alloc_node() { - T *node = memnew(T); - node->next = nodes; - nodes = node; - return node; - } - - ENode *root = nullptr; - ENode *nodes = nullptr; - -protected: - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List<PropertyInfo> *p_list) const; - -public: - virtual void reset_state() override; - - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "operators"; } - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptExpression(); - ~VisualScriptExpression(); -}; - -void register_visual_script_expression_node(); - -#endif // VISUAL_SCRIPT_EXPRESSION_H diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp deleted file mode 100644 index 19bbd834cc..0000000000 --- a/modules/visual_script/visual_script_flow_control.cpp +++ /dev/null @@ -1,880 +0,0 @@ -/*************************************************************************/ -/* visual_script_flow_control.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "visual_script_flow_control.h" - -#include "core/config/project_settings.h" -#include "core/io/resource_loader.h" -#include "core/os/keyboard.h" - -////////////////////////////////////////// -////////////////RETURN//////////////////// -////////////////////////////////////////// - -int VisualScriptReturn::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptReturn::has_input_sequence_port() const { - return true; -} - -int VisualScriptReturn::get_input_value_port_count() const { - return with_value ? 1 : 0; -} - -int VisualScriptReturn::get_output_value_port_count() const { - return 0; -} - -String VisualScriptReturn::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptReturn::get_input_value_port_info(int p_idx) const { - PropertyInfo pinfo; - pinfo.name = "result"; - pinfo.type = type; - return pinfo; -} - -PropertyInfo VisualScriptReturn::get_output_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -String VisualScriptReturn::get_caption() const { - return RTR("Return"); -} - -String VisualScriptReturn::get_text() const { - return get_name(); -} - -void VisualScriptReturn::set_return_type(Variant::Type p_type) { - if (type == p_type) { - return; - } - type = p_type; - ports_changed_notify(); -} - -Variant::Type VisualScriptReturn::get_return_type() const { - return type; -} - -void VisualScriptReturn::set_enable_return_value(bool p_enable) { - if (with_value == p_enable) { - return; - } - - with_value = p_enable; - ports_changed_notify(); -} - -bool VisualScriptReturn::is_return_value_enabled() const { - return with_value; -} - -void VisualScriptReturn::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_return_type", "type"), &VisualScriptReturn::set_return_type); - ClassDB::bind_method(D_METHOD("get_return_type"), &VisualScriptReturn::get_return_type); - ClassDB::bind_method(D_METHOD("set_enable_return_value", "enable"), &VisualScriptReturn::set_enable_return_value); - ClassDB::bind_method(D_METHOD("is_return_value_enabled"), &VisualScriptReturn::is_return_value_enabled); - - String argt = "Any"; - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - argt += "," + Variant::get_type_name(Variant::Type(i)); - } - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "return_enabled"), "set_enable_return_value", "is_return_value_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "return_type", PROPERTY_HINT_ENUM, argt), "set_return_type", "get_return_type"); -} - -class VisualScriptNodeInstanceReturn : public VisualScriptNodeInstance { -public: - VisualScriptReturn *node = nullptr; - VisualScriptInstance *instance = nullptr; - bool with_value = false; - - virtual int get_working_memory_size() const override { return 1; } - //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } - //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - if (with_value) { - *p_working_mem = *p_inputs[0]; - return STEP_EXIT_FUNCTION_BIT; - } else { - *p_working_mem = Variant(); - return 0; - } - } -}; - -VisualScriptNodeInstance *VisualScriptReturn::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceReturn *instance = memnew(VisualScriptNodeInstanceReturn); - instance->node = this; - instance->instance = p_instance; - instance->with_value = with_value; - return instance; -} - -VisualScriptReturn::VisualScriptReturn() { - with_value = false; - type = Variant::NIL; -} - -template <bool with_value> -static Ref<VisualScriptNode> create_return_node(const String &p_name) { - Ref<VisualScriptReturn> node; - node.instantiate(); - node->set_enable_return_value(with_value); - return node; -} - -////////////////////////////////////////// -////////////////CONDITION///////////////// -////////////////////////////////////////// - -int VisualScriptCondition::get_output_sequence_port_count() const { - return 3; -} - -bool VisualScriptCondition::has_input_sequence_port() const { - return true; -} - -int VisualScriptCondition::get_input_value_port_count() const { - return 1; -} - -int VisualScriptCondition::get_output_value_port_count() const { - return 0; -} - -String VisualScriptCondition::get_output_sequence_port_text(int p_port) const { - if (p_port == 0) { - return "true"; - } else if (p_port == 1) { - return "false"; - } else { - return "done"; - } -} - -PropertyInfo VisualScriptCondition::get_input_value_port_info(int p_idx) const { - PropertyInfo pinfo; - pinfo.name = "cond"; - pinfo.type = Variant::BOOL; - return pinfo; -} - -PropertyInfo VisualScriptCondition::get_output_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -String VisualScriptCondition::get_caption() const { - return RTR("Condition"); -} - -String VisualScriptCondition::get_text() const { - return RTR("if (cond) is:"); -} - -void VisualScriptCondition::_bind_methods() { -} - -class VisualScriptNodeInstanceCondition : public VisualScriptNodeInstance { -public: - VisualScriptCondition *node = nullptr; - VisualScriptInstance *instance = nullptr; - - //virtual int get_working_memory_size() const override { return 1; } - //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } - //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - if (p_start_mode == START_MODE_CONTINUE_SEQUENCE) { - return 2; - } else if (p_inputs[0]->operator bool()) { - return 0 | STEP_FLAG_PUSH_STACK_BIT; - } else { - return 1 | STEP_FLAG_PUSH_STACK_BIT; - } - } -}; - -VisualScriptNodeInstance *VisualScriptCondition::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceCondition *instance = memnew(VisualScriptNodeInstanceCondition); - instance->node = this; - instance->instance = p_instance; - return instance; -} - -VisualScriptCondition::VisualScriptCondition() { -} - -////////////////////////////////////////// -////////////////WHILE///////////////// -////////////////////////////////////////// - -int VisualScriptWhile::get_output_sequence_port_count() const { - return 2; -} - -bool VisualScriptWhile::has_input_sequence_port() const { - return true; -} - -int VisualScriptWhile::get_input_value_port_count() const { - return 1; -} - -int VisualScriptWhile::get_output_value_port_count() const { - return 0; -} - -String VisualScriptWhile::get_output_sequence_port_text(int p_port) const { - if (p_port == 0) { - return "repeat"; - } else { - return "exit"; - } -} - -PropertyInfo VisualScriptWhile::get_input_value_port_info(int p_idx) const { - PropertyInfo pinfo; - pinfo.name = "cond"; - pinfo.type = Variant::BOOL; - return pinfo; -} - -PropertyInfo VisualScriptWhile::get_output_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -String VisualScriptWhile::get_caption() const { - return RTR("While"); -} - -String VisualScriptWhile::get_text() const { - return RTR("while (cond):"); -} - -void VisualScriptWhile::_bind_methods() { -} - -class VisualScriptNodeInstanceWhile : public VisualScriptNodeInstance { -public: - VisualScriptWhile *node = nullptr; - VisualScriptInstance *instance = nullptr; - - //virtual int get_working_memory_size() const override { return 1; } - //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } - //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - bool keep_going = p_inputs[0]->operator bool(); - - if (keep_going) { - return 0 | STEP_FLAG_PUSH_STACK_BIT; - } else { - return 1; - } - } -}; - -VisualScriptNodeInstance *VisualScriptWhile::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceWhile *instance = memnew(VisualScriptNodeInstanceWhile); - instance->node = this; - instance->instance = p_instance; - return instance; -} - -VisualScriptWhile::VisualScriptWhile() { -} - -////////////////////////////////////////// -////////////////ITERATOR///////////////// -////////////////////////////////////////// - -int VisualScriptIterator::get_output_sequence_port_count() const { - return 2; -} - -bool VisualScriptIterator::has_input_sequence_port() const { - return true; -} - -int VisualScriptIterator::get_input_value_port_count() const { - return 1; -} - -int VisualScriptIterator::get_output_value_port_count() const { - return 1; -} - -String VisualScriptIterator::get_output_sequence_port_text(int p_port) const { - if (p_port == 0) { - return "each"; - } else { - return "exit"; - } -} - -PropertyInfo VisualScriptIterator::get_input_value_port_info(int p_idx) const { - PropertyInfo pinfo; - pinfo.name = "input"; - pinfo.type = Variant::NIL; - return pinfo; -} - -PropertyInfo VisualScriptIterator::get_output_value_port_info(int p_idx) const { - PropertyInfo pinfo; - pinfo.name = "elem"; - pinfo.type = Variant::NIL; - return pinfo; -} - -String VisualScriptIterator::get_caption() const { - return RTR("Iterator"); -} - -String VisualScriptIterator::get_text() const { - return RTR("for (elem) in (input):"); -} - -void VisualScriptIterator::_bind_methods() { -} - -class VisualScriptNodeInstanceIterator : public VisualScriptNodeInstance { -public: - VisualScriptIterator *node = nullptr; - VisualScriptInstance *instance = nullptr; - - virtual int get_working_memory_size() const override { return 2; } - //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } - //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - if (p_start_mode == START_MODE_BEGIN_SEQUENCE) { - p_working_mem[0] = *p_inputs[0]; - bool valid; - bool can_iter = p_inputs[0]->iter_init(p_working_mem[1], valid); - - if (!valid) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = RTR("Input type not iterable:") + " " + Variant::get_type_name(p_inputs[0]->get_type()); - return 0; - } - - if (!can_iter) { - return 1; //nothing to iterate - } - - *p_outputs[0] = p_working_mem[0].iter_get(p_working_mem[1], valid); - - if (!valid) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = RTR("Iterator became invalid"); - return 0; - } - - } else { //continue sequence - - bool valid; - bool can_iter = p_working_mem[0].iter_next(p_working_mem[1], valid); - - if (!valid) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = RTR("Iterator became invalid:") + " " + Variant::get_type_name(p_inputs[0]->get_type()); - return 0; - } - - if (!can_iter) { - return 1; //nothing to iterate - } - - *p_outputs[0] = p_working_mem[0].iter_get(p_working_mem[1], valid); - - if (!valid) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = RTR("Iterator became invalid"); - return 0; - } - } - - return 0 | STEP_FLAG_PUSH_STACK_BIT; //go around - } -}; - -VisualScriptNodeInstance *VisualScriptIterator::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceIterator *instance = memnew(VisualScriptNodeInstanceIterator); - instance->node = this; - instance->instance = p_instance; - return instance; -} - -VisualScriptIterator::VisualScriptIterator() { -} - -////////////////////////////////////////// -////////////////SEQUENCE///////////////// -////////////////////////////////////////// - -int VisualScriptSequence::get_output_sequence_port_count() const { - return steps; -} - -bool VisualScriptSequence::has_input_sequence_port() const { - return true; -} - -int VisualScriptSequence::get_input_value_port_count() const { - return 0; -} - -int VisualScriptSequence::get_output_value_port_count() const { - return 1; -} - -String VisualScriptSequence::get_output_sequence_port_text(int p_port) const { - return itos(p_port + 1); -} - -PropertyInfo VisualScriptSequence::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptSequence::get_output_value_port_info(int p_idx) const { - return PropertyInfo(Variant::INT, "current"); -} - -String VisualScriptSequence::get_caption() const { - return RTR("Sequence"); -} - -String VisualScriptSequence::get_text() const { - return RTR("in order:"); -} - -void VisualScriptSequence::set_steps(int p_steps) { - ERR_FAIL_COND(p_steps < 1); - if (steps == p_steps) { - return; - } - - steps = p_steps; - ports_changed_notify(); -} - -int VisualScriptSequence::get_steps() const { - return steps; -} - -void VisualScriptSequence::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_steps", "steps"), &VisualScriptSequence::set_steps); - ClassDB::bind_method(D_METHOD("get_steps"), &VisualScriptSequence::get_steps); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "steps", PROPERTY_HINT_RANGE, "1,64,1"), "set_steps", "get_steps"); -} - -class VisualScriptNodeInstanceSequence : public VisualScriptNodeInstance { -public: - VisualScriptSequence *node = nullptr; - VisualScriptInstance *instance = nullptr; - int steps = 0; - - virtual int get_working_memory_size() const override { return 1; } - //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } - //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - if (p_start_mode == START_MODE_BEGIN_SEQUENCE) { - p_working_mem[0] = 0; - } - - int step = p_working_mem[0]; - - *p_outputs[0] = step; - - if (step + 1 == steps) { - return step; - } else { - p_working_mem[0] = step + 1; - return step | STEP_FLAG_PUSH_STACK_BIT; - } - } -}; - -VisualScriptNodeInstance *VisualScriptSequence::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceSequence *instance = memnew(VisualScriptNodeInstanceSequence); - instance->node = this; - instance->instance = p_instance; - instance->steps = steps; - return instance; -} - -VisualScriptSequence::VisualScriptSequence() { - steps = 1; -} - -////////////////////////////////////////// -////////////////EVENT TYPE FILTER/////////// -////////////////////////////////////////// - -int VisualScriptSwitch::get_output_sequence_port_count() const { - return case_values.size() + 1; -} - -bool VisualScriptSwitch::has_input_sequence_port() const { - return true; -} - -int VisualScriptSwitch::get_input_value_port_count() const { - return case_values.size() + 1; -} - -int VisualScriptSwitch::get_output_value_port_count() const { - return 0; -} - -String VisualScriptSwitch::get_output_sequence_port_text(int p_port) const { - if (p_port == case_values.size()) { - return "done"; - } - - return String(); -} - -PropertyInfo VisualScriptSwitch::get_input_value_port_info(int p_idx) const { - if (p_idx < case_values.size()) { - return PropertyInfo(case_values[p_idx].type, " ="); - } else { - return PropertyInfo(Variant::NIL, "input"); - } -} - -PropertyInfo VisualScriptSwitch::get_output_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -String VisualScriptSwitch::get_caption() const { - return RTR("Switch"); -} - -String VisualScriptSwitch::get_text() const { - return RTR("'input' is:"); -} - -class VisualScriptNodeInstanceSwitch : public VisualScriptNodeInstance { -public: - VisualScriptInstance *instance = nullptr; - int case_count = 0; - - //virtual int get_working_memory_size() const override { return 0; } - //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } - //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - if (p_start_mode == START_MODE_CONTINUE_SEQUENCE) { - return case_count; //exit - } - - for (int i = 0; i < case_count; i++) { - if (*p_inputs[i] == *p_inputs[case_count]) { - return i | STEP_FLAG_PUSH_STACK_BIT; - } - } - - return case_count; - } -}; - -VisualScriptNodeInstance *VisualScriptSwitch::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceSwitch *instance = memnew(VisualScriptNodeInstanceSwitch); - instance->instance = p_instance; - instance->case_count = case_values.size(); - return instance; -} - -bool VisualScriptSwitch::_set(const StringName &p_name, const Variant &p_value) { - if (String(p_name) == "case_count") { - case_values.resize(p_value); - notify_property_list_changed(); - ports_changed_notify(); - return true; - } - - if (String(p_name).begins_with("case/")) { - int idx = String(p_name).get_slice("/", 1).to_int(); - ERR_FAIL_INDEX_V(idx, case_values.size(), false); - - case_values.write[idx].type = Variant::Type(int(p_value)); - notify_property_list_changed(); - ports_changed_notify(); - - return true; - } - - return false; -} - -bool VisualScriptSwitch::_get(const StringName &p_name, Variant &r_ret) const { - if (String(p_name) == "case_count") { - r_ret = case_values.size(); - return true; - } - - if (String(p_name).begins_with("case/")) { - int idx = String(p_name).get_slice("/", 1).to_int(); - ERR_FAIL_INDEX_V(idx, case_values.size(), false); - - r_ret = case_values[idx].type; - return true; - } - - return false; -} - -void VisualScriptSwitch::_get_property_list(List<PropertyInfo> *p_list) const { - p_list->push_back(PropertyInfo(Variant::INT, "case_count", PROPERTY_HINT_RANGE, "0,128")); - - String argt = "Any"; - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - argt += "," + Variant::get_type_name(Variant::Type(i)); - } - - for (int i = 0; i < case_values.size(); i++) { - p_list->push_back(PropertyInfo(Variant::INT, "case/" + itos(i), PROPERTY_HINT_ENUM, argt)); - } -} - -void VisualScriptSwitch::reset_state() { - case_values.clear(); -} - -void VisualScriptSwitch::_bind_methods() { -} - -VisualScriptSwitch::VisualScriptSwitch() { -} - -////////////////////////////////////////// -////////////////TYPE CAST/////////// -////////////////////////////////////////// - -int VisualScriptTypeCast::get_output_sequence_port_count() const { - return 2; -} - -bool VisualScriptTypeCast::has_input_sequence_port() const { - return true; -} - -int VisualScriptTypeCast::get_input_value_port_count() const { - return 1; -} - -int VisualScriptTypeCast::get_output_value_port_count() const { - return 1; -} - -String VisualScriptTypeCast::get_output_sequence_port_text(int p_port) const { - return p_port == 0 ? "yes" : "no"; -} - -PropertyInfo VisualScriptTypeCast::get_input_value_port_info(int p_idx) const { - return PropertyInfo(Variant::OBJECT, "instance"); -} - -PropertyInfo VisualScriptTypeCast::get_output_value_port_info(int p_idx) const { - return PropertyInfo(Variant::OBJECT, "", PROPERTY_HINT_TYPE_STRING, get_base_type()); -} - -String VisualScriptTypeCast::get_caption() const { - return RTR("Type Cast"); -} - -String VisualScriptTypeCast::get_text() const { - if (!script.is_empty()) { - return vformat(RTR("Is %s?"), script.get_file()); - } else { - return vformat(RTR("Is %s?"), base_type); - } -} - -void VisualScriptTypeCast::set_base_type(const StringName &p_type) { - if (base_type == p_type) { - return; - } - - base_type = p_type; - notify_property_list_changed(); - ports_changed_notify(); -} - -StringName VisualScriptTypeCast::get_base_type() const { - return base_type; -} - -void VisualScriptTypeCast::set_base_script(const String &p_path) { - if (script == p_path) { - return; - } - - script = p_path; - notify_property_list_changed(); - ports_changed_notify(); -} - -String VisualScriptTypeCast::get_base_script() const { - return script; -} - -VisualScriptTypeCast::TypeGuess VisualScriptTypeCast::guess_output_type(TypeGuess *p_inputs, int p_output) const { - TypeGuess tg; - tg.type = Variant::OBJECT; - if (!script.is_empty()) { - tg.script = ResourceLoader::load(script); - } - //if (!tg.script.is_valid()) { - // tg.gdclass = base_type; - //} - - return tg; -} - -class VisualScriptNodeInstanceTypeCast : public VisualScriptNodeInstance { -public: - VisualScriptInstance *instance = nullptr; - StringName base_type; - String script; - - //virtual int get_working_memory_size() const override { return 0; } - //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } - //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - Object *obj = *p_inputs[0]; - - *p_outputs[0] = Variant(); - - if (!obj) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Instance is null"; - return 0; - } - - if (!script.is_empty()) { - Ref<Script> obj_script = obj->get_script(); - if (!obj_script.is_valid()) { - return 1; //well, definitely not the script because object we got has no script. - } - - if (!ResourceCache::has(script)) { - //if the script is not in use by anyone, we can safely assume whatever we got is not casting to it. - return 1; - } - Ref<Script> cast_script = ResourceCache::get_ref(script); - if (!cast_script.is_valid()) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Script path is not a script: " + script; - return 1; - } - - while (obj_script.is_valid()) { - if (cast_script == obj_script) { - *p_outputs[0] = *p_inputs[0]; //copy - return 0; // it is the script, yey - } - - obj_script = obj_script->get_base_script(); - } - - return 1; //not found sorry - } - - if (ClassDB::is_parent_class(obj->get_class_name(), base_type)) { - *p_outputs[0] = *p_inputs[0]; //copy - return 0; - } else { - return 1; - } - } -}; - -VisualScriptNodeInstance *VisualScriptTypeCast::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceTypeCast *instance = memnew(VisualScriptNodeInstanceTypeCast); - instance->instance = p_instance; - instance->base_type = base_type; - instance->script = script; - return instance; -} - -void VisualScriptTypeCast::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_base_type", "type"), &VisualScriptTypeCast::set_base_type); - ClassDB::bind_method(D_METHOD("get_base_type"), &VisualScriptTypeCast::get_base_type); - - ClassDB::bind_method(D_METHOD("set_base_script", "path"), &VisualScriptTypeCast::set_base_script); - ClassDB::bind_method(D_METHOD("get_base_script"), &VisualScriptTypeCast::get_base_script); - - List<String> script_extensions; - for (int i = 0; i > ScriptServer::get_language_count(); i++) { - ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions); - } - - String script_ext_hint; - for (const String &E : script_extensions) { - if (!script_ext_hint.is_empty()) { - script_ext_hint += ","; - } - script_ext_hint += "*." + E; - } - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); -} - -VisualScriptTypeCast::VisualScriptTypeCast() { - base_type = "Object"; -} - -void register_visual_script_flow_control_nodes() { - VisualScriptLanguage::singleton->add_register_func("flow_control/return", create_return_node<false>); - VisualScriptLanguage::singleton->add_register_func("flow_control/return_with_value", create_return_node<true>); - VisualScriptLanguage::singleton->add_register_func("flow_control/condition", create_node_generic<VisualScriptCondition>); - VisualScriptLanguage::singleton->add_register_func("flow_control/while", create_node_generic<VisualScriptWhile>); - VisualScriptLanguage::singleton->add_register_func("flow_control/iterator", create_node_generic<VisualScriptIterator>); - VisualScriptLanguage::singleton->add_register_func("flow_control/sequence", create_node_generic<VisualScriptSequence>); - VisualScriptLanguage::singleton->add_register_func("flow_control/switch", create_node_generic<VisualScriptSwitch>); - //VisualScriptLanguage::singleton->add_register_func("flow_control/input", create_node_generic<VisualScriptInputFilter>); - VisualScriptLanguage::singleton->add_register_func("flow_control/type_cast", create_node_generic<VisualScriptTypeCast>); -} diff --git a/modules/visual_script/visual_script_flow_control.h b/modules/visual_script/visual_script_flow_control.h deleted file mode 100644 index 7ffdf3df65..0000000000 --- a/modules/visual_script/visual_script_flow_control.h +++ /dev/null @@ -1,268 +0,0 @@ -/*************************************************************************/ -/* visual_script_flow_control.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 VISUAL_SCRIPT_FLOW_CONTROL_H -#define VISUAL_SCRIPT_FLOW_CONTROL_H - -#include "visual_script.h" - -class VisualScriptReturn : public VisualScriptNode { - GDCLASS(VisualScriptReturn, VisualScriptNode); - - Variant::Type type; - bool with_value; - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "flow_control"; } - - void set_return_type(Variant::Type); - Variant::Type get_return_type() const; - - void set_enable_return_value(bool p_enable); - bool is_return_value_enabled() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptReturn(); -}; - -class VisualScriptCondition : public VisualScriptNode { - GDCLASS(VisualScriptCondition, VisualScriptNode); - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "flow_control"; } - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptCondition(); -}; - -class VisualScriptWhile : public VisualScriptNode { - GDCLASS(VisualScriptWhile, VisualScriptNode); - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "flow_control"; } - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptWhile(); -}; - -class VisualScriptIterator : public VisualScriptNode { - GDCLASS(VisualScriptIterator, VisualScriptNode); - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "flow_control"; } - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptIterator(); -}; - -class VisualScriptSequence : public VisualScriptNode { - GDCLASS(VisualScriptSequence, VisualScriptNode); - - int steps; - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "flow_control"; } - - void set_steps(int p_steps); - int get_steps() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptSequence(); -}; - -class VisualScriptSwitch : public VisualScriptNode { - GDCLASS(VisualScriptSwitch, VisualScriptNode); - - struct Case { - Variant::Type type; - Case() { type = Variant::NIL; } - }; - - Vector<Case> case_values; - - friend class VisualScriptNodeInstanceSwitch; - -protected: - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List<PropertyInfo> *p_list) const; - - static void _bind_methods(); - -public: - virtual void reset_state() override; - - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - virtual bool has_mixed_input_and_sequence_ports() const override { return true; } - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "flow_control"; } - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptSwitch(); -}; - -class VisualScriptTypeCast : public VisualScriptNode { - GDCLASS(VisualScriptTypeCast, VisualScriptNode); - - StringName base_type; - String script; - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "flow_control"; } - - void set_base_type(const StringName &p_type); - StringName get_base_type() const; - - void set_base_script(const String &p_path); - String get_base_script() const; - - virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptTypeCast(); -}; - -void register_visual_script_flow_control_nodes(); - -#endif // VISUAL_SCRIPT_FLOW_CONTROL_H diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp deleted file mode 100644 index e79d3bae8a..0000000000 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ /dev/null @@ -1,2444 +0,0 @@ -/*************************************************************************/ -/* visual_script_func_nodes.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "visual_script_func_nodes.h" - -#include "core/config/engine.h" -#include "core/io/resource_loader.h" -#include "core/os/os.h" -#include "core/templates/local_vector.h" -#include "scene/main/node.h" -#include "scene/main/scene_tree.h" -#include "visual_script_nodes.h" - -////////////////////////////////////////// -////////////////CALL////////////////////// -////////////////////////////////////////// - -int VisualScriptFunctionCall::get_output_sequence_port_count() const { - if ((method_cache.flags & METHOD_FLAG_CONST && call_mode != CALL_MODE_INSTANCE) || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_builtin_method_const(basic_type, function))) { - return 0; - } else { - return 1; - } -} - -bool VisualScriptFunctionCall::has_input_sequence_port() const { - return !((method_cache.flags & METHOD_FLAG_CONST && call_mode != CALL_MODE_INSTANCE) || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_builtin_method_const(basic_type, function))); -} -#ifdef TOOLS_ENABLED - -static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) { - if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene) { - return nullptr; - } - - Ref<Script> scr = p_current_node->get_script(); - - if (scr.is_valid() && scr == script) { - return p_current_node; - } - - for (int i = 0; i < p_current_node->get_child_count(); i++) { - Node *n = _find_script_node(p_edited_scene, p_current_node->get_child(i), script); - if (n) { - return n; - } - } - - return nullptr; -} - -#endif -Node *VisualScriptFunctionCall::_get_base_node() const { -#ifdef TOOLS_ENABLED - Ref<Script> script = get_visual_script(); - if (!script.is_valid()) { - return nullptr; - } - - MainLoop *main_loop = OS::get_singleton()->get_main_loop(); - SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop); - - if (!scene_tree) { - return nullptr; - } - - Node *edited_scene = scene_tree->get_edited_scene_root(); - - if (!edited_scene) { - return nullptr; - } - - Node *script_node = _find_script_node(edited_scene, edited_scene, script); - - if (!script_node) { - return nullptr; - } - - if (!script_node->has_node(base_path)) { - return nullptr; - } - - Node *path_to = script_node->get_node(base_path); - - return path_to; -#else - - return nullptr; -#endif -} - -StringName VisualScriptFunctionCall::_get_base_type() const { - if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) { - return get_visual_script()->get_instance_base_type(); - } else if (call_mode == CALL_MODE_NODE_PATH && get_visual_script().is_valid()) { - Node *path = _get_base_node(); - if (path) { - return path->get_class(); - } - } - - return base_type; -} - -int VisualScriptFunctionCall::get_input_value_port_count() const { - if (call_mode == CALL_MODE_BASIC_TYPE) { - Vector<Variant::Type> types; - int argc = Variant::get_builtin_method_argument_count(basic_type, function); - for (int i = 0; i < argc; i++) { - types.push_back(Variant::get_builtin_method_argument_type(basic_type, function, i)); - } - return types.size() + (rpc_call_mode >= RPC_RELIABLE_TO_ID ? 1 : 0) + 1; - - } else { - MethodBind *mb = ClassDB::get_method(_get_base_type(), function); - if (mb) { - int defaulted_args = mb->get_argument_count() < use_default_args ? mb->get_argument_count() : use_default_args; - return mb->get_argument_count() + (call_mode == CALL_MODE_INSTANCE ? 1 : 0) + (rpc_call_mode >= RPC_RELIABLE_TO_ID ? 1 : 0) - defaulted_args; - } - - int defaulted_args = method_cache.arguments.size() < use_default_args ? method_cache.arguments.size() : use_default_args; - return method_cache.arguments.size() + (call_mode == CALL_MODE_INSTANCE ? 1 : 0) + (rpc_call_mode >= RPC_RELIABLE_TO_ID ? 1 : 0) - defaulted_args; - } -} - -int VisualScriptFunctionCall::get_output_value_port_count() const { - if (call_mode == CALL_MODE_BASIC_TYPE) { - bool returns = Variant::has_builtin_method_return_value(basic_type, function); - return returns ? 1 : 0; - - } else { - int ret; - MethodBind *mb = ClassDB::get_method(_get_base_type(), function); - if (mb) { - ret = mb->has_return() ? 1 : 0; - } else { - ret = 1; //it is assumed that script always returns something - } - - if (call_mode == CALL_MODE_INSTANCE) { - ret++; - } - - return ret; - } -} - -String VisualScriptFunctionCall::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptFunctionCall::get_input_value_port_info(int p_idx) const { - if (call_mode == CALL_MODE_INSTANCE || call_mode == CALL_MODE_BASIC_TYPE) { - if (p_idx == 0) { - PropertyInfo pi; - pi.type = (call_mode == CALL_MODE_INSTANCE ? Variant::OBJECT : basic_type); - pi.name = (call_mode == CALL_MODE_INSTANCE ? String("instance") : Variant::get_type_name(basic_type).to_lower()); - return pi; - } else { - p_idx--; - } - } - - if (rpc_call_mode >= RPC_RELIABLE_TO_ID) { - if (p_idx == 0) { - return PropertyInfo(Variant::INT, "peer_id"); - } else { - p_idx--; - } - } - -#ifdef DEBUG_METHODS_ENABLED - - if (call_mode == CALL_MODE_BASIC_TYPE) { - return PropertyInfo(Variant::get_builtin_method_argument_type(basic_type, function, p_idx), Variant::get_builtin_method_argument_name(basic_type, function, p_idx)); - } else { - MethodBind *mb = ClassDB::get_method(_get_base_type(), function); - if (mb) { - return mb->get_argument_info(p_idx); - } - - if (p_idx >= 0 && p_idx < method_cache.arguments.size()) { - return method_cache.arguments[p_idx]; - } - - return PropertyInfo(); - } -#else - return PropertyInfo(); -#endif -} - -PropertyInfo VisualScriptFunctionCall::get_output_value_port_info(int p_idx) const { -#ifdef DEBUG_METHODS_ENABLED - - if (call_mode == CALL_MODE_BASIC_TYPE) { - return PropertyInfo(Variant::get_builtin_method_return_type(basic_type, function), ""); - } else { - if (call_mode == CALL_MODE_INSTANCE) { - if (p_idx == 0) { - return PropertyInfo(Variant::OBJECT, "pass", PROPERTY_HINT_TYPE_STRING, get_base_type()); - } else { - p_idx--; - } - } - - PropertyInfo ret; - - /*MethodBind *mb = ClassDB::get_method(_get_base_type(),function); - if (mb) { - ret = mb->get_argument_info(-1); - } else {*/ - - ret = method_cache.return_val; - - //} - - if (call_mode == CALL_MODE_INSTANCE) { - ret.name = "return"; - } else { - ret.name = ""; - } - return ret; - } -#else - return PropertyInfo(); -#endif -} - -String VisualScriptFunctionCall::get_caption() const { - return " " + String(function) + "()"; -} - -String VisualScriptFunctionCall::get_text() const { - String text; - - if (call_mode == CALL_MODE_BASIC_TYPE) { - text = vformat(RTR("On %s"), Variant::get_type_name(basic_type)); - } else if (call_mode == CALL_MODE_INSTANCE) { - text = vformat(RTR("On %s"), base_type); - } else if (call_mode == CALL_MODE_NODE_PATH) { - text = "[" + String(base_path.simplified()) + "]"; - } else if (call_mode == CALL_MODE_SELF) { - text = RTR("On Self"); - } else if (call_mode == CALL_MODE_SINGLETON) { - text = String(singleton) + ":" + String(function) + "()"; - } - - if (rpc_call_mode) { - text += " RPC"; - if (rpc_call_mode == RPC_UNRELIABLE || rpc_call_mode == RPC_UNRELIABLE_TO_ID) { - text += " UNREL"; - } - } - - return text; -} - -void VisualScriptFunctionCall::set_basic_type(Variant::Type p_type) { - if (basic_type == p_type) { - return; - } - basic_type = p_type; - - notify_property_list_changed(); - ports_changed_notify(); -} - -Variant::Type VisualScriptFunctionCall::get_basic_type() const { - return basic_type; -} - -void VisualScriptFunctionCall::set_base_type(const StringName &p_type) { - if (base_type == p_type) { - return; - } - - base_type = p_type; - notify_property_list_changed(); - ports_changed_notify(); -} - -StringName VisualScriptFunctionCall::get_base_type() const { - return base_type; -} - -void VisualScriptFunctionCall::set_base_script(const String &p_path) { - if (base_script == p_path) { - return; - } - - base_script = p_path; - notify_property_list_changed(); - ports_changed_notify(); -} - -String VisualScriptFunctionCall::get_base_script() const { - return base_script; -} - -void VisualScriptFunctionCall::set_singleton(const StringName &p_type) { - if (singleton == p_type) { - return; - } - - singleton = p_type; - Object *obj = Engine::get_singleton()->get_singleton_object(singleton); - if (obj) { - base_type = obj->get_class(); - } - - notify_property_list_changed(); - ports_changed_notify(); -} - -StringName VisualScriptFunctionCall::get_singleton() const { - return singleton; -} - -void VisualScriptFunctionCall::_update_method_cache() { - StringName type; - Ref<Script> script; - - if (call_mode == CALL_MODE_NODE_PATH) { - Node *node = _get_base_node(); - if (node) { - type = node->get_class(); - base_type = type; //cache, too - script = node->get_script(); - } - } else if (call_mode == CALL_MODE_SELF) { - if (get_visual_script().is_valid()) { - type = get_visual_script()->get_instance_base_type(); - base_type = type; //cache, too - script = get_visual_script(); - } - - } else if (call_mode == CALL_MODE_SINGLETON) { - Object *obj = Engine::get_singleton()->get_singleton_object(singleton); - if (obj) { - type = obj->get_class(); - script = obj->get_script(); - } - - } else if (call_mode == CALL_MODE_INSTANCE) { - type = base_type; - if (!base_script.is_empty()) { - if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { - ScriptServer::edit_request_func(base_script); //make sure it's loaded - } - - if (ResourceCache::has(base_script)) { - script = ResourceCache::get_ref(base_script); - } else { - return; - } - } - } - - MethodBind *mb = ClassDB::get_method(type, function); - if (mb) { - use_default_args = mb->get_default_argument_count(); - method_cache = MethodInfo(); - for (int i = 0; i < mb->get_argument_count(); i++) { -#ifdef DEBUG_METHODS_ENABLED - method_cache.arguments.push_back(mb->get_argument_info(i)); -#else - method_cache.arguments.push_back(PropertyInfo()); -#endif - } - - if (mb->is_const()) { - method_cache.flags |= METHOD_FLAG_CONST; - } - -#ifdef DEBUG_METHODS_ENABLED - - method_cache.return_val = mb->get_return_info(); -#endif - - if (mb->is_vararg()) { - //for vararg just give it 10 arguments (should be enough for most use cases) - for (int i = 0; i < 10; i++) { - method_cache.arguments.push_back(PropertyInfo(Variant::NIL, "arg" + itos(i))); - use_default_args++; - } - } - } else if (script.is_valid() && script->has_method(function)) { - method_cache = script->get_method_info(function); - use_default_args = method_cache.default_arguments.size(); - } -} - -void VisualScriptFunctionCall::set_function(const StringName &p_type) { - if (function == p_type) { - return; - } - - function = p_type; - - if (call_mode == CALL_MODE_BASIC_TYPE) { - use_default_args = Variant::get_builtin_method_default_arguments(basic_type, function).size(); - } else { - //update all caches - - _update_method_cache(); - } - - notify_property_list_changed(); - ports_changed_notify(); -} - -StringName VisualScriptFunctionCall::get_function() const { - return function; -} - -void VisualScriptFunctionCall::set_base_path(const NodePath &p_type) { - if (base_path == p_type) { - return; - } - - base_path = p_type; - notify_property_list_changed(); - ports_changed_notify(); -} - -NodePath VisualScriptFunctionCall::get_base_path() const { - return base_path; -} - -void VisualScriptFunctionCall::set_call_mode(CallMode p_mode) { - if (call_mode == p_mode) { - return; - } - - call_mode = p_mode; - notify_property_list_changed(); - ports_changed_notify(); -} - -VisualScriptFunctionCall::CallMode VisualScriptFunctionCall::get_call_mode() const { - return call_mode; -} - -void VisualScriptFunctionCall::set_use_default_args(int p_amount) { - if (use_default_args == p_amount) { - return; - } - - use_default_args = p_amount; - ports_changed_notify(); -} - -void VisualScriptFunctionCall::set_rpc_call_mode(VisualScriptFunctionCall::RPCCallMode p_mode) { - if (rpc_call_mode == p_mode) { - return; - } - rpc_call_mode = p_mode; - ports_changed_notify(); - notify_property_list_changed(); -} - -VisualScriptFunctionCall::RPCCallMode VisualScriptFunctionCall::get_rpc_call_mode() const { - return rpc_call_mode; -} - -int VisualScriptFunctionCall::get_use_default_args() const { - return use_default_args; -} - -void VisualScriptFunctionCall::set_validate(bool p_amount) { - validate = p_amount; -} - -bool VisualScriptFunctionCall::get_validate() const { - return validate; -} - -void VisualScriptFunctionCall::_set_argument_cache(const Dictionary &p_cache) { - //so everything works in case all else fails - method_cache = MethodInfo::from_dict(p_cache); -} - -Dictionary VisualScriptFunctionCall::_get_argument_cache() const { - return method_cache; -} - -void VisualScriptFunctionCall::_validate_property(PropertyInfo &p_property) const { - if (p_property.name == "base_type") { - if (call_mode != CALL_MODE_INSTANCE) { - p_property.usage = PROPERTY_USAGE_NO_EDITOR; - } - } - - if (p_property.name == "base_script") { - if (call_mode != CALL_MODE_INSTANCE) { - p_property.usage = PROPERTY_USAGE_NONE; - } - } - - if (p_property.name == "basic_type") { - if (call_mode != CALL_MODE_BASIC_TYPE) { - p_property.usage = PROPERTY_USAGE_NONE; - } - } - - if (p_property.name == "singleton") { - if (call_mode != CALL_MODE_SINGLETON) { - p_property.usage = PROPERTY_USAGE_NONE; - } else { - List<Engine::Singleton> names; - Engine::get_singleton()->get_singletons(&names); - p_property.hint = PROPERTY_HINT_ENUM; - String sl; - for (const Engine::Singleton &E : names) { - if (!sl.is_empty()) { - sl += ","; - } - sl += E.name; - } - p_property.hint_string = sl; - } - } - - if (p_property.name == "node_path") { - if (call_mode != CALL_MODE_NODE_PATH) { - p_property.usage = PROPERTY_USAGE_NONE; - } else { - Node *bnode = _get_base_node(); - if (bnode) { - p_property.hint_string = bnode->get_path(); //convert to long string - } - } - } - - if (p_property.name == "function") { - if (call_mode == CALL_MODE_BASIC_TYPE) { - p_property.hint = PROPERTY_HINT_METHOD_OF_VARIANT_TYPE; - p_property.hint_string = Variant::get_type_name(basic_type); - - } else if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) { - p_property.hint = PROPERTY_HINT_METHOD_OF_SCRIPT; - p_property.hint_string = itos(get_visual_script()->get_instance_id()); - } else if (call_mode == CALL_MODE_SINGLETON) { - Object *obj = Engine::get_singleton()->get_singleton_object(singleton); - if (obj) { - p_property.hint = PROPERTY_HINT_METHOD_OF_INSTANCE; - p_property.hint_string = itos(obj->get_instance_id()); - } else { - p_property.hint = PROPERTY_HINT_METHOD_OF_BASE_TYPE; - p_property.hint_string = base_type; //should be cached - } - } else if (call_mode == CALL_MODE_INSTANCE) { - p_property.hint = PROPERTY_HINT_METHOD_OF_BASE_TYPE; - p_property.hint_string = base_type; - - if (!base_script.is_empty()) { - if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { - ScriptServer::edit_request_func(base_script); //make sure it's loaded - } - - if (ResourceCache::has(base_script)) { - Ref<Script> script = ResourceCache::get_ref(base_script); - if (script.is_valid()) { - p_property.hint = PROPERTY_HINT_METHOD_OF_SCRIPT; - p_property.hint_string = itos(script->get_instance_id()); - } - } - } - - } else if (call_mode == CALL_MODE_NODE_PATH) { - Node *node = _get_base_node(); - if (node) { - p_property.hint = PROPERTY_HINT_METHOD_OF_INSTANCE; - p_property.hint_string = itos(node->get_instance_id()); - } else { - p_property.hint = PROPERTY_HINT_METHOD_OF_BASE_TYPE; - p_property.hint_string = get_base_type(); - } - } - } - - if (p_property.name == "use_default_args") { - p_property.hint = PROPERTY_HINT_RANGE; - - int mc = 0; - - if (call_mode == CALL_MODE_BASIC_TYPE) { - mc = Variant::get_builtin_method_default_arguments(basic_type, function).size(); - } else { - MethodBind *mb = ClassDB::get_method(_get_base_type(), function); - if (mb) { - mc = mb->get_default_argument_count(); - } - } - - if (mc == 0) { - p_property.usage = PROPERTY_USAGE_NONE; //do not show - } else { - p_property.hint_string = "0," + itos(mc) + ",1"; - } - } - - if (p_property.name == "rpc_call_mode") { - if (call_mode == CALL_MODE_BASIC_TYPE) { - p_property.usage = PROPERTY_USAGE_NONE; - } - } -} - -void VisualScriptFunctionCall::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_base_type", "base_type"), &VisualScriptFunctionCall::set_base_type); - ClassDB::bind_method(D_METHOD("get_base_type"), &VisualScriptFunctionCall::get_base_type); - - ClassDB::bind_method(D_METHOD("set_base_script", "base_script"), &VisualScriptFunctionCall::set_base_script); - ClassDB::bind_method(D_METHOD("get_base_script"), &VisualScriptFunctionCall::get_base_script); - - ClassDB::bind_method(D_METHOD("set_basic_type", "basic_type"), &VisualScriptFunctionCall::set_basic_type); - ClassDB::bind_method(D_METHOD("get_basic_type"), &VisualScriptFunctionCall::get_basic_type); - - ClassDB::bind_method(D_METHOD("set_singleton", "singleton"), &VisualScriptFunctionCall::set_singleton); - ClassDB::bind_method(D_METHOD("get_singleton"), &VisualScriptFunctionCall::get_singleton); - - ClassDB::bind_method(D_METHOD("set_function", "function"), &VisualScriptFunctionCall::set_function); - ClassDB::bind_method(D_METHOD("get_function"), &VisualScriptFunctionCall::get_function); - - ClassDB::bind_method(D_METHOD("set_call_mode", "mode"), &VisualScriptFunctionCall::set_call_mode); - ClassDB::bind_method(D_METHOD("get_call_mode"), &VisualScriptFunctionCall::get_call_mode); - - ClassDB::bind_method(D_METHOD("set_base_path", "base_path"), &VisualScriptFunctionCall::set_base_path); - ClassDB::bind_method(D_METHOD("get_base_path"), &VisualScriptFunctionCall::get_base_path); - - ClassDB::bind_method(D_METHOD("set_use_default_args", "amount"), &VisualScriptFunctionCall::set_use_default_args); - ClassDB::bind_method(D_METHOD("get_use_default_args"), &VisualScriptFunctionCall::get_use_default_args); - - ClassDB::bind_method(D_METHOD("_set_argument_cache", "argument_cache"), &VisualScriptFunctionCall::_set_argument_cache); - ClassDB::bind_method(D_METHOD("_get_argument_cache"), &VisualScriptFunctionCall::_get_argument_cache); - - ClassDB::bind_method(D_METHOD("set_rpc_call_mode", "mode"), &VisualScriptFunctionCall::set_rpc_call_mode); - ClassDB::bind_method(D_METHOD("get_rpc_call_mode"), &VisualScriptFunctionCall::get_rpc_call_mode); - - ClassDB::bind_method(D_METHOD("set_validate", "enable"), &VisualScriptFunctionCall::set_validate); - ClassDB::bind_method(D_METHOD("get_validate"), &VisualScriptFunctionCall::get_validate); - - String bt; - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - if (i > 0) { - bt += ","; - } - - bt += Variant::get_type_name(Variant::Type(i)); - } - - List<String> script_extensions; - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions); - } - - String script_ext_hint; - for (const String &E : script_extensions) { - if (!script_ext_hint.is_empty()) { - script_ext_hint += ","; - } - script_ext_hint += "*." + E; - } - - ADD_PROPERTY(PropertyInfo(Variant::INT, "call_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type,Singleton"), "set_call_mode", "get_call_mode"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "singleton"), "set_singleton", "get_singleton"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "argument_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_argument_cache", "_get_argument_cache"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "function"), "set_function", "get_function"); //when set, if loaded properly, will override argument count. - ADD_PROPERTY(PropertyInfo(Variant::INT, "use_default_args"), "set_use_default_args", "get_use_default_args"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "validate"), "set_validate", "get_validate"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "rpc_call_mode", PROPERTY_HINT_ENUM, "Disabled,Reliable,Unreliable,ReliableToID,UnreliableToID"), "set_rpc_call_mode", "get_rpc_call_mode"); //when set, if loaded properly, will override argument count. - - BIND_ENUM_CONSTANT(CALL_MODE_SELF); - BIND_ENUM_CONSTANT(CALL_MODE_NODE_PATH); - BIND_ENUM_CONSTANT(CALL_MODE_INSTANCE); - BIND_ENUM_CONSTANT(CALL_MODE_BASIC_TYPE); - BIND_ENUM_CONSTANT(CALL_MODE_SINGLETON); - - BIND_ENUM_CONSTANT(RPC_DISABLED); - BIND_ENUM_CONSTANT(RPC_RELIABLE); - BIND_ENUM_CONSTANT(RPC_UNRELIABLE); - BIND_ENUM_CONSTANT(RPC_RELIABLE_TO_ID); - BIND_ENUM_CONSTANT(RPC_UNRELIABLE_TO_ID); -} - -class VisualScriptNodeInstanceFunctionCall : public VisualScriptNodeInstance { -public: - VisualScriptFunctionCall::CallMode call_mode; - NodePath node_path; - int input_args = 0; - bool validate = false; - int returns = 0; - VisualScriptFunctionCall::RPCCallMode rpc_mode; - StringName function; - StringName singleton; - - VisualScriptFunctionCall *node = nullptr; - VisualScriptInstance *instance = nullptr; - - //virtual int get_working_memory_size() const override { return 0; } - //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } - //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - - _FORCE_INLINE_ bool call_rpc(Object *p_base, const Variant **p_args, int p_argcount) { - if (!p_base) { - return false; - } - - Node *node = Object::cast_to<Node>(p_base); - if (!node) { - return false; - } - - int to_id = 0; - //bool reliable = true; - - if (rpc_mode >= VisualScriptFunctionCall::RPC_RELIABLE_TO_ID) { - to_id = *p_args[0]; - p_args += 1; - p_argcount -= 1; - //if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE_TO_ID) { - //reliable = false; - //} - } - //else if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE) { - //reliable = false; - //} - - // TODO reliable? - node->rpcp(to_id, function, p_args, p_argcount); - - return true; - } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - switch (call_mode) { - case VisualScriptFunctionCall::CALL_MODE_SELF: { - Object *object = instance->get_owner_ptr(); - - if (rpc_mode) { - call_rpc(object, p_inputs, input_args); - } else if (returns) { - *p_outputs[0] = object->callp(function, p_inputs, input_args, r_error); - } else { - object->callp(function, p_inputs, input_args, r_error); - } - } break; - case VisualScriptFunctionCall::CALL_MODE_NODE_PATH: { - Node *node = Object::cast_to<Node>(instance->get_owner_ptr()); - if (!node) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Base object is not a Node!"; - return 0; - } - - Node *another = node->get_node(node_path); - if (!another) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Path does not lead Node!"; - return 0; - } - - if (rpc_mode) { - call_rpc(node, p_inputs, input_args); - } else if (returns) { - *p_outputs[0] = another->callp(function, p_inputs, input_args, r_error); - } else { - another->callp(function, p_inputs, input_args, r_error); - } - - } break; - case VisualScriptFunctionCall::CALL_MODE_INSTANCE: - case VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE: { - Variant v = *p_inputs[0]; - - if (rpc_mode) { - Object *obj = v; - if (obj) { - call_rpc(obj, p_inputs + 1, input_args - 1); - } - } else if (returns) { - if (call_mode == VisualScriptFunctionCall::CALL_MODE_INSTANCE) { - if (returns >= 2) { - v.callp(function, p_inputs + 1, input_args, *p_outputs[1], r_error); - } else if (returns == 1) { - Variant ret; - v.callp(function, p_inputs + 1, input_args, ret, r_error); - } else { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Invalid returns count for call_mode == CALL_MODE_INSTANCE"; - return 0; - } - } else { - v.callp(function, p_inputs + 1, input_args, *p_outputs[0], r_error); - } - } else { - Variant ret; - v.callp(function, p_inputs + 1, input_args, ret, r_error); - } - - if (call_mode == VisualScriptFunctionCall::CALL_MODE_INSTANCE) { - *p_outputs[0] = *p_inputs[0]; - } - - } break; - case VisualScriptFunctionCall::CALL_MODE_SINGLETON: { - Object *object = Engine::get_singleton()->get_singleton_object(singleton); - if (!object) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Invalid singleton name: '" + String(singleton) + "'"; - return 0; - } - - if (rpc_mode) { - call_rpc(object, p_inputs, input_args); - } else if (returns) { - *p_outputs[0] = object->callp(function, p_inputs, input_args, r_error); - } else { - object->callp(function, p_inputs, input_args, r_error); - } - } break; - } - - if (!validate) { - //ignore call errors if validation is disabled - r_error.error = Callable::CallError::CALL_OK; - r_error_str = String(); - } - - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptFunctionCall::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceFunctionCall *instance = memnew(VisualScriptNodeInstanceFunctionCall); - instance->node = this; - instance->instance = p_instance; - instance->singleton = singleton; - instance->function = function; - instance->call_mode = call_mode; - instance->returns = get_output_value_port_count(); - instance->node_path = base_path; - instance->input_args = get_input_value_port_count() - ((call_mode == CALL_MODE_BASIC_TYPE || call_mode == CALL_MODE_INSTANCE) ? 1 : 0); - instance->rpc_mode = rpc_call_mode; - instance->validate = validate; - return instance; -} - -VisualScriptFunctionCall::TypeGuess VisualScriptFunctionCall::guess_output_type(TypeGuess *p_inputs, int p_output) const { - if (p_output == 0 && call_mode == CALL_MODE_INSTANCE) { - return p_inputs[0]; - } - - return VisualScriptNode::guess_output_type(p_inputs, p_output); -} - -VisualScriptFunctionCall::VisualScriptFunctionCall() { - validate = true; - call_mode = CALL_MODE_SELF; - basic_type = Variant::NIL; - use_default_args = 0; - base_type = "Object"; - rpc_call_mode = RPC_DISABLED; -} - -template <VisualScriptFunctionCall::CallMode cmode> -static Ref<VisualScriptNode> create_function_call_node(const String &p_name) { - Ref<VisualScriptFunctionCall> node; - node.instantiate(); - node->set_call_mode(cmode); - return node; -} - -////////////////////////////////////////// -////////////////SET////////////////////// -////////////////////////////////////////// - -int VisualScriptPropertySet::get_output_sequence_port_count() const { - return 1; -} - -bool VisualScriptPropertySet::has_input_sequence_port() const { - return true; -} - -Node *VisualScriptPropertySet::_get_base_node() const { -#ifdef TOOLS_ENABLED - Ref<Script> script = get_visual_script(); - if (!script.is_valid()) { - return nullptr; - } - - MainLoop *main_loop = OS::get_singleton()->get_main_loop(); - - SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop); - - if (!scene_tree) { - return nullptr; - } - - Node *edited_scene = scene_tree->get_edited_scene_root(); - - if (!edited_scene) { - return nullptr; - } - - Node *script_node = _find_script_node(edited_scene, edited_scene, script); - - if (!script_node) { - return nullptr; - } - - if (!script_node->has_node(base_path)) { - return nullptr; - } - - Node *path_to = script_node->get_node(base_path); - - return path_to; -#else - - return nullptr; -#endif -} - -StringName VisualScriptPropertySet::_get_base_type() const { - if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) { - return get_visual_script()->get_instance_base_type(); - } else if (call_mode == CALL_MODE_NODE_PATH && get_visual_script().is_valid()) { - Node *path = _get_base_node(); - if (path) { - return path->get_class(); - } - } - - return base_type; -} - -int VisualScriptPropertySet::get_input_value_port_count() const { - int pc = (call_mode == CALL_MODE_BASIC_TYPE || call_mode == CALL_MODE_INSTANCE) ? 2 : 1; - - return pc; -} - -int VisualScriptPropertySet::get_output_value_port_count() const { - return (call_mode == CALL_MODE_BASIC_TYPE || call_mode == CALL_MODE_INSTANCE) ? 1 : 0; -} - -String VisualScriptPropertySet::get_output_sequence_port_text(int p_port) const { - return String(); -} - -void VisualScriptPropertySet::_adjust_input_index(PropertyInfo &pinfo) const { - if (index != StringName()) { - Variant v; - Callable::CallError ce; - Variant::construct(pinfo.type, v, nullptr, 0, ce); - Variant i = v.get(index); - pinfo.type = i.get_type(); - } -} - -PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const { - if (call_mode == CALL_MODE_INSTANCE || call_mode == CALL_MODE_BASIC_TYPE) { - if (p_idx == 0) { - PropertyInfo pi; - pi.type = (call_mode == CALL_MODE_INSTANCE ? Variant::OBJECT : basic_type); - pi.name = "instance"; - return pi; - } - } - - List<PropertyInfo> props; - ClassDB::get_property_list(_get_base_type(), &props, false); - for (const PropertyInfo &E : props) { - if (E.name == property) { - String detail_prop_name = property; - if (index != StringName()) { - detail_prop_name += "." + String(index); - } - PropertyInfo pinfo = PropertyInfo(E.type, detail_prop_name, E.hint, E.hint_string); - _adjust_input_index(pinfo); - return pinfo; - } - } - - PropertyInfo pinfo = type_cache; - _adjust_input_index(pinfo); - return pinfo; -} - -PropertyInfo VisualScriptPropertySet::get_output_value_port_info(int p_idx) const { - if (call_mode == CALL_MODE_BASIC_TYPE) { - return PropertyInfo(basic_type, "pass"); - } else if (call_mode == CALL_MODE_INSTANCE) { - return PropertyInfo(Variant::OBJECT, "pass", PROPERTY_HINT_TYPE_STRING, get_base_type()); - } else { - return PropertyInfo(); - } -} - -String VisualScriptPropertySet::get_caption() const { - static const LocalVector<String> opname = { - RTR("Set %s"), - RTR("Add %s"), - RTR("Subtract %s"), - RTR("Multiply %s"), - RTR("Divide %s"), - RTR("Mod %s"), - RTR("ShiftLeft %s"), - RTR("ShiftRight %s"), - RTR("BitAnd %s"), - RTR("BitOr %s"), - RTR("BitXor %s"), - }; - - String prop = property; - if (index != StringName()) { - prop += "." + String(index); - } - - return vformat(opname[assign_op], prop); -} - -String VisualScriptPropertySet::get_text() const { - if (!has_input_sequence_port()) { - return ""; - } - if (call_mode == CALL_MODE_BASIC_TYPE) { - return vformat(RTR("On %s"), Variant::get_type_name(basic_type)); - } else if (call_mode == CALL_MODE_INSTANCE) { - return vformat(RTR("On %s"), base_type); - } else if (call_mode == CALL_MODE_NODE_PATH) { - return " [" + String(base_path.simplified()) + "]"; - } else { - return RTR("On Self"); - } -} - -void VisualScriptPropertySet::_update_base_type() { - //cache it because this information may not be available on load - if (call_mode == CALL_MODE_NODE_PATH) { - Node *node = _get_base_node(); - if (node) { - base_type = node->get_class(); - } - } else if (call_mode == CALL_MODE_SELF) { - if (get_visual_script().is_valid()) { - base_type = get_visual_script()->get_instance_base_type(); - } - } -} - -void VisualScriptPropertySet::set_basic_type(Variant::Type p_type) { - if (basic_type == p_type) { - return; - } - basic_type = p_type; - - notify_property_list_changed(); - _update_base_type(); - ports_changed_notify(); -} - -Variant::Type VisualScriptPropertySet::get_basic_type() const { - return basic_type; -} - -void VisualScriptPropertySet::set_base_type(const StringName &p_type) { - if (base_type == p_type) { - return; - } - - base_type = p_type; - notify_property_list_changed(); - ports_changed_notify(); -} - -StringName VisualScriptPropertySet::get_base_type() const { - return base_type; -} - -void VisualScriptPropertySet::set_base_script(const String &p_path) { - if (base_script == p_path) { - return; - } - - base_script = p_path; - notify_property_list_changed(); - ports_changed_notify(); -} - -String VisualScriptPropertySet::get_base_script() const { - return base_script; -} - -void VisualScriptPropertySet::_update_cache() { - if (!Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop())) { - return; - } - - if (!Engine::get_singleton()->is_editor_hint()) { //only update cache if editor exists, it's pointless otherwise - return; - } - - if (call_mode == CALL_MODE_BASIC_TYPE) { - //not super efficient.. - - Variant v; - Callable::CallError ce; - Variant::construct(basic_type, v, nullptr, 0, ce); - - List<PropertyInfo> pinfo; - v.get_property_list(&pinfo); - - for (const PropertyInfo &E : pinfo) { - if (E.name == property) { - type_cache = E; - } - } - - } else { - StringName type; - Ref<Script> script; - Node *node = nullptr; - - if (call_mode == CALL_MODE_NODE_PATH) { - node = _get_base_node(); - if (node) { - type = node->get_class(); - base_type = type; //cache, too - script = node->get_script(); - } - } else if (call_mode == CALL_MODE_SELF) { - if (get_visual_script().is_valid()) { - type = get_visual_script()->get_instance_base_type(); - base_type = type; //cache, too - script = get_visual_script(); - } - } else if (call_mode == CALL_MODE_INSTANCE) { - type = base_type; - if (!base_script.is_empty()) { - if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { - ScriptServer::edit_request_func(base_script); //make sure it's loaded - } - - if (ResourceCache::has(base_script)) { - script = ResourceCache::get_ref(base_script); - } else { - return; - } - } - } - - List<PropertyInfo> pinfo; - - if (node) { - node->get_property_list(&pinfo); - } else { - ClassDB::get_property_list(type, &pinfo); - } - - if (script.is_valid()) { - script->get_script_property_list(&pinfo); - } - - for (const PropertyInfo &E : pinfo) { - if (E.name == property) { - type_cache = E; - return; - } - } - } -} - -void VisualScriptPropertySet::set_property(const StringName &p_type) { - if (property == p_type) { - return; - } - - property = p_type; - index = StringName(); - _update_cache(); - notify_property_list_changed(); - ports_changed_notify(); -} - -StringName VisualScriptPropertySet::get_property() const { - return property; -} - -void VisualScriptPropertySet::set_base_path(const NodePath &p_type) { - if (base_path == p_type) { - return; - } - - base_path = p_type; - _update_base_type(); - notify_property_list_changed(); - ports_changed_notify(); -} - -NodePath VisualScriptPropertySet::get_base_path() const { - return base_path; -} - -void VisualScriptPropertySet::set_call_mode(CallMode p_mode) { - if (call_mode == p_mode) { - return; - } - - call_mode = p_mode; - _update_base_type(); - notify_property_list_changed(); - ports_changed_notify(); -} - -VisualScriptPropertySet::CallMode VisualScriptPropertySet::get_call_mode() const { - return call_mode; -} - -void VisualScriptPropertySet::_set_type_cache(const Dictionary &p_type) { - type_cache = PropertyInfo::from_dict(p_type); -} - -Dictionary VisualScriptPropertySet::_get_type_cache() const { - return type_cache; -} - -void VisualScriptPropertySet::set_index(const StringName &p_type) { - if (index == p_type) { - return; - } - index = p_type; - _update_cache(); - notify_property_list_changed(); - ports_changed_notify(); -} - -StringName VisualScriptPropertySet::get_index() const { - return index; -} - -void VisualScriptPropertySet::set_assign_op(AssignOp p_op) { - ERR_FAIL_INDEX(p_op, ASSIGN_OP_MAX); - if (assign_op == p_op) { - return; - } - - assign_op = p_op; - _update_cache(); - notify_property_list_changed(); - ports_changed_notify(); -} - -VisualScriptPropertySet::AssignOp VisualScriptPropertySet::get_assign_op() const { - return assign_op; -} - -void VisualScriptPropertySet::_validate_property(PropertyInfo &p_property) const { - if (p_property.name == "base_type") { - if (call_mode != CALL_MODE_INSTANCE) { - p_property.usage = PROPERTY_USAGE_NO_EDITOR; - } - } - - if (p_property.name == "base_script") { - if (call_mode != CALL_MODE_INSTANCE) { - p_property.usage = PROPERTY_USAGE_NONE; - } - } - - if (p_property.name == "basic_type") { - if (call_mode != CALL_MODE_BASIC_TYPE) { - p_property.usage = PROPERTY_USAGE_NONE; - } - } - - if (p_property.name == "node_path") { - if (call_mode != CALL_MODE_NODE_PATH) { - p_property.usage = PROPERTY_USAGE_NONE; - } else { - Node *bnode = _get_base_node(); - if (bnode) { - p_property.hint_string = bnode->get_path(); //convert to long string - } - } - } - - if (p_property.name == "property") { - if (call_mode == CALL_MODE_BASIC_TYPE) { - p_property.hint = PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE; - p_property.hint_string = Variant::get_type_name(basic_type); - - } else if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) { - p_property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT; - p_property.hint_string = itos(get_visual_script()->get_instance_id()); - } else if (call_mode == CALL_MODE_INSTANCE) { - p_property.hint = PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; - p_property.hint_string = base_type; - - if (!base_script.is_empty()) { - if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { - ScriptServer::edit_request_func(base_script); //make sure it's loaded - } - - if (ResourceCache::has(base_script)) { - Ref<Script> script = ResourceCache::get_ref(base_script); - if (script.is_valid()) { - p_property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT; - p_property.hint_string = itos(script->get_instance_id()); - } - } - } - - } else if (call_mode == CALL_MODE_NODE_PATH) { - Node *node = _get_base_node(); - if (node) { - p_property.hint = PROPERTY_HINT_PROPERTY_OF_INSTANCE; - p_property.hint_string = itos(node->get_instance_id()); - } else { - p_property.hint = PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; - p_property.hint_string = get_base_type(); - } - } - } - - if (p_property.name == "index") { - Callable::CallError ce; - Variant v; - Variant::construct(type_cache.type, v, nullptr, 0, ce); - List<PropertyInfo> plist; - v.get_property_list(&plist); - String options = ""; - for (const PropertyInfo &E : plist) { - options += "," + E.name; - } - - p_property.hint = PROPERTY_HINT_ENUM; - p_property.hint_string = options; - p_property.type = Variant::STRING; - if (options.is_empty()) { - p_property.usage = PROPERTY_USAGE_NONE; //hide if type has no usable index - } - } -} - -void VisualScriptPropertySet::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_base_type", "base_type"), &VisualScriptPropertySet::set_base_type); - ClassDB::bind_method(D_METHOD("get_base_type"), &VisualScriptPropertySet::get_base_type); - - ClassDB::bind_method(D_METHOD("set_base_script", "base_script"), &VisualScriptPropertySet::set_base_script); - ClassDB::bind_method(D_METHOD("get_base_script"), &VisualScriptPropertySet::get_base_script); - - ClassDB::bind_method(D_METHOD("set_basic_type", "basic_type"), &VisualScriptPropertySet::set_basic_type); - ClassDB::bind_method(D_METHOD("get_basic_type"), &VisualScriptPropertySet::get_basic_type); - - ClassDB::bind_method(D_METHOD("_set_type_cache", "type_cache"), &VisualScriptPropertySet::_set_type_cache); - ClassDB::bind_method(D_METHOD("_get_type_cache"), &VisualScriptPropertySet::_get_type_cache); - - ClassDB::bind_method(D_METHOD("set_property", "property"), &VisualScriptPropertySet::set_property); - ClassDB::bind_method(D_METHOD("get_property"), &VisualScriptPropertySet::get_property); - - ClassDB::bind_method(D_METHOD("set_call_mode", "mode"), &VisualScriptPropertySet::set_call_mode); - ClassDB::bind_method(D_METHOD("get_call_mode"), &VisualScriptPropertySet::get_call_mode); - - ClassDB::bind_method(D_METHOD("set_base_path", "base_path"), &VisualScriptPropertySet::set_base_path); - ClassDB::bind_method(D_METHOD("get_base_path"), &VisualScriptPropertySet::get_base_path); - - ClassDB::bind_method(D_METHOD("set_index", "index"), &VisualScriptPropertySet::set_index); - ClassDB::bind_method(D_METHOD("get_index"), &VisualScriptPropertySet::get_index); - - ClassDB::bind_method(D_METHOD("set_assign_op", "assign_op"), &VisualScriptPropertySet::set_assign_op); - ClassDB::bind_method(D_METHOD("get_assign_op"), &VisualScriptPropertySet::get_assign_op); - - String bt; - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - if (i > 0) { - bt += ","; - } - - bt += Variant::get_type_name(Variant::Type(i)); - } - - List<String> script_extensions; - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions); - } - - String script_ext_hint; - for (const String &E : script_extensions) { - if (!script_ext_hint.is_empty()) { - script_ext_hint += ","; - } - script_ext_hint += "*." + E; - } - - ADD_PROPERTY(PropertyInfo(Variant::INT, "set_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type"), "set_call_mode", "get_call_mode"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "type_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_type_cache", "_get_type_cache"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "property"), "set_property", "get_property"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "index"), "set_index", "get_index"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "assign_op", PROPERTY_HINT_ENUM, "Assign,Add,Sub,Mul,Div,Mod,ShiftLeft,ShiftRight,BitAnd,BitOr,Bitxor"), "set_assign_op", "get_assign_op"); - - BIND_ENUM_CONSTANT(CALL_MODE_SELF); - BIND_ENUM_CONSTANT(CALL_MODE_NODE_PATH); - BIND_ENUM_CONSTANT(CALL_MODE_INSTANCE); - BIND_ENUM_CONSTANT(CALL_MODE_BASIC_TYPE); - - BIND_ENUM_CONSTANT(ASSIGN_OP_NONE); - BIND_ENUM_CONSTANT(ASSIGN_OP_ADD); - BIND_ENUM_CONSTANT(ASSIGN_OP_SUB); - BIND_ENUM_CONSTANT(ASSIGN_OP_MUL); - BIND_ENUM_CONSTANT(ASSIGN_OP_DIV); - BIND_ENUM_CONSTANT(ASSIGN_OP_MOD); - BIND_ENUM_CONSTANT(ASSIGN_OP_SHIFT_LEFT); - BIND_ENUM_CONSTANT(ASSIGN_OP_SHIFT_RIGHT); - BIND_ENUM_CONSTANT(ASSIGN_OP_BIT_AND); - BIND_ENUM_CONSTANT(ASSIGN_OP_BIT_OR); - BIND_ENUM_CONSTANT(ASSIGN_OP_BIT_XOR); -} - -class VisualScriptNodeInstancePropertySet : public VisualScriptNodeInstance { -public: - VisualScriptPropertySet::CallMode call_mode; - NodePath node_path; - StringName property; - - VisualScriptPropertySet *node = nullptr; - VisualScriptInstance *instance = nullptr; - VisualScriptPropertySet::AssignOp assign_op; - StringName index; - bool needs_get = false; - - //virtual int get_working_memory_size() const override { return 0; } - //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } - //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - - _FORCE_INLINE_ void _process_get(Variant &source, const Variant &p_argument, bool &valid) { - if (index != StringName() && assign_op == VisualScriptPropertySet::ASSIGN_OP_NONE) { - source.set_named(index, p_argument, valid); - } else { - Variant value; - if (index != StringName()) { - value = source.get_named(index, valid); - } else { - value = source; - } - - switch (assign_op) { - case VisualScriptPropertySet::ASSIGN_OP_NONE: { - //should never get here - } break; - case VisualScriptPropertySet::ASSIGN_OP_ADD: { - value = Variant::evaluate(Variant::OP_ADD, value, p_argument); - } break; - case VisualScriptPropertySet::ASSIGN_OP_SUB: { - value = Variant::evaluate(Variant::OP_SUBTRACT, value, p_argument); - } break; - case VisualScriptPropertySet::ASSIGN_OP_MUL: { - value = Variant::evaluate(Variant::OP_MULTIPLY, value, p_argument); - } break; - case VisualScriptPropertySet::ASSIGN_OP_DIV: { - value = Variant::evaluate(Variant::OP_DIVIDE, value, p_argument); - } break; - case VisualScriptPropertySet::ASSIGN_OP_MOD: { - value = Variant::evaluate(Variant::OP_MODULE, value, p_argument); - } break; - case VisualScriptPropertySet::ASSIGN_OP_SHIFT_LEFT: { - value = Variant::evaluate(Variant::OP_SHIFT_LEFT, value, p_argument); - } break; - case VisualScriptPropertySet::ASSIGN_OP_SHIFT_RIGHT: { - value = Variant::evaluate(Variant::OP_SHIFT_RIGHT, value, p_argument); - } break; - case VisualScriptPropertySet::ASSIGN_OP_BIT_AND: { - value = Variant::evaluate(Variant::OP_BIT_AND, value, p_argument); - } break; - case VisualScriptPropertySet::ASSIGN_OP_BIT_OR: { - value = Variant::evaluate(Variant::OP_BIT_OR, value, p_argument); - } break; - case VisualScriptPropertySet::ASSIGN_OP_BIT_XOR: { - value = Variant::evaluate(Variant::OP_BIT_XOR, value, p_argument); - } break; - default: { - } - } - - if (index != StringName()) { - source.set_named(index, value, valid); - } else { - source = value; - } - } - } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - switch (call_mode) { - case VisualScriptPropertySet::CALL_MODE_SELF: { - Object *object = instance->get_owner_ptr(); - - bool valid; - - if (needs_get) { - Variant value = object->get(property, &valid); - _process_get(value, *p_inputs[0], valid); - object->set(property, value, &valid); - } else { - object->set(property, *p_inputs[0], &valid); - } - - if (!valid) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Invalid set value '" + String(*p_inputs[0]) + "' on property '" + String(property) + "' of type " + object->get_class(); - } - } break; - case VisualScriptPropertySet::CALL_MODE_NODE_PATH: { - Node *node = Object::cast_to<Node>(instance->get_owner_ptr()); - if (!node) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Base object is not a Node!"; - return 0; - } - - Node *another = node->get_node(node_path); - if (!another) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Path does not lead Node!"; - return 0; - } - - bool valid; - - if (needs_get) { - Variant value = another->get(property, &valid); - _process_get(value, *p_inputs[0], valid); - another->set(property, value, &valid); - } else { - another->set(property, *p_inputs[0], &valid); - } - - if (!valid) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Invalid set value '" + String(*p_inputs[0]) + "' on property '" + String(property) + "' of type " + another->get_class(); - } - - } break; - case VisualScriptPropertySet::CALL_MODE_INSTANCE: - case VisualScriptPropertySet::CALL_MODE_BASIC_TYPE: { - Variant v = *p_inputs[0]; - - bool valid; - - if (needs_get) { - Variant value = v.get_named(property, valid); - _process_get(value, *p_inputs[1], valid); - v.set_named(property, value, valid); - - } else { - v.set_named(property, *p_inputs[1], valid); - } - - if (!valid) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Invalid set value '" + String(*p_inputs[1]) + "' (" + Variant::get_type_name(p_inputs[1]->get_type()) + ") on property '" + String(property) + "' of type " + Variant::get_type_name(v.get_type()); - } - - *p_outputs[0] = v; - - } break; - } - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptPropertySet::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstancePropertySet *instance = memnew(VisualScriptNodeInstancePropertySet); - instance->node = this; - instance->instance = p_instance; - instance->property = property; - instance->call_mode = call_mode; - instance->node_path = base_path; - instance->assign_op = assign_op; - instance->index = index; - instance->needs_get = index != StringName() || assign_op != ASSIGN_OP_NONE; - return instance; -} - -VisualScriptPropertySet::TypeGuess VisualScriptPropertySet::guess_output_type(TypeGuess *p_inputs, int p_output) const { - if (p_output == 0 && call_mode == CALL_MODE_INSTANCE) { - return p_inputs[0]; - } - - return VisualScriptNode::guess_output_type(p_inputs, p_output); -} - -VisualScriptPropertySet::VisualScriptPropertySet() { - assign_op = ASSIGN_OP_NONE; - call_mode = CALL_MODE_SELF; - base_type = "Object"; - basic_type = Variant::NIL; -} - -template <VisualScriptPropertySet::CallMode cmode> -static Ref<VisualScriptNode> create_property_set_node(const String &p_name) { - Ref<VisualScriptPropertySet> node; - node.instantiate(); - node->set_call_mode(cmode); - return node; -} - -////////////////////////////////////////// -////////////////GET////////////////////// -////////////////////////////////////////// - -int VisualScriptPropertyGet::get_output_sequence_port_count() const { - return 0; // (call_mode==CALL_MODE_SELF || call_mode==CALL_MODE_NODE_PATH)?0:1; -} - -bool VisualScriptPropertyGet::has_input_sequence_port() const { - return false; //(call_mode==CALL_MODE_SELF || call_mode==CALL_MODE_NODE_PATH)?false:true; -} - -void VisualScriptPropertyGet::_update_base_type() { - //cache it because this information may not be available on load - if (call_mode == CALL_MODE_NODE_PATH) { - Node *node = _get_base_node(); - if (node) { - base_type = node->get_class(); - } - } else if (call_mode == CALL_MODE_SELF) { - if (get_visual_script().is_valid()) { - base_type = get_visual_script()->get_instance_base_type(); - } - } -} - -Node *VisualScriptPropertyGet::_get_base_node() const { -#ifdef TOOLS_ENABLED - Ref<Script> script = get_visual_script(); - if (!script.is_valid()) { - return nullptr; - } - - MainLoop *main_loop = OS::get_singleton()->get_main_loop(); - - SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop); - - if (!scene_tree) { - return nullptr; - } - - Node *edited_scene = scene_tree->get_edited_scene_root(); - - if (!edited_scene) { - return nullptr; - } - - Node *script_node = _find_script_node(edited_scene, edited_scene, script); - - if (!script_node) { - return nullptr; - } - - if (!script_node->has_node(base_path)) { - return nullptr; - } - - Node *path_to = script_node->get_node(base_path); - - return path_to; -#else - - return nullptr; -#endif -} - -StringName VisualScriptPropertyGet::_get_base_type() const { - if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) { - return get_visual_script()->get_instance_base_type(); - } else if (call_mode == CALL_MODE_NODE_PATH && get_visual_script().is_valid()) { - Node *path = _get_base_node(); - if (path) { - return path->get_class(); - } - } - - return base_type; -} - -int VisualScriptPropertyGet::get_input_value_port_count() const { - return (call_mode == CALL_MODE_BASIC_TYPE || call_mode == CALL_MODE_INSTANCE) ? 1 : 0; -} - -int VisualScriptPropertyGet::get_output_value_port_count() const { - int pc = (call_mode == CALL_MODE_BASIC_TYPE || call_mode == CALL_MODE_INSTANCE) ? 2 : 1; - - return pc; -} - -String VisualScriptPropertyGet::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptPropertyGet::get_input_value_port_info(int p_idx) const { - if (call_mode == CALL_MODE_INSTANCE || call_mode == CALL_MODE_BASIC_TYPE) { - if (p_idx == 0) { - PropertyInfo pi; - pi.type = (call_mode == CALL_MODE_INSTANCE ? Variant::OBJECT : basic_type); - pi.name = (call_mode == CALL_MODE_INSTANCE ? String("instance") : Variant::get_type_name(basic_type).to_lower()); - return pi; - } - } - return PropertyInfo(); -} - -PropertyInfo VisualScriptPropertyGet::get_output_value_port_info(int p_idx) const { - if (call_mode == CALL_MODE_BASIC_TYPE && p_idx == 0) { - return PropertyInfo(basic_type, "pass"); - } else if (call_mode == CALL_MODE_INSTANCE && p_idx == 0) { - return PropertyInfo(Variant::OBJECT, "pass", PROPERTY_HINT_TYPE_STRING, get_base_type()); - } else { - List<PropertyInfo> props; - ClassDB::get_property_list(_get_base_type(), &props, false); - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - if (E->get().name == property) { - PropertyInfo pinfo = PropertyInfo(E->get().type, String(property) + "." + String(index), E->get().hint, E->get().hint_string); - _adjust_input_index(pinfo); - return pinfo; - } - } - } - - PropertyInfo pinfo = PropertyInfo(type_cache, "value"); - _adjust_input_index(pinfo); - return pinfo; -} - -String VisualScriptPropertyGet::get_caption() const { - String prop = property; - if (index != StringName()) { - prop += "." + String(index); - } - - return vformat(RTR("Get %s"), prop); -} - -String VisualScriptPropertyGet::get_text() const { - if (call_mode == CALL_MODE_BASIC_TYPE) { - return vformat(RTR("On %s"), Variant::get_type_name(basic_type)); - } else if (call_mode == CALL_MODE_INSTANCE) { - return vformat(RTR("On %s"), base_type); - } else if (call_mode == CALL_MODE_NODE_PATH) { - return " [" + String(base_path.simplified()) + "]"; - } else { - return RTR("On Self"); - } -} - -void VisualScriptPropertyGet::set_base_type(const StringName &p_type) { - if (base_type == p_type) { - return; - } - - base_type = p_type; - notify_property_list_changed(); - ports_changed_notify(); -} - -StringName VisualScriptPropertyGet::get_base_type() const { - return base_type; -} - -void VisualScriptPropertyGet::set_base_script(const String &p_path) { - if (base_script == p_path) { - return; - } - - base_script = p_path; - notify_property_list_changed(); - ports_changed_notify(); -} - -String VisualScriptPropertyGet::get_base_script() const { - return base_script; -} - -void VisualScriptPropertyGet::_update_cache() { - if (call_mode == CALL_MODE_BASIC_TYPE) { - //not super efficient.. - - Variant v; - Callable::CallError ce; - Variant::construct(basic_type, v, nullptr, 0, ce); - - List<PropertyInfo> pinfo; - v.get_property_list(&pinfo); - - for (const PropertyInfo &E : pinfo) { - if (E.name == property) { - type_cache = E.type; - return; - } - } - - } else { - StringName type; - Ref<Script> script; - Node *node = nullptr; - - if (call_mode == CALL_MODE_NODE_PATH) { - node = _get_base_node(); - if (node) { - type = node->get_class(); - base_type = type; //cache, too - script = node->get_script(); - } - } else if (call_mode == CALL_MODE_SELF) { - if (get_visual_script().is_valid()) { - type = get_visual_script()->get_instance_base_type(); - base_type = type; //cache, too - script = get_visual_script(); - } - } else if (call_mode == CALL_MODE_INSTANCE) { - type = base_type; - if (!base_script.is_empty()) { - if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { - ScriptServer::edit_request_func(base_script); //make sure it's loaded - } - - if (ResourceCache::has(base_script)) { - script = ResourceCache::get_ref(base_script); - } else { - return; - } - } - } - - bool valid = false; - - Variant::Type type_ret; - - type_ret = ClassDB::get_property_type(base_type, property, &valid); - - if (valid) { - type_cache = type_ret; - return; //all dandy - } - - if (node) { - Variant prop = node->get(property, &valid); - if (valid) { - type_cache = prop.get_type(); - return; //all dandy again - } - } - - if (script.is_valid()) { - type_ret = script->get_static_property_type(property, &valid); - - if (valid) { - type_cache = type_ret; - return; //all dandy - } - } - } -} - -void VisualScriptPropertyGet::set_property(const StringName &p_type) { - if (property == p_type) { - return; - } - - property = p_type; - - _update_cache(); - notify_property_list_changed(); - ports_changed_notify(); -} - -StringName VisualScriptPropertyGet::get_property() const { - return property; -} - -void VisualScriptPropertyGet::set_base_path(const NodePath &p_type) { - if (base_path == p_type) { - return; - } - - base_path = p_type; - notify_property_list_changed(); - _update_base_type(); - ports_changed_notify(); -} - -NodePath VisualScriptPropertyGet::get_base_path() const { - return base_path; -} - -void VisualScriptPropertyGet::set_call_mode(CallMode p_mode) { - if (call_mode == p_mode) { - return; - } - - call_mode = p_mode; - notify_property_list_changed(); - _update_base_type(); - ports_changed_notify(); -} - -VisualScriptPropertyGet::CallMode VisualScriptPropertyGet::get_call_mode() const { - return call_mode; -} - -void VisualScriptPropertyGet::set_basic_type(Variant::Type p_type) { - if (basic_type == p_type) { - return; - } - basic_type = p_type; - - notify_property_list_changed(); - ports_changed_notify(); -} - -Variant::Type VisualScriptPropertyGet::get_basic_type() const { - return basic_type; -} - -void VisualScriptPropertyGet::_set_type_cache(Variant::Type p_type) { - type_cache = p_type; -} - -Variant::Type VisualScriptPropertyGet::_get_type_cache() const { - return type_cache; -} - -void VisualScriptPropertyGet::_adjust_input_index(PropertyInfo &pinfo) const { - if (index != StringName()) { - Variant v; - Callable::CallError ce; - Variant::construct(pinfo.type, v, nullptr, 0, ce); - Variant i = v.get(index); - pinfo.type = i.get_type(); - pinfo.name = String(property) + "." + index; - } else { - pinfo.name = String(property); - } -} - -void VisualScriptPropertyGet::set_index(const StringName &p_type) { - if (index == p_type) { - return; - } - index = p_type; - _update_cache(); - notify_property_list_changed(); - ports_changed_notify(); -} - -StringName VisualScriptPropertyGet::get_index() const { - return index; -} - -void VisualScriptPropertyGet::_validate_property(PropertyInfo &p_property) const { - if (p_property.name == "base_type") { - if (call_mode != CALL_MODE_INSTANCE) { - p_property.usage = PROPERTY_USAGE_NO_EDITOR; - } - } - - if (p_property.name == "base_script") { - if (call_mode != CALL_MODE_INSTANCE) { - p_property.usage = PROPERTY_USAGE_NONE; - } - } - - if (p_property.name == "basic_type") { - if (call_mode != CALL_MODE_BASIC_TYPE) { - p_property.usage = PROPERTY_USAGE_NONE; - } - } - - if (p_property.name == "node_path") { - if (call_mode != CALL_MODE_NODE_PATH) { - p_property.usage = PROPERTY_USAGE_NONE; - } else { - Node *bnode = _get_base_node(); - if (bnode) { - p_property.hint_string = bnode->get_path(); //convert to long string - } - } - } - - if (p_property.name == "property") { - if (call_mode == CALL_MODE_BASIC_TYPE) { - p_property.hint = PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE; - p_property.hint_string = Variant::get_type_name(basic_type); - - } else if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) { - p_property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT; - p_property.hint_string = itos(get_visual_script()->get_instance_id()); - } else if (call_mode == CALL_MODE_INSTANCE) { - p_property.hint = PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; - p_property.hint_string = base_type; - - if (!base_script.is_empty()) { - if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { - ScriptServer::edit_request_func(base_script); //make sure it's loaded - } - - if (ResourceCache::has(base_script)) { - Ref<Script> script = ResourceCache::get_ref(base_script); - if (script.is_valid()) { - p_property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT; - p_property.hint_string = itos(script->get_instance_id()); - } - } - } - } else if (call_mode == CALL_MODE_NODE_PATH) { - Node *node = _get_base_node(); - if (node) { - p_property.hint = PROPERTY_HINT_PROPERTY_OF_INSTANCE; - p_property.hint_string = itos(node->get_instance_id()); - } else { - p_property.hint = PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; - p_property.hint_string = get_base_type(); - } - } - } - - if (p_property.name == "index") { - Callable::CallError ce; - Variant v; - Variant::construct(type_cache, v, nullptr, 0, ce); - List<PropertyInfo> plist; - v.get_property_list(&plist); - String options = ""; - for (const PropertyInfo &E : plist) { - options += "," + E.name; - } - - p_property.hint = PROPERTY_HINT_ENUM; - p_property.hint_string = options; - p_property.type = Variant::STRING; - if (options.is_empty()) { - p_property.usage = PROPERTY_USAGE_NONE; //hide if type has no usable index - } - } -} - -void VisualScriptPropertyGet::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_base_type", "base_type"), &VisualScriptPropertyGet::set_base_type); - ClassDB::bind_method(D_METHOD("get_base_type"), &VisualScriptPropertyGet::get_base_type); - - ClassDB::bind_method(D_METHOD("set_base_script", "base_script"), &VisualScriptPropertyGet::set_base_script); - ClassDB::bind_method(D_METHOD("get_base_script"), &VisualScriptPropertyGet::get_base_script); - - ClassDB::bind_method(D_METHOD("set_basic_type", "basic_type"), &VisualScriptPropertyGet::set_basic_type); - ClassDB::bind_method(D_METHOD("get_basic_type"), &VisualScriptPropertyGet::get_basic_type); - - ClassDB::bind_method(D_METHOD("_set_type_cache", "type_cache"), &VisualScriptPropertyGet::_set_type_cache); - ClassDB::bind_method(D_METHOD("_get_type_cache"), &VisualScriptPropertyGet::_get_type_cache); - - ClassDB::bind_method(D_METHOD("set_property", "property"), &VisualScriptPropertyGet::set_property); - ClassDB::bind_method(D_METHOD("get_property"), &VisualScriptPropertyGet::get_property); - - ClassDB::bind_method(D_METHOD("set_call_mode", "mode"), &VisualScriptPropertyGet::set_call_mode); - ClassDB::bind_method(D_METHOD("get_call_mode"), &VisualScriptPropertyGet::get_call_mode); - - ClassDB::bind_method(D_METHOD("set_base_path", "base_path"), &VisualScriptPropertyGet::set_base_path); - ClassDB::bind_method(D_METHOD("get_base_path"), &VisualScriptPropertyGet::get_base_path); - - ClassDB::bind_method(D_METHOD("set_index", "index"), &VisualScriptPropertyGet::set_index); - ClassDB::bind_method(D_METHOD("get_index"), &VisualScriptPropertyGet::get_index); - - String bt; - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - if (i > 0) { - bt += ","; - } - - bt += Variant::get_type_name(Variant::Type(i)); - } - - List<String> script_extensions; - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions); - } - - String script_ext_hint; - for (const String &E : script_extensions) { - if (!script_ext_hint.is_empty()) { - script_ext_hint += ","; - } - script_ext_hint += "." + E; - } - - ADD_PROPERTY(PropertyInfo(Variant::INT, "set_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type"), "set_call_mode", "get_call_mode"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "type_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_type_cache", "_get_type_cache"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "property"), "set_property", "get_property"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "index", PROPERTY_HINT_ENUM), "set_index", "get_index"); - - BIND_ENUM_CONSTANT(CALL_MODE_SELF); - BIND_ENUM_CONSTANT(CALL_MODE_NODE_PATH); - BIND_ENUM_CONSTANT(CALL_MODE_INSTANCE); - BIND_ENUM_CONSTANT(CALL_MODE_BASIC_TYPE); -} - -class VisualScriptNodeInstancePropertyGet : public VisualScriptNodeInstance { -public: - VisualScriptPropertyGet::CallMode call_mode; - NodePath node_path; - StringName property; - StringName index; - - VisualScriptPropertyGet *node = nullptr; - VisualScriptInstance *instance = nullptr; - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - switch (call_mode) { - case VisualScriptPropertyGet::CALL_MODE_SELF: { - Object *object = instance->get_owner_ptr(); - - bool valid; - - *p_outputs[0] = object->get(property, &valid); - - if (index != StringName()) { - *p_outputs[0] = p_outputs[0]->get_named(index, valid); - } - - if (!valid) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = RTR("Invalid index property name."); - return 0; - } - } break; - case VisualScriptPropertyGet::CALL_MODE_NODE_PATH: { - Node *node = Object::cast_to<Node>(instance->get_owner_ptr()); - if (!node) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = RTR("Base object is not a Node!"); - return 0; - } - - Node *another = node->get_node(node_path); - if (!another) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = RTR("Path does not lead Node!"); - return 0; - } - - bool valid; - - *p_outputs[0] = another->get(property, &valid); - - if (index != StringName()) { - *p_outputs[0] = p_outputs[0]->get_named(index, valid); - } - - if (!valid) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = vformat(RTR("Invalid index property name '%s' in node %s."), String(property), another->get_name()); - return 0; - } - - } break; - default: { - bool valid; - Variant v = *p_inputs[0]; - - *p_outputs[1] = v.get(property, &valid); - if (index != StringName()) { - *p_outputs[1] = p_outputs[1]->get_named(index, valid); - } - - if (!valid) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = RTR("Invalid index property name."); - } - - *p_outputs[0] = v; - }; - } - - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptPropertyGet::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstancePropertyGet *instance = memnew(VisualScriptNodeInstancePropertyGet); - instance->node = this; - instance->instance = p_instance; - instance->property = property; - instance->call_mode = call_mode; - instance->node_path = base_path; - instance->index = index; - - return instance; -} - -VisualScriptPropertyGet::VisualScriptPropertyGet() { - call_mode = CALL_MODE_SELF; - base_type = "Object"; - basic_type = Variant::NIL; - type_cache = Variant::NIL; -} - -template <VisualScriptPropertyGet::CallMode cmode> -static Ref<VisualScriptNode> create_property_get_node(const String &p_name) { - Ref<VisualScriptPropertyGet> node; - node.instantiate(); - node->set_call_mode(cmode); - return node; -} - -////////////////////////////////////////// -////////////////EMIT////////////////////// -////////////////////////////////////////// - -int VisualScriptEmitSignal::get_output_sequence_port_count() const { - return 1; -} - -bool VisualScriptEmitSignal::has_input_sequence_port() const { - return true; -} - -int VisualScriptEmitSignal::get_input_value_port_count() const { - Ref<VisualScript> vs = get_visual_script(); - if (vs.is_valid()) { - if (!vs->has_custom_signal(name)) { - return 0; - } - - return vs->custom_signal_get_argument_count(name); - } - - return 0; -} - -int VisualScriptEmitSignal::get_output_value_port_count() const { - return 0; -} - -String VisualScriptEmitSignal::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptEmitSignal::get_input_value_port_info(int p_idx) const { - Ref<VisualScript> vs = get_visual_script(); - if (vs.is_valid()) { - if (!vs->has_custom_signal(name)) { - return PropertyInfo(); - } - - return PropertyInfo(vs->custom_signal_get_argument_type(name, p_idx), vs->custom_signal_get_argument_name(name, p_idx)); - } - - return PropertyInfo(); -} - -PropertyInfo VisualScriptEmitSignal::get_output_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -String VisualScriptEmitSignal::get_caption() const { - return vformat(RTR("Emit %s"), name); -} - -void VisualScriptEmitSignal::set_signal(const StringName &p_type) { - if (name == p_type) { - return; - } - - name = p_type; - - notify_property_list_changed(); - ports_changed_notify(); -} - -StringName VisualScriptEmitSignal::get_signal() const { - return name; -} - -void VisualScriptEmitSignal::_validate_property(PropertyInfo &p_property) const { - if (p_property.name == "signal") { - p_property.hint = PROPERTY_HINT_ENUM; - - List<StringName> sigs; - List<MethodInfo> base_sigs; - - Ref<VisualScript> vs = get_visual_script(); - if (vs.is_valid()) { - vs->get_custom_signal_list(&sigs); - ClassDB::get_signal_list(vs->get_instance_base_type(), &base_sigs); - } - - String ml; - for (const StringName &E : sigs) { - if (!ml.is_empty()) { - ml += ","; - } - ml += E; - } - for (const MethodInfo &E : base_sigs) { - if (!ml.is_empty()) { - ml += ","; - } - ml += E.name; - } - - p_property.hint_string = ml; - } -} - -void VisualScriptEmitSignal::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_signal", "name"), &VisualScriptEmitSignal::set_signal); - ClassDB::bind_method(D_METHOD("get_signal"), &VisualScriptEmitSignal::get_signal); - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "signal"), "set_signal", "get_signal"); -} - -class VisualScriptNodeInstanceEmitSignal : public VisualScriptNodeInstance { -public: - VisualScriptEmitSignal *node = nullptr; - VisualScriptInstance *instance = nullptr; - int argcount = 0; - StringName name; - - //virtual int get_working_memory_size() const override { return 0; } - //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } - //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - Object *obj = instance->get_owner_ptr(); - - obj->emit_signalp(name, p_inputs, argcount); - - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptEmitSignal::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceEmitSignal *instance = memnew(VisualScriptNodeInstanceEmitSignal); - instance->node = this; - instance->instance = p_instance; - instance->name = name; - instance->argcount = get_input_value_port_count(); - return instance; -} - -VisualScriptEmitSignal::VisualScriptEmitSignal() { -} - -static Ref<VisualScriptNode> create_basic_type_call_node(const String &p_name) { - Vector<String> path = p_name.split("/"); - ERR_FAIL_COND_V(path.size() < 4, Ref<VisualScriptNode>()); - String base_type = path[2]; - String method = path[3]; - - Ref<VisualScriptFunctionCall> node; - node.instantiate(); - - Variant::Type type = Variant::VARIANT_MAX; - - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - if (Variant::get_type_name(Variant::Type(i)) == base_type) { - type = Variant::Type(i); - break; - } - } - - ERR_FAIL_COND_V(type == Variant::VARIANT_MAX, Ref<VisualScriptNode>()); - - node->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE); - node->set_basic_type(type); - node->set_function(method); - - return node; -} - -void register_visual_script_func_nodes() { - VisualScriptLanguage::singleton->add_register_func("functions/call", create_node_generic<VisualScriptFunctionCall>); - VisualScriptLanguage::singleton->add_register_func("functions/set", create_node_generic<VisualScriptPropertySet>); - VisualScriptLanguage::singleton->add_register_func("functions/get", create_node_generic<VisualScriptPropertyGet>); - - //VisualScriptLanguage::singleton->add_register_func("functions/call_script/call_self",create_script_call_node<VisualScriptScriptCall::CALL_MODE_SELF>); - //VisualScriptLanguage::singleton->add_register_func("functions/call_script/call_node",create_script_call_node<VisualScriptScriptCall::CALL_MODE_NODE_PATH>); - VisualScriptLanguage::singleton->add_register_func("functions/emit_signal", create_node_generic<VisualScriptEmitSignal>); - - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - Variant::Type t = Variant::Type(i); - String type_name = Variant::get_type_name(t); - Callable::CallError ce; - Variant vt; - Variant::construct(t, vt, nullptr, 0, ce); - List<MethodInfo> ml; - vt.get_method_list(&ml); - - for (const MethodInfo &E : ml) { - VisualScriptLanguage::singleton->add_register_func("functions/by_type/" + type_name + "/" + E.name, create_basic_type_call_node); - } - } -} diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h deleted file mode 100644 index 70f601307b..0000000000 --- a/modules/visual_script/visual_script_func_nodes.h +++ /dev/null @@ -1,363 +0,0 @@ -/*************************************************************************/ -/* visual_script_func_nodes.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 VISUAL_SCRIPT_FUNC_NODES_H -#define VISUAL_SCRIPT_FUNC_NODES_H - -#include "visual_script.h" - -class VisualScriptFunctionCall : public VisualScriptNode { - GDCLASS(VisualScriptFunctionCall, VisualScriptNode); - -public: - enum CallMode { - CALL_MODE_SELF, - CALL_MODE_NODE_PATH, - CALL_MODE_INSTANCE, - CALL_MODE_BASIC_TYPE, - CALL_MODE_SINGLETON, - }; - - enum RPCCallMode { - RPC_DISABLED, - RPC_RELIABLE, - RPC_UNRELIABLE, - RPC_RELIABLE_TO_ID, - RPC_UNRELIABLE_TO_ID - }; - -private: - CallMode call_mode; - StringName base_type; - String base_script; - Variant::Type basic_type; - NodePath base_path; - StringName function; - int use_default_args; - RPCCallMode rpc_call_mode; - StringName singleton; - bool validate; - - Node *_get_base_node() const; - StringName _get_base_type() const; - - MethodInfo method_cache; - void _update_method_cache(); - - void _set_argument_cache(const Dictionary &p_cache); - Dictionary _get_argument_cache() const; - -protected: - void _validate_property(PropertyInfo &p_property) const; - - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "functions"; } - - void set_basic_type(Variant::Type p_type); - Variant::Type get_basic_type() const; - - void set_base_type(const StringName &p_type); - StringName get_base_type() const; - - void set_base_script(const String &p_path); - String get_base_script() const; - - void set_singleton(const StringName &p_type); - StringName get_singleton() const; - - void set_function(const StringName &p_type); - StringName get_function() const; - - void set_base_path(const NodePath &p_type); - NodePath get_base_path() const; - - void set_call_mode(CallMode p_mode); - CallMode get_call_mode() const; - - void set_use_default_args(int p_amount); - int get_use_default_args() const; - - void set_validate(bool p_amount); - bool get_validate() const; - - void set_rpc_call_mode(RPCCallMode p_mode); - RPCCallMode get_rpc_call_mode() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; - - VisualScriptFunctionCall(); -}; - -VARIANT_ENUM_CAST(VisualScriptFunctionCall::CallMode); -VARIANT_ENUM_CAST(VisualScriptFunctionCall::RPCCallMode); - -class VisualScriptPropertySet : public VisualScriptNode { - GDCLASS(VisualScriptPropertySet, VisualScriptNode); - -public: - enum CallMode { - CALL_MODE_SELF, - CALL_MODE_NODE_PATH, - CALL_MODE_INSTANCE, - CALL_MODE_BASIC_TYPE, - - }; - - enum AssignOp { - ASSIGN_OP_NONE, - ASSIGN_OP_ADD, - ASSIGN_OP_SUB, - ASSIGN_OP_MUL, - ASSIGN_OP_DIV, - ASSIGN_OP_MOD, - ASSIGN_OP_SHIFT_LEFT, - ASSIGN_OP_SHIFT_RIGHT, - ASSIGN_OP_BIT_AND, - ASSIGN_OP_BIT_OR, - ASSIGN_OP_BIT_XOR, - ASSIGN_OP_MAX - }; - -private: - PropertyInfo type_cache; - - CallMode call_mode; - Variant::Type basic_type; - StringName base_type; - String base_script; - NodePath base_path; - StringName property; - StringName index; - AssignOp assign_op; - - Node *_get_base_node() const; - StringName _get_base_type() const; - - void _update_base_type(); - - void _update_cache(); - - void _set_type_cache(const Dictionary &p_type); - Dictionary _get_type_cache() const; - - void _adjust_input_index(PropertyInfo &pinfo) const; - -protected: - void _validate_property(PropertyInfo &p_property) const; - - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "functions"; } - - void set_base_type(const StringName &p_type); - StringName get_base_type() const; - - void set_base_script(const String &p_path); - String get_base_script() const; - - void set_basic_type(Variant::Type p_type); - Variant::Type get_basic_type() const; - - void set_property(const StringName &p_type); - StringName get_property() const; - - void set_base_path(const NodePath &p_type); - NodePath get_base_path() const; - - void set_call_mode(CallMode p_mode); - CallMode get_call_mode() const; - - void set_index(const StringName &p_type); - StringName get_index() const; - - void set_assign_op(AssignOp p_op); - AssignOp get_assign_op() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; - - VisualScriptPropertySet(); -}; - -VARIANT_ENUM_CAST(VisualScriptPropertySet::CallMode); -VARIANT_ENUM_CAST(VisualScriptPropertySet::AssignOp); - -class VisualScriptPropertyGet : public VisualScriptNode { - GDCLASS(VisualScriptPropertyGet, VisualScriptNode); - -public: - enum CallMode { - CALL_MODE_SELF, - CALL_MODE_NODE_PATH, - CALL_MODE_INSTANCE, - CALL_MODE_BASIC_TYPE, - - }; - -private: - Variant::Type type_cache; - - CallMode call_mode; - Variant::Type basic_type; - StringName base_type; - String base_script; - NodePath base_path; - StringName property; - StringName index; - - void _update_base_type(); - Node *_get_base_node() const; - StringName _get_base_type() const; - - void _update_cache(); - - void _set_type_cache(Variant::Type p_type); - Variant::Type _get_type_cache() const; - - void _adjust_input_index(PropertyInfo &pinfo) const; - -protected: - void _validate_property(PropertyInfo &p_property) const; - - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "functions"; } - - void set_base_type(const StringName &p_type); - StringName get_base_type() const; - - void set_base_script(const String &p_path); - String get_base_script() const; - - void set_basic_type(Variant::Type p_type); - Variant::Type get_basic_type() const; - - void set_property(const StringName &p_type); - StringName get_property() const; - - void set_base_path(const NodePath &p_type); - NodePath get_base_path() const; - - void set_call_mode(CallMode p_mode); - CallMode get_call_mode() const; - - void set_index(const StringName &p_type); - StringName get_index() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptPropertyGet(); -}; - -VARIANT_ENUM_CAST(VisualScriptPropertyGet::CallMode); - -class VisualScriptEmitSignal : public VisualScriptNode { - GDCLASS(VisualScriptEmitSignal, VisualScriptNode); - -private: - StringName name; - -protected: - void _validate_property(PropertyInfo &p_property) const; - - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - //virtual String get_text() const; - virtual String get_category() const override { return "functions"; } - - void set_signal(const StringName &p_type); - StringName get_signal() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptEmitSignal(); -}; - -void register_visual_script_func_nodes(); - -#endif // VISUAL_SCRIPT_FUNC_NODES_H diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp deleted file mode 100644 index f02a79a617..0000000000 --- a/modules/visual_script/visual_script_nodes.cpp +++ /dev/null @@ -1,4072 +0,0 @@ -/*************************************************************************/ -/* visual_script_nodes.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "visual_script_nodes.h" - -#include "core/config/engine.h" -#include "core/config/project_settings.h" -#include "core/core_constants.h" -#include "core/input/input.h" -#include "core/os/os.h" -#include "scene/main/node.h" -#include "scene/main/scene_tree.h" - -////////////////////////////////////////// -////////////////FUNCTION////////////////// -////////////////////////////////////////// - -bool VisualScriptFunction::_set(const StringName &p_name, const Variant &p_value) { - if (p_name == "argument_count") { - int new_argc = p_value; - int argc = arguments.size(); - if (argc == new_argc) { - return true; - } - - arguments.resize(new_argc); - - for (int i = argc; i < new_argc; i++) { - arguments.write[i].name = "arg" + itos(i + 1); - arguments.write[i].type = Variant::NIL; - } - ports_changed_notify(); - notify_property_list_changed(); - return true; - } - if (String(p_name).begins_with("argument_")) { - int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1; - ERR_FAIL_INDEX_V(idx, arguments.size(), false); - String what = String(p_name).get_slice("/", 1); - if (what == "type") { - Variant::Type new_type = Variant::Type(int(p_value)); - arguments.write[idx].type = new_type; - ports_changed_notify(); - - return true; - } - - if (what == "name") { - arguments.write[idx].name = p_value; - ports_changed_notify(); - return true; - } - } - - if (p_name == "stack/stackless") { - set_stack_less(p_value); - return true; - } - - if (p_name == "stack/size") { - stack_size = p_value; - return true; - } - - if (p_name == "rpc/mode") { - rpc_mode = MultiplayerAPI::RPCMode(int(p_value)); - return true; - } - - if (p_name == "sequenced/sequenced") { - sequenced = p_value; - ports_changed_notify(); - return true; - } - - return false; -} - -bool VisualScriptFunction::_get(const StringName &p_name, Variant &r_ret) const { - if (p_name == "argument_count") { - r_ret = arguments.size(); - return true; - } - if (String(p_name).begins_with("argument_")) { - int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1; - ERR_FAIL_INDEX_V(idx, arguments.size(), false); - String what = String(p_name).get_slice("/", 1); - if (what == "type") { - r_ret = arguments[idx].type; - return true; - } - if (what == "name") { - r_ret = arguments[idx].name; - return true; - } - } - - if (p_name == "stack/stackless") { - r_ret = stack_less; - return true; - } - - if (p_name == "stack/size") { - r_ret = stack_size; - return true; - } - - if (p_name == "rpc/mode") { - r_ret = rpc_mode; - return true; - } - - if (p_name == "sequenced/sequenced") { - r_ret = sequenced; - return true; - } - - return false; -} - -void VisualScriptFunction::_get_property_list(List<PropertyInfo> *p_list) const { - p_list->push_back(PropertyInfo(Variant::INT, "argument_count", PROPERTY_HINT_RANGE, "0,256")); - String argt = "Any"; - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - argt += "," + Variant::get_type_name(Variant::Type(i)); - } - - for (int i = 0; i < arguments.size(); i++) { - p_list->push_back(PropertyInfo(Variant::INT, "argument_" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt)); - p_list->push_back(PropertyInfo(Variant::STRING, "argument_" + itos(i + 1) + "/name")); - } - - p_list->push_back(PropertyInfo(Variant::BOOL, "sequenced/sequenced")); - - if (!stack_less) { - p_list->push_back(PropertyInfo(Variant::INT, "stack/size", PROPERTY_HINT_RANGE, "1,100000")); - } - p_list->push_back(PropertyInfo(Variant::BOOL, "stack/stackless")); - p_list->push_back(PropertyInfo(Variant::INT, "rpc/mode", PROPERTY_HINT_ENUM, "Disabled,Any,Authority")); -} - -int VisualScriptFunction::get_output_sequence_port_count() const { - return 1; -} - -bool VisualScriptFunction::has_input_sequence_port() const { - return false; -} - -int VisualScriptFunction::get_input_value_port_count() const { - return 0; -} - -int VisualScriptFunction::get_output_value_port_count() const { - return arguments.size(); -} - -String VisualScriptFunction::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptFunction::get_input_value_port_info(int p_idx) const { - ERR_FAIL_V(PropertyInfo()); -} - -PropertyInfo VisualScriptFunction::get_output_value_port_info(int p_idx) const { - // Need to check it without ERR_FAIL_COND, to prevent warnings from appearing on node creation via dragging. - if (p_idx < 0 || p_idx >= arguments.size()) { - return PropertyInfo(); - } - PropertyInfo out; - out.type = arguments[p_idx].type; - out.name = arguments[p_idx].name; - out.hint = arguments[p_idx].hint; - out.hint_string = arguments[p_idx].hint_string; - return out; -} - -String VisualScriptFunction::get_caption() const { - return RTR("Function"); -} - -String VisualScriptFunction::get_text() const { - return get_name(); //use name as function name I guess -} - -void VisualScriptFunction::add_argument(Variant::Type p_type, const String &p_name, int p_index, const PropertyHint p_hint, const String &p_hint_string) { - Argument arg; - arg.name = p_name; - arg.type = p_type; - arg.hint = p_hint; - arg.hint_string = p_hint_string; - if (p_index >= 0) { - arguments.insert(p_index, arg); - } else { - arguments.push_back(arg); - } - - ports_changed_notify(); -} - -void VisualScriptFunction::set_argument_type(int p_argidx, Variant::Type p_type) { - ERR_FAIL_INDEX(p_argidx, arguments.size()); - - arguments.write[p_argidx].type = p_type; - ports_changed_notify(); -} - -Variant::Type VisualScriptFunction::get_argument_type(int p_argidx) const { - ERR_FAIL_INDEX_V(p_argidx, arguments.size(), Variant::NIL); - return arguments[p_argidx].type; -} - -void VisualScriptFunction::set_argument_name(int p_argidx, const String &p_name) { - ERR_FAIL_INDEX(p_argidx, arguments.size()); - - arguments.write[p_argidx].name = p_name; - ports_changed_notify(); -} - -String VisualScriptFunction::get_argument_name(int p_argidx) const { - ERR_FAIL_INDEX_V(p_argidx, arguments.size(), String()); - return arguments[p_argidx].name; -} - -void VisualScriptFunction::remove_argument(int p_argidx) { - ERR_FAIL_INDEX(p_argidx, arguments.size()); - - arguments.remove_at(p_argidx); - ports_changed_notify(); -} - -int VisualScriptFunction::get_argument_count() const { - return arguments.size(); -} - -void VisualScriptFunction::set_rpc_mode(MultiplayerAPI::RPCMode p_mode) { - rpc_mode = p_mode; -} - -MultiplayerAPI::RPCMode VisualScriptFunction::get_rpc_mode() const { - return rpc_mode; -} - -class VisualScriptNodeInstanceFunction : public VisualScriptNodeInstance { -public: - VisualScriptFunction *node = nullptr; - VisualScriptInstance *instance = nullptr; - - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - int ac = node->get_argument_count(); - - for (int i = 0; i < ac; i++) { -#ifdef DEBUG_ENABLED - Variant::Type expected = node->get_argument_type(i); - if (expected != Variant::NIL) { - if (!Variant::can_convert_strict(p_inputs[i]->get_type(), expected)) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.expected = expected; - r_error.argument = i; - return 0; - } - } -#endif - - *p_outputs[i] = *p_inputs[i]; - } - - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptFunction::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceFunction *instance = memnew(VisualScriptNodeInstanceFunction); - instance->node = this; - instance->instance = p_instance; - return instance; -} - -void VisualScriptFunction::reset_state() { - arguments.clear(); - stack_size = 256; - stack_less = false; - sequenced = true; - rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; -} - -VisualScriptFunction::VisualScriptFunction() { - stack_size = 256; - stack_less = false; - sequenced = true; - rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; -} - -void VisualScriptFunction::set_stack_less(bool p_enable) { - stack_less = p_enable; - notify_property_list_changed(); -} - -bool VisualScriptFunction::is_stack_less() const { - return stack_less; -} - -void VisualScriptFunction::set_sequenced(bool p_enable) { - sequenced = p_enable; -} - -bool VisualScriptFunction::is_sequenced() const { - return sequenced; -} - -void VisualScriptFunction::set_stack_size(int p_size) { - ERR_FAIL_COND(p_size < 1 || p_size > 100000); - stack_size = p_size; -} - -int VisualScriptFunction::get_stack_size() const { - return stack_size; -} - -////////////////////////////////////////// -/////////////////LISTS//////////////////// -////////////////////////////////////////// - -int VisualScriptLists::get_output_sequence_port_count() const { - if (sequenced) { - return 1; - } - return 0; -} - -bool VisualScriptLists::has_input_sequence_port() const { - return sequenced; -} - -String VisualScriptLists::get_output_sequence_port_text(int p_port) const { - return ""; -} - -int VisualScriptLists::get_input_value_port_count() const { - return inputports.size(); -} - -int VisualScriptLists::get_output_value_port_count() const { - return outputports.size(); -} - -PropertyInfo VisualScriptLists::get_input_value_port_info(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, inputports.size(), PropertyInfo()); - - PropertyInfo pi; - pi.name = inputports[p_idx].name; - pi.type = inputports[p_idx].type; - return pi; -} - -PropertyInfo VisualScriptLists::get_output_value_port_info(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, outputports.size(), PropertyInfo()); - - PropertyInfo pi; - pi.name = outputports[p_idx].name; - pi.type = outputports[p_idx].type; - return pi; -} - -bool VisualScriptLists::is_input_port_editable() const { - return ((flags & INPUT_EDITABLE) == INPUT_EDITABLE); -} - -bool VisualScriptLists::is_input_port_name_editable() const { - return ((flags & INPUT_NAME_EDITABLE) == INPUT_NAME_EDITABLE); -} - -bool VisualScriptLists::is_input_port_type_editable() const { - return ((flags & INPUT_TYPE_EDITABLE) == INPUT_TYPE_EDITABLE); -} - -bool VisualScriptLists::is_output_port_editable() const { - return ((flags & OUTPUT_EDITABLE) == OUTPUT_EDITABLE); -} - -bool VisualScriptLists::is_output_port_name_editable() const { - return ((flags & INPUT_NAME_EDITABLE) == INPUT_NAME_EDITABLE); -} - -bool VisualScriptLists::is_output_port_type_editable() const { - return ((flags & INPUT_TYPE_EDITABLE) == INPUT_TYPE_EDITABLE); -} - -// for the inspector -bool VisualScriptLists::_set(const StringName &p_name, const Variant &p_value) { - if (p_name == "input_count" && is_input_port_editable()) { - int new_argc = p_value; - int argc = inputports.size(); - if (argc == new_argc) { - return true; - } - - inputports.resize(new_argc); - - for (int i = argc; i < new_argc; i++) { - inputports.write[i].name = "arg" + itos(i + 1); - inputports.write[i].type = Variant::NIL; - } - ports_changed_notify(); - notify_property_list_changed(); - return true; - } - if (String(p_name).begins_with("input_") && is_input_port_editable()) { - int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1; - ERR_FAIL_INDEX_V(idx, inputports.size(), false); - String what = String(p_name).get_slice("/", 1); - if (what == "type") { - Variant::Type new_type = Variant::Type(int(p_value)); - inputports.write[idx].type = new_type; - ports_changed_notify(); - - return true; - } - - if (what == "name") { - inputports.write[idx].name = p_value; - ports_changed_notify(); - return true; - } - } - - if (p_name == "output_count" && is_output_port_editable()) { - int new_argc = p_value; - int argc = outputports.size(); - if (argc == new_argc) { - return true; - } - - outputports.resize(new_argc); - - for (int i = argc; i < new_argc; i++) { - outputports.write[i].name = "arg" + itos(i + 1); - outputports.write[i].type = Variant::NIL; - } - ports_changed_notify(); - notify_property_list_changed(); - return true; - } - if (String(p_name).begins_with("output_") && is_output_port_editable()) { - int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1; - ERR_FAIL_INDEX_V(idx, outputports.size(), false); - String what = String(p_name).get_slice("/", 1); - if (what == "type") { - Variant::Type new_type = Variant::Type(int(p_value)); - outputports.write[idx].type = new_type; - ports_changed_notify(); - - return true; - } - - if (what == "name") { - outputports.write[idx].name = p_value; - ports_changed_notify(); - return true; - } - } - - if (p_name == "sequenced/sequenced") { - sequenced = p_value; - ports_changed_notify(); - return true; - } - - return false; -} - -bool VisualScriptLists::_get(const StringName &p_name, Variant &r_ret) const { - if (p_name == "input_count" && is_input_port_editable()) { - r_ret = inputports.size(); - return true; - } - if (String(p_name).begins_with("input_") && is_input_port_editable()) { - int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1; - ERR_FAIL_INDEX_V(idx, inputports.size(), false); - String what = String(p_name).get_slice("/", 1); - if (what == "type") { - r_ret = inputports[idx].type; - return true; - } - if (what == "name") { - r_ret = inputports[idx].name; - return true; - } - } - - if (p_name == "output_count" && is_output_port_editable()) { - r_ret = outputports.size(); - return true; - } - if (String(p_name).begins_with("output_") && is_output_port_editable()) { - int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1; - ERR_FAIL_INDEX_V(idx, outputports.size(), false); - String what = String(p_name).get_slice("/", 1); - if (what == "type") { - r_ret = outputports[idx].type; - return true; - } - if (what == "name") { - r_ret = outputports[idx].name; - return true; - } - } - - if (p_name == "sequenced/sequenced") { - r_ret = sequenced; - return true; - } - - return false; -} - -void VisualScriptLists::_get_property_list(List<PropertyInfo> *p_list) const { - if (is_input_port_editable()) { - p_list->push_back(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,256")); - String argt = "Any"; - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - argt += "," + Variant::get_type_name(Variant::Type(i)); - } - - for (int i = 0; i < inputports.size(); i++) { - p_list->push_back(PropertyInfo(Variant::INT, "input_" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt)); - p_list->push_back(PropertyInfo(Variant::STRING, "input_" + itos(i + 1) + "/name")); - } - } - - if (is_output_port_editable()) { - p_list->push_back(PropertyInfo(Variant::INT, "output_count", PROPERTY_HINT_RANGE, "0,256")); - String argt = "Any"; - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - argt += "," + Variant::get_type_name(Variant::Type(i)); - } - - for (int i = 0; i < outputports.size(); i++) { - p_list->push_back(PropertyInfo(Variant::INT, "output_" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt)); - p_list->push_back(PropertyInfo(Variant::STRING, "output_" + itos(i + 1) + "/name")); - } - } - p_list->push_back(PropertyInfo(Variant::BOOL, "sequenced/sequenced")); -} - -// input data port interaction -void VisualScriptLists::add_input_data_port(Variant::Type p_type, const String &p_name, int p_index) { - if (!is_input_port_editable()) { - return; - } - - Port inp; - inp.name = p_name; - inp.type = p_type; - if (p_index >= 0) { - inputports.insert(p_index, inp); - } else { - inputports.push_back(inp); - } - - ports_changed_notify(); - notify_property_list_changed(); -} - -void VisualScriptLists::set_input_data_port_type(int p_idx, Variant::Type p_type) { - if (!is_input_port_type_editable()) { - return; - } - - ERR_FAIL_INDEX(p_idx, inputports.size()); - - inputports.write[p_idx].type = p_type; - ports_changed_notify(); - notify_property_list_changed(); -} - -void VisualScriptLists::set_input_data_port_name(int p_idx, const String &p_name) { - if (!is_input_port_name_editable()) { - return; - } - - ERR_FAIL_INDEX(p_idx, inputports.size()); - - inputports.write[p_idx].name = p_name; - ports_changed_notify(); - notify_property_list_changed(); -} - -void VisualScriptLists::remove_input_data_port(int p_argidx) { - if (!is_input_port_editable()) { - return; - } - - ERR_FAIL_INDEX(p_argidx, inputports.size()); - - inputports.remove_at(p_argidx); - - ports_changed_notify(); - notify_property_list_changed(); -} - -// output data port interaction -void VisualScriptLists::add_output_data_port(Variant::Type p_type, const String &p_name, int p_index) { - if (!is_output_port_editable()) { - return; - } - - Port out; - out.name = p_name; - out.type = p_type; - if (p_index >= 0) { - outputports.insert(p_index, out); - } else { - outputports.push_back(out); - } - - ports_changed_notify(); - notify_property_list_changed(); -} - -void VisualScriptLists::set_output_data_port_type(int p_idx, Variant::Type p_type) { - if (!is_output_port_type_editable()) { - return; - } - - ERR_FAIL_INDEX(p_idx, outputports.size()); - - outputports.write[p_idx].type = p_type; - ports_changed_notify(); - notify_property_list_changed(); -} - -void VisualScriptLists::set_output_data_port_name(int p_idx, const String &p_name) { - if (!is_output_port_name_editable()) { - return; - } - - ERR_FAIL_INDEX(p_idx, outputports.size()); - - outputports.write[p_idx].name = p_name; - ports_changed_notify(); - notify_property_list_changed(); -} - -void VisualScriptLists::remove_output_data_port(int p_argidx) { - if (!is_output_port_editable()) { - return; - } - - ERR_FAIL_INDEX(p_argidx, outputports.size()); - - outputports.remove_at(p_argidx); - - ports_changed_notify(); - notify_property_list_changed(); -} - -// sequences -void VisualScriptLists::set_sequenced(bool p_enable) { - if (sequenced == p_enable) { - return; - } - sequenced = p_enable; - ports_changed_notify(); -} - -bool VisualScriptLists::is_sequenced() const { - return sequenced; -} - -void VisualScriptLists::reset_state() { - inputports.clear(); - outputports.clear(); - sequenced = false; - flags = 0; -} - -VisualScriptLists::VisualScriptLists() { - // initialize - sequenced = false; - flags = 0; -} - -void VisualScriptLists::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_input_data_port", "type", "name", "index"), &VisualScriptLists::add_input_data_port); - ClassDB::bind_method(D_METHOD("set_input_data_port_name", "index", "name"), &VisualScriptLists::set_input_data_port_name); - ClassDB::bind_method(D_METHOD("set_input_data_port_type", "index", "type"), &VisualScriptLists::set_input_data_port_type); - ClassDB::bind_method(D_METHOD("remove_input_data_port", "index"), &VisualScriptLists::remove_input_data_port); - - ClassDB::bind_method(D_METHOD("add_output_data_port", "type", "name", "index"), &VisualScriptLists::add_output_data_port); - ClassDB::bind_method(D_METHOD("set_output_data_port_name", "index", "name"), &VisualScriptLists::set_output_data_port_name); - ClassDB::bind_method(D_METHOD("set_output_data_port_type", "index", "type"), &VisualScriptLists::set_output_data_port_type); - ClassDB::bind_method(D_METHOD("remove_output_data_port", "index"), &VisualScriptLists::remove_output_data_port); -} - -////////////////////////////////////////// -//////////////COMPOSEARRAY//////////////// -////////////////////////////////////////// - -int VisualScriptComposeArray::get_output_sequence_port_count() const { - if (sequenced) { - return 1; - } - return 0; -} - -bool VisualScriptComposeArray::has_input_sequence_port() const { - return sequenced; -} - -String VisualScriptComposeArray::get_output_sequence_port_text(int p_port) const { - return ""; -} - -int VisualScriptComposeArray::get_input_value_port_count() const { - return inputports.size(); -} - -int VisualScriptComposeArray::get_output_value_port_count() const { - return 1; -} - -PropertyInfo VisualScriptComposeArray::get_input_value_port_info(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, inputports.size(), PropertyInfo()); - - PropertyInfo pi; - pi.name = inputports[p_idx].name; - pi.type = inputports[p_idx].type; - return pi; -} - -PropertyInfo VisualScriptComposeArray::get_output_value_port_info(int p_idx) const { - PropertyInfo pi; - pi.name = "out"; - pi.type = Variant::ARRAY; - return pi; -} - -String VisualScriptComposeArray::get_caption() const { - return RTR("Compose Array"); -} - -String VisualScriptComposeArray::get_text() const { - return ""; -} - -class VisualScriptComposeArrayNode : public VisualScriptNodeInstance { -public: - int input_count = 0; - virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - if (input_count > 0) { - Array arr; - for (int i = 0; i < input_count; i++) { - arr.push_back((*p_inputs[i])); - } - Variant va = Variant(arr); - - *p_outputs[0] = va; - } - - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptComposeArray::instantiate(VisualScriptInstance *p_instance) { - VisualScriptComposeArrayNode *instance = memnew(VisualScriptComposeArrayNode); - instance->input_count = inputports.size(); - return instance; -} - -VisualScriptComposeArray::VisualScriptComposeArray() { - // initialize stuff here - sequenced = false; - flags = INPUT_EDITABLE; -} - -////////////////////////////////////////// -////////////////OPERATOR////////////////// -////////////////////////////////////////// - -int VisualScriptOperator::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptOperator::has_input_sequence_port() const { - return false; -} - -int VisualScriptOperator::get_input_value_port_count() const { - return (op == Variant::OP_BIT_NEGATE || op == Variant::OP_NOT || op == Variant::OP_NEGATE || op == Variant::OP_POSITIVE) ? 1 : 2; -} - -int VisualScriptOperator::get_output_value_port_count() const { - return 1; -} - -String VisualScriptOperator::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptOperator::get_input_value_port_info(int p_idx) const { - static const Variant::Type port_types[Variant::OP_MAX][2] = { - { Variant::NIL, Variant::NIL }, //OP_EQUAL, - { Variant::NIL, Variant::NIL }, //OP_NOT_EQUAL, - { Variant::NIL, Variant::NIL }, //OP_LESS, - { Variant::NIL, Variant::NIL }, //OP_LESS_EQUAL, - { Variant::NIL, Variant::NIL }, //OP_GREATER, - { Variant::NIL, Variant::NIL }, //OP_GREATER_EQUAL, - //mathematic - { Variant::NIL, Variant::NIL }, //OP_ADD, - { Variant::NIL, Variant::NIL }, //OP_SUBTRACT, - { Variant::NIL, Variant::NIL }, //OP_MULTIPLY, - { Variant::NIL, Variant::NIL }, //OP_DIVIDE, - { Variant::NIL, Variant::NIL }, //OP_NEGATE, - { Variant::NIL, Variant::NIL }, //OP_POSITIVE, - { Variant::INT, Variant::INT }, //OP_MODULE, - //bitwise - { Variant::INT, Variant::INT }, //OP_SHIFT_LEFT, - { Variant::INT, Variant::INT }, //OP_SHIFT_RIGHT, - { Variant::INT, Variant::INT }, //OP_BIT_AND, - { Variant::INT, Variant::INT }, //OP_BIT_OR, - { Variant::INT, Variant::INT }, //OP_BIT_XOR, - { Variant::INT, Variant::INT }, //OP_BIT_NEGATE, - //logic - { Variant::BOOL, Variant::BOOL }, //OP_AND, - { Variant::BOOL, Variant::BOOL }, //OP_OR, - { Variant::BOOL, Variant::BOOL }, //OP_XOR, - { Variant::BOOL, Variant::BOOL }, //OP_NOT, - //containment - { Variant::NIL, Variant::NIL } //OP_IN, - }; - - ERR_FAIL_INDEX_V(p_idx, 2, PropertyInfo()); - - PropertyInfo pinfo; - pinfo.name = p_idx == 0 ? "A" : "B"; - pinfo.type = port_types[op][p_idx]; - if (pinfo.type == Variant::NIL) { - pinfo.type = typed; - } - return pinfo; -} - -PropertyInfo VisualScriptOperator::get_output_value_port_info(int p_idx) const { - static const Variant::Type port_types[Variant::OP_MAX] = { - //comparison - Variant::BOOL, //OP_EQUAL, - Variant::BOOL, //OP_NOT_EQUAL, - Variant::BOOL, //OP_LESS, - Variant::BOOL, //OP_LESS_EQUAL, - Variant::BOOL, //OP_GREATER, - Variant::BOOL, //OP_GREATER_EQUAL, - //mathematic - Variant::NIL, //OP_ADD, - Variant::NIL, //OP_SUBTRACT, - Variant::NIL, //OP_MULTIPLY, - Variant::NIL, //OP_DIVIDE, - Variant::NIL, //OP_NEGATE, - Variant::NIL, //OP_POSITIVE, - Variant::INT, //OP_MODULE, - //bitwise - Variant::INT, //OP_SHIFT_LEFT, - Variant::INT, //OP_SHIFT_RIGHT, - Variant::INT, //OP_BIT_AND, - Variant::INT, //OP_BIT_OR, - Variant::INT, //OP_BIT_XOR, - Variant::INT, //OP_BIT_NEGATE, - //logic - Variant::BOOL, //OP_AND, - Variant::BOOL, //OP_OR, - Variant::BOOL, //OP_XOR, - Variant::BOOL, //OP_NOT, - //containment - Variant::BOOL //OP_IN, - }; - - PropertyInfo pinfo; - pinfo.name = ""; - pinfo.type = port_types[op]; - if (pinfo.type == Variant::NIL) { - pinfo.type = typed; - } - return pinfo; -} - -String VisualScriptOperator::get_caption() const { - switch (op) { - // comparison - case Variant::OP_EQUAL: - return U"A = B"; - case Variant::OP_NOT_EQUAL: - return U"A \u2260 B"; - case Variant::OP_LESS: - return U"A < B"; - case Variant::OP_LESS_EQUAL: - return U"A \u2264 B"; - case Variant::OP_GREATER: - return U"A > B"; - case Variant::OP_GREATER_EQUAL: - return U"A \u2265 B"; - - // mathematic - case Variant::OP_ADD: - return U"A + B"; - case Variant::OP_SUBTRACT: - return U"A - B"; - case Variant::OP_MULTIPLY: - return U"A \u00D7 B"; - case Variant::OP_DIVIDE: - return U"A \u00F7 B"; - case Variant::OP_NEGATE: - return U"\u00AC A"; - case Variant::OP_POSITIVE: - return U"+ A"; - case Variant::OP_MODULE: - return U"A mod B"; - - // bitwise - case Variant::OP_SHIFT_LEFT: - return U"A << B"; - case Variant::OP_SHIFT_RIGHT: - return U"A >> B"; - case Variant::OP_BIT_AND: - return U"A & B"; - case Variant::OP_BIT_OR: - return U"A | B"; - case Variant::OP_BIT_XOR: - return U"A ^ B"; - case Variant::OP_BIT_NEGATE: - return U"~A"; - - // logic - case Variant::OP_AND: - return U"A and B"; - case Variant::OP_OR: - return U"A or B"; - case Variant::OP_XOR: - return U"A xor B"; - case Variant::OP_NOT: - return U"not A"; - case Variant::OP_IN: - return U"A in B"; - - default: { - ERR_FAIL_V_MSG( - U"Unknown node", - U"Unknown node type encountered, caption not available."); - } - } -} - -String VisualScriptOperator::get_operator_name(Variant::Operator p_op) { - switch (p_op) { - // comparison - case Variant::OP_EQUAL: - return "Are Equal"; - case Variant::OP_NOT_EQUAL: - return "Are Not Equal"; - case Variant::OP_LESS: - return "Less Than"; - case Variant::OP_LESS_EQUAL: - return "Less Than or Equal"; - case Variant::OP_GREATER: - return "Greater Than"; - case Variant::OP_GREATER_EQUAL: - return "Greater Than or Equal"; - - // mathematic - case Variant::OP_ADD: - return "Add"; - case Variant::OP_SUBTRACT: - return "Subtract"; - case Variant::OP_MULTIPLY: - return "Multiply"; - case Variant::OP_DIVIDE: - return "Divide"; - case Variant::OP_NEGATE: - return "Negate"; - case Variant::OP_POSITIVE: - return "Positive"; - case Variant::OP_MODULE: - return "Remainder"; - - // bitwise - case Variant::OP_SHIFT_LEFT: - return "Bit Shift Left"; - case Variant::OP_SHIFT_RIGHT: - return "Bit Shift Right"; - case Variant::OP_BIT_AND: - return "Bit And"; - case Variant::OP_BIT_OR: - return "Bit Or"; - case Variant::OP_BIT_XOR: - return "Bit Xor"; - case Variant::OP_BIT_NEGATE: - return "Bit Negate"; - - // logic - case Variant::OP_AND: - return "And"; - case Variant::OP_OR: - return "Or"; - case Variant::OP_XOR: - return "Xor"; - case Variant::OP_NOT: - return "Not"; - case Variant::OP_IN: - return "In"; - - default: { - ERR_FAIL_INDEX_V(p_op, Variant::OP_MAX, ""); - return "Unknown Operator"; - } - } -} - -void VisualScriptOperator::set_operator(Variant::Operator p_op) { - if (op == p_op) { - return; - } - op = p_op; - ports_changed_notify(); -} - -Variant::Operator VisualScriptOperator::get_operator() const { - return op; -} - -void VisualScriptOperator::set_typed(Variant::Type p_op) { - if (typed == p_op) { - return; - } - - typed = p_op; - ports_changed_notify(); -} - -Variant::Type VisualScriptOperator::get_typed() const { - return typed; -} - -void VisualScriptOperator::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualScriptOperator::set_operator); - ClassDB::bind_method(D_METHOD("get_operator"), &VisualScriptOperator::get_operator); - - ClassDB::bind_method(D_METHOD("set_typed", "type"), &VisualScriptOperator::set_typed); - ClassDB::bind_method(D_METHOD("get_typed"), &VisualScriptOperator::get_typed); - - String types; - for (int i = 0; i < Variant::OP_MAX; i++) { - if (i > 0) { - types += ","; - } - types += get_operator_name(static_cast<Variant::Operator>(i)); - } - - String argt = "Any"; - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - argt += "," + Variant::get_type_name(Variant::Type(i)); - } - - ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, types), "set_operator", "get_operator"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_typed", "get_typed"); -} - -class VisualScriptNodeInstanceOperator : public VisualScriptNodeInstance { -public: - bool unary = false; - Variant::Operator op; - - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - bool valid; - if (unary) { - Variant::evaluate(op, *p_inputs[0], Variant(), *p_outputs[0], valid); - } else { - Variant::evaluate(op, *p_inputs[0], *p_inputs[1], *p_outputs[0], valid); - } - - if (!valid) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - if (p_outputs[0]->get_type() == Variant::STRING) { - r_error_str = *p_outputs[0]; - } else { - if (unary) { - r_error_str = String(Variant::get_operator_name(op)) + ": " + RTR("Invalid argument of type:") + " " + Variant::get_type_name(p_inputs[0]->get_type()); - } else { - r_error_str = String(Variant::get_operator_name(op)) + ": " + RTR("Invalid arguments:") + " A: " + Variant::get_type_name(p_inputs[0]->get_type()) + ", B: " + Variant::get_type_name(p_inputs[1]->get_type()); - } - } - } - - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptOperator::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceOperator *instance = memnew(VisualScriptNodeInstanceOperator); - instance->unary = get_input_value_port_count() == 1; - instance->op = op; - return instance; -} - -VisualScriptOperator::VisualScriptOperator() { - op = Variant::OP_ADD; - typed = Variant::NIL; -} - -template <Variant::Operator OP> -static Ref<VisualScriptNode> create_op_node(const String &p_name) { - Ref<VisualScriptOperator> node; - node.instantiate(); - node->set_operator(OP); - return node; -} - -////////////////////////////////////////// -////////////////OPERATOR////////////////// -////////////////////////////////////////// - -int VisualScriptSelect::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptSelect::has_input_sequence_port() const { - return false; -} - -int VisualScriptSelect::get_input_value_port_count() const { - return 3; -} - -int VisualScriptSelect::get_output_value_port_count() const { - return 1; -} - -String VisualScriptSelect::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptSelect::get_input_value_port_info(int p_idx) const { - if (p_idx == 0) { - return PropertyInfo(Variant::BOOL, "cond"); - } else if (p_idx == 1) { - return PropertyInfo(typed, "a"); - } else { - return PropertyInfo(typed, "b"); - } -} - -PropertyInfo VisualScriptSelect::get_output_value_port_info(int p_idx) const { - return PropertyInfo(typed, "out"); -} - -String VisualScriptSelect::get_caption() const { - return RTR("Select"); -} - -String VisualScriptSelect::get_text() const { - return RTR("a if cond, else b"); -} - -void VisualScriptSelect::set_typed(Variant::Type p_op) { - if (typed == p_op) { - return; - } - - typed = p_op; - ports_changed_notify(); -} - -Variant::Type VisualScriptSelect::get_typed() const { - return typed; -} - -void VisualScriptSelect::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_typed", "type"), &VisualScriptSelect::set_typed); - ClassDB::bind_method(D_METHOD("get_typed"), &VisualScriptSelect::get_typed); - - String argt = "Any"; - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - argt += "," + Variant::get_type_name(Variant::Type(i)); - } - - ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_typed", "get_typed"); -} - -class VisualScriptNodeInstanceSelect : public VisualScriptNodeInstance { -public: - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - bool cond = *p_inputs[0]; - if (cond) { - *p_outputs[0] = *p_inputs[1]; - } else { - *p_outputs[0] = *p_inputs[2]; - } - - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptSelect::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceSelect *instance = memnew(VisualScriptNodeInstanceSelect); - return instance; -} - -VisualScriptSelect::VisualScriptSelect() { - typed = Variant::NIL; -} - -////////////////////////////////////////// -////////////////VARIABLE GET////////////////// -////////////////////////////////////////// - -int VisualScriptVariableGet::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptVariableGet::has_input_sequence_port() const { - return false; -} - -int VisualScriptVariableGet::get_input_value_port_count() const { - return 0; -} - -int VisualScriptVariableGet::get_output_value_port_count() const { - return 1; -} - -String VisualScriptVariableGet::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptVariableGet::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptVariableGet::get_output_value_port_info(int p_idx) const { - PropertyInfo pinfo; - pinfo.name = "value"; - if (get_visual_script().is_valid() && get_visual_script()->has_variable(variable)) { - PropertyInfo vinfo = get_visual_script()->get_variable_info(variable); - pinfo.type = vinfo.type; - pinfo.hint = vinfo.hint; - pinfo.hint_string = vinfo.hint_string; - } - return pinfo; -} - -String VisualScriptVariableGet::get_caption() const { - return vformat(RTR("Get %s"), variable); -} - -void VisualScriptVariableGet::set_variable(StringName p_variable) { - if (variable == p_variable) { - return; - } - variable = p_variable; - ports_changed_notify(); -} - -StringName VisualScriptVariableGet::get_variable() const { - return variable; -} - -void VisualScriptVariableGet::_validate_property(PropertyInfo &p_property) const { - if (p_property.name == "var_name" && get_visual_script().is_valid()) { - Ref<VisualScript> vs = get_visual_script(); - List<StringName> vars; - vs->get_variable_list(&vars); - - String vhint; - for (const StringName &E : vars) { - if (!vhint.is_empty()) { - vhint += ","; - } - - vhint += E.operator String(); - } - - p_property.hint = PROPERTY_HINT_ENUM; - p_property.hint_string = vhint; - } -} - -void VisualScriptVariableGet::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_variable", "name"), &VisualScriptVariableGet::set_variable); - ClassDB::bind_method(D_METHOD("get_variable"), &VisualScriptVariableGet::get_variable); - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_variable", "get_variable"); -} - -class VisualScriptNodeInstanceVariableGet : public VisualScriptNodeInstance { -public: - VisualScriptVariableGet *node = nullptr; - VisualScriptInstance *instance = nullptr; - StringName variable; - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - if (!instance->get_variable(variable, p_outputs[0])) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = RTR("VariableGet not found in script:") + " '" + String(variable) + "'"; - return 0; - } - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptVariableGet::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceVariableGet *instance = memnew(VisualScriptNodeInstanceVariableGet); - instance->node = this; - instance->instance = p_instance; - instance->variable = variable; - return instance; -} - -VisualScriptVariableGet::VisualScriptVariableGet() { -} - -////////////////////////////////////////// -////////////////VARIABLE SET////////////////// -////////////////////////////////////////// - -int VisualScriptVariableSet::get_output_sequence_port_count() const { - return 1; -} - -bool VisualScriptVariableSet::has_input_sequence_port() const { - return true; -} - -int VisualScriptVariableSet::get_input_value_port_count() const { - return 1; -} - -int VisualScriptVariableSet::get_output_value_port_count() const { - return 0; -} - -String VisualScriptVariableSet::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptVariableSet::get_input_value_port_info(int p_idx) const { - PropertyInfo pinfo; - pinfo.name = "set"; - if (get_visual_script().is_valid() && get_visual_script()->has_variable(variable)) { - PropertyInfo vinfo = get_visual_script()->get_variable_info(variable); - pinfo.type = vinfo.type; - pinfo.hint = vinfo.hint; - pinfo.hint_string = vinfo.hint_string; - } - return pinfo; -} - -PropertyInfo VisualScriptVariableSet::get_output_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -String VisualScriptVariableSet::get_caption() const { - return vformat(RTR("Set %s"), variable); -} - -void VisualScriptVariableSet::set_variable(StringName p_variable) { - if (variable == p_variable) { - return; - } - variable = p_variable; - ports_changed_notify(); -} - -StringName VisualScriptVariableSet::get_variable() const { - return variable; -} - -void VisualScriptVariableSet::_validate_property(PropertyInfo &p_property) const { - if (p_property.name == "var_name" && get_visual_script().is_valid()) { - Ref<VisualScript> vs = get_visual_script(); - List<StringName> vars; - vs->get_variable_list(&vars); - - String vhint; - for (const StringName &E : vars) { - if (!vhint.is_empty()) { - vhint += ","; - } - - vhint += E.operator String(); - } - - p_property.hint = PROPERTY_HINT_ENUM; - p_property.hint_string = vhint; - } -} - -void VisualScriptVariableSet::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_variable", "name"), &VisualScriptVariableSet::set_variable); - ClassDB::bind_method(D_METHOD("get_variable"), &VisualScriptVariableSet::get_variable); - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_variable", "get_variable"); -} - -class VisualScriptNodeInstanceVariableSet : public VisualScriptNodeInstance { -public: - VisualScriptVariableSet *node = nullptr; - VisualScriptInstance *instance = nullptr; - StringName variable; - - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - if (!instance->set_variable(variable, *p_inputs[0])) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = RTR("VariableSet not found in script:") + " '" + String(variable) + "'"; - } - - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptVariableSet::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceVariableSet *instance = memnew(VisualScriptNodeInstanceVariableSet); - instance->node = this; - instance->instance = p_instance; - instance->variable = variable; - return instance; -} - -VisualScriptVariableSet::VisualScriptVariableSet() { -} - -////////////////////////////////////////// -////////////////CONSTANT////////////////// -////////////////////////////////////////// - -int VisualScriptConstant::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptConstant::has_input_sequence_port() const { - return false; -} - -int VisualScriptConstant::get_input_value_port_count() const { - return 0; -} - -int VisualScriptConstant::get_output_value_port_count() const { - return 1; -} - -String VisualScriptConstant::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptConstant::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptConstant::get_output_value_port_info(int p_idx) const { - PropertyInfo pinfo; - pinfo.name = String(value); - pinfo.type = type; - return pinfo; -} - -String VisualScriptConstant::get_caption() const { - return RTR("Constant"); -} - -void VisualScriptConstant::set_constant_type(Variant::Type p_type) { - if (type == p_type) { - return; - } - - type = p_type; - Callable::CallError ce; - Variant::construct(type, value, nullptr, 0, ce); - ports_changed_notify(); - notify_property_list_changed(); -} - -Variant::Type VisualScriptConstant::get_constant_type() const { - return type; -} - -void VisualScriptConstant::set_constant_value(Variant p_value) { - if (value == p_value) { - return; - } - - value = p_value; - ports_changed_notify(); -} - -Variant VisualScriptConstant::get_constant_value() const { - return value; -} - -void VisualScriptConstant::_validate_property(PropertyInfo &p_property) const { - if (p_property.name == "value") { - p_property.type = type; - if (type == Variant::NIL) { - p_property.usage = PROPERTY_USAGE_NONE; //do not save if nil - } - } -} - -void VisualScriptConstant::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_constant_type", "type"), &VisualScriptConstant::set_constant_type); - ClassDB::bind_method(D_METHOD("get_constant_type"), &VisualScriptConstant::get_constant_type); - - ClassDB::bind_method(D_METHOD("set_constant_value", "value"), &VisualScriptConstant::set_constant_value); - ClassDB::bind_method(D_METHOD("get_constant_value"), &VisualScriptConstant::get_constant_value); - - String argt = "Null"; - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - argt += "," + Variant::get_type_name(Variant::Type(i)); - } - - ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_constant_type", "get_constant_type"); - ADD_PROPERTY(PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT | PROPERTY_USAGE_DEFAULT), "set_constant_value", "get_constant_value"); -} - -class VisualScriptNodeInstanceConstant : public VisualScriptNodeInstance { -public: - Variant constant; - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - *p_outputs[0] = constant; - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptConstant::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceConstant *instance = memnew(VisualScriptNodeInstanceConstant); - instance->constant = value; - return instance; -} - -VisualScriptConstant::VisualScriptConstant() { - type = Variant::NIL; -} - -////////////////////////////////////////// -////////////////PRELOAD////////////////// -////////////////////////////////////////// - -int VisualScriptPreload::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptPreload::has_input_sequence_port() const { - return false; -} - -int VisualScriptPreload::get_input_value_port_count() const { - return 0; -} - -int VisualScriptPreload::get_output_value_port_count() const { - return 1; -} - -String VisualScriptPreload::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptPreload::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptPreload::get_output_value_port_info(int p_idx) const { - PropertyInfo pinfo; - pinfo.type = Variant::OBJECT; - if (preload.is_valid()) { - pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE; - pinfo.hint_string = preload->get_class(); - if (preload->get_path().is_resource_file()) { - pinfo.name = preload->get_path(); - } else if (!preload->get_name().is_empty()) { - pinfo.name = preload->get_name(); - } else { - pinfo.name = preload->get_class(); - } - } else { - pinfo.name = "<empty>"; - } - - return pinfo; -} - -String VisualScriptPreload::get_caption() const { - return RTR("Preload"); -} - -void VisualScriptPreload::set_preload(const Ref<Resource> &p_preload) { - if (preload == p_preload) { - return; - } - - preload = p_preload; - ports_changed_notify(); -} - -Ref<Resource> VisualScriptPreload::get_preload() const { - return preload; -} - -void VisualScriptPreload::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_preload", "resource"), &VisualScriptPreload::set_preload); - ClassDB::bind_method(D_METHOD("get_preload"), &VisualScriptPreload::get_preload); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), "set_preload", "get_preload"); -} - -class VisualScriptNodeInstancePreload : public VisualScriptNodeInstance { -public: - Ref<Resource> preload; - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - *p_outputs[0] = preload; - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptPreload::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstancePreload *instance = memnew(VisualScriptNodeInstancePreload); - instance->preload = preload; - return instance; -} - -VisualScriptPreload::VisualScriptPreload() { -} - -////////////////////////////////////////// -////////////////INDEX//////////////////// -////////////////////////////////////////// - -int VisualScriptIndexGet::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptIndexGet::has_input_sequence_port() const { - return false; -} - -int VisualScriptIndexGet::get_input_value_port_count() const { - return 2; -} - -int VisualScriptIndexGet::get_output_value_port_count() const { - return 1; -} - -String VisualScriptIndexGet::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptIndexGet::get_input_value_port_info(int p_idx) const { - if (p_idx == 0) { - return PropertyInfo(Variant::NIL, "base"); - } else { - return PropertyInfo(Variant::NIL, "index"); - } -} - -PropertyInfo VisualScriptIndexGet::get_output_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -String VisualScriptIndexGet::get_caption() const { - return RTR("Get Index"); -} - -class VisualScriptNodeInstanceIndexGet : public VisualScriptNodeInstance { -public: - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - bool valid; - *p_outputs[0] = p_inputs[0]->get(*p_inputs[1], &valid); - - if (!valid) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Invalid get: " + p_inputs[0]->get_construct_string(); - } - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptIndexGet::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceIndexGet *instance = memnew(VisualScriptNodeInstanceIndexGet); - return instance; -} - -VisualScriptIndexGet::VisualScriptIndexGet() { -} - -////////////////////////////////////////// -////////////////INDEXSET////////////////// -////////////////////////////////////////// - -int VisualScriptIndexSet::get_output_sequence_port_count() const { - return 1; -} - -bool VisualScriptIndexSet::has_input_sequence_port() const { - return true; -} - -int VisualScriptIndexSet::get_input_value_port_count() const { - return 3; -} - -int VisualScriptIndexSet::get_output_value_port_count() const { - return 0; -} - -String VisualScriptIndexSet::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptIndexSet::get_input_value_port_info(int p_idx) const { - if (p_idx == 0) { - return PropertyInfo(Variant::NIL, "base"); - } else if (p_idx == 1) { - return PropertyInfo(Variant::NIL, "index"); - - } else { - return PropertyInfo(Variant::NIL, "value"); - } -} - -PropertyInfo VisualScriptIndexSet::get_output_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -String VisualScriptIndexSet::get_caption() const { - return RTR("Set Index"); -} - -class VisualScriptNodeInstanceIndexSet : public VisualScriptNodeInstance { -public: - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - bool valid; - ((Variant *)p_inputs[0])->set(*p_inputs[1], *p_inputs[2], &valid); - - if (!valid) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Invalid set: " + p_inputs[1]->get_construct_string(); - } - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptIndexSet::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceIndexSet *instance = memnew(VisualScriptNodeInstanceIndexSet); - return instance; -} - -VisualScriptIndexSet::VisualScriptIndexSet() { -} - -////////////////////////////////////////// -////////////////GLOBALCONSTANT/////////// -////////////////////////////////////////// - -int VisualScriptGlobalConstant::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptGlobalConstant::has_input_sequence_port() const { - return false; -} - -int VisualScriptGlobalConstant::get_input_value_port_count() const { - return 0; -} - -int VisualScriptGlobalConstant::get_output_value_port_count() const { - return 1; -} - -String VisualScriptGlobalConstant::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptGlobalConstant::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptGlobalConstant::get_output_value_port_info(int p_idx) const { - String name = CoreConstants::get_global_constant_name(index); - return PropertyInfo(Variant::INT, name); -} - -String VisualScriptGlobalConstant::get_caption() const { - return RTR("Global Constant"); -} - -void VisualScriptGlobalConstant::set_global_constant(int p_which) { - index = p_which; - notify_property_list_changed(); - ports_changed_notify(); -} - -int VisualScriptGlobalConstant::get_global_constant() { - return index; -} - -class VisualScriptNodeInstanceGlobalConstant : public VisualScriptNodeInstance { -public: - int index = 0; - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - *p_outputs[0] = CoreConstants::get_global_constant_value(index); - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptGlobalConstant::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceGlobalConstant *instance = memnew(VisualScriptNodeInstanceGlobalConstant); - instance->index = index; - return instance; -} - -void VisualScriptGlobalConstant::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_global_constant", "index"), &VisualScriptGlobalConstant::set_global_constant); - ClassDB::bind_method(D_METHOD("get_global_constant"), &VisualScriptGlobalConstant::get_global_constant); - - String cc; - - for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) { - if (i > 0) { - cc += ","; - } - cc += CoreConstants::get_global_constant_name(i); - } - ADD_PROPERTY(PropertyInfo(Variant::INT, "constant", PROPERTY_HINT_ENUM, cc), "set_global_constant", "get_global_constant"); -} - -VisualScriptGlobalConstant::VisualScriptGlobalConstant() { - index = 0; -} - -////////////////////////////////////////// -////////////////CLASSCONSTANT/////////// -////////////////////////////////////////// - -int VisualScriptClassConstant::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptClassConstant::has_input_sequence_port() const { - return false; -} - -int VisualScriptClassConstant::get_input_value_port_count() const { - return 0; -} - -int VisualScriptClassConstant::get_output_value_port_count() const { - return 1; -} - -String VisualScriptClassConstant::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptClassConstant::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptClassConstant::get_output_value_port_info(int p_idx) const { - if (name == "") { - return PropertyInfo(Variant::INT, String(base_type)); - } else { - return PropertyInfo(Variant::INT, String(base_type) + "." + String(name)); - } -} - -String VisualScriptClassConstant::get_caption() const { - return RTR("Class Constant"); -} - -void VisualScriptClassConstant::set_class_constant(const StringName &p_which) { - name = p_which; - notify_property_list_changed(); - ports_changed_notify(); -} - -StringName VisualScriptClassConstant::get_class_constant() { - return name; -} - -void VisualScriptClassConstant::set_base_type(const StringName &p_which) { - base_type = p_which; - List<String> constants; - ClassDB::get_integer_constant_list(base_type, &constants, true); - if (constants.size() > 0) { - bool found_name = false; - for (const String &E : constants) { - if (E == name) { - found_name = true; - break; - } - } - if (!found_name) { - name = constants[0]; - } - } else { - name = ""; - } - notify_property_list_changed(); - ports_changed_notify(); -} - -StringName VisualScriptClassConstant::get_base_type() { - return base_type; -} - -class VisualScriptNodeInstanceClassConstant : public VisualScriptNodeInstance { -public: - int value = 0; - bool valid = false; - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - if (!valid) { - r_error_str = "Invalid constant name, pick a valid class constant."; - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - } - - *p_outputs[0] = value; - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptClassConstant::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceClassConstant *instance = memnew(VisualScriptNodeInstanceClassConstant); - instance->value = ClassDB::get_integer_constant(base_type, name, &instance->valid); - return instance; -} - -void VisualScriptClassConstant::_validate_property(PropertyInfo &p_property) const { - if (p_property.name == "constant") { - List<String> constants; - ClassDB::get_integer_constant_list(base_type, &constants, true); - - p_property.hint_string = ""; - for (const String &E : constants) { - if (!p_property.hint_string.is_empty()) { - p_property.hint_string += ","; - } - p_property.hint_string += E; - } - } -} - -void VisualScriptClassConstant::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_class_constant", "name"), &VisualScriptClassConstant::set_class_constant); - ClassDB::bind_method(D_METHOD("get_class_constant"), &VisualScriptClassConstant::get_class_constant); - - ClassDB::bind_method(D_METHOD("set_base_type", "name"), &VisualScriptClassConstant::set_base_type); - ClassDB::bind_method(D_METHOD("get_base_type"), &VisualScriptClassConstant::get_base_type); - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "constant", PROPERTY_HINT_ENUM, ""), "set_class_constant", "get_class_constant"); -} - -VisualScriptClassConstant::VisualScriptClassConstant() { - base_type = "Object"; -} - -////////////////////////////////////////// -////////////////BASICTYPECONSTANT/////////// -////////////////////////////////////////// - -int VisualScriptBasicTypeConstant::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptBasicTypeConstant::has_input_sequence_port() const { - return false; -} - -int VisualScriptBasicTypeConstant::get_input_value_port_count() const { - return 0; -} - -int VisualScriptBasicTypeConstant::get_output_value_port_count() const { - return 1; -} - -String VisualScriptBasicTypeConstant::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptBasicTypeConstant::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptBasicTypeConstant::get_output_value_port_info(int p_idx) const { - return PropertyInfo(type, "value"); -} - -String VisualScriptBasicTypeConstant::get_caption() const { - return RTR("Basic Constant"); -} - -String VisualScriptBasicTypeConstant::get_text() const { - if (name == "") { - return Variant::get_type_name(type); - } else { - return Variant::get_type_name(type) + "." + String(name); - } -} - -void VisualScriptBasicTypeConstant::set_basic_type_constant(const StringName &p_which) { - name = p_which; - notify_property_list_changed(); - ports_changed_notify(); -} - -StringName VisualScriptBasicTypeConstant::get_basic_type_constant() const { - return name; -} - -void VisualScriptBasicTypeConstant::set_basic_type(Variant::Type p_which) { - type = p_which; - - List<StringName> constants; - Variant::get_constants_for_type(type, &constants); - if (constants.size() > 0) { - bool found_name = false; - for (const StringName &E : constants) { - if (E == name) { - found_name = true; - break; - } - } - if (!found_name) { - name = constants[0]; - } - } else { - name = ""; - } - notify_property_list_changed(); - ports_changed_notify(); -} - -Variant::Type VisualScriptBasicTypeConstant::get_basic_type() const { - return type; -} - -class VisualScriptNodeInstanceBasicTypeConstant : public VisualScriptNodeInstance { -public: - Variant value; - bool valid = false; - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - if (!valid) { - r_error_str = "Invalid constant name, pick a valid basic type constant."; - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - } - - *p_outputs[0] = value; - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptBasicTypeConstant::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceBasicTypeConstant *instance = memnew(VisualScriptNodeInstanceBasicTypeConstant); - instance->value = Variant::get_constant_value(type, name, &instance->valid); - return instance; -} - -void VisualScriptBasicTypeConstant::_validate_property(PropertyInfo &p_property) const { - if (p_property.name == "constant") { - List<StringName> constants; - Variant::get_constants_for_type(type, &constants); - - if (constants.size() == 0) { - p_property.usage = PROPERTY_USAGE_NONE; - return; - } - p_property.hint_string = ""; - for (const StringName &E : constants) { - if (!p_property.hint_string.is_empty()) { - p_property.hint_string += ","; - } - p_property.hint_string += String(E); - } - } -} - -void VisualScriptBasicTypeConstant::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_basic_type", "name"), &VisualScriptBasicTypeConstant::set_basic_type); - ClassDB::bind_method(D_METHOD("get_basic_type"), &VisualScriptBasicTypeConstant::get_basic_type); - - ClassDB::bind_method(D_METHOD("set_basic_type_constant", "name"), &VisualScriptBasicTypeConstant::set_basic_type_constant); - ClassDB::bind_method(D_METHOD("get_basic_type_constant"), &VisualScriptBasicTypeConstant::get_basic_type_constant); - - String argt = "Null"; - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - argt += "," + Variant::get_type_name(Variant::Type(i)); - } - - ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, argt), "set_basic_type", "get_basic_type"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "constant", PROPERTY_HINT_ENUM, ""), "set_basic_type_constant", "get_basic_type_constant"); -} - -VisualScriptBasicTypeConstant::VisualScriptBasicTypeConstant() { - type = Variant::NIL; -} - -////////////////////////////////////////// -////////////////MATHCONSTANT/////////// -////////////////////////////////////////// - -const char *VisualScriptMathConstant::const_name[MATH_CONSTANT_MAX] = { - "One", - "PI", - "PI/2", - "TAU", - "E", - "Sqrt2", - "INF", - "NAN" -}; - -double VisualScriptMathConstant::const_value[MATH_CONSTANT_MAX] = { - 1.0, - Math_PI, - Math_PI * 0.5, - Math_TAU, - 2.71828182845904523536, - Math::sqrt(2.0), - INFINITY, - NAN -}; - -int VisualScriptMathConstant::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptMathConstant::has_input_sequence_port() const { - return false; -} - -int VisualScriptMathConstant::get_input_value_port_count() const { - return 0; -} - -int VisualScriptMathConstant::get_output_value_port_count() const { - return 1; -} - -String VisualScriptMathConstant::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptMathConstant::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptMathConstant::get_output_value_port_info(int p_idx) const { - return PropertyInfo(Variant::FLOAT, const_name[constant]); -} - -String VisualScriptMathConstant::get_caption() const { - return RTR("Math Constant"); -} - -void VisualScriptMathConstant::set_math_constant(MathConstant p_which) { - constant = p_which; - notify_property_list_changed(); - ports_changed_notify(); -} - -VisualScriptMathConstant::MathConstant VisualScriptMathConstant::get_math_constant() { - return constant; -} - -class VisualScriptNodeInstanceMathConstant : public VisualScriptNodeInstance { -public: - float value = 0.0f; - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - *p_outputs[0] = value; - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptMathConstant::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceMathConstant *instance = memnew(VisualScriptNodeInstanceMathConstant); - instance->value = const_value[constant]; - return instance; -} - -void VisualScriptMathConstant::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_math_constant", "which"), &VisualScriptMathConstant::set_math_constant); - ClassDB::bind_method(D_METHOD("get_math_constant"), &VisualScriptMathConstant::get_math_constant); - - String cc; - - for (int i = 0; i < MATH_CONSTANT_MAX; i++) { - if (i > 0) { - cc += ","; - } - cc += const_name[i]; - } - ADD_PROPERTY(PropertyInfo(Variant::INT, "constant", PROPERTY_HINT_ENUM, cc), "set_math_constant", "get_math_constant"); - - BIND_ENUM_CONSTANT(MATH_CONSTANT_ONE); - BIND_ENUM_CONSTANT(MATH_CONSTANT_PI); - BIND_ENUM_CONSTANT(MATH_CONSTANT_HALF_PI); - BIND_ENUM_CONSTANT(MATH_CONSTANT_TAU); - BIND_ENUM_CONSTANT(MATH_CONSTANT_E); - BIND_ENUM_CONSTANT(MATH_CONSTANT_SQRT2); - BIND_ENUM_CONSTANT(MATH_CONSTANT_INF); - BIND_ENUM_CONSTANT(MATH_CONSTANT_NAN); - BIND_ENUM_CONSTANT(MATH_CONSTANT_MAX); -} - -VisualScriptMathConstant::VisualScriptMathConstant() { - constant = MATH_CONSTANT_ONE; -} - -////////////////////////////////////////// -////////////////ENGINESINGLETON/////////// -////////////////////////////////////////// - -int VisualScriptEngineSingleton::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptEngineSingleton::has_input_sequence_port() const { - return false; -} - -int VisualScriptEngineSingleton::get_input_value_port_count() const { - return 0; -} - -int VisualScriptEngineSingleton::get_output_value_port_count() const { - return 1; -} - -String VisualScriptEngineSingleton::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptEngineSingleton::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptEngineSingleton::get_output_value_port_info(int p_idx) const { - return PropertyInfo(Variant::OBJECT, singleton); -} - -String VisualScriptEngineSingleton::get_caption() const { - return RTR("Get Engine Singleton"); -} - -void VisualScriptEngineSingleton::set_singleton(const String &p_string) { - singleton = p_string; - - notify_property_list_changed(); - ports_changed_notify(); -} - -String VisualScriptEngineSingleton::get_singleton() { - return singleton; -} - -class VisualScriptNodeInstanceEngineSingleton : public VisualScriptNodeInstance { -public: - Object *singleton = nullptr; - - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - *p_outputs[0] = singleton; - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptEngineSingleton::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceEngineSingleton *instance = memnew(VisualScriptNodeInstanceEngineSingleton); - instance->singleton = Engine::get_singleton()->get_singleton_object(singleton); - return instance; -} - -VisualScriptEngineSingleton::TypeGuess VisualScriptEngineSingleton::guess_output_type(TypeGuess *p_inputs, int p_output) const { - Object *obj = Engine::get_singleton()->get_singleton_object(singleton); - TypeGuess tg; - tg.type = Variant::OBJECT; - if (obj) { - tg.gdclass = obj->get_class(); - tg.script = obj->get_script(); - } - - return tg; -} - -void VisualScriptEngineSingleton::_validate_property(PropertyInfo &p_property) const { - String cc; - - List<Engine::Singleton> singletons; - - Engine::get_singleton()->get_singletons(&singletons); - - for (const Engine::Singleton &E : singletons) { - if (E.name == "VS" || E.name == "PS" || E.name == "PS2D" || E.name == "AS" || E.name == "TS" || E.name == "SS" || E.name == "SS2D") { - continue; //skip these, too simple named - } - - if (!cc.is_empty()) { - cc += ","; - } - cc += E.name; - } - - p_property.hint = PROPERTY_HINT_ENUM; - p_property.hint_string = cc; -} - -void VisualScriptEngineSingleton::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_singleton", "name"), &VisualScriptEngineSingleton::set_singleton); - ClassDB::bind_method(D_METHOD("get_singleton"), &VisualScriptEngineSingleton::get_singleton); - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "constant"), "set_singleton", "get_singleton"); -} - -VisualScriptEngineSingleton::VisualScriptEngineSingleton() { - singleton = String(); -} - -////////////////////////////////////////// -////////////////GETNODE/////////// -////////////////////////////////////////// - -int VisualScriptSceneNode::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptSceneNode::has_input_sequence_port() const { - return false; -} - -int VisualScriptSceneNode::get_input_value_port_count() const { - return 0; -} - -int VisualScriptSceneNode::get_output_value_port_count() const { - return 1; -} - -String VisualScriptSceneNode::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptSceneNode::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptSceneNode::get_output_value_port_info(int p_idx) const { - return PropertyInfo(Variant::OBJECT, path.simplified()); -} - -String VisualScriptSceneNode::get_caption() const { - return RTR("Get Scene Node"); -} - -void VisualScriptSceneNode::set_node_path(const NodePath &p_path) { - path = p_path; - notify_property_list_changed(); - ports_changed_notify(); -} - -NodePath VisualScriptSceneNode::get_node_path() { - return path; -} - -class VisualScriptNodeInstanceSceneNode : public VisualScriptNodeInstance { -public: - VisualScriptSceneNode *node = nullptr; - VisualScriptInstance *instance = nullptr; - NodePath path; - - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - Node *node = Object::cast_to<Node>(instance->get_owner_ptr()); - if (!node) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Base object is not a Node!"; - return 0; - } - - Node *another = node->get_node(path); - if (!another) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Path does not lead Node!"; - return 0; - } - - *p_outputs[0] = another; - - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptSceneNode::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceSceneNode *instance = memnew(VisualScriptNodeInstanceSceneNode); - instance->node = this; - instance->instance = p_instance; - instance->path = path; - return instance; -} - -#ifdef TOOLS_ENABLED - -static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) { - if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene) { - return nullptr; - } - - Ref<Script> scr = p_current_node->get_script(); - - if (scr.is_valid() && scr == script) { - return p_current_node; - } - - for (int i = 0; i < p_current_node->get_child_count(); i++) { - Node *n = _find_script_node(p_edited_scene, p_current_node->get_child(i), script); - if (n) { - return n; - } - } - - return nullptr; -} - -#endif - -VisualScriptSceneNode::TypeGuess VisualScriptSceneNode::guess_output_type(TypeGuess *p_inputs, int p_output) const { - VisualScriptSceneNode::TypeGuess tg; - tg.type = Variant::OBJECT; - tg.gdclass = SNAME("Node"); - -#ifdef TOOLS_ENABLED - Ref<Script> script = get_visual_script(); - if (!script.is_valid()) { - return tg; - } - - MainLoop *main_loop = OS::get_singleton()->get_main_loop(); - SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop); - - if (!scene_tree) { - return tg; - } - - Node *edited_scene = scene_tree->get_edited_scene_root(); - - if (!edited_scene) { - return tg; - } - - Node *script_node = _find_script_node(edited_scene, edited_scene, script); - - if (!script_node) { - return tg; - } - - Node *another = script_node->get_node(path); - - if (another) { - tg.gdclass = another->get_class(); - tg.script = another->get_script(); - } -#endif - return tg; -} - -void VisualScriptSceneNode::_validate_property(PropertyInfo &p_property) const { -#ifdef TOOLS_ENABLED - if (p_property.name == "node_path") { - Ref<Script> script = get_visual_script(); - if (!script.is_valid()) { - return; - } - - MainLoop *main_loop = OS::get_singleton()->get_main_loop(); - SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop); - - if (!scene_tree) { - return; - } - - Node *edited_scene = scene_tree->get_edited_scene_root(); - - if (!edited_scene) { - return; - } - - Node *script_node = _find_script_node(edited_scene, edited_scene, script); - - if (!script_node) { - return; - } - - p_property.hint_string = script_node->get_path(); - } -#endif -} - -void VisualScriptSceneNode::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_node_path", "path"), &VisualScriptSceneNode::set_node_path); - ClassDB::bind_method(D_METHOD("get_node_path"), &VisualScriptSceneNode::get_node_path); - - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_node_path", "get_node_path"); -} - -VisualScriptSceneNode::VisualScriptSceneNode() { - path = String("."); -} - -////////////////////////////////////////// -////////////////SceneTree/////////// -////////////////////////////////////////// - -int VisualScriptSceneTree::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptSceneTree::has_input_sequence_port() const { - return false; -} - -int VisualScriptSceneTree::get_input_value_port_count() const { - return 0; -} - -int VisualScriptSceneTree::get_output_value_port_count() const { - return 1; -} - -String VisualScriptSceneTree::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptSceneTree::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptSceneTree::get_output_value_port_info(int p_idx) const { - return PropertyInfo(Variant::OBJECT, "Scene Tree", PROPERTY_HINT_TYPE_STRING, "SceneTree"); -} - -String VisualScriptSceneTree::get_caption() const { - return RTR("Get Scene Tree"); -} - -class VisualScriptNodeInstanceSceneTree : public VisualScriptNodeInstance { -public: - VisualScriptSceneTree *node = nullptr; - VisualScriptInstance *instance = nullptr; - - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - Node *node = Object::cast_to<Node>(instance->get_owner_ptr()); - if (!node) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Base object is not a Node!"; - return 0; - } - - SceneTree *tree = node->get_tree(); - if (!tree) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Attempt to get SceneTree while node is not in the active tree."; - return 0; - } - - *p_outputs[0] = tree; - - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptSceneTree::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceSceneTree *instance = memnew(VisualScriptNodeInstanceSceneTree); - instance->node = this; - instance->instance = p_instance; - return instance; -} - -VisualScriptSceneTree::TypeGuess VisualScriptSceneTree::guess_output_type(TypeGuess *p_inputs, int p_output) const { - TypeGuess tg; - tg.type = Variant::OBJECT; - tg.gdclass = SNAME("SceneTree"); - return tg; -} - -void VisualScriptSceneTree::_validate_property(PropertyInfo &p_property) const { -} - -void VisualScriptSceneTree::_bind_methods() { -} - -VisualScriptSceneTree::VisualScriptSceneTree() { -} - -////////////////////////////////////////// -////////////////RESPATH/////////// -////////////////////////////////////////// - -int VisualScriptResourcePath::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptResourcePath::has_input_sequence_port() const { - return false; -} - -int VisualScriptResourcePath::get_input_value_port_count() const { - return 0; -} - -int VisualScriptResourcePath::get_output_value_port_count() const { - return 1; -} - -String VisualScriptResourcePath::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptResourcePath::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptResourcePath::get_output_value_port_info(int p_idx) const { - return PropertyInfo(Variant::STRING, path); -} - -String VisualScriptResourcePath::get_caption() const { - return RTR("Resource Path"); -} - -void VisualScriptResourcePath::set_resource_path(const String &p_path) { - path = p_path; - notify_property_list_changed(); - ports_changed_notify(); -} - -String VisualScriptResourcePath::get_resource_path() { - return path; -} - -class VisualScriptNodeInstanceResourcePath : public VisualScriptNodeInstance { -public: - String path; - - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - *p_outputs[0] = path; - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptResourcePath::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceResourcePath *instance = memnew(VisualScriptNodeInstanceResourcePath); - instance->path = path; - return instance; -} - -void VisualScriptResourcePath::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_resource_path", "path"), &VisualScriptResourcePath::set_resource_path); - ClassDB::bind_method(D_METHOD("get_resource_path"), &VisualScriptResourcePath::get_resource_path); - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "path", PROPERTY_HINT_FILE), "set_resource_path", "get_resource_path"); -} - -VisualScriptResourcePath::VisualScriptResourcePath() { - path = ""; -} - -////////////////////////////////////////// -////////////////SELF/////////// -////////////////////////////////////////// - -int VisualScriptSelf::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptSelf::has_input_sequence_port() const { - return false; -} - -int VisualScriptSelf::get_input_value_port_count() const { - return 0; -} - -int VisualScriptSelf::get_output_value_port_count() const { - return 1; -} - -String VisualScriptSelf::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptSelf::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptSelf::get_output_value_port_info(int p_idx) const { - StringName type_name; - if (get_visual_script().is_valid()) { - type_name = get_visual_script()->get_instance_base_type(); - } else { - type_name = SNAME("instance"); - } - - return PropertyInfo(Variant::OBJECT, type_name); -} - -String VisualScriptSelf::get_caption() const { - return RTR("Get Self"); -} - -class VisualScriptNodeInstanceSelf : public VisualScriptNodeInstance { -public: - VisualScriptInstance *instance = nullptr; - - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - *p_outputs[0] = instance->get_owner_ptr(); - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptSelf::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceSelf *instance = memnew(VisualScriptNodeInstanceSelf); - instance->instance = p_instance; - return instance; -} - -VisualScriptSelf::TypeGuess VisualScriptSelf::guess_output_type(TypeGuess *p_inputs, int p_output) const { - VisualScriptSceneNode::TypeGuess tg; - tg.type = Variant::OBJECT; - tg.gdclass = SNAME("Object"); - - Ref<Script> script = get_visual_script(); - if (!script.is_valid()) { - return tg; - } - - tg.gdclass = script->get_instance_base_type(); - tg.script = script; - - return tg; -} - -void VisualScriptSelf::_bind_methods() { -} - -VisualScriptSelf::VisualScriptSelf() { -} - -////////////////////////////////////////// -////////////////CUSTOM (SCRIPTED)/////////// -////////////////////////////////////////// - -int VisualScriptCustomNode::get_output_sequence_port_count() const { - int ret; - if (GDVIRTUAL_CALL(_get_output_sequence_port_count, ret)) { - return ret; - } - return 0; -} - -bool VisualScriptCustomNode::has_input_sequence_port() const { - bool ret; - if (GDVIRTUAL_CALL(_has_input_sequence_port, ret)) { - return ret; - } - return false; -} - -int VisualScriptCustomNode::get_input_value_port_count() const { - int ret; - if (GDVIRTUAL_CALL(_get_input_value_port_count, ret)) { - return ret; - } - return 0; -} - -int VisualScriptCustomNode::get_output_value_port_count() const { - int ret; - if (GDVIRTUAL_CALL(_get_output_value_port_count, ret)) { - return ret; - } - return 0; -} - -String VisualScriptCustomNode::get_output_sequence_port_text(int p_port) const { - String ret; - if (GDVIRTUAL_CALL(_get_output_sequence_port_text, p_port, ret)) { - return ret; - } - - return String(); -} - -PropertyInfo VisualScriptCustomNode::get_input_value_port_info(int p_idx) const { - PropertyInfo info; - { - int type; - if (GDVIRTUAL_CALL(_get_input_value_port_type, p_idx, type)) { - info.type = Variant::Type(type); - } - } - { - String name; - if (GDVIRTUAL_CALL(_get_input_value_port_name, p_idx, name)) { - info.name = name; - } - } - { - int hint; - if (GDVIRTUAL_CALL(_get_input_value_port_hint, p_idx, hint)) { - info.hint = PropertyHint(hint); - } - } - - { - String hint_string; - if (GDVIRTUAL_CALL(_get_input_value_port_hint_string, p_idx, hint_string)) { - info.hint_string = hint_string; - } - } - - return info; -} - -PropertyInfo VisualScriptCustomNode::get_output_value_port_info(int p_idx) const { - PropertyInfo info; - { - int type; - if (GDVIRTUAL_CALL(_get_output_value_port_type, p_idx, type)) { - info.type = Variant::Type(type); - } - } - { - String name; - if (GDVIRTUAL_CALL(_get_output_value_port_name, p_idx, name)) { - info.name = name; - } - } - { - int hint; - if (GDVIRTUAL_CALL(_get_output_value_port_hint, p_idx, hint)) { - info.hint = PropertyHint(hint); - } - } - - { - String hint_string; - if (GDVIRTUAL_CALL(_get_output_value_port_hint_string, p_idx, hint_string)) { - info.hint_string = hint_string; - } - } - return info; -} - -VisualScriptCustomNode::TypeGuess VisualScriptCustomNode::guess_output_type(TypeGuess *p_inputs, int p_output) const { - TypeGuess tg; - PropertyInfo pi = VisualScriptCustomNode::get_output_value_port_info(p_output); - tg.type = pi.type; - if (pi.type == Variant::OBJECT) { - if (pi.hint == PROPERTY_HINT_RESOURCE_TYPE) { - if (pi.hint_string.is_resource_file()) { - tg.script = ResourceLoader::load(pi.hint_string); - } else if (ClassDB::class_exists(pi.hint_string)) { - tg.gdclass = pi.hint_string; - } - } - } - return tg; -} - -String VisualScriptCustomNode::get_caption() const { - String ret; - if (GDVIRTUAL_CALL(_get_caption, ret)) { - return ret; - } - return RTR("CustomNode"); -} - -String VisualScriptCustomNode::get_text() const { - String ret; - if (GDVIRTUAL_CALL(_get_text, ret)) { - return ret; - } - return ""; -} - -String VisualScriptCustomNode::get_category() const { - String ret; - if (GDVIRTUAL_CALL(_get_category, ret)) { - return ret; - } - return "Custom"; -} - -class VisualScriptNodeInstanceCustomNode : public VisualScriptNodeInstance { -public: - VisualScriptInstance *instance = nullptr; - VisualScriptCustomNode *node = nullptr; - int in_count = 0; - int out_count = 0; - int work_mem_size = 0; - - virtual int get_working_memory_size() const override { return work_mem_size; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - if (GDVIRTUAL_IS_OVERRIDDEN_PTR(node, _step)) { - Array in_values; - Array out_values; - Array work_mem; - - in_values.resize(in_count); - - for (int i = 0; i < in_count; i++) { - in_values[i] = *p_inputs[i]; - } - - out_values.resize(out_count); - - work_mem.resize(work_mem_size); - - for (int i = 0; i < work_mem_size; i++) { - work_mem[i] = p_working_mem[i]; - } - - int ret_out; - - Variant ret; - GDVIRTUAL_CALL_PTR(node, _step, in_values, out_values, p_start_mode, work_mem, ret); - if (ret.get_type() == Variant::STRING) { - r_error_str = ret; - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - return 0; - } else if (ret.is_num()) { - ret_out = ret; - } else { - r_error_str = RTR("Invalid return value from _step(), must be integer (seq out), or string (error)."); - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - return 0; - } - - for (int i = 0; i < out_count; i++) { - if (i < out_values.size()) { - *p_outputs[i] = out_values[i]; - } - } - - for (int i = 0; i < work_mem_size; i++) { - if (i < work_mem.size()) { - p_working_mem[i] = work_mem[i]; - } - } - - return ret_out; - } else { - r_error_str = RTR("Custom node has no _step() method, can't process graph."); - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - } - - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptCustomNode::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceCustomNode *instance = memnew(VisualScriptNodeInstanceCustomNode); - instance->instance = p_instance; - instance->node = this; - instance->in_count = get_input_value_port_count(); - instance->out_count = get_output_value_port_count(); - - instance->work_mem_size = 0; - GDVIRTUAL_CALL(_get_working_memory_size, instance->work_mem_size); - - return instance; -} - -void VisualScriptCustomNode::_script_changed() { - call_deferred(SNAME("ports_changed_notify")); -} - -void VisualScriptCustomNode::_bind_methods() { - GDVIRTUAL_BIND(_get_output_sequence_port_count); - GDVIRTUAL_BIND(_has_input_sequence_port); - GDVIRTUAL_BIND(_get_output_sequence_port_text, "seq_idx"); - - GDVIRTUAL_BIND(_get_input_value_port_count); - GDVIRTUAL_BIND(_get_input_value_port_type, "input_idx"); - GDVIRTUAL_BIND(_get_input_value_port_name, "input_idx"); - GDVIRTUAL_BIND(_get_input_value_port_hint, "input_idx"); - GDVIRTUAL_BIND(_get_input_value_port_hint_string, "input_idx"); - - GDVIRTUAL_BIND(_get_output_value_port_count); - GDVIRTUAL_BIND(_get_output_value_port_type, "output_idx"); - GDVIRTUAL_BIND(_get_output_value_port_name, "output_idx"); - GDVIRTUAL_BIND(_get_output_value_port_hint, "output_idx"); - GDVIRTUAL_BIND(_get_output_value_port_hint_string, "output_idx"); - - GDVIRTUAL_BIND(_get_caption); - GDVIRTUAL_BIND(_get_text); - GDVIRTUAL_BIND(_get_category); - - GDVIRTUAL_BIND(_get_working_memory_size); - - GDVIRTUAL_BIND(_step, "inputs", "outputs", "start_mode", "working_mem"); - - BIND_ENUM_CONSTANT(START_MODE_BEGIN_SEQUENCE); - BIND_ENUM_CONSTANT(START_MODE_CONTINUE_SEQUENCE); - BIND_ENUM_CONSTANT(START_MODE_RESUME_YIELD); - - BIND_CONSTANT(STEP_PUSH_STACK_BIT); - BIND_CONSTANT(STEP_GO_BACK_BIT); - BIND_CONSTANT(STEP_NO_ADVANCE_BIT); - BIND_CONSTANT(STEP_EXIT_FUNCTION_BIT); - BIND_CONSTANT(STEP_YIELD_BIT); -} - -VisualScriptCustomNode::VisualScriptCustomNode() { - connect("script_changed", callable_mp(this, &VisualScriptCustomNode::_script_changed)); -} - -////////////////////////////////////////// -////////////////SUBCALL/////////// -////////////////////////////////////////// - -int VisualScriptSubCall::get_output_sequence_port_count() const { - return 1; -} - -bool VisualScriptSubCall::has_input_sequence_port() const { - return true; -} - -int VisualScriptSubCall::get_input_value_port_count() const { - Ref<Script> script = get_script(); - - if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) { - MethodInfo mi = script->get_method_info(VisualScriptLanguage::singleton->_subcall); - return mi.arguments.size(); - } - - return 0; -} - -int VisualScriptSubCall::get_output_value_port_count() const { - return 1; -} - -String VisualScriptSubCall::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptSubCall::get_input_value_port_info(int p_idx) const { - Ref<Script> script = get_script(); - if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) { - MethodInfo mi = script->get_method_info(VisualScriptLanguage::singleton->_subcall); - return mi.arguments[p_idx]; - } - - return PropertyInfo(); -} - -PropertyInfo VisualScriptSubCall::get_output_value_port_info(int p_idx) const { - Ref<Script> script = get_script(); - if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) { - MethodInfo mi = script->get_method_info(VisualScriptLanguage::singleton->_subcall); - return mi.return_val; - } - return PropertyInfo(); -} - -String VisualScriptSubCall::get_caption() const { - return RTR("SubCall"); -} - -String VisualScriptSubCall::get_text() const { - Ref<Script> script = get_script(); - if (script.is_valid()) { - if (!script->get_name().is_empty()) { - return script->get_name(); - } - if (script->get_path().is_resource_file()) { - return script->get_path().get_file(); - } - return script->get_class(); - } - return ""; -} - -String VisualScriptSubCall::get_category() const { - return "custom"; -} - -class VisualScriptNodeInstanceSubCall : public VisualScriptNodeInstance { -public: - VisualScriptInstance *instance = nullptr; - VisualScriptSubCall *subcall = nullptr; - int input_args = 0; - bool valid = false; - - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - if (!valid) { - r_error_str = "Node requires a script with a _subcall(<args>) method to work."; - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - return 0; - } - *p_outputs[0] = subcall->callp(VisualScriptLanguage::singleton->_subcall, p_inputs, input_args, r_error); - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptSubCall::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceSubCall *instance = memnew(VisualScriptNodeInstanceSubCall); - instance->instance = p_instance; - Ref<Script> script = get_script(); - if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) { - instance->valid = true; - instance->input_args = get_input_value_port_count(); - } else { - instance->valid = false; - } - return instance; -} - -void VisualScriptSubCall::_bind_methods() { - // Since this is script only, registering virtual function is no longer valid. Will have to go in docs. -} - -VisualScriptSubCall::VisualScriptSubCall() { -} - -////////////////////////////////////////// -////////////////Comment/////////// -////////////////////////////////////////// - -int VisualScriptComment::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptComment::has_input_sequence_port() const { - return false; -} - -int VisualScriptComment::get_input_value_port_count() const { - return 0; -} - -int VisualScriptComment::get_output_value_port_count() const { - return 0; -} - -String VisualScriptComment::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptComment::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptComment::get_output_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -String VisualScriptComment::get_caption() const { - return title; -} - -String VisualScriptComment::get_text() const { - return description; -} - -void VisualScriptComment::set_title(const String &p_title) { - if (title == p_title) { - return; - } - title = p_title; - ports_changed_notify(); -} - -String VisualScriptComment::get_title() const { - return title; -} - -void VisualScriptComment::set_description(const String &p_description) { - if (description == p_description) { - return; - } - description = p_description; - ports_changed_notify(); -} - -String VisualScriptComment::get_description() const { - return description; -} - -void VisualScriptComment::set_size(const Size2 &p_size) { - if (size == p_size) { - return; - } - size = p_size; - ports_changed_notify(); -} - -Size2 VisualScriptComment::get_size() const { - return size; -} - -String VisualScriptComment::get_category() const { - return "data"; -} - -class VisualScriptNodeInstanceComment : public VisualScriptNodeInstance { -public: - VisualScriptInstance *instance = nullptr; - - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptComment::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceComment *instance = memnew(VisualScriptNodeInstanceComment); - instance->instance = p_instance; - return instance; -} - -void VisualScriptComment::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_title", "title"), &VisualScriptComment::set_title); - ClassDB::bind_method(D_METHOD("get_title"), &VisualScriptComment::get_title); - - ClassDB::bind_method(D_METHOD("set_description", "description"), &VisualScriptComment::set_description); - ClassDB::bind_method(D_METHOD("get_description"), &VisualScriptComment::get_description); - - ClassDB::bind_method(D_METHOD("set_size", "size"), &VisualScriptComment::set_size); - ClassDB::bind_method(D_METHOD("get_size"), &VisualScriptComment::get_size); - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "description", PROPERTY_HINT_MULTILINE_TEXT), "set_description", "get_description"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); -} - -VisualScriptComment::VisualScriptComment() { - title = "Comment"; - size = Size2(150, 150); -} - -////////////////////////////////////////// -////////////////Constructor/////////// -////////////////////////////////////////// - -int VisualScriptConstructor::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptConstructor::has_input_sequence_port() const { - return false; -} - -int VisualScriptConstructor::get_input_value_port_count() const { - return constructor.arguments.size(); -} - -int VisualScriptConstructor::get_output_value_port_count() const { - return 1; -} - -String VisualScriptConstructor::get_output_sequence_port_text(int p_port) const { - return ""; -} - -PropertyInfo VisualScriptConstructor::get_input_value_port_info(int p_idx) const { - return constructor.arguments[p_idx]; -} - -PropertyInfo VisualScriptConstructor::get_output_value_port_info(int p_idx) const { - return PropertyInfo(type, "value"); -} - -String VisualScriptConstructor::get_caption() const { - return vformat(RTR("Construct %s"), Variant::get_type_name(type)); -} - -String VisualScriptConstructor::get_category() const { - return "functions"; -} - -void VisualScriptConstructor::set_constructor_type(Variant::Type p_type) { - if (type == p_type) { - return; - } - - type = p_type; - ports_changed_notify(); -} - -Variant::Type VisualScriptConstructor::get_constructor_type() const { - return type; -} - -void VisualScriptConstructor::set_constructor(const Dictionary &p_info) { - constructor = MethodInfo::from_dict(p_info); - ports_changed_notify(); -} - -Dictionary VisualScriptConstructor::get_constructor() const { - return constructor; -} - -class VisualScriptNodeInstanceConstructor : public VisualScriptNodeInstance { -public: - VisualScriptInstance *instance = nullptr; - Variant::Type type; - int argcount = 0; - - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - Callable::CallError ce; - Variant::construct(type, *p_outputs[0], p_inputs, argcount, ce); - if (ce.error != Callable::CallError::CALL_OK) { - r_error_str = "Invalid arguments for constructor"; - } - - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptConstructor::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceConstructor *instance = memnew(VisualScriptNodeInstanceConstructor); - instance->instance = p_instance; - instance->type = type; - instance->argcount = constructor.arguments.size(); - return instance; -} - -void VisualScriptConstructor::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_constructor_type", "type"), &VisualScriptConstructor::set_constructor_type); - ClassDB::bind_method(D_METHOD("get_constructor_type"), &VisualScriptConstructor::get_constructor_type); - - ClassDB::bind_method(D_METHOD("set_constructor", "constructor"), &VisualScriptConstructor::set_constructor); - ClassDB::bind_method(D_METHOD("get_constructor"), &VisualScriptConstructor::get_constructor); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_constructor_type", "get_constructor_type"); - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "constructor", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_constructor", "get_constructor"); -} - -VisualScriptConstructor::VisualScriptConstructor() { - type = Variant::NIL; -} - -static HashMap<String, Pair<Variant::Type, MethodInfo>> constructor_map; - -static Ref<VisualScriptNode> create_constructor_node(const String &p_name) { - ERR_FAIL_COND_V(!constructor_map.has(p_name), Ref<VisualScriptNode>()); - - Ref<VisualScriptConstructor> vsc; - vsc.instantiate(); - vsc->set_constructor_type(constructor_map[p_name].first); - vsc->set_constructor(constructor_map[p_name].second); - - return vsc; -} - -////////////////////////////////////////// -////////////////LocalVar/////////// -////////////////////////////////////////// - -int VisualScriptLocalVar::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptLocalVar::has_input_sequence_port() const { - return false; -} - -int VisualScriptLocalVar::get_input_value_port_count() const { - return 0; -} - -int VisualScriptLocalVar::get_output_value_port_count() const { - return 1; -} - -String VisualScriptLocalVar::get_output_sequence_port_text(int p_port) const { - return ""; -} - -PropertyInfo VisualScriptLocalVar::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptLocalVar::get_output_value_port_info(int p_idx) const { - return PropertyInfo(type, name); -} - -String VisualScriptLocalVar::get_caption() const { - return RTR("Get Local Var"); -} - -String VisualScriptLocalVar::get_category() const { - return "data"; -} - -void VisualScriptLocalVar::set_var_name(const StringName &p_name) { - if (name == p_name) { - return; - } - - name = p_name; - ports_changed_notify(); -} - -StringName VisualScriptLocalVar::get_var_name() const { - return name; -} - -void VisualScriptLocalVar::set_var_type(Variant::Type p_type) { - type = p_type; - ports_changed_notify(); -} - -Variant::Type VisualScriptLocalVar::get_var_type() const { - return type; -} - -class VisualScriptNodeInstanceLocalVar : public VisualScriptNodeInstance { -public: - VisualScriptInstance *instance = nullptr; - StringName name; - - virtual int get_working_memory_size() const override { return 1; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - *p_outputs[0] = *p_working_mem; - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptLocalVar::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceLocalVar *instance = memnew(VisualScriptNodeInstanceLocalVar); - instance->instance = p_instance; - instance->name = name; - - return instance; -} - -void VisualScriptLocalVar::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_var_name", "name"), &VisualScriptLocalVar::set_var_name); - ClassDB::bind_method(D_METHOD("get_var_name"), &VisualScriptLocalVar::get_var_name); - - ClassDB::bind_method(D_METHOD("set_var_type", "type"), &VisualScriptLocalVar::set_var_type); - ClassDB::bind_method(D_METHOD("get_var_type"), &VisualScriptLocalVar::get_var_type); - - String argt = "Any"; - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - argt += "," + Variant::get_type_name(Variant::Type(i)); - } - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_var_name", "get_var_name"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_var_type", "get_var_type"); -} - -VisualScriptLocalVar::VisualScriptLocalVar() { - name = "new_local"; - type = Variant::NIL; -} - -////////////////////////////////////////// -////////////////LocalVar/////////// -////////////////////////////////////////// - -int VisualScriptLocalVarSet::get_output_sequence_port_count() const { - return 1; -} - -bool VisualScriptLocalVarSet::has_input_sequence_port() const { - return true; -} - -int VisualScriptLocalVarSet::get_input_value_port_count() const { - return 1; -} - -int VisualScriptLocalVarSet::get_output_value_port_count() const { - return 1; -} - -String VisualScriptLocalVarSet::get_output_sequence_port_text(int p_port) const { - return ""; -} - -PropertyInfo VisualScriptLocalVarSet::get_input_value_port_info(int p_idx) const { - return PropertyInfo(type, "set"); -} - -PropertyInfo VisualScriptLocalVarSet::get_output_value_port_info(int p_idx) const { - return PropertyInfo(type, "get"); -} - -String VisualScriptLocalVarSet::get_caption() const { - return RTR("Set Local Var"); -} - -String VisualScriptLocalVarSet::get_text() const { - return name; -} - -String VisualScriptLocalVarSet::get_category() const { - return "data"; -} - -void VisualScriptLocalVarSet::set_var_name(const StringName &p_name) { - if (name == p_name) { - return; - } - - name = p_name; - ports_changed_notify(); -} - -StringName VisualScriptLocalVarSet::get_var_name() const { - return name; -} - -void VisualScriptLocalVarSet::set_var_type(Variant::Type p_type) { - type = p_type; - ports_changed_notify(); -} - -Variant::Type VisualScriptLocalVarSet::get_var_type() const { - return type; -} - -class VisualScriptNodeInstanceLocalVarSet : public VisualScriptNodeInstance { -public: - VisualScriptInstance *instance = nullptr; - StringName name; - - virtual int get_working_memory_size() const override { return 1; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - *p_working_mem = *p_inputs[0]; - *p_outputs[0] = *p_working_mem; - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptLocalVarSet::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceLocalVarSet *instance = memnew(VisualScriptNodeInstanceLocalVarSet); - instance->instance = p_instance; - instance->name = name; - - return instance; -} - -void VisualScriptLocalVarSet::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_var_name", "name"), &VisualScriptLocalVarSet::set_var_name); - ClassDB::bind_method(D_METHOD("get_var_name"), &VisualScriptLocalVarSet::get_var_name); - - ClassDB::bind_method(D_METHOD("set_var_type", "type"), &VisualScriptLocalVarSet::set_var_type); - ClassDB::bind_method(D_METHOD("get_var_type"), &VisualScriptLocalVarSet::get_var_type); - - String argt = "Any"; - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - argt += "," + Variant::get_type_name(Variant::Type(i)); - } - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_var_name", "get_var_name"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_var_type", "get_var_type"); -} - -VisualScriptLocalVarSet::VisualScriptLocalVarSet() { - name = "new_local"; - type = Variant::NIL; -} - -////////////////////////////////////////// -////////////////LocalVar/////////// -////////////////////////////////////////// - -int VisualScriptInputAction::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptInputAction::has_input_sequence_port() const { - return false; -} - -int VisualScriptInputAction::get_input_value_port_count() const { - return 0; -} - -int VisualScriptInputAction::get_output_value_port_count() const { - return 1; -} - -String VisualScriptInputAction::get_output_sequence_port_text(int p_port) const { - return ""; -} - -PropertyInfo VisualScriptInputAction::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptInputAction::get_output_value_port_info(int p_idx) const { - String mstr; - switch (mode) { - case MODE_PRESSED: { - mstr = "pressed"; - } break; - case MODE_RELEASED: { - mstr = "not pressed"; - } break; - case MODE_JUST_PRESSED: { - mstr = "just pressed"; - } break; - case MODE_JUST_RELEASED: { - mstr = "just released"; - } break; - } - - return PropertyInfo(Variant::BOOL, mstr); -} - -String VisualScriptInputAction::get_caption() const { - return vformat(RTR("Action %s"), name); -} - -String VisualScriptInputAction::get_category() const { - return "data"; -} - -void VisualScriptInputAction::set_action_name(const StringName &p_name) { - if (name == p_name) { - return; - } - - name = p_name; - ports_changed_notify(); -} - -StringName VisualScriptInputAction::get_action_name() const { - return name; -} - -void VisualScriptInputAction::set_action_mode(Mode p_mode) { - if (mode == p_mode) { - return; - } - - mode = p_mode; - ports_changed_notify(); -} - -VisualScriptInputAction::Mode VisualScriptInputAction::get_action_mode() const { - return mode; -} - -class VisualScriptNodeInstanceInputAction : public VisualScriptNodeInstance { -public: - VisualScriptInstance *instance = nullptr; - StringName action; - VisualScriptInputAction::Mode mode; - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - switch (mode) { - case VisualScriptInputAction::MODE_PRESSED: { - *p_outputs[0] = Input::get_singleton()->is_action_pressed(action); - } break; - case VisualScriptInputAction::MODE_RELEASED: { - *p_outputs[0] = !Input::get_singleton()->is_action_pressed(action); - } break; - case VisualScriptInputAction::MODE_JUST_PRESSED: { - *p_outputs[0] = Input::get_singleton()->is_action_just_pressed(action); - } break; - case VisualScriptInputAction::MODE_JUST_RELEASED: { - *p_outputs[0] = Input::get_singleton()->is_action_just_released(action); - } break; - } - - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptInputAction::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceInputAction *instance = memnew(VisualScriptNodeInstanceInputAction); - instance->instance = p_instance; - instance->action = name; - instance->mode = mode; - - return instance; -} - -void VisualScriptInputAction::_validate_property(PropertyInfo &p_property) const { - if (p_property.name == "action") { - p_property.hint = PROPERTY_HINT_ENUM; - String actions; - - List<PropertyInfo> pinfo; - ProjectSettings::get_singleton()->get_property_list(&pinfo); - Vector<String> al; - - for (const PropertyInfo &pi : pinfo) { - if (!pi.name.begins_with("input/")) { - continue; - } - - String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length()); - - al.push_back(name); - } - - al.sort(); - - for (int i = 0; i < al.size(); i++) { - if (!actions.is_empty()) { - actions += ","; - } - actions += al[i]; - } - - p_property.hint_string = actions; - } -} - -void VisualScriptInputAction::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_action_name", "name"), &VisualScriptInputAction::set_action_name); - ClassDB::bind_method(D_METHOD("get_action_name"), &VisualScriptInputAction::get_action_name); - - ClassDB::bind_method(D_METHOD("set_action_mode", "mode"), &VisualScriptInputAction::set_action_mode); - ClassDB::bind_method(D_METHOD("get_action_mode"), &VisualScriptInputAction::get_action_mode); - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "action"), "set_action_name", "get_action_name"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Pressed,Released,JustPressed,JustReleased"), "set_action_mode", "get_action_mode"); - - BIND_ENUM_CONSTANT(MODE_PRESSED); - BIND_ENUM_CONSTANT(MODE_RELEASED); - BIND_ENUM_CONSTANT(MODE_JUST_PRESSED); - BIND_ENUM_CONSTANT(MODE_JUST_RELEASED); -} - -VisualScriptInputAction::VisualScriptInputAction() { - name = ""; - mode = MODE_PRESSED; -} - -////////////////////////////////////////// -////////////////Constructor/////////// -////////////////////////////////////////// - -int VisualScriptDeconstruct::get_output_sequence_port_count() const { - return 0; -} - -bool VisualScriptDeconstruct::has_input_sequence_port() const { - return false; -} - -int VisualScriptDeconstruct::get_input_value_port_count() const { - return 1; -} - -int VisualScriptDeconstruct::get_output_value_port_count() const { - return elements.size(); -} - -String VisualScriptDeconstruct::get_output_sequence_port_text(int p_port) const { - return ""; -} - -PropertyInfo VisualScriptDeconstruct::get_input_value_port_info(int p_idx) const { - return PropertyInfo(type, "value"); -} - -PropertyInfo VisualScriptDeconstruct::get_output_value_port_info(int p_idx) const { - return PropertyInfo(elements[p_idx].type, elements[p_idx].name); -} - -String VisualScriptDeconstruct::get_caption() const { - return vformat(RTR("Deconstruct %s"), Variant::get_type_name(type)); -} - -String VisualScriptDeconstruct::get_category() const { - return "functions"; -} - -void VisualScriptDeconstruct::_update_elements() { - elements.clear(); - Variant v; - Callable::CallError ce; - Variant::construct(type, v, nullptr, 0, ce); - - List<PropertyInfo> pinfo; - v.get_property_list(&pinfo); - - for (const PropertyInfo &E : pinfo) { - Element e; - e.name = E.name; - e.type = E.type; - elements.push_back(e); - } -} - -void VisualScriptDeconstruct::set_deconstruct_type(Variant::Type p_type) { - if (type == p_type) { - return; - } - - type = p_type; - _update_elements(); - ports_changed_notify(); - notify_property_list_changed(); //to make input appear/disappear -} - -Variant::Type VisualScriptDeconstruct::get_deconstruct_type() const { - return type; -} - -void VisualScriptDeconstruct::_set_elem_cache(const Array &p_elements) { - ERR_FAIL_COND(p_elements.size() % 2 == 1); - elements.resize(p_elements.size() / 2); - for (int i = 0; i < elements.size(); i++) { - elements.write[i].name = p_elements[i * 2 + 0]; - elements.write[i].type = Variant::Type(int(p_elements[i * 2 + 1])); - } -} - -Array VisualScriptDeconstruct::_get_elem_cache() const { - Array ret; - for (int i = 0; i < elements.size(); i++) { - ret.push_back(elements[i].name); - ret.push_back(elements[i].type); - } - return ret; -} - -class VisualScriptNodeInstanceDeconstruct : public VisualScriptNodeInstance { -public: - VisualScriptInstance *instance = nullptr; - Vector<StringName> outputs; - - //virtual int get_working_memory_size() const override { return 0; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - Variant in = *p_inputs[0]; - - for (int i = 0; i < outputs.size(); i++) { - bool valid; - *p_outputs[i] = in.get(outputs[i], &valid); - if (!valid) { - r_error_str = "Can't obtain element '" + String(outputs[i]) + "' from " + Variant::get_type_name(in.get_type()); - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - return 0; - } - } - - return 0; - } -}; - -VisualScriptNodeInstance *VisualScriptDeconstruct::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceDeconstruct *instance = memnew(VisualScriptNodeInstanceDeconstruct); - instance->instance = p_instance; - instance->outputs.resize(elements.size()); - for (int i = 0; i < elements.size(); i++) { - instance->outputs.write[i] = elements[i].name; - } - - return instance; -} - -void VisualScriptDeconstruct::_validate_property(PropertyInfo &p_property) const { -} - -void VisualScriptDeconstruct::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_deconstruct_type", "type"), &VisualScriptDeconstruct::set_deconstruct_type); - ClassDB::bind_method(D_METHOD("get_deconstruct_type"), &VisualScriptDeconstruct::get_deconstruct_type); - - ClassDB::bind_method(D_METHOD("_set_elem_cache", "_cache"), &VisualScriptDeconstruct::_set_elem_cache); - ClassDB::bind_method(D_METHOD("_get_elem_cache"), &VisualScriptDeconstruct::_get_elem_cache); - - String argt = "Any"; - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - argt += "," + Variant::get_type_name(Variant::Type(i)); - } - - ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_deconstruct_type", "get_deconstruct_type"); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "elem_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_elem_cache", "_get_elem_cache"); -} - -VisualScriptDeconstruct::VisualScriptDeconstruct() { - type = Variant::NIL; -} - -template <Variant::Type T> -static Ref<VisualScriptNode> create_node_deconst_typed(const String &p_name) { - Ref<VisualScriptDeconstruct> node; - node.instantiate(); - node->set_deconstruct_type(T); - return node; -} - -void register_visual_script_nodes() { - VisualScriptLanguage::singleton->add_register_func("data/set_variable", create_node_generic<VisualScriptVariableSet>); - VisualScriptLanguage::singleton->add_register_func("data/get_variable", create_node_generic<VisualScriptVariableGet>); - VisualScriptLanguage::singleton->add_register_func("data/engine_singleton", create_node_generic<VisualScriptEngineSingleton>); - VisualScriptLanguage::singleton->add_register_func("data/scene_node", create_node_generic<VisualScriptSceneNode>); - VisualScriptLanguage::singleton->add_register_func("data/scene_tree", create_node_generic<VisualScriptSceneTree>); - VisualScriptLanguage::singleton->add_register_func("data/resource_path", create_node_generic<VisualScriptResourcePath>); - VisualScriptLanguage::singleton->add_register_func("data/self", create_node_generic<VisualScriptSelf>); - VisualScriptLanguage::singleton->add_register_func("data/comment", create_node_generic<VisualScriptComment>); - VisualScriptLanguage::singleton->add_register_func("data/get_local_variable", create_node_generic<VisualScriptLocalVar>); - VisualScriptLanguage::singleton->add_register_func("data/set_local_variable", create_node_generic<VisualScriptLocalVarSet>); - VisualScriptLanguage::singleton->add_register_func("data/preload", create_node_generic<VisualScriptPreload>); - VisualScriptLanguage::singleton->add_register_func("data/action", create_node_generic<VisualScriptInputAction>); - - VisualScriptLanguage::singleton->add_register_func("constants/constant", create_node_generic<VisualScriptConstant>); - VisualScriptLanguage::singleton->add_register_func("constants/math_constant", create_node_generic<VisualScriptMathConstant>); - VisualScriptLanguage::singleton->add_register_func("constants/class_constant", create_node_generic<VisualScriptClassConstant>); - VisualScriptLanguage::singleton->add_register_func("constants/global_constant", create_node_generic<VisualScriptGlobalConstant>); - VisualScriptLanguage::singleton->add_register_func("constants/basic_type_constant", create_node_generic<VisualScriptBasicTypeConstant>); - - VisualScriptLanguage::singleton->add_register_func("custom/custom_node", create_node_generic<VisualScriptCustomNode>); - VisualScriptLanguage::singleton->add_register_func("custom/sub_call", create_node_generic<VisualScriptSubCall>); - - VisualScriptLanguage::singleton->add_register_func("index/get_index", create_node_generic<VisualScriptIndexGet>); - VisualScriptLanguage::singleton->add_register_func("index/set_index", create_node_generic<VisualScriptIndexSet>); - - VisualScriptLanguage::singleton->add_register_func("operators/compare/equal", create_op_node<Variant::OP_EQUAL>); - VisualScriptLanguage::singleton->add_register_func("operators/compare/not_equal", create_op_node<Variant::OP_NOT_EQUAL>); - VisualScriptLanguage::singleton->add_register_func("operators/compare/less", create_op_node<Variant::OP_LESS>); - VisualScriptLanguage::singleton->add_register_func("operators/compare/less_equal", create_op_node<Variant::OP_LESS_EQUAL>); - VisualScriptLanguage::singleton->add_register_func("operators/compare/greater", create_op_node<Variant::OP_GREATER>); - VisualScriptLanguage::singleton->add_register_func("operators/compare/greater_equal", create_op_node<Variant::OP_GREATER_EQUAL>); - //mathematic - VisualScriptLanguage::singleton->add_register_func("operators/math/add", create_op_node<Variant::OP_ADD>); - VisualScriptLanguage::singleton->add_register_func("operators/math/subtract", create_op_node<Variant::OP_SUBTRACT>); - VisualScriptLanguage::singleton->add_register_func("operators/math/multiply", create_op_node<Variant::OP_MULTIPLY>); - VisualScriptLanguage::singleton->add_register_func("operators/math/divide", create_op_node<Variant::OP_DIVIDE>); - VisualScriptLanguage::singleton->add_register_func("operators/math/negate", create_op_node<Variant::OP_NEGATE>); - VisualScriptLanguage::singleton->add_register_func("operators/math/positive", create_op_node<Variant::OP_POSITIVE>); - VisualScriptLanguage::singleton->add_register_func("operators/math/remainder", create_op_node<Variant::OP_MODULE>); - //bitwise - VisualScriptLanguage::singleton->add_register_func("operators/bitwise/shift_left", create_op_node<Variant::OP_SHIFT_LEFT>); - VisualScriptLanguage::singleton->add_register_func("operators/bitwise/shift_right", create_op_node<Variant::OP_SHIFT_RIGHT>); - VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_and", create_op_node<Variant::OP_BIT_AND>); - VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_or", create_op_node<Variant::OP_BIT_OR>); - VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_xor", create_op_node<Variant::OP_BIT_XOR>); - VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_negate", create_op_node<Variant::OP_BIT_NEGATE>); - //logic - VisualScriptLanguage::singleton->add_register_func("operators/logic/and", create_op_node<Variant::OP_AND>); - VisualScriptLanguage::singleton->add_register_func("operators/logic/or", create_op_node<Variant::OP_OR>); - VisualScriptLanguage::singleton->add_register_func("operators/logic/xor", create_op_node<Variant::OP_XOR>); - VisualScriptLanguage::singleton->add_register_func("operators/logic/not", create_op_node<Variant::OP_NOT>); - VisualScriptLanguage::singleton->add_register_func("operators/logic/in", create_op_node<Variant::OP_IN>); - VisualScriptLanguage::singleton->add_register_func("operators/logic/select", create_node_generic<VisualScriptSelect>); - - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR2), create_node_deconst_typed<Variant::Type::VECTOR2>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR2I), create_node_deconst_typed<Variant::Type::VECTOR2I>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR3), create_node_deconst_typed<Variant::Type::VECTOR3>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR3I), create_node_deconst_typed<Variant::Type::VECTOR3I>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR4), create_node_deconst_typed<Variant::Type::VECTOR4>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR4I), create_node_deconst_typed<Variant::Type::VECTOR4I>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::COLOR), create_node_deconst_typed<Variant::Type::COLOR>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::RECT2), create_node_deconst_typed<Variant::Type::RECT2>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::RECT2I), create_node_deconst_typed<Variant::Type::RECT2I>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM2D), create_node_deconst_typed<Variant::Type::TRANSFORM2D>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::PLANE), create_node_deconst_typed<Variant::Type::PLANE>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::QUATERNION), create_node_deconst_typed<Variant::Type::QUATERNION>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::AABB), create_node_deconst_typed<Variant::Type::AABB>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::BASIS), create_node_deconst_typed<Variant::Type::BASIS>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM3D), create_node_deconst_typed<Variant::Type::TRANSFORM3D>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::PROJECTION), create_node_deconst_typed<Variant::Type::PROJECTION>); - VisualScriptLanguage::singleton->add_register_func("functions/compose_array", create_node_generic<VisualScriptComposeArray>); - - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - List<MethodInfo> constructors; - Variant::get_constructor_list(Variant::Type(i), &constructors); - - for (const MethodInfo &E : constructors) { - if (E.arguments.size() > 0) { - String name = "functions/constructors/" + Variant::get_type_name(Variant::Type(i)) + "("; - for (int j = 0; j < E.arguments.size(); j++) { - if (j > 0) { - name += ", "; - } - if (E.arguments.size() == 1) { - name += Variant::get_type_name(E.arguments[j].type); - } else { - name += E.arguments[j].name; - } - } - name += ")"; - VisualScriptLanguage::singleton->add_register_func(name, create_constructor_node); - Pair<Variant::Type, MethodInfo> pair; - pair.first = Variant::Type(i); - pair.second = E; - constructor_map[name] = pair; - } - } - } -} - -void unregister_visual_script_nodes() { - constructor_map.clear(); -} diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h deleted file mode 100644 index 72a99b9fd2..0000000000 --- a/modules/visual_script/visual_script_nodes.h +++ /dev/null @@ -1,1092 +0,0 @@ -/*************************************************************************/ -/* visual_script_nodes.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 VISUAL_SCRIPT_NODES_H -#define VISUAL_SCRIPT_NODES_H - -#include "core/object/gdvirtual.gen.inc" -#include "core/object/script_language.h" -#include "scene/main/multiplayer_api.h" -#include "visual_script.h" - -class VisualScriptFunction : public VisualScriptNode { - GDCLASS(VisualScriptFunction, VisualScriptNode); - - struct Argument { - String name; - Variant::Type type; - PropertyHint hint; - String hint_string; - }; - - Vector<Argument> arguments; - - bool stack_less; - int stack_size; - MultiplayerAPI::RPCMode rpc_mode; - bool sequenced; - -protected: - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List<PropertyInfo> *p_list) const; - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "flow_control"; } - - void add_argument(Variant::Type p_type, const String &p_name, int p_index = -1, const PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = String("")); - void set_argument_type(int p_argidx, Variant::Type p_type); - Variant::Type get_argument_type(int p_argidx) const; - void set_argument_name(int p_argidx, const String &p_name); - String get_argument_name(int p_argidx) const; - void remove_argument(int p_argidx); - int get_argument_count() const; - - void set_stack_less(bool p_enable); - bool is_stack_less() const; - - void set_sequenced(bool p_enable); - bool is_sequenced() const; - - void set_stack_size(int p_size); - int get_stack_size() const; - - void set_rpc_mode(MultiplayerAPI::RPCMode p_mode); - MultiplayerAPI::RPCMode get_rpc_mode() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - virtual void reset_state() override; - - VisualScriptFunction(); -}; - -class VisualScriptLists : public VisualScriptNode { - GDCLASS(VisualScriptLists, VisualScriptNode) - - struct Port { - String name; - Variant::Type type; - }; - -protected: - Vector<Port> inputports; - Vector<Port> outputports; - - enum { - OUTPUT_EDITABLE = 0x0001, - OUTPUT_NAME_EDITABLE = 0x0002, - OUTPUT_TYPE_EDITABLE = 0x0004, - INPUT_EDITABLE = 0x0008, - INPUT_NAME_EDITABLE = 0x000F, - INPUT_TYPE_EDITABLE = 0x0010, - }; - - int flags; - - bool sequenced; - - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List<PropertyInfo> *p_list) const; - - static void _bind_methods(); - -public: - virtual void reset_state() override; - - virtual bool is_output_port_editable() const; - virtual bool is_output_port_name_editable() const; - virtual bool is_output_port_type_editable() const; - - virtual bool is_input_port_editable() const; - virtual bool is_input_port_name_editable() const; - virtual bool is_input_port_type_editable() const; - - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - void add_input_data_port(Variant::Type p_type, const String &p_name, int p_index = -1); - void set_input_data_port_type(int p_idx, Variant::Type p_type); - void set_input_data_port_name(int p_idx, const String &p_name); - void remove_input_data_port(int p_argidx); - - void add_output_data_port(Variant::Type p_type, const String &p_name, int p_index = -1); - void set_output_data_port_type(int p_idx, Variant::Type p_type); - void set_output_data_port_name(int p_idx, const String &p_name); - void remove_output_data_port(int p_argidx); - - void set_sequenced(bool p_enable); - bool is_sequenced() const; - - VisualScriptLists(); -}; - -class VisualScriptComposeArray : public VisualScriptLists { - GDCLASS(VisualScriptComposeArray, VisualScriptLists) - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "functions"; } - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptComposeArray(); -}; - -class VisualScriptOperator : public VisualScriptNode { - GDCLASS(VisualScriptOperator, VisualScriptNode); - - Variant::Type typed; - Variant::Operator op; - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override { return "operators"; } - - void set_operator(Variant::Operator p_op); - Variant::Operator get_operator() const; - - void set_typed(Variant::Type p_op); - Variant::Type get_typed() const; - - static String get_operator_name(Variant::Operator p_op); - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptOperator(); -}; - -class VisualScriptSelect : public VisualScriptNode { - GDCLASS(VisualScriptSelect, VisualScriptNode); - - Variant::Type typed; - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "operators"; } - - void set_typed(Variant::Type p_op); - Variant::Type get_typed() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptSelect(); -}; - -class VisualScriptVariableGet : public VisualScriptNode { - GDCLASS(VisualScriptVariableGet, VisualScriptNode); - - StringName variable; - -protected: - void _validate_property(PropertyInfo &p_property) const; - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override { return "data"; } - - void set_variable(StringName p_variable); - StringName get_variable() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptVariableGet(); -}; - -class VisualScriptVariableSet : public VisualScriptNode { - GDCLASS(VisualScriptVariableSet, VisualScriptNode); - - StringName variable; - -protected: - void _validate_property(PropertyInfo &p_property) const; - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override { return "data"; } - - void set_variable(StringName p_variable); - StringName get_variable() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptVariableSet(); -}; - -class VisualScriptConstant : public VisualScriptNode { - GDCLASS(VisualScriptConstant, VisualScriptNode); - - Variant::Type type; - Variant value; - -protected: - void _validate_property(PropertyInfo &p_property) const; - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override { return "constants"; } - - void set_constant_type(Variant::Type p_type); - Variant::Type get_constant_type() const; - - void set_constant_value(Variant p_value); - Variant get_constant_value() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptConstant(); -}; - -class VisualScriptPreload : public VisualScriptNode { - GDCLASS(VisualScriptPreload, VisualScriptNode); - - Ref<Resource> preload; - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override { return "data"; } - - void set_preload(const Ref<Resource> &p_preload); - Ref<Resource> get_preload() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptPreload(); -}; - -class VisualScriptIndexGet : public VisualScriptNode { - GDCLASS(VisualScriptIndexGet, VisualScriptNode); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override { return "operators"; } - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptIndexGet(); -}; - -class VisualScriptIndexSet : public VisualScriptNode { - GDCLASS(VisualScriptIndexSet, VisualScriptNode); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override { return "operators"; } - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptIndexSet(); -}; - -class VisualScriptGlobalConstant : public VisualScriptNode { - GDCLASS(VisualScriptGlobalConstant, VisualScriptNode); - - int index; - - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override { return "constants"; } - - void set_global_constant(int p_which); - int get_global_constant(); - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptGlobalConstant(); -}; - -class VisualScriptClassConstant : public VisualScriptNode { - GDCLASS(VisualScriptClassConstant, VisualScriptNode); - - StringName base_type; - StringName name; - -protected: - static void _bind_methods(); - void _validate_property(PropertyInfo &p_property) const; - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override { return "constants"; } - - void set_class_constant(const StringName &p_which); - StringName get_class_constant(); - - void set_base_type(const StringName &p_which); - StringName get_base_type(); - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptClassConstant(); -}; - -class VisualScriptBasicTypeConstant : public VisualScriptNode { - GDCLASS(VisualScriptBasicTypeConstant, VisualScriptNode); - - Variant::Type type; - StringName name; - -protected: - static void _bind_methods(); - void _validate_property(PropertyInfo &p_property) const; - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "constants"; } - - void set_basic_type_constant(const StringName &p_which); - StringName get_basic_type_constant() const; - - void set_basic_type(Variant::Type p_which); - Variant::Type get_basic_type() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptBasicTypeConstant(); -}; - -class VisualScriptMathConstant : public VisualScriptNode { - GDCLASS(VisualScriptMathConstant, VisualScriptNode); - -public: - enum MathConstant { - MATH_CONSTANT_ONE, - MATH_CONSTANT_PI, - MATH_CONSTANT_HALF_PI, - MATH_CONSTANT_TAU, - MATH_CONSTANT_E, - MATH_CONSTANT_SQRT2, - MATH_CONSTANT_INF, - MATH_CONSTANT_NAN, - MATH_CONSTANT_MAX - }; - -private: - static const char *const_name[MATH_CONSTANT_MAX]; - static double const_value[MATH_CONSTANT_MAX]; - MathConstant constant; - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override { return "constants"; } - - void set_math_constant(MathConstant p_which); - MathConstant get_math_constant(); - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptMathConstant(); -}; - -VARIANT_ENUM_CAST(VisualScriptMathConstant::MathConstant) - -class VisualScriptEngineSingleton : public VisualScriptNode { - GDCLASS(VisualScriptEngineSingleton, VisualScriptNode); - - String singleton; - -protected: - void _validate_property(PropertyInfo &p_property) const; - - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override { return "data"; } - - void set_singleton(const String &p_string); - String get_singleton(); - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; - - VisualScriptEngineSingleton(); -}; - -class VisualScriptSceneNode : public VisualScriptNode { - GDCLASS(VisualScriptSceneNode, VisualScriptNode); - - NodePath path; - -protected: - void _validate_property(PropertyInfo &p_property) const; - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override { return "data"; } - - void set_node_path(const NodePath &p_path); - NodePath get_node_path(); - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; - - VisualScriptSceneNode(); -}; - -class VisualScriptSceneTree : public VisualScriptNode { - GDCLASS(VisualScriptSceneTree, VisualScriptNode); - -protected: - void _validate_property(PropertyInfo &p_property) const; - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override { return "data"; } - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; - - VisualScriptSceneTree(); -}; - -class VisualScriptResourcePath : public VisualScriptNode { - GDCLASS(VisualScriptResourcePath, VisualScriptNode); - - String path; - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override { return "data"; } - - void set_resource_path(const String &p_path); - String get_resource_path(); - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptResourcePath(); -}; - -class VisualScriptSelf : public VisualScriptNode { - GDCLASS(VisualScriptSelf, VisualScriptNode); - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override { return "data"; } - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; - - VisualScriptSelf(); -}; - -class VisualScriptCustomNode : public VisualScriptNode { - GDCLASS(VisualScriptCustomNode, VisualScriptNode); - -protected: - static void _bind_methods(); - friend class VisualScriptNodeInstanceCustomNode; - GDVIRTUAL0RC(int, _get_output_sequence_port_count) - GDVIRTUAL0RC(bool, _has_input_sequence_port) - GDVIRTUAL1RC(String, _get_output_sequence_port_text, int) - - GDVIRTUAL0RC(int, _get_input_value_port_count) - GDVIRTUAL1RC(int, _get_input_value_port_type, int) - GDVIRTUAL1RC(String, _get_input_value_port_name, int) - GDVIRTUAL1RC(int, _get_input_value_port_hint, int) - GDVIRTUAL1RC(String, _get_input_value_port_hint_string, int) - - GDVIRTUAL0RC(int, _get_output_value_port_count) - GDVIRTUAL1RC(int, _get_output_value_port_type, int) - GDVIRTUAL1RC(String, _get_output_value_port_name, int) - GDVIRTUAL1RC(int, _get_output_value_port_hint, int) - GDVIRTUAL1RC(String, _get_output_value_port_hint_string, int) - - GDVIRTUAL0RC(String, _get_caption) - GDVIRTUAL0RC(String, _get_text) - GDVIRTUAL0RC(String, _get_category) - - GDVIRTUAL0RC(int, _get_working_memory_size) - - GDVIRTUAL4RC(Variant, _step, Array, Array, int, Array) - -public: - enum StartMode { //replicated for step - START_MODE_BEGIN_SEQUENCE, - START_MODE_CONTINUE_SEQUENCE, - START_MODE_RESUME_YIELD - }; - - enum { //replicated for step - STEP_SHIFT = 1 << 24, - STEP_MASK = STEP_SHIFT - 1, - STEP_PUSH_STACK_BIT = STEP_SHIFT, //push bit to stack - STEP_GO_BACK_BIT = STEP_SHIFT << 1, //go back to previous node - STEP_NO_ADVANCE_BIT = STEP_SHIFT << 2, //do not advance past this node - STEP_EXIT_FUNCTION_BIT = STEP_SHIFT << 3, //return from function - STEP_YIELD_BIT = STEP_SHIFT << 4, //yield (will find VisualScriptFunctionState state in first working memory) - }; - - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; - - void _script_changed(); - - VisualScriptCustomNode(); -}; - -VARIANT_ENUM_CAST(VisualScriptCustomNode::StartMode); - -class VisualScriptSubCall : public VisualScriptNode { - GDCLASS(VisualScriptSubCall, VisualScriptNode); - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptSubCall(); -}; - -class VisualScriptComment : public VisualScriptNode { - GDCLASS(VisualScriptComment, VisualScriptNode); - - String title; - String description; - Size2 size; - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override; - - void set_title(const String &p_title); - String get_title() const; - - void set_description(const String &p_description); - String get_description() const; - - void set_size(const Size2 &p_size); - Size2 get_size() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptComment(); -}; - -class VisualScriptConstructor : public VisualScriptNode { - GDCLASS(VisualScriptConstructor, VisualScriptNode); - - Variant::Type type; - MethodInfo constructor; - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override; - - void set_constructor_type(Variant::Type p_type); - Variant::Type get_constructor_type() const; - - void set_constructor(const Dictionary &p_info); - Dictionary get_constructor() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptConstructor(); -}; - -class VisualScriptLocalVar : public VisualScriptNode { - GDCLASS(VisualScriptLocalVar, VisualScriptNode); - - StringName name; - Variant::Type type; - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override; - - void set_var_name(const StringName &p_name); - StringName get_var_name() const; - - void set_var_type(Variant::Type p_type); - Variant::Type get_var_type() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptLocalVar(); -}; - -class VisualScriptLocalVarSet : public VisualScriptNode { - GDCLASS(VisualScriptLocalVarSet, VisualScriptNode); - - StringName name; - Variant::Type type; - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override; - - void set_var_name(const StringName &p_name); - StringName get_var_name() const; - - void set_var_type(Variant::Type p_type); - Variant::Type get_var_type() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptLocalVarSet(); -}; - -class VisualScriptInputAction : public VisualScriptNode { - GDCLASS(VisualScriptInputAction, VisualScriptNode); - -public: - enum Mode { - MODE_PRESSED, - MODE_RELEASED, - MODE_JUST_PRESSED, - MODE_JUST_RELEASED, - }; - - StringName name; - Mode mode; - -protected: - void _validate_property(PropertyInfo &p_property) const; - - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override; - - void set_action_name(const StringName &p_name); - StringName get_action_name() const; - - void set_action_mode(Mode p_mode); - Mode get_action_mode() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptInputAction(); -}; - -VARIANT_ENUM_CAST(VisualScriptInputAction::Mode) - -class VisualScriptDeconstruct : public VisualScriptNode { - GDCLASS(VisualScriptDeconstruct, VisualScriptNode); - - struct Element { - StringName name; - Variant::Type type; - }; - - Vector<Element> elements; - - void _update_elements(); - Variant::Type type; - - void _set_elem_cache(const Array &p_elements); - Array _get_elem_cache() const; - - void _validate_property(PropertyInfo &p_property) const; - -protected: - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_category() const override; - - void set_deconstruct_type(Variant::Type p_type); - Variant::Type get_deconstruct_type() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptDeconstruct(); -}; - -void register_visual_script_nodes(); -void unregister_visual_script_nodes(); - -#endif // VISUAL_SCRIPT_NODES_H diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp deleted file mode 100644 index 05dbe102f5..0000000000 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ /dev/null @@ -1,598 +0,0 @@ -/*************************************************************************/ -/* visual_script_yield_nodes.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "visual_script_yield_nodes.h" - -#include "core/os/os.h" -#include "scene/main/node.h" -#include "scene/main/scene_tree.h" -#include "visual_script_nodes.h" - -////////////////////////////////////////// -////////////////YIELD/////////// -////////////////////////////////////////// - -int VisualScriptYield::get_output_sequence_port_count() const { - return 1; -} - -bool VisualScriptYield::has_input_sequence_port() const { - return true; -} - -int VisualScriptYield::get_input_value_port_count() const { - return 0; -} - -int VisualScriptYield::get_output_value_port_count() const { - return 0; -} - -String VisualScriptYield::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptYield::get_input_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -PropertyInfo VisualScriptYield::get_output_value_port_info(int p_idx) const { - return PropertyInfo(); -} - -String VisualScriptYield::get_caption() const { - return yield_mode == YIELD_RETURN ? RTR("Yield") : RTR("Wait"); -} - -String VisualScriptYield::get_text() const { - switch (yield_mode) { - case YIELD_RETURN: - return ""; - break; - case YIELD_FRAME: - return RTR("Next Frame"); - break; - case YIELD_PHYSICS_FRAME: - return RTR("Next Physics Frame"); - break; - case YIELD_WAIT: - return vformat(RTR("%s sec(s)"), rtos(wait_time)); - break; - } - - return String(); -} - -class VisualScriptNodeInstanceYield : public VisualScriptNodeInstance { -public: - VisualScriptYield::YieldMode mode; - double wait_time = 0.0; - - virtual int get_working_memory_size() const override { return 1; } //yield needs at least 1 - //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } - //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - if (p_start_mode == START_MODE_RESUME_YIELD) { - return 0; //resuming yield - } else { - //yield - - SceneTree *tree = Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop()); - if (!tree) { - r_error_str = "Main Loop is not SceneTree"; - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - return 0; - } - - Ref<VisualScriptFunctionState> state; - state.instantiate(); - - int ret = STEP_YIELD_BIT; - switch (mode) { - case VisualScriptYield::YIELD_RETURN: - ret = STEP_EXIT_FUNCTION_BIT; - break; //return the yield - case VisualScriptYield::YIELD_FRAME: - state->connect_to_signal(tree, "process_frame", Array()); - break; - case VisualScriptYield::YIELD_PHYSICS_FRAME: - state->connect_to_signal(tree, "physics_frame", Array()); - break; - case VisualScriptYield::YIELD_WAIT: - state->connect_to_signal(tree->create_timer(wait_time).ptr(), "timeout", Array()); - break; - } - - *p_working_mem = state; - - return ret; - } - } -}; - -VisualScriptNodeInstance *VisualScriptYield::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceYield *instance = memnew(VisualScriptNodeInstanceYield); - //instance->instance=p_instance; - instance->mode = yield_mode; - instance->wait_time = wait_time; - return instance; -} - -void VisualScriptYield::set_yield_mode(YieldMode p_mode) { - if (yield_mode == p_mode) { - return; - } - yield_mode = p_mode; - ports_changed_notify(); - notify_property_list_changed(); -} - -VisualScriptYield::YieldMode VisualScriptYield::get_yield_mode() { - return yield_mode; -} - -void VisualScriptYield::set_wait_time(double p_time) { - if (wait_time == p_time) { - return; - } - wait_time = p_time; - ports_changed_notify(); -} - -double VisualScriptYield::get_wait_time() { - return wait_time; -} - -void VisualScriptYield::_validate_property(PropertyInfo &p_property) const { - if (p_property.name == "wait_time") { - if (yield_mode != YIELD_WAIT) { - p_property.usage = PROPERTY_USAGE_NONE; - } - } -} - -void VisualScriptYield::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_yield_mode", "mode"), &VisualScriptYield::set_yield_mode); - ClassDB::bind_method(D_METHOD("get_yield_mode"), &VisualScriptYield::get_yield_mode); - - ClassDB::bind_method(D_METHOD("set_wait_time", "sec"), &VisualScriptYield::set_wait_time); - ClassDB::bind_method(D_METHOD("get_wait_time"), &VisualScriptYield::get_wait_time); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Frame,Physics Frame,Time", PROPERTY_USAGE_NO_EDITOR), "set_yield_mode", "get_yield_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wait_time"), "set_wait_time", "get_wait_time"); - - BIND_ENUM_CONSTANT(YIELD_FRAME); - BIND_ENUM_CONSTANT(YIELD_PHYSICS_FRAME); - BIND_ENUM_CONSTANT(YIELD_WAIT); -} - -VisualScriptYield::VisualScriptYield() { - yield_mode = YIELD_FRAME; - wait_time = 1; -} - -template <VisualScriptYield::YieldMode MODE> -static Ref<VisualScriptNode> create_yield_node(const String &p_name) { - Ref<VisualScriptYield> node; - node.instantiate(); - node->set_yield_mode(MODE); - return node; -} - -/////////////////////////////////////////////////// -////////////////YIELD SIGNAL////////////////////// -////////////////////////////////////////////////// - -int VisualScriptYieldSignal::get_output_sequence_port_count() const { - return 1; -} - -bool VisualScriptYieldSignal::has_input_sequence_port() const { - return true; -} -#ifdef TOOLS_ENABLED - -static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) { - if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene) { - return nullptr; - } - - Ref<Script> scr = p_current_node->get_script(); - - if (scr.is_valid() && scr == script) { - return p_current_node; - } - - for (int i = 0; i < p_current_node->get_child_count(); i++) { - Node *n = _find_script_node(p_edited_scene, p_current_node->get_child(i), script); - if (n) { - return n; - } - } - - return nullptr; -} - -#endif -Node *VisualScriptYieldSignal::_get_base_node() const { -#ifdef TOOLS_ENABLED - Ref<Script> script = get_visual_script(); - if (!script.is_valid()) { - return nullptr; - } - - MainLoop *main_loop = OS::get_singleton()->get_main_loop(); - SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop); - - if (!scene_tree) { - return nullptr; - } - - Node *edited_scene = scene_tree->get_edited_scene_root(); - - if (!edited_scene) { - return nullptr; - } - - Node *script_node = _find_script_node(edited_scene, edited_scene, script); - - if (!script_node) { - return nullptr; - } - - if (!script_node->has_node(base_path)) { - return nullptr; - } - - Node *path_to = script_node->get_node(base_path); - - return path_to; -#else - - return nullptr; -#endif -} - -StringName VisualScriptYieldSignal::_get_base_type() const { - if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) { - return get_visual_script()->get_instance_base_type(); - } else if (call_mode == CALL_MODE_NODE_PATH && get_visual_script().is_valid()) { - Node *path = _get_base_node(); - if (path) { - return path->get_class(); - } - } - - return base_type; -} - -int VisualScriptYieldSignal::get_input_value_port_count() const { - if (call_mode == CALL_MODE_INSTANCE) { - return 1; - } else { - return 0; - } -} - -int VisualScriptYieldSignal::get_output_value_port_count() const { - MethodInfo sr; - - if (!ClassDB::get_signal(_get_base_type(), signal, &sr)) { - return 0; - } - - return sr.arguments.size(); -} - -String VisualScriptYieldSignal::get_output_sequence_port_text(int p_port) const { - return String(); -} - -PropertyInfo VisualScriptYieldSignal::get_input_value_port_info(int p_idx) const { - if (call_mode == CALL_MODE_INSTANCE) { - return PropertyInfo(Variant::OBJECT, "instance"); - } else { - return PropertyInfo(); - } -} - -PropertyInfo VisualScriptYieldSignal::get_output_value_port_info(int p_idx) const { - MethodInfo sr; - - if (!ClassDB::get_signal(_get_base_type(), signal, &sr)) { - return PropertyInfo(); //no signal - } - ERR_FAIL_INDEX_V(p_idx, sr.arguments.size(), PropertyInfo()); - return sr.arguments[p_idx]; -} - -String VisualScriptYieldSignal::get_caption() const { - switch (call_mode) { - case CALL_MODE_SELF: { - return RTR("WaitSignal"); - } break; - case CALL_MODE_NODE_PATH: { - return RTR("WaitNodeSignal"); - } break; - case CALL_MODE_INSTANCE: { - return RTR("WaitInstanceSignal"); - } break; - } - return String(); -} - -String VisualScriptYieldSignal::get_text() const { - if (call_mode == CALL_MODE_SELF) { - return " " + String(signal) + "()"; - } else { - return " " + _get_base_type() + "." + String(signal) + "()"; - } -} - -void VisualScriptYieldSignal::set_base_type(const StringName &p_type) { - if (base_type == p_type) { - return; - } - - base_type = p_type; - - notify_property_list_changed(); - ports_changed_notify(); -} - -StringName VisualScriptYieldSignal::get_base_type() const { - return base_type; -} - -void VisualScriptYieldSignal::set_signal(const StringName &p_type) { - if (signal == p_type) { - return; - } - - signal = p_type; - - notify_property_list_changed(); - ports_changed_notify(); -} - -StringName VisualScriptYieldSignal::get_signal() const { - return signal; -} - -void VisualScriptYieldSignal::set_base_path(const NodePath &p_type) { - if (base_path == p_type) { - return; - } - - base_path = p_type; - - notify_property_list_changed(); - ports_changed_notify(); -} - -NodePath VisualScriptYieldSignal::get_base_path() const { - return base_path; -} - -void VisualScriptYieldSignal::set_call_mode(CallMode p_mode) { - if (call_mode == p_mode) { - return; - } - - call_mode = p_mode; - - notify_property_list_changed(); - ports_changed_notify(); -} - -VisualScriptYieldSignal::CallMode VisualScriptYieldSignal::get_call_mode() const { - return call_mode; -} - -void VisualScriptYieldSignal::_validate_property(PropertyInfo &p_property) const { - if (p_property.name == "base_type") { - if (call_mode != CALL_MODE_INSTANCE) { - p_property.usage = PROPERTY_USAGE_NO_EDITOR; - } - } - - if (p_property.name == "node_path") { - if (call_mode != CALL_MODE_NODE_PATH) { - p_property.usage = PROPERTY_USAGE_NONE; - } else { - Node *bnode = _get_base_node(); - if (bnode) { - p_property.hint_string = bnode->get_path(); //convert to long string - } - } - } - - if (p_property.name == "signal") { - p_property.hint = PROPERTY_HINT_ENUM; - - List<MethodInfo> methods; - - ClassDB::get_signal_list(_get_base_type(), &methods); - - List<String> mstring; - for (const MethodInfo &E : methods) { - if (E.name.begins_with("_")) { - continue; - } - mstring.push_back(E.name.get_slice(":", 0)); - } - - mstring.sort(); - - String ml; - for (const String &E : mstring) { - if (!ml.is_empty()) { - ml += ","; - } - ml += E; - } - - p_property.hint_string = ml; - } -} - -void VisualScriptYieldSignal::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_base_type", "base_type"), &VisualScriptYieldSignal::set_base_type); - ClassDB::bind_method(D_METHOD("get_base_type"), &VisualScriptYieldSignal::get_base_type); - - ClassDB::bind_method(D_METHOD("set_signal", "signal"), &VisualScriptYieldSignal::set_signal); - ClassDB::bind_method(D_METHOD("get_signal"), &VisualScriptYieldSignal::get_signal); - - ClassDB::bind_method(D_METHOD("set_call_mode", "mode"), &VisualScriptYieldSignal::set_call_mode); - ClassDB::bind_method(D_METHOD("get_call_mode"), &VisualScriptYieldSignal::get_call_mode); - - ClassDB::bind_method(D_METHOD("set_base_path", "base_path"), &VisualScriptYieldSignal::set_base_path); - ClassDB::bind_method(D_METHOD("get_base_path"), &VisualScriptYieldSignal::get_base_path); - - String bt; - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - if (i > 0) { - bt += ","; - } - - bt += Variant::get_type_name(Variant::Type(i)); - } - - ADD_PROPERTY(PropertyInfo(Variant::INT, "call_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance"), "set_call_mode", "get_call_mode"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "signal"), "set_signal", "get_signal"); - - BIND_ENUM_CONSTANT(CALL_MODE_SELF); - BIND_ENUM_CONSTANT(CALL_MODE_NODE_PATH); - BIND_ENUM_CONSTANT(CALL_MODE_INSTANCE); -} - -class VisualScriptNodeInstanceYieldSignal : public VisualScriptNodeInstance { -public: - VisualScriptYieldSignal::CallMode call_mode; - NodePath node_path; - int output_args = 0; - StringName signal; - - VisualScriptYieldSignal *node = nullptr; - VisualScriptInstance *instance = nullptr; - - virtual int get_working_memory_size() const override { return 1; } - //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } - //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override { - if (p_start_mode == START_MODE_RESUME_YIELD) { - return 0; //resuming yield - } else { - //yield - - Object *object = nullptr; - - switch (call_mode) { - case VisualScriptYieldSignal::CALL_MODE_SELF: { - object = instance->get_owner_ptr(); - - } break; - case VisualScriptYieldSignal::CALL_MODE_NODE_PATH: { - Node *node = Object::cast_to<Node>(instance->get_owner_ptr()); - if (!node) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Base object is not a Node!"; - return 0; - } - - Node *another = node->get_node(node_path); - if (!another) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Path does not lead Node!"; - return 0; - } - - object = another; - - } break; - case VisualScriptYieldSignal::CALL_MODE_INSTANCE: { - object = *p_inputs[0]; - if (!object) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - r_error_str = "Supplied instance input is null."; - return 0; - } - - } break; - } - - Ref<VisualScriptFunctionState> state; - state.instantiate(); - - state->connect_to_signal(object, signal, Array()); - - *p_working_mem = state; - - return STEP_YIELD_BIT; - } - } -}; - -VisualScriptNodeInstance *VisualScriptYieldSignal::instantiate(VisualScriptInstance *p_instance) { - VisualScriptNodeInstanceYieldSignal *instance = memnew(VisualScriptNodeInstanceYieldSignal); - instance->node = this; - instance->instance = p_instance; - instance->signal = signal; - instance->call_mode = call_mode; - instance->node_path = base_path; - instance->output_args = get_output_value_port_count(); - return instance; -} - -VisualScriptYieldSignal::VisualScriptYieldSignal() { - call_mode = CALL_MODE_SELF; - base_type = "Object"; -} - -template <VisualScriptYieldSignal::CallMode cmode> -static Ref<VisualScriptNode> create_yield_signal_node(const String &p_name) { - Ref<VisualScriptYieldSignal> node; - node.instantiate(); - node->set_call_mode(cmode); - return node; -} - -void register_visual_script_yield_nodes() { - VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_frame", create_yield_node<VisualScriptYield::YIELD_FRAME>); - VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_physics_frame", create_yield_node<VisualScriptYield::YIELD_PHYSICS_FRAME>); - VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_time", create_yield_node<VisualScriptYield::YIELD_WAIT>); - - VisualScriptLanguage::singleton->add_register_func("functions/yield", create_yield_node<VisualScriptYield::YIELD_RETURN>); - VisualScriptLanguage::singleton->add_register_func("functions/yield_signal", create_node_generic<VisualScriptYieldSignal>); -} diff --git a/modules/visual_script/visual_script_yield_nodes.h b/modules/visual_script/visual_script_yield_nodes.h deleted file mode 100644 index 248f2b6e94..0000000000 --- a/modules/visual_script/visual_script_yield_nodes.h +++ /dev/null @@ -1,147 +0,0 @@ -/*************************************************************************/ -/* visual_script_yield_nodes.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 VISUAL_SCRIPT_YIELD_NODES_H -#define VISUAL_SCRIPT_YIELD_NODES_H - -#include "visual_script.h" - -class VisualScriptYield : public VisualScriptNode { - GDCLASS(VisualScriptYield, VisualScriptNode); - -public: - enum YieldMode { - YIELD_RETURN, - YIELD_FRAME, - YIELD_PHYSICS_FRAME, - YIELD_WAIT - - }; - -private: - YieldMode yield_mode; - double wait_time; - -protected: - void _validate_property(PropertyInfo &p_property) const; - - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "functions"; } - - void set_yield_mode(YieldMode p_mode); - YieldMode get_yield_mode(); - - void set_wait_time(double p_time); - double get_wait_time(); - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptYield(); -}; -VARIANT_ENUM_CAST(VisualScriptYield::YieldMode) - -class VisualScriptYieldSignal : public VisualScriptNode { - GDCLASS(VisualScriptYieldSignal, VisualScriptNode); - -public: - enum CallMode { - CALL_MODE_SELF, - CALL_MODE_NODE_PATH, - CALL_MODE_INSTANCE, - - }; - -private: - CallMode call_mode; - StringName base_type; - NodePath base_path; - StringName signal; - - Node *_get_base_node() const; - StringName _get_base_type() const; - -protected: - void _validate_property(PropertyInfo &p_property) const; - - static void _bind_methods(); - -public: - virtual int get_output_sequence_port_count() const override; - virtual bool has_input_sequence_port() const override; - - virtual String get_output_sequence_port_text(int p_port) const override; - - virtual int get_input_value_port_count() const override; - virtual int get_output_value_port_count() const override; - - virtual PropertyInfo get_input_value_port_info(int p_idx) const override; - virtual PropertyInfo get_output_value_port_info(int p_idx) const override; - - virtual String get_caption() const override; - virtual String get_text() const override; - virtual String get_category() const override { return "functions"; } - - void set_base_type(const StringName &p_type); - StringName get_base_type() const; - - void set_signal(const StringName &p_type); - StringName get_signal() const; - - void set_base_path(const NodePath &p_type); - NodePath get_base_path() const; - - void set_call_mode(CallMode p_mode); - CallMode get_call_mode() const; - - virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; - - VisualScriptYieldSignal(); -}; - -VARIANT_ENUM_CAST(VisualScriptYieldSignal::CallMode); - -void register_visual_script_yield_nodes(); - -#endif // VISUAL_SCRIPT_YIELD_NODES_H diff --git a/modules/webp/SCsub b/modules/webp/SCsub index 80d62400c8..72ad1ea5e4 100644 --- a/modules/webp/SCsub +++ b/modules/webp/SCsub @@ -12,123 +12,129 @@ thirdparty_obj = [] if env["builtin_libwebp"]: thirdparty_dir = "#thirdparty/libwebp/" thirdparty_sources = [ - "dec/alpha_dec.c", - "dec/buffer_dec.c", - "dec/frame_dec.c", - "dec/idec_dec.c", - "dec/io_dec.c", - "dec/quant_dec.c", - "dec/tree_dec.c", - "dec/vp8_dec.c", - "dec/vp8l_dec.c", - "dec/webp_dec.c", - "demux/anim_decode.c", - "demux/demux.c", - "dsp/alpha_processing.c", - "dsp/alpha_processing_mips_dsp_r2.c", - "dsp/alpha_processing_neon.c", - "dsp/alpha_processing_sse2.c", - "dsp/alpha_processing_sse41.c", - "dsp/cost.c", - "dsp/cost_mips32.c", - "dsp/cost_mips_dsp_r2.c", - "dsp/cost_neon.c", - "dsp/cost_sse2.c", - "dsp/cpu.c", - "dsp/dec.c", - "dsp/dec_clip_tables.c", - "dsp/dec_mips32.c", - "dsp/dec_mips_dsp_r2.c", - "dsp/dec_msa.c", - "dsp/dec_neon.c", - "dsp/dec_sse2.c", - "dsp/dec_sse41.c", - "dsp/enc.c", - "dsp/enc_mips32.c", - "dsp/enc_mips_dsp_r2.c", - "dsp/enc_msa.c", - "dsp/enc_neon.c", - "dsp/enc_sse2.c", - "dsp/enc_sse41.c", - "dsp/filters.c", - "dsp/filters_mips_dsp_r2.c", - "dsp/filters_msa.c", - "dsp/filters_neon.c", - "dsp/filters_sse2.c", - "dsp/lossless.c", - "dsp/lossless_enc.c", - "dsp/lossless_enc_mips32.c", - "dsp/lossless_enc_mips_dsp_r2.c", - "dsp/lossless_enc_msa.c", - "dsp/lossless_enc_neon.c", - "dsp/lossless_enc_sse2.c", - "dsp/lossless_enc_sse41.c", - "dsp/lossless_mips_dsp_r2.c", - "dsp/lossless_msa.c", - "dsp/lossless_neon.c", - "dsp/lossless_sse2.c", - "dsp/lossless_sse41.c", - "dsp/rescaler.c", - "dsp/rescaler_mips32.c", - "dsp/rescaler_mips_dsp_r2.c", - "dsp/rescaler_msa.c", - "dsp/rescaler_neon.c", - "dsp/rescaler_sse2.c", - "dsp/ssim.c", - "dsp/ssim_sse2.c", - "dsp/upsampling.c", - "dsp/upsampling_mips_dsp_r2.c", - "dsp/upsampling_msa.c", - "dsp/upsampling_neon.c", - "dsp/upsampling_sse2.c", - "dsp/upsampling_sse41.c", - "dsp/yuv.c", - "dsp/yuv_mips32.c", - "dsp/yuv_mips_dsp_r2.c", - "dsp/yuv_neon.c", - "dsp/yuv_sse2.c", - "dsp/yuv_sse41.c", - "enc/alpha_enc.c", - "enc/analysis_enc.c", - "enc/backward_references_cost_enc.c", - "enc/backward_references_enc.c", - "enc/config_enc.c", - "enc/cost_enc.c", - "enc/filter_enc.c", - "enc/frame_enc.c", - "enc/histogram_enc.c", - "enc/iterator_enc.c", - "enc/near_lossless_enc.c", - "enc/picture_csp_enc.c", - "enc/picture_enc.c", - "enc/picture_psnr_enc.c", - "enc/picture_rescale_enc.c", - "enc/picture_tools_enc.c", - "enc/predictor_enc.c", - "enc/quant_enc.c", - "enc/syntax_enc.c", - "enc/token_enc.c", - "enc/tree_enc.c", - "enc/vp8l_enc.c", - "enc/webp_enc.c", - "mux/anim_encode.c", - "mux/muxedit.c", - "mux/muxinternal.c", - "mux/muxread.c", - "utils/bit_reader_utils.c", - "utils/bit_writer_utils.c", - "utils/color_cache_utils.c", - "utils/filters_utils.c", - "utils/huffman_encode_utils.c", - "utils/huffman_utils.c", - "utils/quant_levels_dec_utils.c", - "utils/quant_levels_utils.c", - "utils/random_utils.c", - "utils/rescaler_utils.c", - "utils/thread_utils.c", - "utils/utils.c", + "sharpyuv/sharpyuv.c", + "sharpyuv/sharpyuv_csp.c", + "sharpyuv/sharpyuv_dsp.c", + "sharpyuv/sharpyuv_gamma.c", + "sharpyuv/sharpyuv_neon.c", + "sharpyuv/sharpyuv_sse2.c", + "src/dec/alpha_dec.c", + "src/dec/buffer_dec.c", + "src/dec/frame_dec.c", + "src/dec/idec_dec.c", + "src/dec/io_dec.c", + "src/dec/quant_dec.c", + "src/dec/tree_dec.c", + "src/dec/vp8_dec.c", + "src/dec/vp8l_dec.c", + "src/dec/webp_dec.c", + "src/demux/anim_decode.c", + "src/demux/demux.c", + "src/dsp/alpha_processing.c", + "src/dsp/alpha_processing_mips_dsp_r2.c", + "src/dsp/alpha_processing_neon.c", + "src/dsp/alpha_processing_sse2.c", + "src/dsp/alpha_processing_sse41.c", + "src/dsp/cost.c", + "src/dsp/cost_mips32.c", + "src/dsp/cost_mips_dsp_r2.c", + "src/dsp/cost_neon.c", + "src/dsp/cost_sse2.c", + "src/dsp/cpu.c", + "src/dsp/dec.c", + "src/dsp/dec_clip_tables.c", + "src/dsp/dec_mips32.c", + "src/dsp/dec_mips_dsp_r2.c", + "src/dsp/dec_msa.c", + "src/dsp/dec_neon.c", + "src/dsp/dec_sse2.c", + "src/dsp/dec_sse41.c", + "src/dsp/enc.c", + "src/dsp/enc_mips32.c", + "src/dsp/enc_mips_dsp_r2.c", + "src/dsp/enc_msa.c", + "src/dsp/enc_neon.c", + "src/dsp/enc_sse2.c", + "src/dsp/enc_sse41.c", + "src/dsp/filters.c", + "src/dsp/filters_mips_dsp_r2.c", + "src/dsp/filters_msa.c", + "src/dsp/filters_neon.c", + "src/dsp/filters_sse2.c", + "src/dsp/lossless.c", + "src/dsp/lossless_enc.c", + "src/dsp/lossless_enc_mips32.c", + "src/dsp/lossless_enc_mips_dsp_r2.c", + "src/dsp/lossless_enc_msa.c", + "src/dsp/lossless_enc_neon.c", + "src/dsp/lossless_enc_sse2.c", + "src/dsp/lossless_enc_sse41.c", + "src/dsp/lossless_mips_dsp_r2.c", + "src/dsp/lossless_msa.c", + "src/dsp/lossless_neon.c", + "src/dsp/lossless_sse2.c", + "src/dsp/lossless_sse41.c", + "src/dsp/rescaler.c", + "src/dsp/rescaler_mips32.c", + "src/dsp/rescaler_mips_dsp_r2.c", + "src/dsp/rescaler_msa.c", + "src/dsp/rescaler_neon.c", + "src/dsp/rescaler_sse2.c", + "src/dsp/ssim.c", + "src/dsp/ssim_sse2.c", + "src/dsp/upsampling.c", + "src/dsp/upsampling_mips_dsp_r2.c", + "src/dsp/upsampling_msa.c", + "src/dsp/upsampling_neon.c", + "src/dsp/upsampling_sse2.c", + "src/dsp/upsampling_sse41.c", + "src/dsp/yuv.c", + "src/dsp/yuv_mips32.c", + "src/dsp/yuv_mips_dsp_r2.c", + "src/dsp/yuv_neon.c", + "src/dsp/yuv_sse2.c", + "src/dsp/yuv_sse41.c", + "src/enc/alpha_enc.c", + "src/enc/analysis_enc.c", + "src/enc/backward_references_cost_enc.c", + "src/enc/backward_references_enc.c", + "src/enc/config_enc.c", + "src/enc/cost_enc.c", + "src/enc/filter_enc.c", + "src/enc/frame_enc.c", + "src/enc/histogram_enc.c", + "src/enc/iterator_enc.c", + "src/enc/near_lossless_enc.c", + "src/enc/picture_csp_enc.c", + "src/enc/picture_enc.c", + "src/enc/picture_psnr_enc.c", + "src/enc/picture_rescale_enc.c", + "src/enc/picture_tools_enc.c", + "src/enc/predictor_enc.c", + "src/enc/quant_enc.c", + "src/enc/syntax_enc.c", + "src/enc/token_enc.c", + "src/enc/tree_enc.c", + "src/enc/vp8l_enc.c", + "src/enc/webp_enc.c", + "src/mux/anim_encode.c", + "src/mux/muxedit.c", + "src/mux/muxinternal.c", + "src/mux/muxread.c", + "src/utils/bit_reader_utils.c", + "src/utils/bit_writer_utils.c", + "src/utils/color_cache_utils.c", + "src/utils/filters_utils.c", + "src/utils/huffman_encode_utils.c", + "src/utils/huffman_utils.c", + "src/utils/quant_levels_dec_utils.c", + "src/utils/quant_levels_utils.c", + "src/utils/random_utils.c", + "src/utils/rescaler_utils.c", + "src/utils/thread_utils.c", + "src/utils/utils.c", ] - thirdparty_sources = [thirdparty_dir + "src/" + file for file in thirdparty_sources] + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] env_webp.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "src/"]) diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp index 778d562278..705ab508ab 100644 --- a/modules/webp/image_loader_webp.cpp +++ b/modules/webp/image_loader_webp.cpp @@ -48,7 +48,7 @@ static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) { return img; } -Error ImageLoaderWebP::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { +Error ImageLoaderWebP::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); diff --git a/modules/webp/image_loader_webp.h b/modules/webp/image_loader_webp.h index 9a5dc6cd7c..d868ae3f7f 100644 --- a/modules/webp/image_loader_webp.h +++ b/modules/webp/image_loader_webp.h @@ -35,7 +35,7 @@ class ImageLoaderWebP : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderWebP(); }; diff --git a/platform/android/README.md b/platform/android/README.md index 343e588553..f6aabab708 100644 --- a/platform/android/README.md +++ b/platform/android/README.md @@ -3,6 +3,13 @@ This folder contains the Java and C++ (JNI) code for the Android platform port, using [Gradle](https://gradle.org/) as a build system. +## Documentation + +- [Compiling for Android](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_android.html) + - Instructions on building this platform port from source. +- [Exporting for Android](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_android.html) + - Instructions on using the compiled export templates to export a project. + ## Artwork license [`logo.png`](logo.png) and [`run_icon.png`](run_icon.png) are licensed under diff --git a/platform/android/SCsub b/platform/android/SCsub index d370a4d18d..344ca036de 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -41,13 +41,13 @@ lib = env_android.add_shared_library("#bin/libgodot", [android_objects], SHLIBSU env.Depends(lib, thirdparty_obj) lib_arch_dir = "" -if env["android_arch"] == "armv7": +if env["arch"] == "arm32": lib_arch_dir = "armeabi-v7a" -elif env["android_arch"] == "arm64v8": +elif env["arch"] == "arm64": lib_arch_dir = "arm64-v8a" -elif env["android_arch"] == "x86": +elif env["arch"] == "x86_32": lib_arch_dir = "x86" -elif env["android_arch"] == "x86_64": +elif env["arch"] == "x86_64": lib_arch_dir = "x86_64" else: print("WARN: Architecture not suitable for embedding into APK; keeping .so at \\bin") diff --git a/platform/android/detect.py b/platform/android/detect.py index 2ff5bf59ea..ad63821162 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -22,7 +22,6 @@ def get_opts(): return [ ("ANDROID_SDK_ROOT", "Path to the Android SDK", get_env_android_sdk_root()), ("ndk_platform", 'Target platform (android-<api>, e.g. "android-24")', "android-24"), - EnumVariable("android_arch", "Target architecture", "arm64v8", ("armv7", "arm64v8", "x86", "x86_64")), ] @@ -46,6 +45,7 @@ def get_ndk_version(): def get_flags(): return [ + ("arch", "arm64"), # Default for convenience. ("tools", False), ] @@ -75,35 +75,37 @@ def install_ndk_if_needed(env): def configure(env): + # Validate arch. + supported_arches = ["x86_32", "x86_64", "arm32", "arm64"] + if env["arch"] not in supported_arches: + print( + 'Unsupported CPU architecture "%s" for Android. Supported architectures are: %s.' + % (env["arch"], ", ".join(supported_arches)) + ) + sys.exit() + install_ndk_if_needed(env) ndk_root = env["ANDROID_NDK_ROOT"] # Architecture - if env["android_arch"] not in ["armv7", "arm64v8", "x86", "x86_64"]: - env["android_arch"] = "arm64v8" - - print("Building for Android, platform " + env["ndk_platform"] + " (" + env["android_arch"] + ")") - - if get_min_sdk_version(env["ndk_platform"]) < 21: - if env["android_arch"] == "x86_64" or env["android_arch"] == "arm64v8": - print( - "WARNING: android_arch=" - + env["android_arch"] - + " is not supported by ndk_platform lower than android-21; setting ndk_platform=android-21" - ) - env["ndk_platform"] = "android-21" + if get_min_sdk_version(env["ndk_platform"]) < 21 and env["arch"] in ["x86_64", "arm64"]: + print( + 'WARNING: arch="%s" is not supported with "ndk_platform" lower than "android-21". Forcing platform 21.' + % env["arch"] + ) + env["ndk_platform"] = "android-21" - if env["android_arch"] == "armv7": + if env["arch"] == "arm32": target_triple = "armv7a-linux-androideabi" env.extra_suffix = ".armv7" + env.extra_suffix - elif env["android_arch"] == "arm64v8": + elif env["arch"] == "arm64": target_triple = "aarch64-linux-android" env.extra_suffix = ".armv8" + env.extra_suffix - elif env["android_arch"] == "x86": + elif env["arch"] == "x86_32": target_triple = "i686-linux-android" env.extra_suffix = ".x86" + env.extra_suffix - elif env["android_arch"] == "x86_64": + elif env["arch"] == "x86_64": target_triple = "x86_64-linux-android" env.extra_suffix = ".x86_64" + env.extra_suffix @@ -176,14 +178,14 @@ def configure(env): if get_min_sdk_version(env["ndk_platform"]) >= 24: env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)]) - if env["android_arch"] == "x86": + if env["arch"] == "x86_32": # The NDK adds this if targeting API < 24, so we can drop it when Godot targets it at least env.Append(CCFLAGS=["-mstackrealign"]) - elif env["android_arch"] == "armv7": + elif env["arch"] == "arm32": env.Append(CCFLAGS="-march=armv7-a -mfloat-abi=softfp".split()) env.Append(CPPDEFINES=["__ARM_ARCH_7__", "__ARM_ARCH_7A__"]) env.Append(CPPDEFINES=["__ARM_NEON__"]) - elif env["android_arch"] == "arm64v8": + elif env["arch"] == "arm64": env.Append(CCFLAGS=["-mfix-cortex-a53-835769"]) env.Append(CPPDEFINES=["__ARM_ARCH_8A__"]) diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp index eb344d3b43..428135de56 100644 --- a/platform/android/dir_access_jandroid.cpp +++ b/platform/android/dir_access_jandroid.cpp @@ -135,6 +135,20 @@ String DirAccessJAndroid::get_drive(int p_drive) { } } +String DirAccessJAndroid::get_current_dir(bool p_include_drive) const { + String base = _get_root_path(); + String bd = current_dir; + if (!base.is_empty()) { + bd = current_dir.replace_first(base, ""); + } + + if (bd.begins_with("/")) { + return _get_root_string() + bd.substr(1, bd.length()); + } else { + return _get_root_string() + bd; + } +} + Error DirAccessJAndroid::change_dir(String p_dir) { String new_dir = get_absolute_path(p_dir); if (new_dir == current_dir) { diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h index d469c9d317..5b7b4a9c4d 100644 --- a/platform/android/dir_access_jandroid.h +++ b/platform/android/dir_access_jandroid.h @@ -67,6 +67,7 @@ public: virtual int get_drive_count() override; virtual String get_drive(int p_drive) override; + virtual String get_current_dir(bool p_include_drive = true) const override; ///< return current dir location virtual Error change_dir(String p_dir) override; ///< can be relative or absolute, return false on success diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index b51dd18af6..d3bce12de1 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -83,7 +83,7 @@ bool DisplayServerAndroid::tts_is_paused() const { return TTS_Android::is_paused(); } -Array DisplayServerAndroid::tts_get_voices() const { +TypedArray<Dictionary> DisplayServerAndroid::tts_get_voices() const { return TTS_Android::get_voices(); } @@ -136,7 +136,7 @@ bool DisplayServerAndroid::clipboard_has() const { } } -Array DisplayServerAndroid::get_display_cutouts() const { +TypedArray<Rect2> DisplayServerAndroid::get_display_cutouts() const { GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java(); ERR_FAIL_NULL_V(godot_io_java, Array()); return godot_io_java->get_display_cutouts(); diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h index 2f30642319..6e14ba3e23 100644 --- a/platform/android/display_server_android.h +++ b/platform/android/display_server_android.h @@ -93,7 +93,7 @@ public: virtual bool tts_is_speaking() const override; virtual bool tts_is_paused() const override; - virtual Array tts_get_voices() const override; + virtual TypedArray<Dictionary> tts_get_voices() const override; virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override; virtual void tts_pause() override; @@ -104,7 +104,7 @@ public: virtual String clipboard_get() const override; virtual bool clipboard_has() const override; - virtual Array get_display_cutouts() const override; + virtual TypedArray<Rect2> get_display_cutouts() const override; virtual Rect2i get_display_safe_area() const override; virtual void screen_set_keep_on(bool p_enable) override; diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle index da30bd3a95..81c7130c03 100644 --- a/platform/android/java/build.gradle +++ b/platform/android/java/build.gradle @@ -28,7 +28,7 @@ allprojects { } ext { - supportedAbis = ["armv7", "arm64v8", "x86", "x86_64"] + supportedAbis = ["arm32", "arm64", "x86_32", "x86_64"] supportedTargetsMap = [release: "release", dev: "debug", debug: "release_debug"] supportedFlavors = ["editor", "template"] @@ -37,7 +37,7 @@ ext { // If building manually on the command line, it's recommended to use the // `./gradlew generateGodotTemplates` build command instead after running the `scons` command(s). // The {selectedAbis} values must be from the {supportedAbis} values. - selectedAbis = ["arm64v8"] + selectedAbis = ["arm64"] } def rootDir = "../../.." diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle index 6b82326a27..318ae1143f 100644 --- a/platform/android/java/lib/build.gradle +++ b/platform/android/java/lib/build.gradle @@ -159,7 +159,7 @@ android { def taskName = getSconsTaskName(flavorName, buildType, selectedAbi) tasks.create(name: taskName, type: Exec) { executable sconsExecutableFile.absolutePath - args "--directory=${pathToRootDir}", "platform=android", "tools=${toolsFlag}", "target=${sconsTarget}", "android_arch=${selectedAbi}", "-j" + Runtime.runtime.availableProcessors() + args "--directory=${pathToRootDir}", "platform=android", "tools=${toolsFlag}", "target=${sconsTarget}", "arch=${selectedAbi}", "-j" + Runtime.runtime.availableProcessors() } // Schedule the tasks so the generated libs are present before the aar file is packaged. diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp index 5877c15114..cea64a7f22 100644 --- a/platform/android/java_godot_io_wrapper.cpp +++ b/platform/android/java_godot_io_wrapper.cpp @@ -165,8 +165,8 @@ float GodotIOJavaWrapper::get_screen_refresh_rate(float fallback) { return fallback; } -Array GodotIOJavaWrapper::get_display_cutouts() { - Array result; +TypedArray<Rect2> GodotIOJavaWrapper::get_display_cutouts() { + TypedArray<Rect2> result; ERR_FAIL_NULL_V(_get_display_cutouts, result); JNIEnv *env = get_jni_env(); ERR_FAIL_NULL_V(env, result); diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h index dc68f4d90d..9a1a877b6f 100644 --- a/platform/android/java_godot_io_wrapper.h +++ b/platform/android/java_godot_io_wrapper.h @@ -38,7 +38,7 @@ #include <jni.h> #include "core/math/rect2i.h" -#include "core/variant/array.h" +#include "core/variant/typed_array.h" #include "string_android.h" // Class that makes functions in java/src/org/godotengine/godot/GodotIO.java callable from C++ @@ -78,7 +78,7 @@ public: int get_screen_dpi(); float get_scaled_density(); float get_screen_refresh_rate(float fallback); - Array get_display_cutouts(); + TypedArray<Rect2> get_display_cutouts(); Rect2i get_display_safe_area(); String get_unique_id(); bool has_vk(); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 0f551e7f4f..f94614c741 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -370,15 +370,15 @@ bool OS_Android::_check_internal_feature_support(const String &p_feature) { return true; } #if defined(__aarch64__) - if (p_feature == "arm64-v8a") { + if (p_feature == "arm64-v8a" || p_feature == "arm64") { return true; } #elif defined(__ARM_ARCH_7A__) - if (p_feature == "armeabi-v7a" || p_feature == "armeabi") { + if (p_feature == "armeabi-v7a" || p_feature == "armeabi" || p_feature == "arm32") { return true; } #elif defined(__arm__) - if (p_feature == "armeabi") { + if (p_feature == "armeabi" || p_feature == "arm") { return true; } #endif diff --git a/platform/ios/README.md b/platform/ios/README.md new file mode 100644 index 0000000000..82c275ad31 --- /dev/null +++ b/platform/ios/README.md @@ -0,0 +1,14 @@ +# iOS platform port + +This folder contains the C++, Objective-C and Objective-C++ code for the iOS +platform port. + +See also [`misc/dist/ios_xcode`](/misc/dist/ios_xcode) folder for the Xcode +project template used for packaging the iOS export templates. + +## Documentation + +- [Compiling for iOS](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_ios.html) + - Instructions on building this platform port from source. +- [Exporting for iOS](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_ios.html) + - Instructions on using the compiled export templates to export a project. diff --git a/platform/ios/detect.py b/platform/ios/detect.py index 67c90b10a0..1a8d24d12d 100644 --- a/platform/ios/detect.py +++ b/platform/ios/detect.py @@ -36,12 +36,22 @@ def get_opts(): def get_flags(): return [ + ("arch", "arm64"), # Default for convenience. ("tools", False), ("use_volk", False), ] def configure(env): + # Validate arch. + supported_arches = ["x86_64", "arm64"] + if env["arch"] not in supported_arches: + print( + 'Unsupported CPU architecture "%s" for iOS. Supported architectures are: %s.' + % (env["arch"], ", ".join(supported_arches)) + ) + sys.exit() + ## Build type if env["target"].startswith("release"): @@ -64,11 +74,6 @@ def configure(env): env.Append(CCFLAGS=["-flto"]) env.Append(LINKFLAGS=["-flto"]) - ## Architecture - env["bits"] = "64" - if env["arch"] != "x86_64": - env["arch"] = "arm64" - ## Compiler configuration # Save this in environment for use by other modules diff --git a/platform/ios/display_server_ios.h b/platform/ios/display_server_ios.h index bbb2dd3ab3..f3624f24ab 100644 --- a/platform/ios/display_server_ios.h +++ b/platform/ios/display_server_ios.h @@ -127,7 +127,7 @@ public: virtual bool tts_is_speaking() const override; virtual bool tts_is_paused() const override; - virtual Array tts_get_voices() const override; + virtual TypedArray<Dictionary> tts_get_voices() const override; virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override; virtual void tts_pause() override; diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm index 6ce7e676a2..74d6bc2e97 100644 --- a/platform/ios/display_server_ios.mm +++ b/platform/ios/display_server_ios.mm @@ -336,8 +336,8 @@ bool DisplayServerIOS::tts_is_paused() const { return [tts isPaused]; } -Array DisplayServerIOS::tts_get_voices() const { - ERR_FAIL_COND_V(!tts, Array()); +TypedArray<Dictionary> DisplayServerIOS::tts_get_voices() const { + ERR_FAIL_COND_V(!tts, TypedArray<Dictionary>()); return [tts getVoices]; } diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index 425a977569..f49cf7a88d 100644 --- a/platform/ios/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -140,27 +140,27 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photolibrary_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need access to the photo library"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/photolibrary_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_120x120", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPhone/iPod Touch with Retina display - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_180x180", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPhone with Retina HD display + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_120x120", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPhone/iPod Touch with Retina display + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_180x180", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPhone with Retina HD display - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_76x76", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_152x152", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad with Retina display - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_167x167", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad Pro + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_76x76", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_152x152", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad with Retina display + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_167x167", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad Pro - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/app_store_1024x1024", PROPERTY_HINT_FILE, "*.png"), "")); // App Store + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/app_store_1024x1024", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // App Store - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight on devices with Retina display + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Spotlight + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Spotlight on devices with Retina display r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_launch_screen_storyboard"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "storyboard/image_scale_mode", PROPERTY_HINT_ENUM, "Same as Logo,Center,Scale to Fit,Scale to Fill,Scale"), 0)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_custom_bg_color"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "storyboard/custom_bg_color"), Color())); for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) { - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, loading_screen_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, loading_screen_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); } } @@ -387,13 +387,17 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ String locale_files; Vector<String> translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations"); if (translations.size() > 0) { - int index = 0; + HashSet<String> languages; for (const String &E : translations) { Ref<Translation> tr = ResourceLoader::load(E); - if (tr.is_valid()) { - String lang = tr->get_locale(); - locale_files += "D0BCFE4518AEBDA2004A" + itos(index).pad_zeros(4) + " /* " + lang + " */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = " + lang + "; path = " + lang + ".lproj/InfoPlist.strings; sourceTree = \"<group>\"; };"; + if (tr.is_valid() && tr->get_locale() != "en") { + languages.insert(tr->get_locale()); } + } + + int index = 0; + for (const String &lang : languages) { + locale_files += "D0BCFE4518AEBDA2004A" + itos(index).pad_zeros(4) + " /* " + lang + " */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = " + lang + "; path = " + lang + ".lproj/InfoPlist.strings; sourceTree = \"<group>\"; };\n"; index++; } } @@ -402,13 +406,17 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ String locale_files; Vector<String> translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations"); if (translations.size() > 0) { - int index = 0; + HashSet<String> languages; for (const String &E : translations) { Ref<Translation> tr = ResourceLoader::load(E); - if (tr.is_valid()) { - String lang = tr->get_locale(); - locale_files += "D0BCFE4518AEBDA2004A" + itos(index).pad_zeros(4) + " /* " + lang + " */,"; + if (tr.is_valid() && tr->get_locale() != "en") { + languages.insert(tr->get_locale()); } + } + + int index = 0; + for (const String &lang : languages) { + locale_files += "D0BCFE4518AEBDA2004A" + itos(index).pad_zeros(4) + " /* " + lang + " */,\n"; index++; } } @@ -531,26 +539,27 @@ struct IconInfo { const char *actual_size_side; const char *scale; const char *unscaled_size; + const bool force_opaque; }; static const IconInfo icon_infos[] = { // Home screen on iPhone - { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "2x", "60x60" }, - { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "3x", "40x40" }, - { "icons/iphone_180x180", "iphone", "Icon-180.png", "180", "3x", "60x60" }, + { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "2x", "60x60", false }, + { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "3x", "40x40", false }, + { "icons/iphone_180x180", "iphone", "Icon-180.png", "180", "3x", "60x60", false }, // Home screen on iPad - { "icons/ipad_76x76", "ipad", "Icon-76.png", "76", "1x", "76x76" }, - { "icons/ipad_152x152", "ipad", "Icon-152.png", "152", "2x", "76x76" }, - { "icons/ipad_167x167", "ipad", "Icon-167.png", "167", "2x", "83.5x83.5" }, + { "icons/ipad_76x76", "ipad", "Icon-76.png", "76", "1x", "76x76", false }, + { "icons/ipad_152x152", "ipad", "Icon-152.png", "152", "2x", "76x76", false }, + { "icons/ipad_167x167", "ipad", "Icon-167.png", "167", "2x", "83.5x83.5", false }, // App Store - { "icons/app_store_1024x1024", "ios-marketing", "Icon-1024.png", "1024", "1x", "1024x1024" }, + { "icons/app_store_1024x1024", "ios-marketing", "Icon-1024.png", "1024", "1x", "1024x1024", true }, // Spotlight - { "icons/spotlight_40x40", "ipad", "Icon-40.png", "40", "1x", "40x40" }, - { "icons/spotlight_80x80", "iphone", "Icon-80.png", "80", "2x", "40x40" }, - { "icons/spotlight_80x80", "ipad", "Icon-80.png", "80", "2x", "40x40" } + { "icons/spotlight_40x40", "ipad", "Icon-40.png", "40", "1x", "40x40", false }, + { "icons/spotlight_80x80", "iphone", "Icon-80.png", "80", "2x", "40x40", false }, + { "icons/spotlight_80x80", "ipad", "Icon-80.png", "80", "2x", "40x40", false } }; Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir) { @@ -570,14 +579,17 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr Ref<Image> img = memnew(Image); Error err = ImageLoader::load_image(icon_path, img); if (err != OK) { - ERR_PRINT("Invalid icon (" + String(info.preset_key) + "): '" + icon_path + "'."); + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Invalid icon (%s): '%s'.", info.preset_key, icon_path)); + return ERR_UNCONFIGURED; + } + if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) { + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key)); return ERR_UNCONFIGURED; } img->resize(side_size, side_size); err = img->save_png(p_iconset_dir + info.export_name); if (err) { - String err_str = String("Failed to export icon(" + String(info.preset_key) + "): '" + icon_path + "'."); - ERR_PRINT(err_str.utf8().get_data()); + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Failed to export icon (%s): '%s'.", info.preset_key, icon_path)); return err; } } else { @@ -585,11 +597,15 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr Ref<Image> img = memnew(Image); Error err = ImageLoader::load_image(icon_path, img); if (err != OK) { - ERR_PRINT("Invalid icon (" + String(info.preset_key) + "): '" + icon_path + "'."); + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Invalid icon (%s): '%s'.", info.preset_key, icon_path)); + return ERR_UNCONFIGURED; + } + if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) { + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key)); return ERR_UNCONFIGURED; } if (img->get_width() != side_size || img->get_height() != side_size) { - WARN_PRINT("Icon (" + String(info.preset_key) + "): '" + icon_path + "' has incorrect size (" + String::num_int64(img->get_width()) + "x" + String::num_int64(img->get_height()) + ") and was automatically resized to " + String::num_int64(side_size) + "x" + String::num_int64(side_size) + "."); + add_message(EXPORT_MESSAGE_WARNING, TTR("Export Icons"), vformat("Icon (%s): '%s' has incorrect size %s and was automatically resized to %s.", info.preset_key, icon_path, img->get_size(), Vector2i(side_size, side_size))); img->resize(side_size, side_size); err = img->save_png(p_iconset_dir + info.export_name); } else { @@ -597,8 +613,7 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr } if (err) { - String err_str = String("Failed to export icon(" + String(info.preset_key) + "): '" + icon_path + "'."); - ERR_PRINT(err_str.utf8().get_data()); + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Failed to export icon (%s): '%s'.", info.preset_key, icon_path)); return err; } } @@ -1651,27 +1666,31 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p f->store_line("NSPhotoLibraryUsageDescription = \"" + p_preset->get("privacy/photolibrary_usage_description").operator String() + "\";"); } + HashSet<String> languages; for (const String &E : translations) { Ref<Translation> tr = ResourceLoader::load(E); - if (tr.is_valid()) { - String lang = tr->get_locale(); - String fname = dest_dir + binary_name + "/" + lang + ".lproj"; - tmp_app_path->make_dir_recursive(fname); - Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); - f->store_line("/* Localized versions of Info.plist keys */"); - f->store_line(""); - if (appnames.has(lang)) { - f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String() + "\";"); - } - if (camera_usage_descriptions.has(lang)) { - f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String() + "\";"); - } - if (microphone_usage_descriptions.has(lang)) { - f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String() + "\";"); - } - if (photolibrary_usage_descriptions.has(lang)) { - f->store_line("NSPhotoLibraryUsageDescription = \"" + photolibrary_usage_descriptions[lang].operator String() + "\";"); - } + if (tr.is_valid() && tr->get_locale() != "en") { + languages.insert(tr->get_locale()); + } + } + + for (const String &lang : languages) { + String fname = dest_dir + binary_name + "/" + lang + ".lproj"; + tmp_app_path->make_dir_recursive(fname); + Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); + f->store_line("/* Localized versions of Info.plist keys */"); + f->store_line(""); + if (appnames.has(lang)) { + f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String() + "\";"); + } + if (camera_usage_descriptions.has(lang)) { + f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String() + "\";"); + } + if (microphone_usage_descriptions.has(lang)) { + f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String() + "\";"); + } + if (photolibrary_usage_descriptions.has(lang)) { + f->store_line("NSPhotoLibraryUsageDescription = \"" + photolibrary_usage_descriptions[lang].operator String() + "\";"); } } } diff --git a/platform/javascript/README.md b/platform/javascript/README.md index f181bea9e0..812ab6778b 100644 --- a/platform/javascript/README.md +++ b/platform/javascript/README.md @@ -5,8 +5,15 @@ compiled using [Emscripten](https://emscripten.org/). It also contains a ESLint linting setup (see [`package.json`](package.json)). -See also [`misc/dist/html`](/misc/dist/html) folder for files used by this platform -such as the HTML5 shell. +See also [`misc/dist/html`](/misc/dist/html) folder for additional files used by +this platform such as the HTML5 shell. + +## Documentation + +- [Compiling for the Web](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_web.html) + - Instructions on building this platform port from source. +- [Exporting for the Web](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_web.html) + - Instructions on using the compiled export templates to export a project. ## Artwork license diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index a769260f01..048c9c2eb4 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -46,6 +46,7 @@ def get_opts(): def get_flags(): return [ + ("arch", "wasm32"), ("tools", False), ("builtin_pcre2_with_jit", False), ("vulkan", False), @@ -53,6 +54,15 @@ def get_flags(): def configure(env): + # Validate arch. + supported_arches = ["wasm32"] + if env["arch"] not in supported_arches: + print( + 'Unsupported CPU architecture "%s" for iOS. Supported architectures are: %s.' + % (env["arch"], ", ".join(supported_arches)) + ) + sys.exit() + try: env["initial_memory"] = int(env["initial_memory"]) except Exception: diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp index 48f637fcfe..30240ad2db 100644 --- a/platform/javascript/display_server_javascript.cpp +++ b/platform/javascript/display_server_javascript.cpp @@ -296,7 +296,7 @@ void DisplayServerJavaScript::update_voices_callback(int p_size, const char **p_ } } -Array DisplayServerJavaScript::tts_get_voices() const { +TypedArray<Dictionary> DisplayServerJavaScript::tts_get_voices() const { godot_js_tts_get_voices(update_voices_callback); return voices; } diff --git a/platform/javascript/display_server_javascript.h b/platform/javascript/display_server_javascript.h index fb7f5d02a8..cbb91477b7 100644 --- a/platform/javascript/display_server_javascript.h +++ b/platform/javascript/display_server_javascript.h @@ -124,7 +124,7 @@ public: // tts virtual bool tts_is_speaking() const override; virtual bool tts_is_paused() const override; - virtual Array tts_get_voices() const override; + virtual TypedArray<Dictionary> tts_get_voices() const override; virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override; virtual void tts_pause() override; diff --git a/platform/linuxbsd/README.md b/platform/linuxbsd/README.md index 0d3fb37be5..efa8682062 100644 --- a/platform/linuxbsd/README.md +++ b/platform/linuxbsd/README.md @@ -2,10 +2,20 @@ This folder contains the C++ code for the Linux/*BSD platform port. +See also [`misc/dist/linux`](/misc/dist/linux) folder for additional files +used by this platform. + +## Documentation + +- [Compiling for Linux/*BSD](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_linuxbsd.html) + - Instructions on building this platform port from source. +- [Exporting for Linux/*BSD](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_linux.html) + - Instructions on using the compiled export templates to export a project. + ## Artwork license [`logo.png`](logo.png) is derived from the [Linux logo](https://isc.tamu.edu/~lewing/linux/): > Permission to use and/or modify this image is granted provided you acknowledge me - <lewing@isc.tamu.edu> and [The GIMP](https://isc.tamu.edu/~lewing/gimp/) - if someone asks. +> <lewing@isc.tamu.edu> and [The GIMP](https://isc.tamu.edu/~lewing/gimp/) +> if someone asks. diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index 00e2b9e6eb..8563cc3cb2 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -2,6 +2,7 @@ import os import platform import sys from methods import get_compiler_version, using_gcc +from platform_methods import detect_arch def is_active(): @@ -52,10 +53,21 @@ def get_opts(): def get_flags(): - return [] + return [ + ("arch", detect_arch()), + ] def configure(env): + # Validate arch. + supported_arches = ["x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64"] + if env["arch"] not in supported_arches: + print( + 'Unsupported CPU architecture "%s" for Linux / *BSD. Supported architectures are: %s.' + % (env["arch"], ", ".join(supported_arches)) + ) + sys.exit() + ## Build type if env["target"] == "release": @@ -80,23 +92,7 @@ def configure(env): env.Prepend(CCFLAGS=["-g3"]) env.Append(LINKFLAGS=["-rdynamic"]) - ## Architecture - - is64 = sys.maxsize > 2**32 - if env["bits"] == "default": - env["bits"] = "64" if is64 else "32" - - machines = { - "riscv64": "rv64", - "ppc64le": "ppc64", - "ppc64": "ppc64", - "ppcle": "ppc", - "ppc": "ppc", - } - - if env["arch"] == "" and platform.machine() in machines: - env["arch"] = machines[platform.machine()] - + # CPU architecture flags. if env["arch"] == "rv64": # G = General-purpose extensions, C = Compression extension (very common). env.Append(CCFLAGS=["-march=rv64gc"]) @@ -262,8 +258,7 @@ def configure(env): env["builtin_libvorbis"] = False # Needed to link against system libtheora env.ParseConfig("pkg-config theora theoradec --cflags --libs") else: - list_of_x86 = ["x86_64", "x86", "i386", "i586"] - if any(platform.machine() in s for s in list_of_x86): + if env["arch"] in ["x86_64", "x86_32"]: env["x86_libtheora_opt_gcc"] = True if not env["builtin_libvorbis"]: @@ -405,11 +400,12 @@ def configure(env): env.Append(LINKFLAGS=["-T", "platform/linuxbsd/pck_embed.legacy.ld"]) ## Cross-compilation - - if is64 and env["bits"] == "32": + # TODO: Support cross-compilation on architectures other than x86. + host_is_64_bit = sys.maxsize > 2**32 + if host_is_64_bit and env["arch"] == "x86_32": env.Append(CCFLAGS=["-m32"]) env.Append(LINKFLAGS=["-m32", "-L/usr/lib/i386-linux-gnu"]) - elif not is64 and env["bits"] == "64": + elif not host_is_64_bit and env["arch"] == "x86_64": env.Append(CCFLAGS=["-m64"]) env.Append(LINKFLAGS=["-m64", "-L/usr/lib/i686-linux-gnu"]) diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index 8efbd2e3c5..63998e2fde 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -322,8 +322,8 @@ bool DisplayServerX11::tts_is_paused() const { return tts->is_paused(); } -Array DisplayServerX11::tts_get_voices() const { - ERR_FAIL_COND_V(!tts, Array()); +TypedArray<Dictionary> DisplayServerX11::tts_get_voices() const { + ERR_FAIL_COND_V(!tts, TypedArray<Dictionary>()); return tts->get_voices(); } diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index 9ce6a557db..0174cfb881 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -308,7 +308,7 @@ public: #ifdef SPEECHD_ENABLED virtual bool tts_is_speaking() const override; virtual bool tts_is_paused() const override; - virtual Array tts_get_voices() const override; + virtual TypedArray<Dictionary> tts_get_voices() const override; virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override; virtual void tts_pause() override; diff --git a/platform/macos/README.md b/platform/macos/README.md new file mode 100644 index 0000000000..feead80736 --- /dev/null +++ b/platform/macos/README.md @@ -0,0 +1,19 @@ +# macOS platform port + +This folder contains the C++, Objective-C and Objective-C++ code for the macOS +platform port. + +See also [`misc/dist/macos`](/misc/dist/macos) folder for additional files used +by this platform. [`misc/dist/macos_tools.app`](/misc/dist/macos_tools.app) is +an `.app` bundle template used for packaging the macOS editor, while +[`misc/dist/macos_template.app`](/misc/dist/macos_template.app) is used for +packaging macOS export templates. + +## Documentation + +- [Compiling for macOS](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_macos.html) + - Instructions on building this platform port from source. +- [Exporting for macOS](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_macos.html) + - Instructions on using the compiled export templates to export a project. +- [Running Godot apps on macOS](https://docs.godotengine.org/en/latest/tutorials/export/running_on_macos.html) + - Instructions on running Godot projects on macOS. diff --git a/platform/macos/detect.py b/platform/macos/detect.py index 20e7afa772..e5bcb46b02 100644 --- a/platform/macos/detect.py +++ b/platform/macos/detect.py @@ -1,6 +1,7 @@ import os import sys from methods import detect_darwin_sdk_path +from platform_methods import detect_arch def is_active(): @@ -37,6 +38,7 @@ def get_opts(): def get_flags(): return [ + ("arch", detect_arch()), ("use_volk", False), ] @@ -71,6 +73,15 @@ def get_mvk_sdk_path(): def configure(env): + # Validate arch. + supported_arches = ["x86_64", "arm64"] + if env["arch"] not in supported_arches: + print( + 'Unsupported CPU architecture "%s" for macOS. Supported architectures are: %s.' + % (env["arch"], ", ".join(supported_arches)) + ) + sys.exit() + ## Build type if env["target"] == "release": @@ -96,25 +107,20 @@ def configure(env): env.Prepend(CCFLAGS=["-g3"]) env.Prepend(LINKFLAGS=["-Xlinker", "-no_deduplicate"]) - ## Architecture - - # macOS no longer runs on 32-bit since 10.7 which is unsupported since 2014 - # As such, we only support 64-bit - env["bits"] = "64" - ## Compiler configuration # Save this in environment for use by other modules if "OSXCROSS_ROOT" in os.environ: env["osxcross"] = True + # CPU architecture. if env["arch"] == "arm64": - print("Building for macOS 11.0+, platform arm64.") + print("Building for macOS 11.0+.") env.Append(ASFLAGS=["-arch", "arm64", "-mmacosx-version-min=11.0"]) env.Append(CCFLAGS=["-arch", "arm64", "-mmacosx-version-min=11.0"]) env.Append(LINKFLAGS=["-arch", "arm64", "-mmacosx-version-min=11.0"]) - else: - print("Building for macOS 10.12+, platform x86_64.") + elif env["arch"] == "x86_64": + print("Building for macOS 10.12+.") env.Append(ASFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"]) env.Append(CCFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"]) env.Append(LINKFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"]) @@ -185,9 +191,8 @@ def configure(env): ## Dependencies - if env["builtin_libtheora"]: - if env["arch"] != "arm64": - env["x86_libtheora_opt_gcc"] = True + if env["builtin_libtheora"] and env["arch"] == "x86_64": + env["x86_libtheora_opt_gcc"] = True ## Flags diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h index 5fda5dd974..e305ff3593 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -277,7 +277,7 @@ public: virtual bool tts_is_speaking() const override; virtual bool tts_is_paused() const override; - virtual Array tts_get_voices() const override; + virtual TypedArray<Dictionary> tts_get_voices() const override; virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override; virtual void tts_pause() override; diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index 8142f44bb0..fa6bcda902 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -1656,7 +1656,7 @@ bool DisplayServerMacOS::tts_is_paused() const { return [tts isPaused]; } -Array DisplayServerMacOS::tts_get_voices() const { +TypedArray<Dictionary> DisplayServerMacOS::tts_get_voices() const { ERR_FAIL_COND_V(!tts, Array()); return [tts getVoices]; } diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index edce9c0380..76052f7938 100644 --- a/platform/macos/export/export_plugin.cpp +++ b/platform/macos/export/export_plugin.cpp @@ -919,54 +919,58 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p f->store_line("NSHumanReadableCopyright = \"" + p_preset->get("application/copyright").operator String() + "\";"); } + HashSet<String> languages; for (const String &E : translations) { Ref<Translation> tr = ResourceLoader::load(E); - if (tr.is_valid()) { - String lang = tr->get_locale(); - String fname = tmp_app_path_name + "/Contents/Resources/" + lang + ".lproj"; - tmp_app_dir->make_dir_recursive(fname); - Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); - f->store_line("/* Localized versions of Info.plist keys */"); - f->store_line(""); - if (appnames.has(lang)) { - f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String() + "\";"); - } - if (microphone_usage_descriptions.has(lang)) { - f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String() + "\";"); - } - if (camera_usage_descriptions.has(lang)) { - f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String() + "\";"); - } - if (location_usage_descriptions.has(lang)) { - f->store_line("NSLocationUsageDescription = \"" + location_usage_descriptions[lang].operator String() + "\";"); - } - if (address_book_usage_descriptions.has(lang)) { - f->store_line("NSContactsUsageDescription = \"" + address_book_usage_descriptions[lang].operator String() + "\";"); - } - if (calendar_usage_descriptions.has(lang)) { - f->store_line("NSCalendarsUsageDescription = \"" + calendar_usage_descriptions[lang].operator String() + "\";"); - } - if (photos_library_usage_descriptions.has(lang)) { - f->store_line("NSPhotoLibraryUsageDescription = \"" + photos_library_usage_descriptions[lang].operator String() + "\";"); - } - if (desktop_folder_usage_descriptions.has(lang)) { - f->store_line("NSDesktopFolderUsageDescription = \"" + desktop_folder_usage_descriptions[lang].operator String() + "\";"); - } - if (documents_folder_usage_descriptions.has(lang)) { - f->store_line("NSDocumentsFolderUsageDescription = \"" + documents_folder_usage_descriptions[lang].operator String() + "\";"); - } - if (downloads_folder_usage_descriptions.has(lang)) { - f->store_line("NSDownloadsFolderUsageDescription = \"" + downloads_folder_usage_descriptions[lang].operator String() + "\";"); - } - if (network_volumes_usage_descriptions.has(lang)) { - f->store_line("NSNetworkVolumesUsageDescription = \"" + network_volumes_usage_descriptions[lang].operator String() + "\";"); - } - if (removable_volumes_usage_descriptions.has(lang)) { - f->store_line("NSRemovableVolumesUsageDescription = \"" + removable_volumes_usage_descriptions[lang].operator String() + "\";"); - } - if (copyrights.has(lang)) { - f->store_line("NSHumanReadableCopyright = \"" + copyrights[lang].operator String() + "\";"); - } + if (tr.is_valid() && tr->get_locale() != "en") { + languages.insert(tr->get_locale()); + } + } + + for (const String &lang : languages) { + String fname = tmp_app_path_name + "/Contents/Resources/" + lang + ".lproj"; + tmp_app_dir->make_dir_recursive(fname); + Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); + f->store_line("/* Localized versions of Info.plist keys */"); + f->store_line(""); + if (appnames.has(lang)) { + f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String() + "\";"); + } + if (microphone_usage_descriptions.has(lang)) { + f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String() + "\";"); + } + if (camera_usage_descriptions.has(lang)) { + f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String() + "\";"); + } + if (location_usage_descriptions.has(lang)) { + f->store_line("NSLocationUsageDescription = \"" + location_usage_descriptions[lang].operator String() + "\";"); + } + if (address_book_usage_descriptions.has(lang)) { + f->store_line("NSContactsUsageDescription = \"" + address_book_usage_descriptions[lang].operator String() + "\";"); + } + if (calendar_usage_descriptions.has(lang)) { + f->store_line("NSCalendarsUsageDescription = \"" + calendar_usage_descriptions[lang].operator String() + "\";"); + } + if (photos_library_usage_descriptions.has(lang)) { + f->store_line("NSPhotoLibraryUsageDescription = \"" + photos_library_usage_descriptions[lang].operator String() + "\";"); + } + if (desktop_folder_usage_descriptions.has(lang)) { + f->store_line("NSDesktopFolderUsageDescription = \"" + desktop_folder_usage_descriptions[lang].operator String() + "\";"); + } + if (documents_folder_usage_descriptions.has(lang)) { + f->store_line("NSDocumentsFolderUsageDescription = \"" + documents_folder_usage_descriptions[lang].operator String() + "\";"); + } + if (downloads_folder_usage_descriptions.has(lang)) { + f->store_line("NSDownloadsFolderUsageDescription = \"" + downloads_folder_usage_descriptions[lang].operator String() + "\";"); + } + if (network_volumes_usage_descriptions.has(lang)) { + f->store_line("NSNetworkVolumesUsageDescription = \"" + network_volumes_usage_descriptions[lang].operator String() + "\";"); + } + if (removable_volumes_usage_descriptions.has(lang)) { + f->store_line("NSRemovableVolumesUsageDescription = \"" + removable_volumes_usage_descriptions[lang].operator String() + "\";"); + } + if (copyrights.has(lang)) { + f->store_line("NSHumanReadableCopyright = \"" + copyrights[lang].operator String() + "\";"); } } } diff --git a/platform/uwp/README.md b/platform/uwp/README.md new file mode 100644 index 0000000000..575f90e3c7 --- /dev/null +++ b/platform/uwp/README.md @@ -0,0 +1,20 @@ +# UWP platform port + +> **Warning** +> +> The UWP platform port is not currently in a working state for the `master` +> branch, and may be dropped in the future. + +This folder contains the C++ code for the Universal Windows Platform (UWP) +platform port. **This is not to be confused with the "standard" Win32 port**, +which is available in [`platform/windows`](/platform/windows). + +See also [`misc/dist/uwp_template`](/misc/dist/uwp_template) folder for the UWP +project template used for packaging the UWP export templates. + +## Documentation + +- [Compiling for Universal Windows Platform](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_uwp.html) + - Instructions on building this platform port from source. +- [Exporting for Universal Windows Platform](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_uwp.html) + - Instructions on using the compiled export templates to export a project. diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py index 9c91378b22..2c5746cb06 100644 --- a/platform/uwp/detect.py +++ b/platform/uwp/detect.py @@ -1,6 +1,7 @@ import methods import os import sys +from platform_methods import detect_arch def is_active(): @@ -31,6 +32,7 @@ def get_opts(): def get_flags(): return [ + ("arch", detect_arch()), ("tools", False), ("xaudio2", True), ("builtin_pcre2_with_jit", False), @@ -38,19 +40,17 @@ def get_flags(): def configure(env): - env.msvc = True - - if env["bits"] != "default": - print("Error: bits argument is disabled for MSVC") + # Validate arch. + supported_arches = ["x86_32", "x86_64", "arm32"] + if env["arch"] not in supported_arches: print( - """ - Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console - (or Visual Studio settings) that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits - argument (example: scons p=uwp) and SCons will attempt to detect what MSVC compiler will be executed and inform you. - """ + 'Unsupported CPU architecture "%s" for UWP. Supported architectures are: %s.' + % (env["arch"], ", ".join(supported_arches)) ) sys.exit() + env.msvc = True + ## Build type if env["target"] == "release": @@ -101,11 +101,10 @@ def configure(env): arch = "" if str(os.getenv("Platform")).lower() == "arm": - - print("Compiled program architecture will be an ARM executable. (forcing bits=32).") + print("Compiled program architecture will be an ARM executable (forcing arch=arm32).") arch = "arm" - env["bits"] = "32" + env["arch"] = "arm32" env.Append(LINKFLAGS=["/MACHINE:ARM"]) env.Append(LIBPATH=[vc_base_path + "lib/store/arm"]) @@ -117,20 +116,20 @@ def configure(env): compiler_version_str = methods.detect_visual_c_compiler_version(env["ENV"]) if compiler_version_str == "amd64" or compiler_version_str == "x86_amd64": - env["bits"] = "64" - print("Compiled program architecture will be a x64 executable (forcing bits=64).") + env["arch"] = "x86_64" + print("Compiled program architecture will be a x64 executable (forcing arch=x86_64).") elif compiler_version_str == "x86" or compiler_version_str == "amd64_x86": - env["bits"] = "32" - print("Compiled program architecture will be a x86 executable. (forcing bits=32).") + env["arch"] = "x86_32" + print("Compiled program architecture will be a x86 executable (forcing arch=x86_32).") else: print( - "Failed to detect MSVC compiler architecture version... Defaulting to 32-bit executable settings" - " (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture" + "Failed to detect MSVC compiler architecture version... Defaulting to x86 32-bit executable settings" + " (forcing arch=x86_32). Compilation attempt will continue, but SCons can not detect for what architecture" " this build is compiled for. You should check your settings/compilation setup." ) - env["bits"] = "32" + env["arch"] = "x86_32" - if env["bits"] == "32": + if env["arch"] == "x86_32": arch = "x86" angle_build_cmd += "Win32" diff --git a/platform/windows/README.md b/platform/windows/README.md new file mode 100644 index 0000000000..17ce6f216b --- /dev/null +++ b/platform/windows/README.md @@ -0,0 +1,15 @@ +# Windows platform port + +This folder contains the C++ and JavaScript code for the Windows platform port. + +See also [`misc/dist/windows`](/misc/dist/windows) folder for additional files +used by this platform. + +## Documentation + +- [Compiling for Windows](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_windows.html) + - Instructions on building this platform port from source. +- [Exporting for Windows](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_windows.html) + - Instructions on using the compiled export templates to export a project. +- [Changing application icon for Windows](https://docs.godotengine.org/en/stable/tutorials/export/changing_application_icon_for_windows.html) + - Instructions on using a custom icon for the exported project executable. diff --git a/platform/windows/detect.py b/platform/windows/detect.py index dd2df1f004..6dd6892757 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -1,5 +1,6 @@ import methods import os +from platform_methods import detect_arch # To match other platforms STACK_SIZE = 8388608 @@ -46,6 +47,7 @@ def can_build(): def get_opts(): from SCons.Variables import BoolVariable, EnumVariable + # TODO: These shouldn't be hard-coded for x86. mingw32 = "" mingw64 = "" if os.name == "posix": @@ -77,11 +79,14 @@ def get_opts(): def get_flags(): - return [] + return [ + ("arch", detect_arch()), + ] def build_res_file(target, source, env): - if env["bits"] == "32": + # TODO: This shouldn't be hard-coded for x86. + if env["arch"] == "x86_32": cmdbase = env["mingw_prefix_32"] else: cmdbase = env["mingw_prefix_64"] @@ -100,21 +105,27 @@ def build_res_file(target, source, env): def setup_msvc_manual(env): + # FIXME: This is super hacky, and probably obsolete. + # Won't work with detect_arch() used for `arch` by default. + """Set up env to use MSVC manually, using VCINSTALLDIR""" - if env["bits"] != "default": + if env["arch"] != "auto": print( """ - Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console - (or Visual Studio settings) that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits - argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler will be executed and inform you. + Arch argument is not supported for MSVC manual configuration (VCINSTALLDIR configured). + Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console (or Visual Studio settings) that is being used to run SCons. + As a consequence, the arch argument is disabled. Run scons again without arch argument (example: scons p=windows) + and SCons will attempt to detect what MSVC compiler will be executed and inform you. """ ) - raise SCons.Errors.UserError("Bits argument should not be used when using VCINSTALLDIR") + raise SCons.Errors.UserError("Arch argument should not be used when using VCINSTALLDIR") - # Force bits arg + # Force ARCH arg # (Actually msys2 mingw can support 64-bit, we could detect that) - env["bits"] = "32" - env["x86_libtheora_opt_vc"] = True + # TODO: This is wrong, but not sure what to do about it. + # We want to determine the arch and bitness in the SConstruct only. + # We can check if it's correct in here, but if it's not, it should + # just fail with an error message instead of trying to force it. # find compiler manually compiler_version_str = methods.detect_visual_c_compiler_version(env["ENV"]) @@ -122,17 +133,19 @@ def setup_msvc_manual(env): # If building for 64bit architecture, disable assembly optimisations for 32 bit builds (theora as of writing)... vc compiler for 64bit can not compile _asm if compiler_version_str == "amd64" or compiler_version_str == "x86_amd64": - env["bits"] = "64" + env["arch"] = "x86_64" env["x86_libtheora_opt_vc"] = False - print("Compiled program architecture will be a 64 bit executable (forcing bits=64).") + print("Compiled program architecture will be a 64 bit executable (forcing arch=x86_64).") elif compiler_version_str == "x86" or compiler_version_str == "amd64_x86": - print("Compiled program architecture will be a 32 bit executable. (forcing bits=32).") + env["arch"] = "x86_32" + env["x86_libtheora_opt_vc"] = True + print("Compiled program architecture will be a 32 bit executable (forcing arch=x86_32).") else: print( - "Failed to manually detect MSVC compiler architecture version... Defaulting to 32bit executable settings" - " (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this" - " build is compiled for. You should check your settings/compilation setup, or avoid setting VCINSTALLDIR." + "Failed to manually detect MSVC compiler architecture version.\n" + "You should check your settings/compilation setup, or avoid setting VCINSTALLDIR." ) + sys.exit() def setup_msvc_auto(env): @@ -141,6 +154,18 @@ def setup_msvc_auto(env): # If MSVC_VERSION is set by SCons, we know MSVC is installed. # But we may want a different version or target arch. + # Valid architectures for MSVC's TARGET_ARCH: + # ['amd64', 'emt64', 'i386', 'i486', 'i586', 'i686', 'ia64', 'itanium', 'x86', 'x86_64', 'arm', 'arm64', 'aarch64'] + # Our x86_64 and arm64 are the same, and we need to map the 32-bit + # architectures to other names since MSVC isn't as explicit. + # The rest we don't need to worry about because they are + # aliases or aren't supported by Godot (itanium & ia64). + msvc_arch_aliases = {"x86_32": "x86", "arm32": "arm"} + if env["arch"] in msvc_arch_aliases.keys(): + env["TARGET_ARCH"] = msvc_arch_aliases[env["arch"]] + else: + env["TARGET_ARCH"] = env["arch"] + # The env may have already been set up with default MSVC tools, so # reset a few things so we can set it up with the tools we want. # (Ideally we'd decide on the tool config before configuring any @@ -149,21 +174,14 @@ def setup_msvc_auto(env): env["MSVC_SETUP_RUN"] = False # Need to set this to re-run the tool env["MSVS_VERSION"] = None env["MSVC_VERSION"] = None - env["TARGET_ARCH"] = None - if env["bits"] != "default": - env["TARGET_ARCH"] = {"32": "x86", "64": "x86_64"}[env["bits"]] + if "msvc_version" in env: env["MSVC_VERSION"] = env["msvc_version"] env.Tool("msvc") env.Tool("mssdk") # we want the MS SDK # Note: actual compiler version can be found in env['MSVC_VERSION'], e.g. "14.1" for VS2015 - # Get actual target arch into bits (it may be "default" at this point): - if env["TARGET_ARCH"] in ("amd64", "x86_64"): - env["bits"] = "64" - else: - env["bits"] = "32" - print("Found MSVC version %s, arch %s, bits=%s" % (env["MSVC_VERSION"], env["TARGET_ARCH"], env["bits"])) - if env["TARGET_ARCH"] in ("amd64", "x86_64"): + print("Found MSVC version %s, arch %s" % (env["MSVC_VERSION"], env["TARGET_ARCH"])) + if env["arch"] == "x86_32": env["x86_libtheora_opt_vc"] = False @@ -244,7 +262,7 @@ def configure_msvc(env, manual_msvc_config): ] ) env.AppendUnique(CPPDEFINES=["NOMINMAX"]) # disable bogus min/max WinDef.h macros - if env["bits"] == "64": + if env["arch"] == "x86_64": env.AppendUnique(CPPDEFINES=["_WIN64"]) ## Libs @@ -328,10 +346,10 @@ def configure_mingw(env): env.Append(CCFLAGS=["-msse2"]) if env["optimize"] == "speed": # optimize for speed (default) - if env["bits"] == "64": - env.Append(CCFLAGS=["-O3"]) - else: + if env["arch"] == "x86_32": env.Append(CCFLAGS=["-O2"]) + else: + env.Append(CCFLAGS=["-O3"]) else: # optimize for size env.Prepend(CCFLAGS=["-Os"]) @@ -365,15 +383,12 @@ def configure_mingw(env): if os.name != "nt": env["PROGSUFFIX"] = env["PROGSUFFIX"] + ".exe" # for linux cross-compilation - if env["bits"] == "default": - if os.name == "nt": - env["bits"] = "64" if "PROGRAMFILES(X86)" in os.environ else "32" - else: # default to 64-bit on Linux - env["bits"] = "64" - mingw_prefix = "" - if env["bits"] == "32": + # TODO: This doesn't seem to be working, or maybe I just have + # MinGW set up incorrectly. It always gives me x86_64 builds, + # even though arch == "x86_32" and the file name has x86_32 in it. + if env["arch"] == "x86_32": if env["use_static_cpp"]: env.Append(LINKFLAGS=["-static"]) env.Append(LINKFLAGS=["-static-libgcc"]) @@ -460,11 +475,18 @@ def configure_mingw(env): def configure(env): + # Validate arch. + supported_arches = ["x86_32", "x86_64", "arm32", "arm64"] + if env["arch"] not in supported_arches: + print( + 'Unsupported CPU architecture "%s" for Windows. Supported architectures are: %s.' + % (env["arch"], ", ".join(supported_arches)) + ) + sys.exit() + # At this point the env has been set up with basic tools/compilers. env.Prepend(CPPPATH=["#platform/windows"]) - print("Configuring for Windows: target=%s, bits=%s" % (env["target"], env["bits"])) - if os.name == "nt": env["ENV"] = os.environ # this makes build less repeatable, but simplifies some things env["ENV"]["TMP"] = os.environ["TMP"] diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 8c8dbef8a4..7eb61b3038 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -144,8 +144,8 @@ bool DisplayServerWindows::tts_is_paused() const { return tts->is_paused(); } -Array DisplayServerWindows::tts_get_voices() const { - ERR_FAIL_COND_V(!tts, Array()); +TypedArray<Dictionary> DisplayServerWindows::tts_get_voices() const { + ERR_FAIL_COND_V(!tts, TypedArray<Dictionary>()); return tts->get_voices(); } diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index db9b589304..556ce9ff5d 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -478,7 +478,7 @@ public: virtual bool tts_is_speaking() const override; virtual bool tts_is_paused() const override; - virtual Array tts_get_voices() const override; + virtual TypedArray<Dictionary> tts_get_voices() const override; virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override; virtual void tts_pause() override; diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py index 22e33b51b4..33ca2e8ffa 100644 --- a/platform/windows/platform_windows_builders.py +++ b/platform/windows/platform_windows_builders.py @@ -9,7 +9,7 @@ from platform_methods import subprocess_main def make_debug_mingw(target, source, env): mingw_prefix = "" - if env["bits"] == "32": + if env["arch"] == "x86_32": mingw_prefix = env["mingw_prefix_32"] else: mingw_prefix = env["mingw_prefix_64"] diff --git a/platform_methods.py b/platform_methods.py index be4957475d..1a2520794c 100644 --- a/platform_methods.py +++ b/platform_methods.py @@ -1,6 +1,7 @@ import os import sys import json +import platform import uuid import functools import subprocess @@ -71,9 +72,42 @@ def run_in_subprocess(builder_function): def subprocess_main(namespace): - with open(sys.argv[1]) as json_file: data = json.load(json_file) fn = namespace[data["fn"]] fn(*data["args"]) + + +# CPU architecture options. +architectures = ["x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64", "wasm32"] +architecture_aliases = { + "x86": "x86_32", + "x64": "x86_64", + "amd64": "x86_64", + "armv7": "arm32", + "armv8": "arm64", + "arm64v8": "arm64", + "aarch64": "arm64", + "rv": "rv64", + "riscv": "rv64", + "riscv64": "rv64", + "ppcle": "ppc32", + "ppc": "ppc32", + "ppc64le": "ppc64", +} + + +def detect_arch(): + host_machine = platform.machine().lower() + if host_machine in architectures: + return host_machine + elif host_machine in architecture_aliases.keys(): + return architecture_aliases[host_machine] + elif "86" in host_machine: + # Catches x86, i386, i486, i586, i686, etc. + return "x86_32" + else: + print("Unsupported CPU architecture: " + host_machine) + print("Falling back to x86_64.") + return "x86_64" diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index 177f587f4f..4565462247 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -115,14 +115,17 @@ void AnimatedSprite2D::_validate_property(PropertyInfo &p_property) const { names.sort_custom<StringName::AlphCompare>(); bool current_found = false; + bool is_first_element = true; - for (List<StringName>::Element *E = names.front(); E; E = E->next()) { - if (E->prev()) { + for (const StringName &E : names) { + if (!is_first_element) { p_property.hint_string += ","; + } else { + is_first_element = false; } - p_property.hint_string += String(E->get()); - if (animation == E->get()) { + p_property.hint_string += String(E); + if (animation == E) { current_found = true; } } diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index 7f991df36c..85de1fedee 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -361,8 +361,8 @@ void CollisionObject2D::get_shape_owners(List<uint32_t> *r_owners) { } } -Array CollisionObject2D::_get_shape_owners() { - Array ret; +PackedInt32Array CollisionObject2D::_get_shape_owners() { + PackedInt32Array ret; for (const KeyValue<uint32_t, ShapeData> &E : shapes) { ret.push_back(E.key); } diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index f03c6fc72e..af216edc98 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -125,7 +125,7 @@ public: uint32_t create_shape_owner(Object *p_owner); void remove_shape_owner(uint32_t owner); void get_shape_owners(List<uint32_t> *r_owners); - Array _get_shape_owners(); + PackedInt32Array _get_shape_owners(); void shape_owner_set_transform(uint32_t p_owner, const Transform2D &p_transform); Transform2D shape_owner_get_transform(uint32_t p_owner) const; diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 40f74d3f50..15d2cdf2a8 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -32,7 +32,7 @@ #include "core/core_string_names.h" #include "scene/2d/gpu_particles_2d.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" void CPUParticles2D::set_emitting(bool p_emitting) { if (emitting == p_emitting) { @@ -890,7 +890,7 @@ void CPUParticles2D::_particles_process(double p_delta) { real_t orbit_amount = tex_orbit_velocity * Math::lerp(parameters_min[PARAM_ORBIT_VELOCITY], parameters_max[PARAM_ORBIT_VELOCITY], rand_from_seed(alt_seed)); if (orbit_amount != 0.0) { real_t ang = orbit_amount * local_delta * Math_TAU; - // Not sure why the ParticlesMaterial code uses a clockwise rotation matrix, + // Not sure why the ParticleProcessMaterial code uses a clockwise rotation matrix, // but we use -ang here to reproduce its behavior. Transform2D rot = Transform2D(-ang, Vector2()); p.transform[2] -= diff; @@ -1184,7 +1184,7 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) { set_material(mat); } - Ref<ParticlesMaterial> material = particles->get_process_material(); + Ref<ParticleProcessMaterial> material = particles->get_process_material(); if (material.is_null()) { return; } @@ -1205,14 +1205,14 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) { set_color_initial_ramp(gti->get_gradient()); } - set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY)); + set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY)); set_emission_shape(EmissionShape(material->get_emission_shape())); set_emission_sphere_radius(material->get_emission_sphere_radius()); Vector2 rect_extents = Vector2(material->get_emission_box_extents().x, material->get_emission_box_extents().y); set_emission_rect_extents(rect_extents); - Ref<CurveXYZTexture> scale3D = material->get_param_texture(ParticlesMaterial::PARAM_SCALE); + Ref<CurveXYZTexture> scale3D = material->get_param_texture(ParticleProcessMaterial::PARAM_SCALE); if (scale3D.is_valid()) { split_scale = true; scale_curve_x = scale3D->get_curve_x(); @@ -1222,14 +1222,14 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) { set_gravity(gravity); set_lifetime_randomness(material->get_lifetime_randomness()); -#define CONVERT_PARAM(m_param) \ - set_param_min(m_param, material->get_param_min(ParticlesMaterial::m_param)); \ - { \ - Ref<CurveTexture> ctex = material->get_param_texture(ParticlesMaterial::m_param); \ - if (ctex.is_valid()) \ - set_param_curve(m_param, ctex->get_curve()); \ - } \ - set_param_max(m_param, material->get_param_max(ParticlesMaterial::m_param)); +#define CONVERT_PARAM(m_param) \ + set_param_min(m_param, material->get_param_min(ParticleProcessMaterial::m_param)); \ + { \ + Ref<CurveTexture> ctex = material->get_param_texture(ParticleProcessMaterial::m_param); \ + if (ctex.is_valid()) \ + set_param_curve(m_param, ctex->get_curve()); \ + } \ + set_param_max(m_param, material->get_param_max(ParticleProcessMaterial::m_param)); CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY); CONVERT_PARAM(PARAM_ANGULAR_VELOCITY); diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index e4354a69e2..65ead7afbc 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -30,7 +30,7 @@ #include "gpu_particles_2d.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" #ifdef TOOLS_ENABLED #include "core/config/engine.h" @@ -123,10 +123,10 @@ void GPUParticles2D::_update_particle_emission_transform() { void GPUParticles2D::set_process_material(const Ref<Material> &p_material) { process_material = p_material; - Ref<ParticlesMaterial> pm = p_material; - if (pm.is_valid() && !pm->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) { + Ref<ParticleProcessMaterial> pm = p_material; + if (pm.is_valid() && !pm->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) { // Likely a new (3D) material, modify it to match 2D space - pm->set_particle_flag(ParticlesMaterial::PARTICLE_FLAG_DISABLE_Z, true); + pm->set_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_DISABLE_Z, true); pm->set_gravity(Vector3(0, 98, 0)); } RID material_rid; @@ -308,10 +308,10 @@ TypedArray<String> GPUParticles2D::get_configuration_warnings() const { CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr()); if (get_material().is_null() || (mat && !mat->get_particles_animation())) { - const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr()); + const ParticleProcessMaterial *process = Object::cast_to<ParticleProcessMaterial>(process_material.ptr()); if (process && - (process->get_param_max(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 || - process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) { + (process->get_param_max(ParticleProcessMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticleProcessMaterial::PARAM_ANIM_OFFSET) != 0.0 || + process->get_param_texture(ParticleProcessMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticleProcessMaterial::PARAM_ANIM_OFFSET).is_valid())) { warnings.push_back(RTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.")); } } @@ -625,7 +625,7 @@ void GPUParticles2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_sections", PROPERTY_HINT_RANGE, "2,128,1"), "set_trail_sections", "get_trail_sections"); ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_section_subdivisions", PROPERTY_HINT_RANGE, "1,1024,1"), "set_trail_section_subdivisions", "get_trail_section_subdivisions"); ADD_GROUP("Process Material", "process_"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticleProcessMaterial"), "set_process_material", "get_process_material"); ADD_GROUP("Textures", ""); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); diff --git a/scene/2d/position_2d.cpp b/scene/2d/marker_2d.cpp index cfa4d0401e..ba1d2ffbfd 100644 --- a/scene/2d/position_2d.cpp +++ b/scene/2d/marker_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* position_2d.cpp */ +/* marker_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,9 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "position_2d.h" +#include "marker_2d.h" -void Position2D::_draw_cross() { +void Marker2D::_draw_cross() { const real_t extents = get_gizmo_extents(); // Add more points to create a "hard stop" in the color gradient. @@ -50,7 +50,7 @@ void Position2D::_draw_cross() { // Use the axis color which is brighter for the positive axis. // Use a darkened axis color for the negative axis. - // This makes it possible to see in which direction the Position3D node is rotated + // This makes it possible to see in which direction the Marker3D node is rotated // (which can be important depending on how it's used). // Axis colors are taken from `axis_x_color` and `axis_y_color` (defined in `editor/editor_themes.cpp`). const Color color_x = Color(0.96, 0.20, 0.32); @@ -73,17 +73,17 @@ void Position2D::_draw_cross() { } #ifdef TOOLS_ENABLED -Rect2 Position2D::_edit_get_rect() const { +Rect2 Marker2D::_edit_get_rect() const { real_t extents = get_gizmo_extents(); return Rect2(Point2(-extents, -extents), Size2(extents * 2, extents * 2)); } -bool Position2D::_edit_use_rect() const { +bool Marker2D::_edit_use_rect() const { return false; } #endif -void Position2D::_notification(int p_what) { +void Marker2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { update(); @@ -100,21 +100,21 @@ void Position2D::_notification(int p_what) { } } -void Position2D::set_gizmo_extents(real_t p_extents) { +void Marker2D::set_gizmo_extents(real_t p_extents) { gizmo_extents = p_extents; update(); } -real_t Position2D::get_gizmo_extents() const { +real_t Marker2D::get_gizmo_extents() const { return gizmo_extents; } -void Position2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_gizmo_extents", "extents"), &Position2D::set_gizmo_extents); - ClassDB::bind_method(D_METHOD("get_gizmo_extents"), &Position2D::get_gizmo_extents); +void Marker2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_gizmo_extents", "extents"), &Marker2D::set_gizmo_extents); + ClassDB::bind_method(D_METHOD("get_gizmo_extents"), &Marker2D::get_gizmo_extents); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gizmo_extents", PROPERTY_HINT_RANGE, "0,1000,0.1,or_greater,suffix:px"), "set_gizmo_extents", "get_gizmo_extents"); } -Position2D::Position2D() { +Marker2D::Marker2D() { } diff --git a/scene/2d/position_2d.h b/scene/2d/marker_2d.h index 99b0266130..e287018dfc 100644 --- a/scene/2d/position_2d.h +++ b/scene/2d/marker_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* position_2d.h */ +/* marker_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef POSITION_2D_H -#define POSITION_2D_H +#ifndef MARKER_2D_H +#define MARKER_2D_H #include "scene/2d/node_2d.h" -class Position2D : public Node2D { - GDCLASS(Position2D, Node2D); +class Marker2D : public Node2D { + GDCLASS(Marker2D, Node2D); real_t gizmo_extents = 10.0; @@ -53,7 +53,7 @@ public: void set_gizmo_extents(real_t p_extents); real_t get_gizmo_extents() const; - Position2D(); + Marker2D(); }; -#endif // POSITION_2D_H +#endif // MARKER_2D_H diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index a5f7faffef..d7f75c63a4 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -49,8 +49,8 @@ void NavigationAgent2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationAgent2D::set_radius); ClassDB::bind_method(D_METHOD("get_radius"), &NavigationAgent2D::get_radius); - ClassDB::bind_method(D_METHOD("set_neighbor_dist", "neighbor_dist"), &NavigationAgent2D::set_neighbor_dist); - ClassDB::bind_method(D_METHOD("get_neighbor_dist"), &NavigationAgent2D::get_neighbor_dist); + ClassDB::bind_method(D_METHOD("set_neighbor_distance", "neighbor_distance"), &NavigationAgent2D::set_neighbor_distance); + ClassDB::bind_method(D_METHOD("get_neighbor_distance"), &NavigationAgent2D::get_neighbor_distance); ClassDB::bind_method(D_METHOD("set_max_neighbors", "max_neighbors"), &NavigationAgent2D::set_max_neighbors); ClassDB::bind_method(D_METHOD("get_max_neighbors"), &NavigationAgent2D::get_max_neighbors); @@ -96,7 +96,7 @@ void NavigationAgent2D::_bind_methods() { ADD_GROUP("Avoidance", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.1,500,0.01,suffix:px"), "set_radius", "get_radius"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_dist", PROPERTY_HINT_RANGE, "0.1,100000,0.01,suffix:px"), "set_neighbor_dist", "get_neighbor_dist"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_distance", PROPERTY_HINT_RANGE, "0.1,100000,0.01,suffix:px"), "set_neighbor_distance", "get_neighbor_distance"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_neighbors", PROPERTY_HINT_RANGE, "1,10000,1"), "set_max_neighbors", "get_max_neighbors"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:s"), "set_time_horizon", "get_time_horizon"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,100000,0.01,suffix:px/s"), "set_max_speed", "get_max_speed"); @@ -173,7 +173,7 @@ void NavigationAgent2D::_notification(int p_what) { NavigationAgent2D::NavigationAgent2D() { agent = NavigationServer2D::get_singleton()->agent_create(); - set_neighbor_dist(500.0); + set_neighbor_distance(500.0); set_max_neighbors(10); set_time_horizon(20.0); set_radius(10.0); @@ -275,9 +275,9 @@ void NavigationAgent2D::set_radius(real_t p_radius) { NavigationServer2D::get_singleton()->agent_set_radius(agent, radius); } -void NavigationAgent2D::set_neighbor_dist(real_t p_dist) { - neighbor_dist = p_dist; - NavigationServer2D::get_singleton()->agent_set_neighbor_dist(agent, neighbor_dist); +void NavigationAgent2D::set_neighbor_distance(real_t p_distance) { + neighbor_distance = p_distance; + NavigationServer2D::get_singleton()->agent_set_neighbor_distance(agent, neighbor_distance); } void NavigationAgent2D::set_max_neighbors(int p_count) { diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h index 76eba20058..11b845665d 100644 --- a/scene/2d/navigation_agent_2d.h +++ b/scene/2d/navigation_agent_2d.h @@ -50,7 +50,7 @@ class NavigationAgent2D : public Node { real_t path_desired_distance = 1.0; real_t target_desired_distance = 1.0; real_t radius = 0.0; - real_t neighbor_dist = 0.0; + real_t neighbor_distance = 0.0; int max_neighbors = 0; real_t time_horizon = 0.0; real_t max_speed = 0.0; @@ -110,9 +110,9 @@ public: return radius; } - void set_neighbor_dist(real_t p_dist); - real_t get_neighbor_dist() const { - return neighbor_dist; + void set_neighbor_distance(real_t p_distance); + real_t get_neighbor_distance() const { + return neighbor_distance; } void set_max_neighbors(int p_count); diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp index 0320c6c917..c5966bedd2 100644 --- a/scene/2d/navigation_obstacle_2d.cpp +++ b/scene/2d/navigation_obstacle_2d.cpp @@ -135,7 +135,7 @@ TypedArray<String> NavigationObstacle2D::get_configuration_warnings() const { } void NavigationObstacle2D::initialize_agent() { - NavigationServer2D::get_singleton()->agent_set_neighbor_dist(agent, 0.0); + NavigationServer2D::get_singleton()->agent_set_neighbor_distance(agent, 0.0); NavigationServer2D::get_singleton()->agent_set_max_neighbors(agent, 0); NavigationServer2D::get_singleton()->agent_set_time_horizon(agent, 0.0); NavigationServer2D::get_singleton()->agent_set_max_speed(agent, 0.0); diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index 3c393f9752..bbc326a4b4 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -175,10 +175,10 @@ void PathFollow2D::_update_transform() { if (path_length == 0) { return; } - Vector2 pos = c->interpolate_baked(offset, cubic); + Vector2 pos = c->interpolate_baked(progress, cubic); if (rotates) { - real_t ahead = offset + lookahead; + real_t ahead = progress + lookahead; if (loop && ahead >= path_length) { // If our lookahead will loop, we need to check if the path is closed. @@ -202,7 +202,7 @@ void PathFollow2D::_update_transform() { // This will happen at the end of non-looping or non-closed paths. // We'll try a look behind instead, in order to get a meaningful angle. tangent_to_curve = - (pos - c->interpolate_baked(offset - lookahead, cubic)).normalized(); + (pos - c->interpolate_baked(progress - lookahead, cubic)).normalized(); } else { tangent_to_curve = (ahead_pos - pos).normalized(); } @@ -269,8 +269,8 @@ TypedArray<String> PathFollow2D::get_configuration_warnings() const { } void PathFollow2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_offset", "offset"), &PathFollow2D::set_offset); - ClassDB::bind_method(D_METHOD("get_offset"), &PathFollow2D::get_offset); + ClassDB::bind_method(D_METHOD("set_progress", "progress"), &PathFollow2D::set_progress); + ClassDB::bind_method(D_METHOD("get_progress"), &PathFollow2D::get_progress); ClassDB::bind_method(D_METHOD("set_h_offset", "h_offset"), &PathFollow2D::set_h_offset); ClassDB::bind_method(D_METHOD("get_h_offset"), &PathFollow2D::get_h_offset); @@ -278,8 +278,8 @@ void PathFollow2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_v_offset", "v_offset"), &PathFollow2D::set_v_offset); ClassDB::bind_method(D_METHOD("get_v_offset"), &PathFollow2D::get_v_offset); - ClassDB::bind_method(D_METHOD("set_unit_offset", "unit_offset"), &PathFollow2D::set_unit_offset); - ClassDB::bind_method(D_METHOD("get_unit_offset"), &PathFollow2D::get_unit_offset); + ClassDB::bind_method(D_METHOD("set_progress_ratio", "ratio"), &PathFollow2D::set_progress_ratio); + ClassDB::bind_method(D_METHOD("get_progress_ratio"), &PathFollow2D::get_progress_ratio); ClassDB::bind_method(D_METHOD("set_rotates", "enable"), &PathFollow2D::set_rotates); ClassDB::bind_method(D_METHOD("is_rotating"), &PathFollow2D::is_rotating); @@ -293,8 +293,8 @@ void PathFollow2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_lookahead", "lookahead"), &PathFollow2D::set_lookahead); ClassDB::bind_method(D_METHOD("get_lookahead"), &PathFollow2D::get_lookahead); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater,suffix:px"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater,suffix:px"), "set_progress", "get_progress"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset"), "set_h_offset", "get_h_offset"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset"), "set_v_offset", "get_v_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotates"), "set_rotates", "is_rotating"); @@ -303,20 +303,20 @@ void PathFollow2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lookahead", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001"), "set_lookahead", "get_lookahead"); } -void PathFollow2D::set_offset(real_t p_offset) { - ERR_FAIL_COND(!isfinite(p_offset)); - offset = p_offset; +void PathFollow2D::set_progress(real_t p_progress) { + ERR_FAIL_COND(!isfinite(p_progress)); + progress = p_progress; if (path) { if (path->get_curve().is_valid()) { real_t path_length = path->get_curve()->get_baked_length(); if (loop && path_length) { - offset = Math::fposmod(offset, path_length); - if (!Math::is_zero_approx(p_offset) && Math::is_zero_approx(offset)) { - offset = path_length; + progress = Math::fposmod(progress, path_length); + if (!Math::is_zero_approx(p_progress) && Math::is_zero_approx(progress)) { + progress = path_length; } } else { - offset = CLAMP(offset, 0, path_length); + progress = CLAMP(progress, 0, path_length); } } @@ -346,19 +346,19 @@ real_t PathFollow2D::get_v_offset() const { return v_offset; } -real_t PathFollow2D::get_offset() const { - return offset; +real_t PathFollow2D::get_progress() const { + return progress; } -void PathFollow2D::set_unit_offset(real_t p_unit_offset) { +void PathFollow2D::set_progress_ratio(real_t p_ratio) { if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) { - set_offset(p_unit_offset * path->get_curve()->get_baked_length()); + set_progress(p_ratio * path->get_curve()->get_baked_length()); } } -real_t PathFollow2D::get_unit_offset() const { +real_t PathFollow2D::get_progress_ratio() const { if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) { - return get_offset() / path->get_curve()->get_baked_length(); + return get_progress() / path->get_curve()->get_baked_length(); } else { return 0; } diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h index 1f3ee08a2b..3d66ca1fab 100644 --- a/scene/2d/path_2d.h +++ b/scene/2d/path_2d.h @@ -65,7 +65,7 @@ class PathFollow2D : public Node2D { public: private: Path2D *path = nullptr; - real_t offset = 0.0; + real_t progress = 0.0; real_t h_offset = 0.0; real_t v_offset = 0.0; real_t lookahead = 4.0; @@ -82,8 +82,8 @@ protected: static void _bind_methods(); public: - void set_offset(real_t p_offset); - real_t get_offset() const; + void set_progress(real_t p_progress); + real_t get_progress() const; void set_h_offset(real_t p_h_offset); real_t get_h_offset() const; @@ -91,8 +91,8 @@ public: void set_v_offset(real_t p_v_offset); real_t get_v_offset() const; - void set_unit_offset(real_t p_unit_offset); - real_t get_unit_offset() const; + void set_progress_ratio(real_t p_ratio); + real_t get_progress_ratio() const; void set_lookahead(real_t p_lookahead); real_t get_lookahead() const; diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 797f08058f..a317285a1b 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -787,6 +787,12 @@ int RigidDynamicBody2D::get_max_contacts_reported() const { return max_contacts_reported; } +int RigidDynamicBody2D::get_contact_count() const { + PhysicsDirectBodyState2D *bs = PhysicsServer2D::get_singleton()->body_get_direct_state(get_rid()); + ERR_FAIL_NULL_V(bs, 0); + return bs->get_contact_count(); +} + void RigidDynamicBody2D::apply_central_impulse(const Vector2 &p_impulse) { PhysicsServer2D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse); } @@ -849,7 +855,7 @@ RigidDynamicBody2D::CCDMode RigidDynamicBody2D::get_continuous_collision_detecti } TypedArray<Node2D> RigidDynamicBody2D::get_colliding_bodies() const { - ERR_FAIL_COND_V(!contact_monitor, Array()); + ERR_FAIL_COND_V(!contact_monitor, TypedArray<Node2D>()); TypedArray<Node2D> ret; ret.resize(contact_monitor->body_map.size()); @@ -966,6 +972,7 @@ void RigidDynamicBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidDynamicBody2D::set_max_contacts_reported); ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidDynamicBody2D::get_max_contacts_reported); + ClassDB::bind_method(D_METHOD("get_contact_count"), &RigidDynamicBody2D::get_contact_count); ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidDynamicBody2D::set_use_custom_integrator); ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidDynamicBody2D::is_using_custom_integrator); @@ -1023,7 +1030,7 @@ void RigidDynamicBody2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); ADD_PROPERTY(PropertyInfo(Variant::INT, "continuous_cd", PROPERTY_HINT_ENUM, "Disabled,Cast Ray,Cast Shape"), "set_continuous_collision_detection_mode", "get_continuous_collision_detection_mode"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "contacts_reported", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_max_contacts_reported", "get_max_contacts_reported"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_contacts_reported", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_max_contacts_reported", "get_max_contacts_reported"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); @@ -1107,9 +1114,9 @@ bool CharacterBody2D::move_and_slide() { if ((on_floor || on_wall) && platform_rid.is_valid()) { bool excluded = false; if (on_floor) { - excluded = (moving_platform_floor_layers & platform_layer) == 0; + excluded = (platform_floor_layers & platform_layer) == 0; } else if (on_wall) { - excluded = (moving_platform_wall_layers & platform_layer) == 0; + excluded = (platform_wall_layers & platform_layer) == 0; } if (!excluded) { //this approach makes sure there is less delay between the actual body velocity and the one we saved @@ -1159,10 +1166,10 @@ bool CharacterBody2D::move_and_slide() { // Compute real velocity. real_velocity = get_position_delta() / delta; - if (moving_platform_apply_velocity_on_leave != PLATFORM_VEL_ON_LEAVE_NEVER) { + if (platform_on_leave != PLATFORM_ON_LEAVE_DO_NOTHING) { // Add last platform velocity when just left a moving platform. if (!on_floor && !on_wall) { - if (moving_platform_apply_velocity_on_leave == PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY && current_platform_velocity.dot(up_direction) < 0) { + if (platform_on_leave == PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY && current_platform_velocity.dot(up_direction) < 0) { current_platform_velocity = current_platform_velocity.slide(up_direction); } velocity += current_platform_velocity; @@ -1606,20 +1613,20 @@ void CharacterBody2D::set_slide_on_ceiling_enabled(bool p_enabled) { slide_on_ceiling = p_enabled; } -uint32_t CharacterBody2D::get_moving_platform_floor_layers() const { - return moving_platform_floor_layers; +uint32_t CharacterBody2D::get_platform_floor_layers() const { + return platform_floor_layers; } -void CharacterBody2D::set_moving_platform_floor_layers(uint32_t p_exclude_layers) { - moving_platform_floor_layers = p_exclude_layers; +void CharacterBody2D::set_platform_floor_layers(uint32_t p_exclude_layers) { + platform_floor_layers = p_exclude_layers; } -uint32_t CharacterBody2D::get_moving_platform_wall_layers() const { - return moving_platform_wall_layers; +uint32_t CharacterBody2D::get_platform_wall_layers() const { + return platform_wall_layers; } -void CharacterBody2D::set_moving_platform_wall_layers(uint32_t p_exclude_layers) { - moving_platform_wall_layers = p_exclude_layers; +void CharacterBody2D::set_platform_wall_layers(uint32_t p_exclude_layers) { + platform_wall_layers = p_exclude_layers; } void CharacterBody2D::set_motion_mode(MotionMode p_mode) { @@ -1630,12 +1637,12 @@ CharacterBody2D::MotionMode CharacterBody2D::get_motion_mode() const { return motion_mode; } -void CharacterBody2D::set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_apply_velocity) { - moving_platform_apply_velocity_on_leave = p_on_leave_apply_velocity; +void CharacterBody2D::set_platform_on_leave(PlatformOnLeave p_on_leave_apply_velocity) { + platform_on_leave = p_on_leave_apply_velocity; } -CharacterBody2D::MovingPlatformApplyVelocityOnLeave CharacterBody2D::get_moving_platform_apply_velocity_on_leave() const { - return moving_platform_apply_velocity_on_leave; +CharacterBody2D::PlatformOnLeave CharacterBody2D::get_platform_on_leave() const { + return platform_on_leave; } int CharacterBody2D::get_max_slides() const { @@ -1702,7 +1709,7 @@ void CharacterBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &CharacterBody2D::set_velocity); ClassDB::bind_method(D_METHOD("get_velocity"), &CharacterBody2D::get_velocity); - ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody2D::set_safe_margin); + ClassDB::bind_method(D_METHOD("set_safe_margin", "margin"), &CharacterBody2D::set_safe_margin); ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody2D::get_safe_margin); ClassDB::bind_method(D_METHOD("is_floor_stop_on_slope_enabled"), &CharacterBody2D::is_floor_stop_on_slope_enabled); ClassDB::bind_method(D_METHOD("set_floor_stop_on_slope_enabled", "enabled"), &CharacterBody2D::set_floor_stop_on_slope_enabled); @@ -1713,10 +1720,10 @@ void CharacterBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_slide_on_ceiling_enabled", "enabled"), &CharacterBody2D::set_slide_on_ceiling_enabled); ClassDB::bind_method(D_METHOD("is_slide_on_ceiling_enabled"), &CharacterBody2D::is_slide_on_ceiling_enabled); - ClassDB::bind_method(D_METHOD("set_moving_platform_floor_layers", "exclude_layer"), &CharacterBody2D::set_moving_platform_floor_layers); - ClassDB::bind_method(D_METHOD("get_moving_platform_floor_layers"), &CharacterBody2D::get_moving_platform_floor_layers); - ClassDB::bind_method(D_METHOD("set_moving_platform_wall_layers", "exclude_layer"), &CharacterBody2D::set_moving_platform_wall_layers); - ClassDB::bind_method(D_METHOD("get_moving_platform_wall_layers"), &CharacterBody2D::get_moving_platform_wall_layers); + ClassDB::bind_method(D_METHOD("set_platform_floor_layers", "exclude_layer"), &CharacterBody2D::set_platform_floor_layers); + ClassDB::bind_method(D_METHOD("get_platform_floor_layers"), &CharacterBody2D::get_platform_floor_layers); + ClassDB::bind_method(D_METHOD("set_platform_wall_layers", "exclude_layer"), &CharacterBody2D::set_platform_wall_layers); + ClassDB::bind_method(D_METHOD("get_platform_wall_layers"), &CharacterBody2D::get_platform_wall_layers); ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody2D::get_max_slides); ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody2D::set_max_slides); @@ -1730,8 +1737,8 @@ void CharacterBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody2D::set_up_direction); ClassDB::bind_method(D_METHOD("set_motion_mode", "mode"), &CharacterBody2D::set_motion_mode); ClassDB::bind_method(D_METHOD("get_motion_mode"), &CharacterBody2D::get_motion_mode); - ClassDB::bind_method(D_METHOD("set_moving_platform_apply_velocity_on_leave", "on_leave_apply_velocity"), &CharacterBody2D::set_moving_platform_apply_velocity_on_leave); - ClassDB::bind_method(D_METHOD("get_moving_platform_apply_velocity_on_leave"), &CharacterBody2D::get_moving_platform_apply_velocity_on_leave); + ClassDB::bind_method(D_METHOD("set_platform_on_leave", "on_leave_apply_velocity"), &CharacterBody2D::set_platform_on_leave); + ClassDB::bind_method(D_METHOD("get_platform_on_leave"), &CharacterBody2D::get_platform_on_leave); ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody2D::is_on_floor); ClassDB::bind_method(D_METHOD("is_on_floor_only"), &CharacterBody2D::is_on_floor_only); @@ -1756,24 +1763,28 @@ void CharacterBody2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_slides", "get_max_slides"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle"); + ADD_GROUP("Floor", "floor_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_stop_on_slope"), "set_floor_stop_on_slope_enabled", "is_floor_stop_on_slope_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_constant_speed"), "set_floor_constant_speed_enabled", "is_floor_constant_speed_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_block_on_wall"), "set_floor_block_on_wall_enabled", "is_floor_block_on_wall_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater,suffix:px"), "set_floor_snap_length", "get_floor_snap_length"); - ADD_GROUP("Moving Platform", "moving_platform"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_apply_velocity_on_leave", PROPERTY_HINT_ENUM, "Always,Upward Only,Never", PROPERTY_USAGE_DEFAULT), "set_moving_platform_apply_velocity_on_leave", "get_moving_platform_apply_velocity_on_leave"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_floor_layers", "get_moving_platform_floor_layers"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_wall_layers", "get_moving_platform_wall_layers"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001,suffix:px"), "set_safe_margin", "get_safe_margin"); + + ADD_GROUP("Moving Platform", "platform"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_on_leave", PROPERTY_HINT_ENUM, "Add Velocity,Add Upward Velocity,Do Nothing", PROPERTY_USAGE_DEFAULT), "set_platform_on_leave", "get_platform_on_leave"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_platform_floor_layers", "get_platform_floor_layers"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_platform_wall_layers", "get_platform_wall_layers"); + + ADD_GROUP("Collision", ""); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001,suffix:px"), "set_safe_margin", "get_safe_margin"); BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED); BIND_ENUM_CONSTANT(MOTION_MODE_FLOATING); - BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_ALWAYS); - BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY); - BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_NEVER); + BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_ADD_VELOCITY); + BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY); + BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_DO_NOTHING); } void CharacterBody2D::_validate_property(PropertyInfo &p_property) const { diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 75ea535424..fe64c087c6 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -284,6 +284,7 @@ public: void set_max_contacts_reported(int p_amount); int get_max_contacts_reported() const; + int get_contact_count() const; void set_continuous_collision_detection_mode(CCDMode p_mode); CCDMode get_continuous_collision_detection_mode() const; @@ -330,10 +331,10 @@ public: MOTION_MODE_GROUNDED, MOTION_MODE_FLOATING, }; - enum MovingPlatformApplyVelocityOnLeave { - PLATFORM_VEL_ON_LEAVE_ALWAYS, - PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY, - PLATFORM_VEL_ON_LEAVE_NEVER, + enum PlatformOnLeave { + PLATFORM_ON_LEAVE_ADD_VELOCITY, + PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY, + PLATFORM_ON_LEAVE_DO_NOTHING, }; bool move_and_slide(); @@ -364,7 +365,7 @@ public: private: real_t margin = 0.08; MotionMode motion_mode = MOTION_MODE_GROUNDED; - MovingPlatformApplyVelocityOnLeave moving_platform_apply_velocity_on_leave = PLATFORM_VEL_ON_LEAVE_ALWAYS; + PlatformOnLeave platform_on_leave = PLATFORM_ON_LEAVE_ADD_VELOCITY; bool floor_constant_speed = false; bool floor_stop_on_slope = true; @@ -376,8 +377,8 @@ private: real_t floor_snap_length = 1; real_t wall_min_slide_angle = Math::deg2rad((real_t)15.0); Vector2 up_direction = Vector2(0.0, -1.0); - uint32_t moving_platform_floor_layers = UINT32_MAX; - uint32_t moving_platform_wall_layers = 0; + uint32_t platform_floor_layers = UINT32_MAX; + uint32_t platform_wall_layers = 0; Vector2 velocity; Vector2 floor_normal; @@ -423,17 +424,17 @@ private: real_t get_wall_min_slide_angle() const; void set_wall_min_slide_angle(real_t p_radians); - uint32_t get_moving_platform_floor_layers() const; - void set_moving_platform_floor_layers(const uint32_t p_exclude_layer); + uint32_t get_platform_floor_layers() const; + void set_platform_floor_layers(const uint32_t p_exclude_layer); - uint32_t get_moving_platform_wall_layers() const; - void set_moving_platform_wall_layers(const uint32_t p_exclude_layer); + uint32_t get_platform_wall_layers() const; + void set_platform_wall_layers(const uint32_t p_exclude_layer); void set_motion_mode(MotionMode p_mode); MotionMode get_motion_mode() const; - void set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_velocity); - MovingPlatformApplyVelocityOnLeave get_moving_platform_apply_velocity_on_leave() const; + void set_platform_on_leave(PlatformOnLeave p_on_leave_velocity); + PlatformOnLeave get_platform_on_leave() const; void _move_and_slide_floating(double p_delta); void _move_and_slide_grounded(double p_delta, bool p_was_on_floor); @@ -454,7 +455,7 @@ protected: }; VARIANT_ENUM_CAST(CharacterBody2D::MotionMode); -VARIANT_ENUM_CAST(CharacterBody2D::MovingPlatformApplyVelocityOnLeave); +VARIANT_ENUM_CAST(CharacterBody2D::PlatformOnLeave); class KinematicCollision2D : public RefCounted { GDCLASS(KinematicCollision2D, RefCounted); diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index cb918ecb8b..8161fb5bd9 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -602,8 +602,8 @@ void Polygon2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture_scale", "texture_scale"), &Polygon2D::set_texture_scale); ClassDB::bind_method(D_METHOD("get_texture_scale"), &Polygon2D::get_texture_scale); - ClassDB::bind_method(D_METHOD("set_invert", "invert"), &Polygon2D::set_invert); - ClassDB::bind_method(D_METHOD("get_invert"), &Polygon2D::get_invert); + ClassDB::bind_method(D_METHOD("set_invert_enabled", "invert"), &Polygon2D::set_invert); + ClassDB::bind_method(D_METHOD("get_invert_enabled"), &Polygon2D::get_invert); ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &Polygon2D::set_antialiased); ClassDB::bind_method(D_METHOD("get_antialiased"), &Polygon2D::get_antialiased); @@ -646,7 +646,7 @@ void Polygon2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton2D"), "set_skeleton", "get_skeleton"); ADD_GROUP("Invert", "invert_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_enable"), "set_invert", "get_invert"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_enabled"), "set_invert_enabled", "get_invert_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "invert_border", PROPERTY_HINT_RANGE, "0.1,16384,0.1,suffix:px"), "set_invert_border", "get_invert_border"); ADD_GROUP("Data", ""); diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index e07f89fc65..b8b6296c45 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -485,7 +485,7 @@ void Camera3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_keep_aspect_mode"), &Camera3D::get_keep_aspect_mode); ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera3D::set_doppler_tracking); ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera3D::get_doppler_tracking); - ClassDB::bind_method(D_METHOD("get_frustum"), &Camera3D::get_frustum); + ClassDB::bind_method(D_METHOD("get_frustum"), &Camera3D::_get_frustum); ClassDB::bind_method(D_METHOD("is_position_in_frustum", "world_point"), &Camera3D::is_position_in_frustum); ClassDB::bind_method(D_METHOD("get_camera_rid"), &Camera3D::get_camera); ClassDB::bind_method(D_METHOD("get_pyramid_shape_rid"), &Camera3D::get_pyramid_shape_rid); @@ -615,6 +615,11 @@ Vector<Plane> Camera3D::get_frustum() const { return cm.get_projection_planes(get_camera_transform()); } +TypedArray<Plane> Camera3D::_get_frustum() const { + Variant ret = get_frustum(); + return ret; +} + bool Camera3D::is_position_in_frustum(const Vector3 &p_position) const { Vector<Plane> frustum = get_frustum(); for (int i = 0; i < frustum.size(); i++) { diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h index 1a00017b0b..bba9b7d1e4 100644 --- a/scene/3d/camera_3d.h +++ b/scene/3d/camera_3d.h @@ -86,6 +86,7 @@ private: // void _camera_make_current(Node *p_camera); friend class Viewport; void _update_audio_listener_state(); + TypedArray<Plane> _get_frustum() const; DopplerTracking doppler_tracking = DOPPLER_TRACKING_DISABLED; Ref<VelocityTracker3D> velocity_tracker; diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index 22de9a47a2..48eb2a66b1 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -546,8 +546,8 @@ void CollisionObject3D::get_shape_owners(List<uint32_t> *r_owners) { } } -Array CollisionObject3D::_get_shape_owners() { - Array ret; +PackedInt32Array CollisionObject3D::_get_shape_owners() { + PackedInt32Array ret; for (const KeyValue<uint32_t, ShapeData> &E : shapes) { ret.push_back(E.key); } diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h index 3f0d070db4..51c31da79f 100644 --- a/scene/3d/collision_object_3d.h +++ b/scene/3d/collision_object_3d.h @@ -135,7 +135,7 @@ public: uint32_t create_shape_owner(Object *p_owner); void remove_shape_owner(uint32_t owner); void get_shape_owners(List<uint32_t> *r_owners); - Array _get_shape_owners(); + PackedInt32Array _get_shape_owners(); void shape_owner_set_transform(uint32_t p_owner, const Transform3D &p_transform); Transform3D shape_owner_get_transform(uint32_t p_owner) const; diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index a79fd15b1a..719dc42f3a 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -33,7 +33,7 @@ #include "scene/3d/camera_3d.h" #include "scene/3d/gpu_particles_3d.h" #include "scene/main/viewport.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" AABB CPUParticles3D::get_aabb() const { return AABB(); @@ -983,7 +983,7 @@ void CPUParticles3D::_particles_process(double p_delta) { real_t orbit_amount = tex_orbit_velocity * Math::lerp(parameters_min[PARAM_ORBIT_VELOCITY], parameters_max[PARAM_ORBIT_VELOCITY], rand_from_seed(alt_seed)); if (orbit_amount != 0.0) { real_t ang = orbit_amount * local_delta * Math_TAU; - // Not sure why the ParticlesMaterial code uses a clockwise rotation matrix, + // Not sure why the ParticleProcessMaterial code uses a clockwise rotation matrix, // but we use -ang here to reproduce its behavior. Transform2D rot = Transform2D(-ang, Vector2()); Vector2 rotv = rot.basis_xform(Vector2(diff.x, diff.y)); @@ -1343,7 +1343,7 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) { set_draw_order(DrawOrder(particles->get_draw_order())); set_mesh(particles->get_draw_pass_mesh(0)); - Ref<ParticlesMaterial> material = particles->get_process_material(); + Ref<ParticleProcessMaterial> material = particles->get_process_material(); if (material.is_null()) { return; } @@ -1364,14 +1364,14 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) { set_color_initial_ramp(gti->get_gradient()); } - set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY)); - set_particle_flag(PARTICLE_FLAG_ROTATE_Y, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ROTATE_Y)); - set_particle_flag(PARTICLE_FLAG_DISABLE_Z, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_DISABLE_Z)); + set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY)); + set_particle_flag(PARTICLE_FLAG_ROTATE_Y, material->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ROTATE_Y)); + set_particle_flag(PARTICLE_FLAG_DISABLE_Z, material->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_DISABLE_Z)); set_emission_shape(EmissionShape(material->get_emission_shape())); set_emission_sphere_radius(material->get_emission_sphere_radius()); set_emission_box_extents(material->get_emission_box_extents()); - Ref<CurveXYZTexture> scale3D = material->get_param_texture(ParticlesMaterial::PARAM_SCALE); + Ref<CurveXYZTexture> scale3D = material->get_param_texture(ParticleProcessMaterial::PARAM_SCALE); if (scale3D.is_valid()) { split_scale = true; scale_curve_x = scale3D->get_curve_x(); @@ -1382,14 +1382,14 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) { set_gravity(material->get_gravity()); set_lifetime_randomness(material->get_lifetime_randomness()); -#define CONVERT_PARAM(m_param) \ - set_param_min(m_param, material->get_param_min(ParticlesMaterial::m_param)); \ - { \ - Ref<CurveTexture> ctex = material->get_param_texture(ParticlesMaterial::m_param); \ - if (ctex.is_valid()) \ - set_param_curve(m_param, ctex->get_curve()); \ - } \ - set_param_max(m_param, material->get_param_max(ParticlesMaterial::m_param)); +#define CONVERT_PARAM(m_param) \ + set_param_min(m_param, material->get_param_min(ParticleProcessMaterial::m_param)); \ + { \ + Ref<CurveTexture> ctex = material->get_param_texture(ParticleProcessMaterial::m_param); \ + if (ctex.is_valid()) \ + set_param_curve(m_param, ctex->get_curve()); \ + } \ + set_param_max(m_param, material->get_param_max(ParticleProcessMaterial::m_param)); CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY); CONVERT_PARAM(PARAM_ANGULAR_VELOCITY); diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index b46e6a8b71..bd63939d74 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -30,7 +30,7 @@ #include "gpu_particles_3d.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" AABB GPUParticles3D::get_aabb() const { return AABB(); @@ -306,10 +306,10 @@ TypedArray<String> GPUParticles3D::get_configuration_warnings() const { if (process_material.is_null()) { warnings.push_back(RTR("A material to process the particles is not assigned, so no behavior is imprinted.")); } else { - const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr()); + const ParticleProcessMaterial *process = Object::cast_to<ParticleProcessMaterial>(process_material.ptr()); if (!anim_material_found && process && - (process->get_param_max(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 || - process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) { + (process->get_param_max(ParticleProcessMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticleProcessMaterial::PARAM_ANIM_OFFSET) != 0.0 || + process->get_param_texture(ParticleProcessMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticleProcessMaterial::PARAM_ANIM_OFFSET).is_valid())) { warnings.push_back(RTR("Particles animation requires the usage of a BaseMaterial3D whose Billboard Mode is set to \"Particle Billboard\".")); } } @@ -585,7 +585,7 @@ void GPUParticles3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_trail_enabled", "is_trail_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,10,0.01,suffix:s"), "set_trail_length", "get_trail_length"); ADD_GROUP("Process Material", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticleProcessMaterial"), "set_process_material", "get_process_material"); ADD_GROUP("Draw Passes", "draw_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_passes", PROPERTY_HINT_RANGE, "0," + itos(MAX_DRAW_PASSES) + ",1"), "set_draw_passes", "get_draw_passes"); for (int i = 0; i < MAX_DRAW_PASSES; i++) { diff --git a/scene/3d/joint_3d.cpp b/scene/3d/joint_3d.cpp index b0509475a7..d5cab6728a 100644 --- a/scene/3d/joint_3d.cpp +++ b/scene/3d/joint_3d.cpp @@ -221,11 +221,11 @@ void Joint3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint3D::set_exclude_nodes_from_collision); ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint3D::get_exclude_nodes_from_collision); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody3D"), "set_node_a", "get_node_a"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody3D"), "set_node_b", "get_node_b"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "solver/priority", PROPERTY_HINT_RANGE, "1,8,1"), "set_solver_priority", "get_solver_priority"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody3D"), "set_node_a", "get_node_a"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody3D"), "set_node_b", "get_node_b"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "solver_priority", PROPERTY_HINT_RANGE, "1,8,1"), "set_solver_priority", "get_solver_priority"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision/exclude_nodes"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_nodes_from_collision"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision"); } Joint3D::Joint3D() { @@ -292,22 +292,6 @@ PinJoint3D::PinJoint3D() { /////////////////////////////////// -void HingeJoint3D::_set_upper_limit(real_t p_limit) { - set_param(PARAM_LIMIT_UPPER, Math::deg2rad(p_limit)); -} - -real_t HingeJoint3D::_get_upper_limit() const { - return Math::rad2deg(get_param(PARAM_LIMIT_UPPER)); -} - -void HingeJoint3D::_set_lower_limit(real_t p_limit) { - set_param(PARAM_LIMIT_LOWER, Math::deg2rad(p_limit)); -} - -real_t HingeJoint3D::_get_lower_limit() const { - return Math::rad2deg(get_param(PARAM_LIMIT_LOWER)); -} - void HingeJoint3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &HingeJoint3D::set_param); ClassDB::bind_method(D_METHOD("get_param", "param"), &HingeJoint3D::get_param); @@ -315,17 +299,11 @@ void HingeJoint3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_flag", "flag", "enabled"), &HingeJoint3D::set_flag); ClassDB::bind_method(D_METHOD("get_flag", "flag"), &HingeJoint3D::get_flag); - ClassDB::bind_method(D_METHOD("_set_upper_limit", "upper_limit"), &HingeJoint3D::_set_upper_limit); - ClassDB::bind_method(D_METHOD("_get_upper_limit"), &HingeJoint3D::_get_upper_limit); - - ClassDB::bind_method(D_METHOD("_set_lower_limit", "lower_limit"), &HingeJoint3D::_set_lower_limit); - ClassDB::bind_method(D_METHOD("_get_lower_limit"), &HingeJoint3D::_get_lower_limit); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/bias", PROPERTY_HINT_RANGE, "0.00,0.99,0.01"), "set_param", "get_param", PARAM_BIAS); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit/enable"), "set_flag", "get_flag", FLAG_USE_LIMIT); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/upper", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_upper_limit", "_get_upper_limit"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/lower", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_lower_limit", "_get_lower_limit"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/upper", PROPERTY_HINT_RANGE, "-180,180,0.1,radians"), "set_param", "get_param", PARAM_LIMIT_UPPER); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/lower", PROPERTY_HINT_RANGE, "-180,180,0.1,radians"), "set_param", "get_param", PARAM_LIMIT_LOWER); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_LIMIT_BIAS); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_SOFTNESS); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_RELAXATION); @@ -420,34 +398,10 @@ HingeJoint3D::HingeJoint3D() { ///////////////////////////////////////////////// -////////////////////////////////// - -void SliderJoint3D::_set_upper_limit_angular(real_t p_limit_angular) { - set_param(PARAM_ANGULAR_LIMIT_UPPER, Math::deg2rad(p_limit_angular)); -} - -real_t SliderJoint3D::_get_upper_limit_angular() const { - return Math::rad2deg(get_param(PARAM_ANGULAR_LIMIT_UPPER)); -} - -void SliderJoint3D::_set_lower_limit_angular(real_t p_limit_angular) { - set_param(PARAM_ANGULAR_LIMIT_LOWER, Math::deg2rad(p_limit_angular)); -} - -real_t SliderJoint3D::_get_lower_limit_angular() const { - return Math::rad2deg(get_param(PARAM_ANGULAR_LIMIT_LOWER)); -} - void SliderJoint3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &SliderJoint3D::set_param); ClassDB::bind_method(D_METHOD("get_param", "param"), &SliderJoint3D::get_param); - ClassDB::bind_method(D_METHOD("_set_upper_limit_angular", "upper_limit_angular"), &SliderJoint3D::_set_upper_limit_angular); - ClassDB::bind_method(D_METHOD("_get_upper_limit_angular"), &SliderJoint3D::_get_upper_limit_angular); - - ClassDB::bind_method(D_METHOD("_set_lower_limit_angular", "lower_limit_angular"), &SliderJoint3D::_set_lower_limit_angular); - ClassDB::bind_method(D_METHOD("_get_lower_limit_angular"), &SliderJoint3D::_get_lower_limit_angular); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/upper_distance", PROPERTY_HINT_RANGE, "-1024,1024,0.01,suffix:m"), "set_param", "get_param", PARAM_LINEAR_LIMIT_UPPER); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/lower_distance", PROPERTY_HINT_RANGE, "-1024,1024,0.01,suffix:m"), "set_param", "get_param", PARAM_LINEAR_LIMIT_LOWER); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_SOFTNESS); @@ -460,8 +414,8 @@ void SliderJoint3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_RESTITUTION); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_DAMPING); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_upper_limit_angular", "_get_upper_limit_angular"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_lower_limit_angular", "_get_lower_limit_angular"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.1,radians"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_UPPER); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.1,radians"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_LOWER); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_SOFTNESS); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_RESTITUTION); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_DAMPING); @@ -562,34 +516,12 @@ SliderJoint3D::SliderJoint3D() { ////////////////////////////////// -void ConeTwistJoint3D::_set_swing_span(real_t p_limit_angular) { - set_param(PARAM_SWING_SPAN, Math::deg2rad(p_limit_angular)); -} - -real_t ConeTwistJoint3D::_get_swing_span() const { - return Math::rad2deg(get_param(PARAM_SWING_SPAN)); -} - -void ConeTwistJoint3D::_set_twist_span(real_t p_limit_angular) { - set_param(PARAM_TWIST_SPAN, Math::deg2rad(p_limit_angular)); -} - -real_t ConeTwistJoint3D::_get_twist_span() const { - return Math::rad2deg(get_param(PARAM_TWIST_SPAN)); -} - void ConeTwistJoint3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &ConeTwistJoint3D::set_param); ClassDB::bind_method(D_METHOD("get_param", "param"), &ConeTwistJoint3D::get_param); - ClassDB::bind_method(D_METHOD("_set_swing_span", "swing_span"), &ConeTwistJoint3D::_set_swing_span); - ClassDB::bind_method(D_METHOD("_get_swing_span"), &ConeTwistJoint3D::_get_swing_span); - - ClassDB::bind_method(D_METHOD("_set_twist_span", "twist_span"), &ConeTwistJoint3D::_set_twist_span); - ClassDB::bind_method(D_METHOD("_get_twist_span"), &ConeTwistJoint3D::_get_twist_span); - - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "swing_span", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_swing_span", "_get_swing_span"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1"), "_set_twist_span", "_get_twist_span"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "swing_span", PROPERTY_HINT_RANGE, "-180,180,0.1,radians"), "set_param", "get_param", PARAM_SWING_SPAN); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1,radians"), "set_param", "get_param", PARAM_TWIST_SPAN); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_BIAS); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_SOFTNESS); @@ -620,8 +552,6 @@ real_t ConeTwistJoint3D::get_param(Param p_param) const { void ConeTwistJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { Transform3D gt = get_global_transform(); - //Vector3 cone_twistpos = gt.origin; - //Vector3 cone_twistdir = gt.basis.get_axis(2); Transform3D ainv = body_a->get_global_transform().affine_inverse(); @@ -652,73 +582,7 @@ ConeTwistJoint3D::ConeTwistJoint3D() { ///////////////////////////////////////////////////////////////////// -void Generic6DOFJoint3D::_set_angular_hi_limit_x(real_t p_limit_angular) { - set_param_x(PARAM_ANGULAR_UPPER_LIMIT, Math::deg2rad(p_limit_angular)); -} - -real_t Generic6DOFJoint3D::_get_angular_hi_limit_x() const { - return Math::rad2deg(get_param_x(PARAM_ANGULAR_UPPER_LIMIT)); -} - -void Generic6DOFJoint3D::_set_angular_lo_limit_x(real_t p_limit_angular) { - set_param_x(PARAM_ANGULAR_LOWER_LIMIT, Math::deg2rad(p_limit_angular)); -} - -real_t Generic6DOFJoint3D::_get_angular_lo_limit_x() const { - return Math::rad2deg(get_param_x(PARAM_ANGULAR_LOWER_LIMIT)); -} - -void Generic6DOFJoint3D::_set_angular_hi_limit_y(real_t p_limit_angular) { - set_param_y(PARAM_ANGULAR_UPPER_LIMIT, Math::deg2rad(p_limit_angular)); -} - -real_t Generic6DOFJoint3D::_get_angular_hi_limit_y() const { - return Math::rad2deg(get_param_y(PARAM_ANGULAR_UPPER_LIMIT)); -} - -void Generic6DOFJoint3D::_set_angular_lo_limit_y(real_t p_limit_angular) { - set_param_y(PARAM_ANGULAR_LOWER_LIMIT, Math::deg2rad(p_limit_angular)); -} - -real_t Generic6DOFJoint3D::_get_angular_lo_limit_y() const { - return Math::rad2deg(get_param_y(PARAM_ANGULAR_LOWER_LIMIT)); -} - -void Generic6DOFJoint3D::_set_angular_hi_limit_z(real_t p_limit_angular) { - set_param_z(PARAM_ANGULAR_UPPER_LIMIT, Math::deg2rad(p_limit_angular)); -} - -real_t Generic6DOFJoint3D::_get_angular_hi_limit_z() const { - return Math::rad2deg(get_param_z(PARAM_ANGULAR_UPPER_LIMIT)); -} - -void Generic6DOFJoint3D::_set_angular_lo_limit_z(real_t p_limit_angular) { - set_param_z(PARAM_ANGULAR_LOWER_LIMIT, Math::deg2rad(p_limit_angular)); -} - -real_t Generic6DOFJoint3D::_get_angular_lo_limit_z() const { - return Math::rad2deg(get_param_z(PARAM_ANGULAR_LOWER_LIMIT)); -} - void Generic6DOFJoint3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("_set_angular_hi_limit_x", "angle"), &Generic6DOFJoint3D::_set_angular_hi_limit_x); - ClassDB::bind_method(D_METHOD("_get_angular_hi_limit_x"), &Generic6DOFJoint3D::_get_angular_hi_limit_x); - - ClassDB::bind_method(D_METHOD("_set_angular_lo_limit_x", "angle"), &Generic6DOFJoint3D::_set_angular_lo_limit_x); - ClassDB::bind_method(D_METHOD("_get_angular_lo_limit_x"), &Generic6DOFJoint3D::_get_angular_lo_limit_x); - - ClassDB::bind_method(D_METHOD("_set_angular_hi_limit_y", "angle"), &Generic6DOFJoint3D::_set_angular_hi_limit_y); - ClassDB::bind_method(D_METHOD("_get_angular_hi_limit_y"), &Generic6DOFJoint3D::_get_angular_hi_limit_y); - - ClassDB::bind_method(D_METHOD("_set_angular_lo_limit_y", "angle"), &Generic6DOFJoint3D::_set_angular_lo_limit_y); - ClassDB::bind_method(D_METHOD("_get_angular_lo_limit_y"), &Generic6DOFJoint3D::_get_angular_lo_limit_y); - - ClassDB::bind_method(D_METHOD("_set_angular_hi_limit_z", "angle"), &Generic6DOFJoint3D::_set_angular_hi_limit_z); - ClassDB::bind_method(D_METHOD("_get_angular_hi_limit_z"), &Generic6DOFJoint3D::_get_angular_hi_limit_z); - - ClassDB::bind_method(D_METHOD("_set_angular_lo_limit_z", "angle"), &Generic6DOFJoint3D::_set_angular_lo_limit_z); - ClassDB::bind_method(D_METHOD("_get_angular_lo_limit_z"), &Generic6DOFJoint3D::_get_angular_lo_limit_z); - ClassDB::bind_method(D_METHOD("set_param_x", "param", "value"), &Generic6DOFJoint3D::set_param_x); ClassDB::bind_method(D_METHOD("get_param_x", "param"), &Generic6DOFJoint3D::get_param_x); @@ -794,8 +658,8 @@ void Generic6DOFJoint3D::_bind_methods() { ADD_GROUP("Angular Limit", "angular_limit_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_ANGULAR_LIMIT); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_x/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_x", "_get_angular_hi_limit_x"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_x/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_x", "_get_angular_lo_limit_x"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01,radians"), "set_param_x", "get_param_x", PARAM_ANGULAR_UPPER_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01,radians"), "set_param_x", "get_param_x", PARAM_ANGULAR_LOWER_LIMIT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_LIMIT_SOFTNESS); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_RESTITUTION); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_DAMPING); @@ -803,8 +667,8 @@ void Generic6DOFJoint3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/erp"), "set_param_x", "get_param_x", PARAM_ANGULAR_ERP); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_ANGULAR_LIMIT); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_y/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_y", "_get_angular_hi_limit_y"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_y/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_y", "_get_angular_lo_limit_y"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01,radians"), "set_param_y", "get_param_y", PARAM_ANGULAR_UPPER_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01,radians"), "set_param_y", "get_param_y", PARAM_ANGULAR_LOWER_LIMIT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_LIMIT_SOFTNESS); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_RESTITUTION); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_DAMPING); @@ -812,8 +676,8 @@ void Generic6DOFJoint3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/erp"), "set_param_y", "get_param_y", PARAM_ANGULAR_ERP); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_ANGULAR_LIMIT); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_z/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_z", "_get_angular_hi_limit_z"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_z/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_z", "_get_angular_lo_limit_z"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01,radians"), "set_param_z", "get_param_z", PARAM_ANGULAR_UPPER_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01,radians"), "set_param_z", "get_param_z", PARAM_ANGULAR_LOWER_LIMIT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_LIMIT_SOFTNESS); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_RESTITUTION); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_DAMPING); diff --git a/scene/3d/joint_3d.h b/scene/3d/joint_3d.h index ea356ef3b7..cb967023e8 100644 --- a/scene/3d/joint_3d.h +++ b/scene/3d/joint_3d.h @@ -136,12 +136,6 @@ protected: virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; static void _bind_methods(); - void _set_upper_limit(real_t p_limit); - real_t _get_upper_limit() const; - - void _set_lower_limit(real_t p_limit); - real_t _get_lower_limit() const; - public: void set_param(Param p_param, real_t p_value); real_t get_param(Param p_param) const; @@ -188,12 +182,6 @@ public: }; protected: - void _set_upper_limit_angular(real_t p_limit_angular); - real_t _get_upper_limit_angular() const; - - void _set_lower_limit_angular(real_t p_limit_angular); - real_t _get_lower_limit_angular() const; - real_t params[PARAM_MAX]; virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; static void _bind_methods(); @@ -221,12 +209,6 @@ public: }; protected: - void _set_swing_span(real_t p_limit_angular); - real_t _get_swing_span() const; - - void _set_twist_span(real_t p_limit_angular); - real_t _get_twist_span() const; - real_t params[PARAM_MAX]; virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; static void _bind_methods(); @@ -281,24 +263,6 @@ public: }; protected: - void _set_angular_hi_limit_x(real_t p_limit_angular); - real_t _get_angular_hi_limit_x() const; - - void _set_angular_hi_limit_y(real_t p_limit_angular); - real_t _get_angular_hi_limit_y() const; - - void _set_angular_hi_limit_z(real_t p_limit_angular); - real_t _get_angular_hi_limit_z() const; - - void _set_angular_lo_limit_x(real_t p_limit_angular); - real_t _get_angular_lo_limit_x() const; - - void _set_angular_lo_limit_y(real_t p_limit_angular); - real_t _get_angular_lo_limit_y() const; - - void _set_angular_lo_limit_z(real_t p_limit_angular); - real_t _get_angular_lo_limit_z() const; - real_t params_x[PARAM_MAX]; bool flags_x[FLAG_MAX]; real_t params_y[PARAM_MAX]; diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp index f2d3dda792..40b8af7d63 100644 --- a/scene/3d/label_3d.cpp +++ b/scene/3d/label_3d.cpp @@ -31,6 +31,7 @@ #include "label_3d.h" #include "core/core_string_names.h" +#include "scene/main/viewport.h" #include "scene/resources/theme.h" #include "scene/scene_string_names.h" @@ -184,6 +185,14 @@ void Label3D::_notification(int p_what) { if (!pending_update) { _im_update(); } + Viewport *viewport = get_viewport(); + ERR_FAIL_COND(!viewport); + viewport->connect("size_changed", callable_mp(this, &Label3D::_font_changed)); + } break; + case NOTIFICATION_EXIT_TREE: { + Viewport *viewport = get_viewport(); + ERR_FAIL_COND(!viewport); + viewport->disconnect("size_changed", callable_mp(this, &Label3D::_font_changed)); } break; case NOTIFICATION_TRANSLATION_CHANGED: { String new_text = tr(text); @@ -432,7 +441,7 @@ void Label3D::_shape() { TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i))); } - Array stt; + TypedArray<Vector2i> stt; if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) { GDVIRTUAL_CALL(_structured_text_parser, st_args, text, stt); } else { diff --git a/scene/3d/position_3d.cpp b/scene/3d/marker_3d.cpp index 7dc1b1ace0..3987172561 100644 --- a/scene/3d/position_3d.cpp +++ b/scene/3d/marker_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* position_3d.cpp */ +/* marker_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "position_3d.h" +#include "marker_3d.h" -Position3D::Position3D() { +Marker3D::Marker3D() { } diff --git a/scene/3d/position_3d.h b/scene/3d/marker_3d.h index 5514399e6e..95caa101c5 100644 --- a/scene/3d/position_3d.h +++ b/scene/3d/marker_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* position_3d.h */ +/* marker_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,16 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef POSITION_3D_H -#define POSITION_3D_H +#ifndef MARKER_3D_H +#define MARKER_3D_H #include "scene/3d/node_3d.h" -class Position3D : public Node3D { - GDCLASS(Position3D, Node3D); +class Marker3D : public Node3D { + GDCLASS(Marker3D, Node3D); public: - Position3D(); + Marker3D(); }; -#endif // POSITION_3D_H +#endif // MARKER_3D_H diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index 3752713d6a..34e84861a2 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -53,8 +53,8 @@ void NavigationAgent3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_ignore_y", "ignore"), &NavigationAgent3D::set_ignore_y); ClassDB::bind_method(D_METHOD("get_ignore_y"), &NavigationAgent3D::get_ignore_y); - ClassDB::bind_method(D_METHOD("set_neighbor_dist", "neighbor_dist"), &NavigationAgent3D::set_neighbor_dist); - ClassDB::bind_method(D_METHOD("get_neighbor_dist"), &NavigationAgent3D::get_neighbor_dist); + ClassDB::bind_method(D_METHOD("set_neighbor_distance", "neighbor_distance"), &NavigationAgent3D::set_neighbor_distance); + ClassDB::bind_method(D_METHOD("get_neighbor_distance"), &NavigationAgent3D::get_neighbor_distance); ClassDB::bind_method(D_METHOD("set_max_neighbors", "max_neighbors"), &NavigationAgent3D::set_max_neighbors); ClassDB::bind_method(D_METHOD("get_max_neighbors"), &NavigationAgent3D::get_max_neighbors); @@ -101,7 +101,7 @@ void NavigationAgent3D::_bind_methods() { ADD_GROUP("Avoidance", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_radius", "get_radius"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_dist", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:m"), "set_neighbor_dist", "get_neighbor_dist"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_distance", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:m"), "set_neighbor_distance", "get_neighbor_distance"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_neighbors", PROPERTY_HINT_RANGE, "1,10000,1"), "set_max_neighbors", "get_max_neighbors"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon", PROPERTY_HINT_RANGE, "0.01,100,0.01,suffix:s"), "set_time_horizon", "get_time_horizon"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:m/s"), "set_max_speed", "get_max_speed"); @@ -179,7 +179,7 @@ void NavigationAgent3D::_notification(int p_what) { NavigationAgent3D::NavigationAgent3D() { agent = NavigationServer3D::get_singleton()->agent_create(); - set_neighbor_dist(50.0); + set_neighbor_distance(50.0); set_max_neighbors(10); set_time_horizon(5.0); set_radius(1.0); @@ -291,9 +291,9 @@ void NavigationAgent3D::set_ignore_y(bool p_ignore_y) { NavigationServer3D::get_singleton()->agent_set_ignore_y(agent, ignore_y); } -void NavigationAgent3D::set_neighbor_dist(real_t p_dist) { - neighbor_dist = p_dist; - NavigationServer3D::get_singleton()->agent_set_neighbor_dist(agent, neighbor_dist); +void NavigationAgent3D::set_neighbor_distance(real_t p_distance) { + neighbor_distance = p_distance; + NavigationServer3D::get_singleton()->agent_set_neighbor_distance(agent, neighbor_distance); } void NavigationAgent3D::set_max_neighbors(int p_count) { diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h index e05f0287f7..35c1b1175a 100644 --- a/scene/3d/navigation_agent_3d.h +++ b/scene/3d/navigation_agent_3d.h @@ -52,7 +52,7 @@ class NavigationAgent3D : public Node { real_t radius = 0.0; real_t navigation_height_offset = 0.0; bool ignore_y = false; - real_t neighbor_dist = 0.0; + real_t neighbor_distance = 0.0; int max_neighbors = 0; real_t time_horizon = 0.0; real_t max_speed = 0.0; @@ -122,9 +122,9 @@ public: return ignore_y; } - void set_neighbor_dist(real_t p_dist); - real_t get_neighbor_dist() const { - return neighbor_dist; + void set_neighbor_distance(real_t p_distance); + real_t get_neighbor_distance() const { + return neighbor_distance; } void set_max_neighbors(int p_count); diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp index c6eda1f9cd..ef9e191f69 100644 --- a/scene/3d/navigation_obstacle_3d.cpp +++ b/scene/3d/navigation_obstacle_3d.cpp @@ -141,7 +141,7 @@ TypedArray<String> NavigationObstacle3D::get_configuration_warnings() const { } void NavigationObstacle3D::initialize_agent() { - NavigationServer3D::get_singleton()->agent_set_neighbor_dist(agent, 0.0); + NavigationServer3D::get_singleton()->agent_set_neighbor_distance(agent, 0.0); NavigationServer3D::get_singleton()->agent_set_max_neighbors(agent, 0); NavigationServer3D::get_singleton()->agent_set_time_horizon(agent, 0.0); NavigationServer3D::get_singleton()->agent_set_max_speed(agent, 0.0); diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index ec60c8fdc2..426a8c1684 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -561,8 +561,8 @@ void Node3D::clear_gizmos() { #endif } -Array Node3D::get_gizmos_bind() const { - Array ret; +TypedArray<Node3DGizmo> Node3D::get_gizmos_bind() const { + TypedArray<Node3DGizmo> ret; #ifdef TOOLS_ENABLED for (int i = 0; i < data.gizmos.size(); i++) { @@ -1054,7 +1054,7 @@ void Node3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_lesser,no_slider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation"); - ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "quaternion", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_quaternion", "get_quaternion"); + ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "quaternion", PROPERTY_HINT_HIDE_QUATERNION_EDIT, "", PROPERTY_USAGE_EDITOR), "set_quaternion", "get_quaternion"); ADD_PROPERTY(PropertyInfo(Variant::BASIS, "basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_basis", "get_basis"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_LINK, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_edit_mode", PROPERTY_HINT_ENUM, "Euler,Quaternion,Basis"), "set_rotation_edit_mode", "get_rotation_edit_mode"); diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h index 2757f9e9ed..90c7bc89ef 100644 --- a/scene/3d/node_3d.h +++ b/scene/3d/node_3d.h @@ -216,7 +216,7 @@ public: void set_subgizmo_selection(Ref<Node3DGizmo> p_gizmo, int p_id, Transform3D p_transform = Transform3D()); void clear_subgizmo_selection(); Vector<Ref<Node3DGizmo>> get_gizmos() const; - Array get_gizmos_bind() const; + TypedArray<Node3DGizmo> get_gizmos_bind() const; void add_gizmo(Ref<Node3DGizmo> p_gizmo); void remove_gizmo(Ref<Node3DGizmo> p_gizmo); void clear_gizmos(); diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index 8c4e5c5275..7d79d9b4fd 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -183,8 +183,8 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { return; } real_t bi = c->get_bake_interval(); - real_t o_next = offset + bi; - real_t o_prev = offset - bi; + real_t o_next = progress + bi; + real_t o_prev = progress - bi; if (loop) { o_next = Math::fposmod(o_next, bl); @@ -198,7 +198,7 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { } } - Vector3 pos = c->interpolate_baked(offset, cubic); + Vector3 pos = c->interpolate_baked(progress, cubic); Transform3D t = get_transform(); // Vector3 pos_offset = Vector3(h_offset, v_offset, 0); not used in all cases // will be replaced by "Vector3(h_offset, v_offset, 0)" where it was formerly used @@ -217,9 +217,9 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { forward.normalize(); } - Vector3 up = c->interpolate_baked_up_vector(offset, true); + Vector3 up = c->interpolate_baked_up_vector(progress, true); - if (o_next < offset) { + if (o_next < progress) { Vector3 up1 = c->interpolate_baked_up_vector(o_next, true); Vector3 axis = up.cross(up1); @@ -247,12 +247,12 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { // for a discussion about why not Frenet frame. t.origin = pos; - if (p_update_xyz_rot && prev_offset != offset) { // Only update rotation if some parameter has changed - i.e. not on addition to scene tree. + if (p_update_xyz_rot && prev_offset != progress) { // Only update rotation if some parameter has changed - i.e. not on addition to scene tree. real_t sample_distance = bi * 0.01; Vector3 t_prev_pos_a = c->interpolate_baked(prev_offset - sample_distance, cubic); Vector3 t_prev_pos_b = c->interpolate_baked(prev_offset + sample_distance, cubic); - Vector3 t_cur_pos_a = c->interpolate_baked(offset - sample_distance, cubic); - Vector3 t_cur_pos_b = c->interpolate_baked(offset + sample_distance, cubic); + Vector3 t_cur_pos_a = c->interpolate_baked(progress - sample_distance, cubic); + Vector3 t_cur_pos_b = c->interpolate_baked(progress + sample_distance, cubic); Vector3 t_prev = (t_prev_pos_a - t_prev_pos_b).normalized(); Vector3 t_cur = (t_cur_pos_a - t_cur_pos_b).normalized(); @@ -277,7 +277,7 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { } // do the additional tilting - real_t tilt_angle = c->interpolate_baked_tilt(offset); + real_t tilt_angle = c->interpolate_baked_tilt(progress); Vector3 tilt_axis = t_cur; // not sure what tilt is supposed to do, is this correct?? if (likely(!Math::is_zero_approx(Math::abs(tilt_angle)))) { @@ -359,8 +359,8 @@ TypedArray<String> PathFollow3D::get_configuration_warnings() const { } void PathFollow3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_offset", "offset"), &PathFollow3D::set_offset); - ClassDB::bind_method(D_METHOD("get_offset"), &PathFollow3D::get_offset); + ClassDB::bind_method(D_METHOD("set_progress", "progress"), &PathFollow3D::set_progress); + ClassDB::bind_method(D_METHOD("get_progress"), &PathFollow3D::get_progress); ClassDB::bind_method(D_METHOD("set_h_offset", "h_offset"), &PathFollow3D::set_h_offset); ClassDB::bind_method(D_METHOD("get_h_offset"), &PathFollow3D::get_h_offset); @@ -368,8 +368,8 @@ void PathFollow3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_v_offset", "v_offset"), &PathFollow3D::set_v_offset); ClassDB::bind_method(D_METHOD("get_v_offset"), &PathFollow3D::get_v_offset); - ClassDB::bind_method(D_METHOD("set_unit_offset", "unit_offset"), &PathFollow3D::set_unit_offset); - ClassDB::bind_method(D_METHOD("get_unit_offset"), &PathFollow3D::get_unit_offset); + ClassDB::bind_method(D_METHOD("set_progress_ratio", "ratio"), &PathFollow3D::set_progress_ratio); + ClassDB::bind_method(D_METHOD("get_progress_ratio"), &PathFollow3D::get_progress_ratio); ClassDB::bind_method(D_METHOD("set_rotation_mode", "rotation_mode"), &PathFollow3D::set_rotation_mode); ClassDB::bind_method(D_METHOD("get_rotation_mode"), &PathFollow3D::get_rotation_mode); @@ -380,8 +380,8 @@ void PathFollow3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow3D::set_loop); ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow3D::has_loop); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater,suffix:m"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater,suffix:m"), "set_progress", "get_progress"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_h_offset", "get_h_offset"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_v_offset", "get_v_offset"); ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM, "None,Y,XY,XYZ,Oriented"), "set_rotation_mode", "get_rotation_mode"); @@ -395,22 +395,22 @@ void PathFollow3D::_bind_methods() { BIND_ENUM_CONSTANT(ROTATION_ORIENTED); } -void PathFollow3D::set_offset(real_t p_offset) { - ERR_FAIL_COND(!isfinite(p_offset)); - prev_offset = offset; - offset = p_offset; +void PathFollow3D::set_progress(real_t p_progress) { + ERR_FAIL_COND(!isfinite(p_progress)); + prev_offset = progress; + progress = p_progress; if (path) { if (path->get_curve().is_valid()) { real_t path_length = path->get_curve()->get_baked_length(); if (loop && path_length) { - offset = Math::fposmod(offset, path_length); - if (!Math::is_zero_approx(p_offset) && Math::is_zero_approx(offset)) { - offset = path_length; + progress = Math::fposmod(progress, path_length); + if (!Math::is_zero_approx(p_progress) && Math::is_zero_approx(progress)) { + progress = path_length; } } else { - offset = CLAMP(offset, 0, path_length); + progress = CLAMP(progress, 0, path_length); } } @@ -440,19 +440,19 @@ real_t PathFollow3D::get_v_offset() const { return v_offset; } -real_t PathFollow3D::get_offset() const { - return offset; +real_t PathFollow3D::get_progress() const { + return progress; } -void PathFollow3D::set_unit_offset(real_t p_unit_offset) { +void PathFollow3D::set_progress_ratio(real_t p_ratio) { if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) { - set_offset(p_unit_offset * path->get_curve()->get_baked_length()); + set_progress(p_ratio * path->get_curve()->get_baked_length()); } } -real_t PathFollow3D::get_unit_offset() const { +real_t PathFollow3D::get_progress_ratio() const { if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) { - return get_offset() / path->get_curve()->get_baked_length(); + return get_progress() / path->get_curve()->get_baked_length(); } else { return 0; } diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h index bc4db61a01..45fa2c8917 100644 --- a/scene/3d/path_3d.h +++ b/scene/3d/path_3d.h @@ -75,7 +75,7 @@ public: private: Path3D *path = nullptr; real_t prev_offset = 0.0; // Offset during the last _update_transform. - real_t offset = 0.0; + real_t progress = 0.0; real_t h_offset = 0.0; real_t v_offset = 0.0; bool cubic = true; @@ -91,8 +91,8 @@ protected: static void _bind_methods(); public: - void set_offset(real_t p_offset); - real_t get_offset() const; + void set_progress(real_t p_progress); + real_t get_progress() const; void set_h_offset(real_t p_h_offset); real_t get_h_offset() const; @@ -100,8 +100,8 @@ public: void set_v_offset(real_t p_v_offset); real_t get_v_offset() const; - void set_unit_offset(real_t p_unit_offset); - real_t get_unit_offset() const; + void set_progress_ratio(real_t p_ratio); + real_t get_progress_ratio() const; void set_loop(bool p_loop); bool has_loop() const; diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index 515665bde6..c690b5d6ff 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -525,7 +525,7 @@ void RigidDynamicBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) } _RigidDynamicBodyInOut *toadd = (_RigidDynamicBodyInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidDynamicBodyInOut)); - int toadd_count = 0; //state->get_contact_count(); + int toadd_count = 0; RigidDynamicBody3D_RemoveAction *toremove = (RigidDynamicBody3D_RemoveAction *)alloca(rc * sizeof(RigidDynamicBody3D_RemoveAction)); int toremove_count = 0; @@ -537,8 +537,6 @@ void RigidDynamicBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) int local_shape = p_state->get_contact_local_shape(i); int shape = p_state->get_contact_collider_shape(i); - //bool found=false; - HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(obj); if (!E) { toadd[toadd_count].rid = rid; @@ -865,6 +863,12 @@ int RigidDynamicBody3D::get_max_contacts_reported() const { return max_contacts_reported; } +int RigidDynamicBody3D::get_contact_count() const { + PhysicsDirectBodyState3D *bs = PhysicsServer3D::get_singleton()->body_get_direct_state(get_rid()); + ERR_FAIL_NULL_V(bs, 0); + return bs->get_contact_count(); +} + void RigidDynamicBody3D::apply_central_impulse(const Vector3 &p_impulse) { PhysicsServer3D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse); } @@ -960,10 +964,10 @@ bool RigidDynamicBody3D::is_contact_monitor_enabled() const { return contact_monitor != nullptr; } -Array RigidDynamicBody3D::get_colliding_bodies() const { - ERR_FAIL_COND_V(!contact_monitor, Array()); +TypedArray<Node3D> RigidDynamicBody3D::get_colliding_bodies() const { + ERR_FAIL_COND_V(!contact_monitor, TypedArray<Node3D>()); - Array ret; + TypedArray<Node3D> ret; ret.resize(contact_monitor->body_map.size()); int idx = 0; for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { @@ -1031,6 +1035,7 @@ void RigidDynamicBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidDynamicBody3D::set_max_contacts_reported); ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidDynamicBody3D::get_max_contacts_reported); + ClassDB::bind_method(D_METHOD("get_contact_count"), &RigidDynamicBody3D::get_contact_count); ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidDynamicBody3D::set_use_custom_integrator); ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidDynamicBody3D::is_using_custom_integrator); @@ -1089,7 +1094,7 @@ void RigidDynamicBody3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "continuous_cd"), "set_use_continuous_collision_detection", "is_using_continuous_collision_detection"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "contacts_reported", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_max_contacts_reported", "get_max_contacts_reported"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_contacts_reported", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_max_contacts_reported", "get_max_contacts_reported"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); @@ -1176,9 +1181,9 @@ bool CharacterBody3D::move_and_slide() { if ((collision_state.floor || collision_state.wall) && platform_rid.is_valid()) { bool excluded = false; if (collision_state.floor) { - excluded = (moving_platform_floor_layers & platform_layer) == 0; + excluded = (platform_floor_layers & platform_layer) == 0; } else if (collision_state.wall) { - excluded = (moving_platform_wall_layers & platform_layer) == 0; + excluded = (platform_wall_layers & platform_layer) == 0; } if (!excluded) { //this approach makes sure there is less delay between the actual body velocity and the one we saved @@ -1230,10 +1235,10 @@ bool CharacterBody3D::move_and_slide() { // Compute real velocity. real_velocity = get_position_delta() / delta; - if (moving_platform_apply_velocity_on_leave != PLATFORM_VEL_ON_LEAVE_NEVER) { + if (platform_on_leave != PLATFORM_ON_LEAVE_DO_NOTHING) { // Add last platform velocity when just left a moving platform. if (!collision_state.floor && !collision_state.wall) { - if (moving_platform_apply_velocity_on_leave == PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY && current_platform_velocity.dot(up_direction) < 0) { + if (platform_on_leave == PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY && current_platform_velocity.dot(up_direction) < 0) { current_platform_velocity = current_platform_velocity.slide(up_direction); } velocity += current_platform_velocity; @@ -1853,20 +1858,20 @@ void CharacterBody3D::set_slide_on_ceiling_enabled(bool p_enabled) { slide_on_ceiling = p_enabled; } -uint32_t CharacterBody3D::get_moving_platform_floor_layers() const { - return moving_platform_floor_layers; +uint32_t CharacterBody3D::get_platform_floor_layers() const { + return platform_floor_layers; } -void CharacterBody3D::set_moving_platform_floor_layers(uint32_t p_exclude_layers) { - moving_platform_floor_layers = p_exclude_layers; +void CharacterBody3D::set_platform_floor_layers(uint32_t p_exclude_layers) { + platform_floor_layers = p_exclude_layers; } -uint32_t CharacterBody3D::get_moving_platform_wall_layers() const { - return moving_platform_wall_layers; +uint32_t CharacterBody3D::get_platform_wall_layers() const { + return platform_wall_layers; } -void CharacterBody3D::set_moving_platform_wall_layers(uint32_t p_exclude_layers) { - moving_platform_wall_layers = p_exclude_layers; +void CharacterBody3D::set_platform_wall_layers(uint32_t p_exclude_layers) { + platform_wall_layers = p_exclude_layers; } void CharacterBody3D::set_motion_mode(MotionMode p_mode) { @@ -1877,12 +1882,12 @@ CharacterBody3D::MotionMode CharacterBody3D::get_motion_mode() const { return motion_mode; } -void CharacterBody3D::set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_apply_velocity) { - moving_platform_apply_velocity_on_leave = p_on_leave_apply_velocity; +void CharacterBody3D::set_platform_on_leave(PlatformOnLeave p_on_leave_apply_velocity) { + platform_on_leave = p_on_leave_apply_velocity; } -CharacterBody3D::MovingPlatformApplyVelocityOnLeave CharacterBody3D::get_moving_platform_apply_velocity_on_leave() const { - return moving_platform_apply_velocity_on_leave; +CharacterBody3D::PlatformOnLeave CharacterBody3D::get_platform_on_leave() const { + return platform_on_leave; } int CharacterBody3D::get_max_slides() const { @@ -1947,7 +1952,7 @@ void CharacterBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &CharacterBody3D::set_velocity); ClassDB::bind_method(D_METHOD("get_velocity"), &CharacterBody3D::get_velocity); - ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody3D::set_safe_margin); + ClassDB::bind_method(D_METHOD("set_safe_margin", "margin"), &CharacterBody3D::set_safe_margin); ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody3D::get_safe_margin); ClassDB::bind_method(D_METHOD("is_floor_stop_on_slope_enabled"), &CharacterBody3D::is_floor_stop_on_slope_enabled); ClassDB::bind_method(D_METHOD("set_floor_stop_on_slope_enabled", "enabled"), &CharacterBody3D::set_floor_stop_on_slope_enabled); @@ -1958,10 +1963,10 @@ void CharacterBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_slide_on_ceiling_enabled", "enabled"), &CharacterBody3D::set_slide_on_ceiling_enabled); ClassDB::bind_method(D_METHOD("is_slide_on_ceiling_enabled"), &CharacterBody3D::is_slide_on_ceiling_enabled); - ClassDB::bind_method(D_METHOD("set_moving_platform_floor_layers", "exclude_layer"), &CharacterBody3D::set_moving_platform_floor_layers); - ClassDB::bind_method(D_METHOD("get_moving_platform_floor_layers"), &CharacterBody3D::get_moving_platform_floor_layers); - ClassDB::bind_method(D_METHOD("set_moving_platform_wall_layers", "exclude_layer"), &CharacterBody3D::set_moving_platform_wall_layers); - ClassDB::bind_method(D_METHOD("get_moving_platform_wall_layers"), &CharacterBody3D::get_moving_platform_wall_layers); + ClassDB::bind_method(D_METHOD("set_platform_floor_layers", "exclude_layer"), &CharacterBody3D::set_platform_floor_layers); + ClassDB::bind_method(D_METHOD("get_platform_floor_layers"), &CharacterBody3D::get_platform_floor_layers); + ClassDB::bind_method(D_METHOD("set_platform_wall_layers", "exclude_layer"), &CharacterBody3D::set_platform_wall_layers); + ClassDB::bind_method(D_METHOD("get_platform_wall_layers"), &CharacterBody3D::get_platform_wall_layers); ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody3D::get_max_slides); ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody3D::set_max_slides); @@ -1975,8 +1980,8 @@ void CharacterBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody3D::set_up_direction); ClassDB::bind_method(D_METHOD("set_motion_mode", "mode"), &CharacterBody3D::set_motion_mode); ClassDB::bind_method(D_METHOD("get_motion_mode"), &CharacterBody3D::get_motion_mode); - ClassDB::bind_method(D_METHOD("set_moving_platform_apply_velocity_on_leave", "on_leave_apply_velocity"), &CharacterBody3D::set_moving_platform_apply_velocity_on_leave); - ClassDB::bind_method(D_METHOD("get_moving_platform_apply_velocity_on_leave"), &CharacterBody3D::get_moving_platform_apply_velocity_on_leave); + ClassDB::bind_method(D_METHOD("set_platform_on_leave", "on_leave_apply_velocity"), &CharacterBody3D::set_platform_on_leave); + ClassDB::bind_method(D_METHOD("get_platform_on_leave"), &CharacterBody3D::get_platform_on_leave); ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody3D::is_on_floor); ClassDB::bind_method(D_METHOD("is_on_floor_only"), &CharacterBody3D::is_on_floor_only); @@ -2001,24 +2006,28 @@ void CharacterBody3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "velocity", PROPERTY_HINT_NONE, "suffix:m/s", PROPERTY_USAGE_NO_EDITOR), "set_velocity", "get_velocity"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_slides", "get_max_slides"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle"); + ADD_GROUP("Floor", "floor_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_stop_on_slope"), "set_floor_stop_on_slope_enabled", "is_floor_stop_on_slope_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_constant_speed"), "set_floor_constant_speed_enabled", "is_floor_constant_speed_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_block_on_wall"), "set_floor_block_on_wall_enabled", "is_floor_block_on_wall_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,1,0.01,or_greater,suffix:m"), "set_floor_snap_length", "get_floor_snap_length"); - ADD_GROUP("Moving Platform", "moving_platform"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_apply_velocity_on_leave", PROPERTY_HINT_ENUM, "Always,Upward Only,Never", PROPERTY_USAGE_DEFAULT), "set_moving_platform_apply_velocity_on_leave", "get_moving_platform_apply_velocity_on_leave"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_floor_layers", "get_moving_platform_floor_layers"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_wall_layers", "get_moving_platform_wall_layers"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001,suffix:m"), "set_safe_margin", "get_safe_margin"); + + ADD_GROUP("Moving Platform", "platform_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_on_leave", PROPERTY_HINT_ENUM, "Add Velocity,Add Upward Velocity,Do Nothing", PROPERTY_USAGE_DEFAULT), "set_platform_on_leave", "get_platform_on_leave"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_platform_floor_layers", "get_platform_floor_layers"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_platform_wall_layers", "get_platform_wall_layers"); + + ADD_GROUP("Collision", ""); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001,suffix:m"), "set_safe_margin", "get_safe_margin"); BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED); BIND_ENUM_CONSTANT(MOTION_MODE_FLOATING); - BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_ALWAYS); - BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY); - BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_NEVER); + BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_ADD_VELOCITY); + BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY); + BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_DO_NOTHING); } void CharacterBody3D::_validate_property(PropertyInfo &p_property) const { diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index 5d466f7e3c..14a1cf7228 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -300,11 +300,12 @@ public: void set_max_contacts_reported(int p_amount); int get_max_contacts_reported() const; + int get_contact_count() const; void set_use_continuous_collision_detection(bool p_enable); bool is_using_continuous_collision_detection() const; - Array get_colliding_bodies() const; + TypedArray<Node3D> get_colliding_bodies() const; void apply_central_impulse(const Vector3 &p_impulse); void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3()); @@ -347,10 +348,10 @@ public: MOTION_MODE_GROUNDED, MOTION_MODE_FLOATING, }; - enum MovingPlatformApplyVelocityOnLeave { - PLATFORM_VEL_ON_LEAVE_ALWAYS, - PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY, - PLATFORM_VEL_ON_LEAVE_NEVER, + enum PlatformOnLeave { + PLATFORM_ON_LEAVE_ADD_VELOCITY, + PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY, + PLATFORM_ON_LEAVE_DO_NOTHING, }; bool move_and_slide(); @@ -382,7 +383,7 @@ public: private: real_t margin = 0.001; MotionMode motion_mode = MOTION_MODE_GROUNDED; - MovingPlatformApplyVelocityOnLeave moving_platform_apply_velocity_on_leave = PLATFORM_VEL_ON_LEAVE_ALWAYS; + PlatformOnLeave platform_on_leave = PLATFORM_ON_LEAVE_ADD_VELOCITY; union CollisionState { uint32_t state = 0; struct { @@ -410,8 +411,8 @@ private: int platform_layer = 0; RID platform_rid; ObjectID platform_object_id; - uint32_t moving_platform_floor_layers = UINT32_MAX; - uint32_t moving_platform_wall_layers = 0; + uint32_t platform_floor_layers = UINT32_MAX; + uint32_t platform_wall_layers = 0; real_t floor_snap_length = 0.1; real_t floor_max_angle = Math::deg2rad((real_t)45.0); real_t wall_min_slide_angle = Math::deg2rad((real_t)15.0); @@ -456,17 +457,17 @@ private: real_t get_wall_min_slide_angle() const; void set_wall_min_slide_angle(real_t p_radians); - uint32_t get_moving_platform_floor_layers() const; - void set_moving_platform_floor_layers(const uint32_t p_exclude_layer); + uint32_t get_platform_floor_layers() const; + void set_platform_floor_layers(const uint32_t p_exclude_layer); - uint32_t get_moving_platform_wall_layers() const; - void set_moving_platform_wall_layers(const uint32_t p_exclude_layer); + uint32_t get_platform_wall_layers() const; + void set_platform_wall_layers(const uint32_t p_exclude_layer); void set_motion_mode(MotionMode p_mode); MotionMode get_motion_mode() const; - void set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_velocity); - MovingPlatformApplyVelocityOnLeave get_moving_platform_apply_velocity_on_leave() const; + void set_platform_on_leave(PlatformOnLeave p_on_leave_velocity); + PlatformOnLeave get_platform_on_leave() const; void _move_and_slide_floating(double p_delta); void _move_and_slide_grounded(double p_delta, bool p_was_on_floor); @@ -487,7 +488,7 @@ protected: }; VARIANT_ENUM_CAST(CharacterBody3D::MotionMode); -VARIANT_ENUM_CAST(CharacterBody3D::MovingPlatformApplyVelocityOnLeave); +VARIANT_ENUM_CAST(CharacterBody3D::PlatformOnLeave); class KinematicCollision3D : public RefCounted { GDCLASS(KinematicCollision3D, RefCounted); diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 0cd7188c23..1bc138704e 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -613,42 +613,6 @@ Vector<int> Skeleton3D::get_bone_children(int p_bone) { return bones[p_bone].child_bones; } -void Skeleton3D::set_bone_children(int p_bone, Vector<int> p_children) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX(p_bone, bone_size); - bones.write[p_bone].child_bones = p_children; - - process_order_dirty = true; - rest_dirty = true; - _make_dirty(); -} - -void Skeleton3D::add_bone_child(int p_bone, int p_child) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX(p_bone, bone_size); - bones.write[p_bone].child_bones.push_back(p_child); - - process_order_dirty = true; - rest_dirty = true; - _make_dirty(); -} - -void Skeleton3D::remove_bone_child(int p_bone, int p_child) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX(p_bone, bone_size); - - int child_idx = bones[p_bone].child_bones.find(p_child); - if (child_idx >= 0) { - bones.write[p_bone].child_bones.remove_at(child_idx); - } else { - WARN_PRINT("Cannot remove child bone: Child bone not found."); - } - - process_order_dirty = true; - rest_dirty = true; - _make_dirty(); -} - Vector<int> Skeleton3D::get_parentless_bones() { _update_process_order(); return parentless_bones; @@ -1238,9 +1202,6 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("unparent_bone_and_rest", "bone_idx"), &Skeleton3D::unparent_bone_and_rest); ClassDB::bind_method(D_METHOD("get_bone_children", "bone_idx"), &Skeleton3D::get_bone_children); - ClassDB::bind_method(D_METHOD("set_bone_children", "bone_idx", "bone_children"), &Skeleton3D::set_bone_children); - ClassDB::bind_method(D_METHOD("add_bone_child", "bone_idx", "child_bone_idx"), &Skeleton3D::add_bone_child); - ClassDB::bind_method(D_METHOD("remove_bone_child", "bone_idx", "child_bone_idx"), &Skeleton3D::remove_bone_child); ClassDB::bind_method(D_METHOD("get_parentless_bones"), &Skeleton3D::get_parentless_bones); diff --git a/scene/3d/soft_dynamic_body_3d.cpp b/scene/3d/soft_dynamic_body_3d.cpp index c9eafc77e0..2650d62fa4 100644 --- a/scene/3d/soft_dynamic_body_3d.cpp +++ b/scene/3d/soft_dynamic_body_3d.cpp @@ -591,10 +591,10 @@ Vector<SoftDynamicBody3D::PinnedPoint> SoftDynamicBody3D::get_pinned_points_indi return pinned_points; } -Array SoftDynamicBody3D::get_collision_exceptions() { +TypedArray<PhysicsBody3D> SoftDynamicBody3D::get_collision_exceptions() { List<RID> exceptions; PhysicsServer3D::get_singleton()->soft_body_get_collision_exceptions(physics_rid, &exceptions); - Array ret; + TypedArray<PhysicsBody3D> ret; for (const RID &body : exceptions) { ObjectID instance_id = PhysicsServer3D::get_singleton()->body_get_object_instance_id(body); Object *obj = ObjectDB::get_instance(instance_id); diff --git a/scene/3d/soft_dynamic_body_3d.h b/scene/3d/soft_dynamic_body_3d.h index 04f3365f72..2b86fe2cae 100644 --- a/scene/3d/soft_dynamic_body_3d.h +++ b/scene/3d/soft_dynamic_body_3d.h @@ -34,6 +34,7 @@ #include "scene/3d/mesh_instance_3d.h" #include "servers/physics_server_3d.h" +class PhysicsBody3D; class SoftDynamicBody3D; class SoftDynamicBodyRenderingServerHandler : public PhysicsServer3DRenderingServerHandler { @@ -168,7 +169,7 @@ public: void set_drag_coefficient(real_t p_drag_coefficient); real_t get_drag_coefficient(); - Array get_collision_exceptions(); + TypedArray<PhysicsBody3D> get_collision_exceptions(); void add_collision_exception_with(Node *p_node); void remove_collision_exception_with(Node *p_node); diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 212d220ace..669c3eb7fd 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -1004,14 +1004,17 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const { names.sort_custom<StringName::AlphCompare>(); bool current_found = false; + bool is_first_element = true; - for (List<StringName>::Element *E = names.front(); E; E = E->next()) { - if (E->prev()) { + for (const StringName &E : names) { + if (!is_first_element) { p_property.hint_string += ","; + } else { + is_first_element = false; } - p_property.hint_string += String(E->get()); - if (animation == E->get()) { + p_property.hint_string += String(E); + if (animation == E) { current_found = true; } } diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 4b3d7fd0a6..afb52de307 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -403,7 +403,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s bool do_start = (p_seek && p_time == 0) || play_start || current == StringName(); if (do_start) { - if (p_state_machine->start_node != StringName() && p_seek && p_time == 0) { + if (p_state_machine->start_node != StringName() && p_seek && p_time == 0 && current == StringName()) { current = p_state_machine->start_node; } diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index dbc71cd9e7..7d9f83b7a2 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -479,12 +479,8 @@ Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, f case Variant::QUATERNION: { Quaternion i = p_initial_val; Quaternion d = p_delta_val; - Quaternion r; - - APPLY_EQUATION(x); - APPLY_EQUATION(y); - APPLY_EQUATION(z); - APPLY_EQUATION(w); + Quaternion r = i * d; + r = i.slerp(r, run_equation(p_trans, p_ease, p_time, 0.0, 1.0, p_duration)); return r; } diff --git a/scene/gui/aspect_ratio_container.cpp b/scene/gui/aspect_ratio_container.cpp index 75f19ac452..e4a79c7aa3 100644 --- a/scene/gui/aspect_ratio_container.cpp +++ b/scene/gui/aspect_ratio_container.cpp @@ -51,21 +51,33 @@ Size2 AspectRatioContainer::get_minimum_size() const { } void AspectRatioContainer::set_ratio(float p_ratio) { + if (ratio == p_ratio) { + return; + } ratio = p_ratio; queue_sort(); } void AspectRatioContainer::set_stretch_mode(StretchMode p_mode) { + if (stretch_mode == p_mode) { + return; + } stretch_mode = p_mode; queue_sort(); } void AspectRatioContainer::set_alignment_horizontal(AlignmentMode p_alignment_horizontal) { + if (alignment_horizontal == p_alignment_horizontal) { + return; + } alignment_horizontal = p_alignment_horizontal; queue_sort(); } void AspectRatioContainer::set_alignment_vertical(AlignmentMode p_alignment_vertical) { + if (alignment_vertical == p_alignment_vertical) { + return; + } alignment_vertical = p_alignment_vertical; queue_sort(); } diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index 776623f7ce..87a7355bb2 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -64,6 +64,8 @@ void BaseButton::gui_input(const Ref<InputEvent> &p_event) { bool button_masked = mouse_button.is_valid() && (mouse_button_to_mask(mouse_button->get_button_index()) & button_mask) != MouseButton::NONE; if (button_masked || ui_accept) { + was_mouse_pressed = button_masked; + on_action_event(p_event); return; } @@ -417,6 +419,10 @@ bool BaseButton::_is_focus_owner_in_shortcut_context() const { return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus)); } +bool BaseButton::_was_pressed_by_mouse() const { + return was_mouse_pressed; +} + void BaseButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &BaseButton::set_pressed); ClassDB::bind_method(D_METHOD("is_pressed"), &BaseButton::is_pressed); @@ -490,8 +496,8 @@ void ButtonGroup::get_buttons(List<BaseButton *> *r_buttons) { } } -Array ButtonGroup::_get_buttons() { - Array btns; +TypedArray<BaseButton> ButtonGroup::_get_buttons() { + TypedArray<BaseButton> btns; for (const BaseButton *E : buttons) { btns.push_back(E); } diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index 7cf8de6432..c83b08aadf 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -49,6 +49,7 @@ private: MouseButton button_mask = MouseButton::MASK_LEFT; bool toggle_mode = false; bool shortcut_in_tooltip = true; + bool was_mouse_pressed = false; bool keep_pressed_outside = false; Ref<Shortcut> shortcut; ObjectID shortcut_context; @@ -81,6 +82,7 @@ protected: void _notification(int p_what); bool _is_focus_owner_in_shortcut_context() const; + bool _was_pressed_by_mouse() const; GDVIRTUAL0(_pressed) GDVIRTUAL1(_toggled, bool) @@ -151,7 +153,7 @@ protected: public: BaseButton *get_pressed_button(); void get_buttons(List<BaseButton *> *r_buttons); - Array _get_buttons(); + TypedArray<BaseButton> _get_buttons(); ButtonGroup(); }; diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp index df695feba8..a56a51a547 100644 --- a/scene/gui/box_container.cpp +++ b/scene/gui/box_container.cpp @@ -308,6 +308,9 @@ void BoxContainer::_notification(int p_what) { } void BoxContainer::set_alignment(AlignmentMode p_alignment) { + if (alignment == p_alignment) { + return; + } alignment = p_alignment; _resort(); } diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 8968c1cc17..e54ba7ce13 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -1280,8 +1280,8 @@ void CodeEdit::clear_breakpointed_lines() { } } -Array CodeEdit::get_breakpointed_lines() const { - Array ret; +PackedInt32Array CodeEdit::get_breakpointed_lines() const { + PackedInt32Array ret; for (int i = 0; i < get_line_count(); i++) { if (is_line_breakpointed(i)) { ret.append(i); @@ -1309,8 +1309,8 @@ void CodeEdit::clear_bookmarked_lines() { } } -Array CodeEdit::get_bookmarked_lines() const { - Array ret; +PackedInt32Array CodeEdit::get_bookmarked_lines() const { + PackedInt32Array ret; for (int i = 0; i < get_line_count(); i++) { if (is_line_bookmarked(i)) { ret.append(i); @@ -1338,8 +1338,8 @@ void CodeEdit::clear_executing_lines() { } } -Array CodeEdit::get_executing_lines() const { - Array ret; +PackedInt32Array CodeEdit::get_executing_lines() const { + PackedInt32Array ret; for (int i = 0; i < get_line_count(); i++) { if (is_line_executing(i)) { ret.append(i); @@ -2769,7 +2769,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() { i++; } - Array completion_options; + TypedArray<Dictionary> completion_options; GDVIRTUAL_CALL(_filter_code_completion_candidates, completion_options_sources, completion_options); diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h index 08bd91a368..2065f3e681 100644 --- a/scene/gui/code_edit.h +++ b/scene/gui/code_edit.h @@ -266,7 +266,7 @@ protected: GDVIRTUAL1(_confirm_code_completion, bool) GDVIRTUAL1(_request_code_completion, bool) - GDVIRTUAL1RC(Array, _filter_code_completion_candidates, TypedArray<Dictionary>) + GDVIRTUAL1RC(TypedArray<Dictionary>, _filter_code_completion_candidates, TypedArray<Dictionary>) public: /* General overrides */ @@ -322,19 +322,19 @@ public: void set_line_as_breakpoint(int p_line, bool p_breakpointed); bool is_line_breakpointed(int p_line) const; void clear_breakpointed_lines(); - Array get_breakpointed_lines() const; + PackedInt32Array get_breakpointed_lines() const; // bookmarks void set_line_as_bookmarked(int p_line, bool p_bookmarked); bool is_line_bookmarked(int p_line) const; void clear_bookmarked_lines(); - Array get_bookmarked_lines() const; + PackedInt32Array get_bookmarked_lines() const; // executing lines void set_line_as_executing(int p_line, bool p_executing); bool is_line_executing(int p_line) const; void clear_executing_lines(); - Array get_executing_lines() const; + PackedInt32Array get_executing_lines() const; /* Line numbers */ void set_draw_line_numbers(bool p_draw); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 8cbe14c492..9eef45f412 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -292,6 +292,9 @@ bool ColorPicker::is_displaying_old_color() const { } void ColorPicker::set_edit_alpha(bool p_show) { + if (edit_alpha == p_show) { + return; + } edit_alpha = p_show; _update_controls(); @@ -509,6 +512,9 @@ Color ColorPicker::get_pick_color() const { void ColorPicker::set_picker_shape(PickerShapeType p_shape) { ERR_FAIL_INDEX(p_shape, SHAPE_MAX); + if (current_shape == p_shape) { + return; + } current_shape = p_shape; _copy_color_to_hsv(); @@ -1131,6 +1137,9 @@ void ColorPicker::_html_focus_exit() { } void ColorPicker::set_presets_enabled(bool p_enabled) { + if (presets_enabled == p_enabled) { + return; + } presets_enabled = p_enabled; if (!p_enabled) { btn_add_preset->set_disabled(true); @@ -1146,6 +1155,9 @@ bool ColorPicker::are_presets_enabled() const { } void ColorPicker::set_presets_visible(bool p_visible) { + if (presets_visible == p_visible) { + return; + } presets_visible = p_visible; preset_separator->set_visible(p_visible); preset_container->set_visible(p_visible); @@ -1419,6 +1431,9 @@ void ColorPickerButton::_notification(int p_what) { } void ColorPickerButton::set_pick_color(const Color &p_color) { + if (color == p_color) { + return; + } color = p_color; if (picker) { picker->set_pick_color(p_color); @@ -1432,6 +1447,9 @@ Color ColorPickerButton::get_pick_color() const { } void ColorPickerButton::set_edit_alpha(bool p_show) { + if (edit_alpha == p_show) { + return; + } edit_alpha = p_show; if (picker) { picker->set_edit_alpha(p_show); diff --git a/scene/gui/color_rect.cpp b/scene/gui/color_rect.cpp index 2955f74a0c..c30fa8461a 100644 --- a/scene/gui/color_rect.cpp +++ b/scene/gui/color_rect.cpp @@ -31,6 +31,9 @@ #include "color_rect.h" void ColorRect::set_color(const Color &p_color) { + if (color == p_color) { + return; + } color = p_color; update(); } diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 545c39a605..9b6a19c50a 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -252,36 +252,36 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) { if (name.begins_with("theme_override_icons/")) { String dname = name.get_slicec('/', 1); if (data.icon_override.has(dname)) { - data.icon_override[dname]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed)); + data.icon_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } data.icon_override.erase(dname); - notification(NOTIFICATION_THEME_CHANGED); + _notify_theme_override_changed(); } else if (name.begins_with("theme_override_styles/")) { String dname = name.get_slicec('/', 1); if (data.style_override.has(dname)) { - data.style_override[dname]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed)); + data.style_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } data.style_override.erase(dname); - notification(NOTIFICATION_THEME_CHANGED); + _notify_theme_override_changed(); } else if (name.begins_with("theme_override_fonts/")) { String dname = name.get_slicec('/', 1); if (data.font_override.has(dname)) { - data.font_override[dname]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed)); + data.font_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } data.font_override.erase(dname); - notification(NOTIFICATION_THEME_CHANGED); + _notify_theme_override_changed(); } else if (name.begins_with("theme_override_font_sizes/")) { String dname = name.get_slicec('/', 1); data.font_size_override.erase(dname); - notification(NOTIFICATION_THEME_CHANGED); + _notify_theme_override_changed(); } else if (name.begins_with("theme_override_colors/")) { String dname = name.get_slicec('/', 1); data.color_override.erase(dname); - notification(NOTIFICATION_THEME_CHANGED); + _notify_theme_override_changed(); } else if (name.begins_with("theme_override_constants/")) { String dname = name.get_slicec('/', 1); data.constant_override.erase(dname); - notification(NOTIFICATION_THEME_CHANGED); + _notify_theme_override_changed(); } else { return false; } @@ -723,6 +723,9 @@ real_t Control::get_anchor(Side p_side) const { void Control::set_offset(Side p_side, real_t p_value) { ERR_FAIL_INDEX((int)p_side, 4); + if (data.offset[p_side] == p_value) { + return; + } data.offset[p_side] = p_value; _size_changed(); @@ -740,6 +743,10 @@ void Control::set_anchor_and_offset(Side p_side, real_t p_anchor, real_t p_pos, } void Control::set_begin(const Size2 &p_point) { + if (data.offset[0] == p_point.x && data.offset[1] == p_point.y) { + return; + } + data.offset[0] = p_point.x; data.offset[1] = p_point.y; _size_changed(); @@ -750,6 +757,10 @@ Size2 Control::get_begin() const { } void Control::set_end(const Size2 &p_point) { + if (data.offset[2] == p_point.x && data.offset[3] == p_point.y) { + return; + } + data.offset[2] = p_point.x; data.offset[3] = p_point.y; _size_changed(); @@ -760,6 +771,10 @@ Size2 Control::get_end() const { } void Control::set_h_grow_direction(GrowDirection p_direction) { + if (data.h_grow == p_direction) { + return; + } + ERR_FAIL_INDEX((int)p_direction, 3); data.h_grow = p_direction; @@ -771,6 +786,10 @@ Control::GrowDirection Control::get_h_grow_direction() const { } void Control::set_v_grow_direction(GrowDirection p_direction) { + if (data.v_grow == p_direction) { + return; + } + ERR_FAIL_INDEX((int)p_direction, 3); data.v_grow = p_direction; @@ -1427,6 +1446,10 @@ Rect2 Control::get_anchorable_rect() const { } void Control::set_scale(const Vector2 &p_scale) { + if (data.scale == p_scale) { + return; + } + data.scale = p_scale; // Avoid having 0 scale values, can lead to errors in physics and rendering. if (data.scale.x == 0) { @@ -1444,6 +1467,10 @@ Vector2 Control::get_scale() const { } void Control::set_rotation(real_t p_radians) { + if (data.rotation == p_radians) { + return; + } + data.rotation = p_radians; update(); _notify_transform(); @@ -1454,6 +1481,10 @@ real_t Control::get_rotation() const { } void Control::set_pivot_offset(const Vector2 &p_pivot) { + if (data.pivot_offset == p_pivot) { + return; + } + data.pivot_offset = p_pivot; update(); _notify_transform(); @@ -2204,6 +2235,9 @@ Control::CursorShape Control::get_cursor_shape(const Point2 &p_pos) const { } void Control::set_disable_visibility_clip(bool p_ignore) { + if (data.disable_visibility_clip == p_ignore) { + return; + } data.disable_visibility_clip = p_ignore; update(); } @@ -2213,6 +2247,9 @@ bool Control::is_visibility_clip_disabled() const { } void Control::set_clip_contents(bool p_clip) { + if (data.clip_contents == p_clip) { + return; + } data.clip_contents = p_clip; update(); } @@ -2223,62 +2260,62 @@ bool Control::is_clipping_contents() { // Theming. -void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign) { +void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_notify, bool p_assign) { Control *c = Object::cast_to<Control>(p_at); - - if (c && c != p_owner && c->data.theme.is_valid()) { // has a theme, this can't be propagated - return; - } - Window *w = c == nullptr ? Object::cast_to<Window>(p_at) : nullptr; - if (w && w != p_owner_window && w->theme.is_valid()) { // has a theme, this can't be propagated + if (!c && !w) { + // Theme inheritance chains are broken by nodes that aren't Control or Window. return; } - for (int i = 0; i < p_at->get_child_count(); i++) { - CanvasItem *child = Object::cast_to<CanvasItem>(p_at->get_child(i)); - if (child) { - _propagate_theme_changed(child, p_owner, p_owner_window, p_assign); - } else { - Window *window = Object::cast_to<Window>(p_at->get_child(i)); - if (window) { - _propagate_theme_changed(window, p_owner, p_owner_window, p_assign); - } + bool assign = p_assign; + if (c) { + if (c != p_owner && c->data.theme.is_valid()) { + // Has a theme, so we don't want to change the theme owner, + // but we still want to propagate in case this child has theme items + // it inherits from the theme this node uses. + // See https://github.com/godotengine/godot/issues/62844. + assign = false; } - } - if (c) { - if (p_assign) { + if (assign) { c->data.theme_owner = p_owner; c->data.theme_owner_window = p_owner_window; } - c->notification(Control::NOTIFICATION_THEME_CHANGED); - c->emit_signal(SceneStringNames::get_singleton()->theme_changed); - } - if (w) { - if (p_assign) { + if (p_notify) { + c->notification(Control::NOTIFICATION_THEME_CHANGED); + } + } else if (w) { + if (w != p_owner_window && w->theme.is_valid()) { + // Same as above. + assign = false; + } + + if (assign) { w->theme_owner = p_owner; w->theme_owner_window = p_owner_window; } - w->notification(Window::NOTIFICATION_THEME_CHANGED); - w->emit_signal(SceneStringNames::get_singleton()->theme_changed); + + if (p_notify) { + w->notification(Window::NOTIFICATION_THEME_CHANGED); + } } -} -void Control::_theme_changed() { - _propagate_theme_changed(this, this, nullptr, false); + for (int i = 0; i < p_at->get_child_count(); i++) { + _propagate_theme_changed(p_at->get_child(i), p_owner, p_owner_window, p_notify, assign); + } } -void Control::_theme_property_override_changed() { - notification(NOTIFICATION_THEME_CHANGED); - emit_signal(SceneStringNames::get_singleton()->theme_changed); - update_minimum_size(); // Overrides are likely to affect minimum size. +void Control::_theme_changed() { + if (is_inside_tree()) { + _propagate_theme_changed(this, this, nullptr, true, false); + } } -void Control::_notify_theme_changed() { - if (!data.bulk_theme_override) { +void Control::_notify_theme_override_changed() { + if (!data.bulk_theme_override && is_inside_tree()) { notification(NOTIFICATION_THEME_CHANGED); } } @@ -2302,28 +2339,25 @@ void Control::set_theme(const Ref<Theme> &p_theme) { } data.theme = p_theme; - if (!p_theme.is_null()) { - data.theme_owner = this; - data.theme_owner_window = nullptr; - _propagate_theme_changed(this, this, nullptr); - } else { - Control *parent_c = Object::cast_to<Control>(get_parent()); + if (data.theme.is_valid()) { + _propagate_theme_changed(this, this, nullptr, is_inside_tree(), true); + data.theme->connect("changed", callable_mp(this, &Control::_theme_changed), CONNECT_DEFERRED); + return; + } - if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) { - Control::_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window); - } else { - Window *parent_w = cast_to<Window>(get_parent()); - if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) { - Control::_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window); - } else { - Control::_propagate_theme_changed(this, nullptr, nullptr); - } - } + Control *parent_c = Object::cast_to<Control>(get_parent()); + if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) { + _propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window, is_inside_tree(), true); + return; } - if (data.theme.is_valid()) { - data.theme->connect("changed", callable_mp(this, &Control::_theme_changed), CONNECT_DEFERRED); + Window *parent_w = cast_to<Window>(get_parent()); + if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) { + _propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window, is_inside_tree(), true); + return; } + + _propagate_theme_changed(this, nullptr, nullptr, is_inside_tree(), true); } Ref<Theme> Control::get_theme() const { @@ -2331,8 +2365,13 @@ Ref<Theme> Control::get_theme() const { } void Control::set_theme_type_variation(const StringName &p_theme_type) { + if (data.theme_type_variation == p_theme_type) { + return; + } data.theme_type_variation = p_theme_type; - _propagate_theme_changed(this, data.theme_owner, data.theme_owner_window); + if (is_inside_tree()) { + notification(NOTIFICATION_THEME_CHANGED); + } } StringName Control::get_theme_type_variation() const { @@ -2657,93 +2696,93 @@ void Control::add_theme_icon_override(const StringName &p_name, const Ref<Textur ERR_FAIL_COND(!p_icon.is_valid()); if (data.icon_override.has(p_name)) { - data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed)); + data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } data.icon_override[p_name] = p_icon; - data.icon_override[p_name]->connect("changed", callable_mp(this, &Control::_theme_property_override_changed), CONNECT_REFERENCE_COUNTED); - _notify_theme_changed(); + data.icon_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED); + _notify_theme_override_changed(); } void Control::add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) { ERR_FAIL_COND(!p_style.is_valid()); if (data.style_override.has(p_name)) { - data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed)); + data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } data.style_override[p_name] = p_style; - data.style_override[p_name]->connect("changed", callable_mp(this, &Control::_theme_property_override_changed), CONNECT_REFERENCE_COUNTED); - _notify_theme_changed(); + data.style_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED); + _notify_theme_override_changed(); } void Control::add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font) { ERR_FAIL_COND(!p_font.is_valid()); if (data.font_override.has(p_name)) { - data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed)); + data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } data.font_override[p_name] = p_font; - data.font_override[p_name]->connect("changed", callable_mp(this, &Control::_theme_property_override_changed), CONNECT_REFERENCE_COUNTED); - _notify_theme_changed(); + data.font_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED); + _notify_theme_override_changed(); } void Control::add_theme_font_size_override(const StringName &p_name, int p_font_size) { data.font_size_override[p_name] = p_font_size; - _notify_theme_changed(); + _notify_theme_override_changed(); } void Control::add_theme_color_override(const StringName &p_name, const Color &p_color) { data.color_override[p_name] = p_color; - _notify_theme_changed(); + _notify_theme_override_changed(); } void Control::add_theme_constant_override(const StringName &p_name, int p_constant) { data.constant_override[p_name] = p_constant; - _notify_theme_changed(); + _notify_theme_override_changed(); } void Control::remove_theme_icon_override(const StringName &p_name) { if (data.icon_override.has(p_name)) { - data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed)); + data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } data.icon_override.erase(p_name); - _notify_theme_changed(); + _notify_theme_override_changed(); } void Control::remove_theme_style_override(const StringName &p_name) { if (data.style_override.has(p_name)) { - data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed)); + data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } data.style_override.erase(p_name); - _notify_theme_changed(); + _notify_theme_override_changed(); } void Control::remove_theme_font_override(const StringName &p_name) { if (data.font_override.has(p_name)) { - data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed)); + data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } data.font_override.erase(p_name); - _notify_theme_changed(); + _notify_theme_override_changed(); } void Control::remove_theme_font_size_override(const StringName &p_name) { data.font_size_override.erase(p_name); - _notify_theme_changed(); + _notify_theme_override_changed(); } void Control::remove_theme_color_override(const StringName &p_name) { data.color_override.erase(p_name); - _notify_theme_changed(); + _notify_theme_override_changed(); } void Control::remove_theme_constant_override(const StringName &p_name) { data.constant_override.erase(p_name); - _notify_theme_changed(); + _notify_theme_override_changed(); } bool Control::has_theme_icon_override(const StringName &p_name) const { @@ -2941,18 +2980,18 @@ void Control::end_bulk_theme_override() { ERR_FAIL_COND(!data.bulk_theme_override); data.bulk_theme_override = false; - _notify_theme_changed(); + _notify_theme_override_changed(); } // Internationalization. -Array Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { +TypedArray<Vector2i> Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { if (p_parser_type == TextServer::STRUCTURED_TEXT_CUSTOM) { - Array ret; + TypedArray<Vector2i> ret; if (GDVIRTUAL_CALL(_structured_text_parser, p_args, p_text, ret)) { return ret; } else { - return Array(); + return TypedArray<Vector2i>(); } } else { return TS->parse_structured_text(p_parser_type, p_args, p_text); @@ -2960,6 +2999,9 @@ Array Control::structured_text_parser(TextServer::StructuredTextParser p_parser_ } void Control::set_layout_direction(Control::LayoutDirection p_direction) { + if (data.layout_dir == p_direction) { + return; + } ERR_FAIL_INDEX((int)p_direction, 4); data.layout_dir = p_direction; @@ -3044,37 +3086,26 @@ Control *Control::make_custom_tooltip(const String &p_text) const { // Base object overrides. void Control::add_child_notify(Node *p_child) { - Control *child_c = Object::cast_to<Control>(p_child); - - if (child_c && child_c->data.theme.is_null() && (data.theme_owner || data.theme_owner_window)) { - _propagate_theme_changed(child_c, data.theme_owner, data.theme_owner_window); //need to propagate here, since many controls may require setting up stuff - } - - Window *child_w = Object::cast_to<Window>(p_child); - - if (child_w && child_w->theme.is_null() && (data.theme_owner || data.theme_owner_window)) { - _propagate_theme_changed(child_w, data.theme_owner, data.theme_owner_window); //need to propagate here, since many controls may require setting up stuff + // We propagate when this node uses a custom theme, so it can pass it on to its children. + if (data.theme_owner || data.theme_owner_window) { + // `p_notify` is false here as `NOTIFICATION_THEME_CHANGED` will be handled by `NOTIFICATION_ENTER_TREE`. + _propagate_theme_changed(p_child, data.theme_owner, data.theme_owner_window, false, true); } } void Control::remove_child_notify(Node *p_child) { - Control *child_c = Object::cast_to<Control>(p_child); - - if (child_c && (child_c->data.theme_owner || child_c->data.theme_owner_window) && child_c->data.theme.is_null()) { - _propagate_theme_changed(child_c, nullptr, nullptr); - } - - Window *child_w = Object::cast_to<Window>(p_child); - - if (child_w && (child_w->theme_owner || child_w->theme_owner_window) && child_w->theme.is_null()) { - _propagate_theme_changed(child_w, nullptr, nullptr); + // If the removed child isn't inheriting any theme items through this node, then there's no need to propagate. + if (data.theme_owner || data.theme_owner_window) { + _propagate_theme_changed(p_child, nullptr, nullptr, false, true); } } void Control::_notification(int p_notification) { switch (p_notification) { case NOTIFICATION_ENTER_TREE: { - _invalidate_theme_cache(); + // Need to defer here, because theme owner information might be set in + // add_child_notify, which doesn't get called until right after this. + call_deferred(SNAME("notification"), NOTIFICATION_THEME_CHANGED); } break; case NOTIFICATION_POST_ENTER_TREE: { @@ -3099,18 +3130,6 @@ void Control::_notification(int p_notification) { data.parent_window = Object::cast_to<Window>(get_parent()); data.is_rtl_dirty = true; - if (data.theme.is_null()) { - if (data.parent && (data.parent->data.theme_owner || data.parent->data.theme_owner_window)) { - data.theme_owner = data.parent->data.theme_owner; - data.theme_owner_window = data.parent->data.theme_owner_window; - notification(NOTIFICATION_THEME_CHANGED); - } else if (data.parent_window && (data.parent_window->theme_owner || data.parent_window->theme_owner_window)) { - data.theme_owner = data.parent_window->theme_owner; - data.theme_owner_window = data.parent_window->theme_owner_window; - notification(NOTIFICATION_THEME_CHANGED); - } - } - CanvasItem *node = this; bool has_parent_control = false; @@ -3214,6 +3233,7 @@ void Control::_notification(int p_notification) { } break; case NOTIFICATION_THEME_CHANGED: { + emit_signal(SceneStringNames::get_singleton()->theme_changed); _invalidate_theme_cache(); update_minimum_size(); update(); @@ -3579,3 +3599,24 @@ void Control::_bind_methods() { GDVIRTUAL_BIND(_gui_input, "event"); } + +Control::~Control() { + // Resources need to be disconnected. + for (KeyValue<StringName, Ref<Texture2D>> &E : data.icon_override) { + E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); + } + for (KeyValue<StringName, Ref<StyleBox>> &E : data.style_override) { + E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); + } + for (KeyValue<StringName, Ref<Font>> &E : data.font_override) { + E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); + } + + // Then override maps can be simply cleared. + data.icon_override.clear(); + data.style_override.clear(); + data.font_override.clear(); + data.font_size_override.clear(); + data.color_override.clear(); + data.constant_override.clear(); +} diff --git a/scene/gui/control.h b/scene/gui/control.h index a50c66b634..82d3d8d24a 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -300,11 +300,10 @@ private: // Theming. void _theme_changed(); - void _theme_property_override_changed(); - void _notify_theme_changed(); + void _notify_theme_override_changed(); void _invalidate_theme_cache(); - static void _propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign = true); + static void _propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_notify, bool p_assign); template <class T> static T get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types); @@ -328,7 +327,7 @@ protected: // Internationalization. - virtual Array structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; + virtual TypedArray<Vector2i> structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; // Base object overrides. @@ -341,7 +340,7 @@ protected: // Exposed virtual methods. GDVIRTUAL1RC(bool, _has_point, Vector2) - GDVIRTUAL2RC(Array, _structured_text_parser, Array, String) + GDVIRTUAL2RC(TypedArray<Vector2i>, _structured_text_parser, Array, String) GDVIRTUAL0RC(Vector2, _get_minimum_size) GDVIRTUAL1RC(Variant, _get_drag_data, Vector2) @@ -610,6 +609,7 @@ public: virtual Control *make_custom_tooltip(const String &p_text) const; Control() {} + ~Control(); }; VARIANT_ENUM_CAST(Control::FocusMode); diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index f075510aa4..b4e0747ab8 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -130,6 +130,9 @@ String AcceptDialog::get_text() const { } void AcceptDialog::set_text(String p_text) { + if (label->get_text() == p_text) { + return; + } label->set_text(p_text); child_controls_changed(); if (is_visible()) { diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index e26976a402..7965b12edd 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -685,6 +685,9 @@ void FileDialog::add_filter(const String &p_filter, const String &p_description) } void FileDialog::set_filters(const Vector<String> &p_filters) { + if (filters == p_filters) { + return; + } filters = p_filters; update_filters(); invalidate(); @@ -708,10 +711,14 @@ String FileDialog::get_current_path() const { void FileDialog::set_current_dir(const String &p_dir) { _change_dir(p_dir); + _push_history(); } void FileDialog::set_current_file(const String &p_file) { + if (file->get_text() == p_file) { + return; + } file->set_text(p_file); update_dir(); invalidate(); @@ -764,7 +771,9 @@ bool FileDialog::is_mode_overriding_title() const { void FileDialog::set_file_mode(FileMode p_mode) { ERR_FAIL_INDEX((int)p_mode, 5); - + if (mode == p_mode) { + return; + } mode = p_mode; switch (mode) { case FILE_MODE_OPEN_FILE: @@ -977,6 +986,9 @@ void FileDialog::_bind_methods() { } void FileDialog::set_show_hidden_files(bool p_show) { + if (show_hidden_files == p_show) { + return; + } show_hidden_files = p_show; invalidate(); } diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 8d3a61b52e..e6198b44ff 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -1591,10 +1591,10 @@ void GraphEdit::remove_valid_left_disconnect_type(int p_type) { valid_left_disconnect_types.erase(p_type); } -Array GraphEdit::_get_connection_list() const { +TypedArray<Dictionary> GraphEdit::_get_connection_list() const { List<Connection> conns; get_connection_list(&conns); - Array arr; + TypedArray<Dictionary> arr; for (const Connection &E : conns) { Dictionary d; d["from"] = E.from; @@ -1640,6 +1640,9 @@ bool GraphEdit::is_valid_connection_type(int p_type, int p_with_type) const { } void GraphEdit::set_use_snap(bool p_enable) { + if (snap_button->is_pressed() == p_enable) { + return; + } snap_button->set_pressed(p_enable); update(); } @@ -1683,6 +1686,9 @@ Vector2 GraphEdit::get_minimap_size() const { } void GraphEdit::set_minimap_opacity(float p_opacity) { + if (minimap->get_modulate().a == p_opacity) { + return; + } minimap->set_modulate(Color(1, 1, 1, p_opacity)); minimap->update(); } @@ -1693,6 +1699,9 @@ float GraphEdit::get_minimap_opacity() const { } void GraphEdit::set_minimap_enabled(bool p_enable) { + if (minimap_button->is_pressed() == p_enable) { + return; + } minimap_button->set_pressed(p_enable); _minimap_toggled(); minimap->update(); @@ -1721,6 +1730,9 @@ float GraphEdit::get_connection_lines_curvature() const { } void GraphEdit::set_connection_lines_thickness(float p_thickness) { + if (lines_thickness == p_thickness) { + return; + } lines_thickness = p_thickness; update(); } @@ -1730,6 +1742,9 @@ float GraphEdit::get_connection_lines_thickness() const { } void GraphEdit::set_connection_lines_antialiased(bool p_antialiased) { + if (lines_antialiased == p_antialiased) { + return; + } lines_antialiased = p_antialiased; update(); } diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index cf35aeb8b2..b8c9be9983 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -206,7 +206,7 @@ private: void _minimap_draw(); void _update_scroll_offset(); - Array _get_connection_list() const; + TypedArray<Dictionary> _get_connection_list() const; bool lines_on_bg = false; diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 582519e70f..7d31e929dc 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -32,9 +32,7 @@ #include "core/string/translation.h" -#ifdef TOOLS_ENABLED #include "graph_edit.h" -#endif struct _MinSizeCache { int min_size; @@ -445,6 +443,7 @@ void GraphNode::_edit_set_position(const Point2 &p_position) { } set_position(p_position); } +#endif void GraphNode::_validate_property(PropertyInfo &p_property) const { GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent()); @@ -454,7 +453,6 @@ void GraphNode::_validate_property(PropertyInfo &p_property) const { } } } -#endif void GraphNode::set_slot(int p_idx, bool p_enable_left, int p_type_left, const Color &p_color_left, bool p_enable_right, int p_type_right, const Color &p_color_right, const Ref<Texture2D> &p_custom_left, const Ref<Texture2D> &p_custom_right, bool p_draw_stylebox) { ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set slot with p_idx (%d) lesser than zero.", p_idx)); @@ -505,6 +503,10 @@ bool GraphNode::is_slot_enabled_left(int p_idx) const { void GraphNode::set_slot_enabled_left(int p_idx, bool p_enable_left) { ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set enable_left for the slot with p_idx (%d) lesser than zero.", p_idx)); + if (slot_info[p_idx].enable_left == p_enable_left) { + return; + } + slot_info[p_idx].enable_left = p_enable_left; update(); connpos_dirty = true; @@ -515,6 +517,10 @@ void GraphNode::set_slot_enabled_left(int p_idx, bool p_enable_left) { void GraphNode::set_slot_type_left(int p_idx, int p_type_left) { ERR_FAIL_COND_MSG(!slot_info.has(p_idx), vformat("Cannot set type_left for the slot '%d' because it hasn't been enabled.", p_idx)); + if (slot_info[p_idx].type_left == p_type_left) { + return; + } + slot_info[p_idx].type_left = p_type_left; update(); connpos_dirty = true; @@ -532,6 +538,10 @@ int GraphNode::get_slot_type_left(int p_idx) const { void GraphNode::set_slot_color_left(int p_idx, const Color &p_color_left) { ERR_FAIL_COND_MSG(!slot_info.has(p_idx), vformat("Cannot set color_left for the slot '%d' because it hasn't been enabled.", p_idx)); + if (slot_info[p_idx].color_left == p_color_left) { + return; + } + slot_info[p_idx].color_left = p_color_left; update(); connpos_dirty = true; @@ -556,6 +566,10 @@ bool GraphNode::is_slot_enabled_right(int p_idx) const { void GraphNode::set_slot_enabled_right(int p_idx, bool p_enable_right) { ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set enable_right for the slot with p_idx (%d) lesser than zero.", p_idx)); + if (slot_info[p_idx].enable_right == p_enable_right) { + return; + } + slot_info[p_idx].enable_right = p_enable_right; update(); connpos_dirty = true; @@ -566,6 +580,10 @@ void GraphNode::set_slot_enabled_right(int p_idx, bool p_enable_right) { void GraphNode::set_slot_type_right(int p_idx, int p_type_right) { ERR_FAIL_COND_MSG(!slot_info.has(p_idx), vformat("Cannot set type_right for the slot '%d' because it hasn't been enabled.", p_idx)); + if (slot_info[p_idx].type_right == p_type_right) { + return; + } + slot_info[p_idx].type_right = p_type_right; update(); connpos_dirty = true; @@ -583,6 +601,10 @@ int GraphNode::get_slot_type_right(int p_idx) const { void GraphNode::set_slot_color_right(int p_idx, const Color &p_color_right) { ERR_FAIL_COND_MSG(!slot_info.has(p_idx), vformat("Cannot set color_right for the slot '%d' because it hasn't been enabled.", p_idx)); + if (slot_info[p_idx].color_right == p_color_right) { + return; + } + slot_info[p_idx].color_right = p_color_right; update(); connpos_dirty = true; @@ -700,6 +722,10 @@ String GraphNode::get_language() const { } void GraphNode::set_position_offset(const Vector2 &p_offset) { + if (position_offset == p_offset) { + return; + } + position_offset = p_offset; emit_signal(SNAME("position_offset_changed")); update(); @@ -710,6 +736,10 @@ Vector2 GraphNode::get_position_offset() const { } void GraphNode::set_selected(bool p_selected) { + if (selected == p_selected) { + return; + } + selected = p_selected; update(); } @@ -731,6 +761,10 @@ Vector2 GraphNode::get_drag_from() { } void GraphNode::set_show_close_button(bool p_enable) { + if (show_close == p_enable) { + return; + } + show_close = p_enable; update(); } @@ -931,6 +965,10 @@ void GraphNode::gui_input(const Ref<InputEvent> &p_ev) { } void GraphNode::set_overlay(Overlay p_overlay) { + if (overlay == p_overlay) { + return; + } + overlay = p_overlay; update(); } @@ -940,6 +978,10 @@ GraphNode::Overlay GraphNode::get_overlay() const { } void GraphNode::set_comment(bool p_enable) { + if (comment == p_enable) { + return; + } + comment = p_enable; update(); } @@ -949,6 +991,10 @@ bool GraphNode::is_comment() const { } void GraphNode::set_resizable(bool p_enable) { + if (resizable == p_enable) { + return; + } + resizable = p_enable; update(); } diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h index 6d5bb4361e..d575b6ceed 100644 --- a/scene/gui/graph_node.h +++ b/scene/gui/graph_node.h @@ -101,7 +101,6 @@ private: #ifdef TOOLS_ENABLED void _edit_set_position(const Point2 &p_position) override; - void _validate_property(PropertyInfo &p_property) const; #endif protected: @@ -112,6 +111,7 @@ protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + void _validate_property(PropertyInfo &p_property) const; public: bool has_point(const Point2 &p_point) const override; diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp index eaa6943ad2..3163d17846 100644 --- a/scene/gui/grid_container.cpp +++ b/scene/gui/grid_container.cpp @@ -246,6 +246,11 @@ void GridContainer::_notification(int p_what) { void GridContainer::set_columns(int p_columns) { ERR_FAIL_COND(p_columns < 1); + + if (columns == p_columns) { + return; + } + columns = p_columns; queue_sort(); update_minimum_size(); diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index e3e9499705..086f729603 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -88,6 +88,10 @@ void ItemList::set_item_text(int p_idx, const String &p_text) { } ERR_FAIL_INDEX(p_idx, items.size()); + if (items[p_idx].text == p_text) { + return; + } + items.write[p_idx].text = p_text; _shape(p_idx); update(); @@ -153,6 +157,10 @@ void ItemList::set_item_tooltip(int p_idx, const String &p_tooltip) { } ERR_FAIL_INDEX(p_idx, items.size()); + if (items[p_idx].tooltip == p_tooltip) { + return; + } + items.write[p_idx].tooltip = p_tooltip; update(); shape_changed = true; @@ -169,6 +177,10 @@ void ItemList::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) { } ERR_FAIL_INDEX(p_idx, items.size()); + if (items[p_idx].icon == p_icon) { + return; + } + items.write[p_idx].icon = p_icon; update(); shape_changed = true; @@ -186,6 +198,10 @@ void ItemList::set_item_icon_transposed(int p_idx, const bool p_transposed) { } ERR_FAIL_INDEX(p_idx, items.size()); + if (items[p_idx].icon_transposed == p_transposed) { + return; + } + items.write[p_idx].icon_transposed = p_transposed; update(); shape_changed = true; @@ -203,6 +219,10 @@ void ItemList::set_item_icon_region(int p_idx, const Rect2 &p_region) { } ERR_FAIL_INDEX(p_idx, items.size()); + if (items[p_idx].icon_region == p_region) { + return; + } + items.write[p_idx].icon_region = p_region; update(); shape_changed = true; @@ -220,6 +240,10 @@ void ItemList::set_item_icon_modulate(int p_idx, const Color &p_modulate) { } ERR_FAIL_INDEX(p_idx, items.size()); + if (items[p_idx].icon_modulate == p_modulate) { + return; + } + items.write[p_idx].icon_modulate = p_modulate; update(); } @@ -236,6 +260,10 @@ void ItemList::set_item_custom_bg_color(int p_idx, const Color &p_custom_bg_colo } ERR_FAIL_INDEX(p_idx, items.size()); + if (items[p_idx].custom_bg == p_custom_bg_color) { + return; + } + items.write[p_idx].custom_bg = p_custom_bg_color; update(); } @@ -252,6 +280,10 @@ void ItemList::set_item_custom_fg_color(int p_idx, const Color &p_custom_fg_colo } ERR_FAIL_INDEX(p_idx, items.size()); + if (items[p_idx].custom_fg == p_custom_fg_color) { + return; + } + items.write[p_idx].custom_fg = p_custom_fg_color; update(); } @@ -268,6 +300,10 @@ void ItemList::set_item_tag_icon(int p_idx, const Ref<Texture2D> &p_tag_icon) { } ERR_FAIL_INDEX(p_idx, items.size()); + if (items[p_idx].tag_icon == p_tag_icon) { + return; + } + items.write[p_idx].tag_icon = p_tag_icon; update(); shape_changed = true; @@ -299,6 +335,10 @@ void ItemList::set_item_disabled(int p_idx, bool p_disabled) { } ERR_FAIL_INDEX(p_idx, items.size()); + if (items[p_idx].disabled == p_disabled) { + return; + } + items.write[p_idx].disabled = p_disabled; update(); } @@ -314,6 +354,10 @@ void ItemList::set_item_metadata(int p_idx, const Variant &p_metadata) { } ERR_FAIL_INDEX(p_idx, items.size()); + if (items[p_idx].metadata == p_metadata) { + return; + } + items.write[p_idx].metadata = p_metadata; update(); shape_changed = true; @@ -379,6 +423,10 @@ bool ItemList::is_selected(int p_idx) const { void ItemList::set_current(int p_current) { ERR_FAIL_INDEX(p_current, items.size()); + if (current == p_current) { + return; + } + if (select_mode == SELECT_SINGLE) { select(p_current, true); } else { @@ -410,6 +458,11 @@ void ItemList::move_item(int p_from_idx, int p_to_idx) { void ItemList::set_item_count(int p_count) { ERR_FAIL_COND(p_count < 0); + + if (items.size() == p_count) { + return; + } + items.resize(p_count); update(); shape_changed = true; @@ -445,6 +498,11 @@ void ItemList::clear() { void ItemList::set_fixed_column_width(int p_size) { ERR_FAIL_COND(p_size < 0); + + if (fixed_column_width == p_size) { + return; + } + fixed_column_width = p_size; update(); shape_changed = true; @@ -455,6 +513,10 @@ int ItemList::get_fixed_column_width() const { } void ItemList::set_same_column_width(bool p_enable) { + if (same_column_width == p_enable) { + return; + } + same_column_width = p_enable; update(); shape_changed = true; @@ -487,6 +549,11 @@ int ItemList::get_max_text_lines() const { void ItemList::set_max_columns(int p_amount) { ERR_FAIL_COND(p_amount < 0); + + if (max_columns == p_amount) { + return; + } + max_columns = p_amount; update(); shape_changed = true; @@ -497,6 +564,10 @@ int ItemList::get_max_columns() const { } void ItemList::set_select_mode(SelectMode p_mode) { + if (select_mode == p_mode) { + return; + } + select_mode = p_mode; update(); } @@ -526,6 +597,10 @@ ItemList::IconMode ItemList::get_icon_mode() const { } void ItemList::set_fixed_icon_size(const Size2 &p_size) { + if (fixed_icon_size == p_size) { + return; + } + fixed_icon_size = p_size; update(); } @@ -1512,6 +1587,10 @@ void ItemList::set_autoscroll_to_bottom(const bool p_enable) { } void ItemList::set_auto_height(bool p_enable) { + if (auto_height == p_enable) { + return; + } + auto_height = p_enable; shape_changed = true; update(); diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 4ef1e48a32..7a88afaa3b 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -38,10 +38,12 @@ #include "servers/text_server.h" void Label::set_autowrap_mode(TextServer::AutowrapMode p_mode) { - if (autowrap_mode != p_mode) { - autowrap_mode = p_mode; - lines_dirty = true; + if (autowrap_mode == p_mode) { + return; } + + autowrap_mode = p_mode; + lines_dirty = true; update(); if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { @@ -54,6 +56,10 @@ TextServer::AutowrapMode Label::get_autowrap_mode() const { } void Label::set_uppercase(bool p_uppercase) { + if (uppercase == p_uppercase) { + return; + } + uppercase = p_uppercase; dirty = true; @@ -608,12 +614,15 @@ int Label::get_visible_line_count() const { void Label::set_horizontal_alignment(HorizontalAlignment p_alignment) { ERR_FAIL_INDEX((int)p_alignment, 4); - if (horizontal_alignment != p_alignment) { - if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL || p_alignment == HORIZONTAL_ALIGNMENT_FILL) { - lines_dirty = true; // Reshape lines. - } - horizontal_alignment = p_alignment; + if (horizontal_alignment == p_alignment) { + return; } + + if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL || p_alignment == HORIZONTAL_ALIGNMENT_FILL) { + lines_dirty = true; // Reshape lines. + } + horizontal_alignment = p_alignment; + update(); } @@ -623,6 +632,11 @@ HorizontalAlignment Label::get_horizontal_alignment() const { void Label::set_vertical_alignment(VerticalAlignment p_alignment) { ERR_FAIL_INDEX((int)p_alignment, 4); + + if (vertical_alignment == p_alignment) { + return; + } + vertical_alignment = p_alignment; update(); } @@ -689,6 +703,10 @@ TextServer::StructuredTextParser Label::get_structured_text_bidi_override() cons } void Label::set_structured_text_bidi_override_options(Array p_args) { + if (st_args == p_args) { + return; + } + st_args = p_args; dirty = true; update(); @@ -715,6 +733,10 @@ String Label::get_language() const { } void Label::set_clip_text(bool p_clip) { + if (clip == p_clip) { + return; + } + clip = p_clip; update(); update_minimum_size(); @@ -725,10 +747,12 @@ bool Label::is_clipping_text() const { } void Label::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) { - if (overrun_behavior != p_behavior) { - overrun_behavior = p_behavior; - lines_dirty = true; + if (overrun_behavior == p_behavior) { + return; } + + overrun_behavior = p_behavior; + lines_dirty = true; update(); if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { update_minimum_size(); @@ -800,6 +824,11 @@ void Label::set_visible_characters_behavior(TextServer::VisibleCharactersBehavio void Label::set_lines_skipped(int p_lines) { ERR_FAIL_COND(p_lines < 0); + + if (lines_skipped == p_lines) { + return; + } + lines_skipped = p_lines; _update_visible(); update(); @@ -810,6 +839,10 @@ int Label::get_lines_skipped() const { } void Label::set_max_lines_visible(int p_lines) { + if (max_lines_visible == p_lines) { + return; + } + max_lines_visible = p_lines; _update_visible(); update(); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index b523c2bb8b..34a60b907c 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -607,10 +607,12 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { void LineEdit::set_horizontal_alignment(HorizontalAlignment p_alignment) { ERR_FAIL_INDEX((int)p_alignment, 4); - if (alignment != p_alignment) { - alignment = p_alignment; - _shape(); + if (alignment == p_alignment) { + return; } + + alignment = p_alignment; + _shape(); update(); } @@ -716,7 +718,7 @@ void LineEdit::_notification(int p_what) { case NOTIFICATION_RESIZED: { _fit_to_width(); - scroll_offset = 0; + scroll_offset = 0.0; set_caret_column(get_caret_column()); } break; @@ -799,7 +801,7 @@ void LineEdit::_notification(int p_what) { } } break; case HORIZONTAL_ALIGNMENT_CENTER: { - if (scroll_offset != 0) { + if (!Math::is_zero_approx(scroll_offset)) { x_ofs = style->get_offset().x; } else { x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - (text_width)) / 2); @@ -844,7 +846,7 @@ void LineEdit::_notification(int p_what) { r_icon->draw(ci, Point2(width - r_icon->get_width() - style->get_margin(SIDE_RIGHT), height / 2 - r_icon->get_height() / 2), color_icon); if (alignment == HORIZONTAL_ALIGNMENT_CENTER) { - if (scroll_offset == 0) { + if (Math::is_zero_approx(scroll_offset)) { x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2); } } else { @@ -1206,7 +1208,7 @@ void LineEdit::set_caret_at_pixel_pos(int p_x) { } } break; case HORIZONTAL_ALIGNMENT_CENTER: { - if (scroll_offset != 0) { + if (!Math::is_zero_approx(scroll_offset)) { x_ofs = style->get_offset().x; } else { x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - (text_width)) / 2); @@ -1226,7 +1228,7 @@ void LineEdit::set_caret_at_pixel_pos(int p_x) { if (right_icon.is_valid() || display_clear_icon) { Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon; if (alignment == HORIZONTAL_ALIGNMENT_CENTER) { - if (scroll_offset == 0) { + if (Math::is_zero_approx(scroll_offset)) { x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2); } } else { @@ -1234,11 +1236,11 @@ void LineEdit::set_caret_at_pixel_pos(int p_x) { } } - int ofs = TS->shaped_text_hit_test_position(text_rid, p_x - x_ofs - scroll_offset); + int ofs = ceil(TS->shaped_text_hit_test_position(text_rid, p_x - x_ofs - scroll_offset)); set_caret_column(ofs); } -Vector2i LineEdit::get_caret_pixel_pos() { +Vector2 LineEdit::get_caret_pixel_pos() { Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); bool rtl = is_layout_rtl(); @@ -1254,7 +1256,7 @@ Vector2i LineEdit::get_caret_pixel_pos() { } } break; case HORIZONTAL_ALIGNMENT_CENTER: { - if (scroll_offset != 0) { + if (!Math::is_zero_approx(scroll_offset)) { x_ofs = style->get_offset().x; } else { x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - (text_width)) / 2); @@ -1274,7 +1276,7 @@ Vector2i LineEdit::get_caret_pixel_pos() { if (right_icon.is_valid() || display_clear_icon) { Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon; if (alignment == HORIZONTAL_ALIGNMENT_CENTER) { - if (scroll_offset == 0) { + if (Math::is_zero_approx(scroll_offset)) { x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2); } } else { @@ -1282,7 +1284,7 @@ Vector2i LineEdit::get_caret_pixel_pos() { } } - Vector2i ret; + Vector2 ret; CaretInfo caret; // Get position of the start of caret. if (ime_text.length() != 0 && ime_selection.x != 0) { @@ -1425,7 +1427,7 @@ void LineEdit::set_text(String p_text) { update(); caret_column = 0; - scroll_offset = 0; + scroll_offset = 0.0; } void LineEdit::set_text_direction(Control::TextDirection p_text_direction) { @@ -1525,6 +1527,10 @@ String LineEdit::get_text() const { } void LineEdit::set_placeholder(String p_text) { + if (placeholder == p_text) { + return; + } + placeholder = p_text; placeholder_translated = atr(placeholder); _shape(); @@ -1549,7 +1555,7 @@ void LineEdit::set_caret_column(int p_column) { // Fit to window. if (!is_inside_tree()) { - scroll_offset = 0; + scroll_offset = 0.0; return; } @@ -1568,7 +1574,7 @@ void LineEdit::set_caret_column(int p_column) { } } break; case HORIZONTAL_ALIGNMENT_CENTER: { - if (scroll_offset != 0) { + if (!Math::is_zero_approx(scroll_offset)) { x_ofs = style->get_offset().x; } else { x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - (text_width)) / 2); @@ -1589,7 +1595,7 @@ void LineEdit::set_caret_column(int p_column) { if (right_icon.is_valid() || display_clear_icon) { Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon; if (alignment == HORIZONTAL_ALIGNMENT_CENTER) { - if (scroll_offset == 0) { + if (Math::is_zero_approx(scroll_offset)) { x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2); } } else { @@ -1599,12 +1605,12 @@ void LineEdit::set_caret_column(int p_column) { } // Note: Use two coordinates to fit IME input range. - Vector2i primary_catret_offset = get_caret_pixel_pos(); + Vector2 primary_caret_offset = get_caret_pixel_pos(); - if (MIN(primary_catret_offset.x, primary_catret_offset.y) <= x_ofs) { - scroll_offset += (x_ofs - MIN(primary_catret_offset.x, primary_catret_offset.y)); - } else if (MAX(primary_catret_offset.x, primary_catret_offset.y) >= ofs_max) { - scroll_offset += (ofs_max - MAX(primary_catret_offset.x, primary_catret_offset.y)); + if (MIN(primary_caret_offset.x, primary_caret_offset.y) <= x_ofs) { + scroll_offset += x_ofs - MIN(primary_caret_offset.x, primary_caret_offset.y); + } else if (MAX(primary_caret_offset.x, primary_caret_offset.y) >= ofs_max) { + scroll_offset += ofs_max - MAX(primary_caret_offset.x, primary_caret_offset.y); } scroll_offset = MIN(0, scroll_offset); @@ -1615,14 +1621,14 @@ int LineEdit::get_caret_column() const { return caret_column; } -void LineEdit::set_scroll_offset(int p_pos) { +void LineEdit::set_scroll_offset(float p_pos) { scroll_offset = p_pos; - if (scroll_offset < 0) { - scroll_offset = 0; + if (scroll_offset < 0.0) { + scroll_offset = 0.0; } } -int LineEdit::get_scroll_offset() const { +float LineEdit::get_scroll_offset() const { return scroll_offset; } @@ -1650,7 +1656,7 @@ void LineEdit::clear_internal() { deselect(); _clear_undo_stack(); caret_column = 0; - scroll_offset = 0; + scroll_offset = 0.0; undo_text = ""; text = ""; _shape(); @@ -1781,10 +1787,12 @@ bool LineEdit::is_editable() const { } void LineEdit::set_secret(bool p_secret) { - if (pass != p_secret) { - pass = p_secret; - _shape(); + if (pass == p_secret) { + return; } + + pass = p_secret; + _shape(); update(); } @@ -1797,10 +1805,12 @@ void LineEdit::set_secret_character(const String &p_string) { // It also wouldn't make sense to use multiple characters as the secret character. ERR_FAIL_COND_MSG(p_string.length() != 1, "Secret character must be exactly one character long (" + itos(p_string.length()) + " characters given)."); - if (secret_character != p_string) { - secret_character = p_string; - _shape(); + if (secret_character == p_string) { + return; } + + secret_character = p_string; + _shape(); update(); } @@ -2057,6 +2067,10 @@ bool LineEdit::is_middle_mouse_paste_enabled() const { } void LineEdit::set_selecting_enabled(bool p_enabled) { + if (selecting_enabled == p_enabled) { + return; + } + selecting_enabled = p_enabled; if (!selecting_enabled) { @@ -2069,6 +2083,10 @@ bool LineEdit::is_selecting_enabled() const { } void LineEdit::set_deselect_on_focus_loss_enabled(const bool p_enabled) { + if (deselect_on_focus_loss_enabled == p_enabled) { + return; + } + deselect_on_focus_loss_enabled = p_enabled; if (p_enabled && selection.enabled && !has_focus()) { deselect(); diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index 254f842b66..dabdaa3395 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -113,7 +113,7 @@ private: bool caret_mid_grapheme_enabled = true; int caret_column = 0; - int scroll_offset = 0; + float scroll_offset = 0.0; int max_length = 0; // 0 for no maximum. String language; @@ -153,8 +153,7 @@ private: struct TextOperation { int caret_column = 0; - int scroll_offset = 0; - int cached_width = 0; + float scroll_offset = 0.0; String text; }; List<TextOperation> undo_stack; @@ -192,11 +191,11 @@ private: void shift_selection_check_post(bool); void selection_fill_at_caret(); - void set_scroll_offset(int p_pos); - int get_scroll_offset() const; + void set_scroll_offset(float p_pos); + float get_scroll_offset() const; void set_caret_at_pixel_pos(int p_x); - Vector2i get_caret_pixel_pos(); + Vector2 get_caret_pixel_pos(); void _reset_caret_blink_timer(); void _toggle_draw_caret(); diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp index 30c0bb3321..ee3f64e0e5 100644 --- a/scene/gui/link_button.cpp +++ b/scene/gui/link_button.cpp @@ -109,6 +109,10 @@ String LinkButton::get_language() const { } void LinkButton::set_underline_mode(UnderlineMode p_underline_mode) { + if (underline_mode == p_underline_mode) { + return; + } + underline_mode = p_underline_mode; update(); } diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index 0252f25888..a03db82332 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -99,9 +99,7 @@ void MenuButton::pressed() { popup->set_parent_rect(Rect2(Point2(gp - popup->get_position()), size)); // If not triggered by the mouse, start the popup with its first item selected. - if (popup->get_item_count() > 0 && - ((get_action_mode() == ActionMode::ACTION_MODE_BUTTON_PRESS && Input::get_singleton()->is_action_just_pressed("ui_accept")) || - (get_action_mode() == ActionMode::ACTION_MODE_BUTTON_RELEASE && Input::get_singleton()->is_action_just_released("ui_accept")))) { + if (popup->get_item_count() > 0 && !_was_pressed_by_mouse()) { popup->set_current_index(0); } @@ -130,6 +128,11 @@ bool MenuButton::is_switch_on_hover() { void MenuButton::set_item_count(int p_count) { ERR_FAIL_COND(p_count < 0); + + if (popup->get_item_count() == p_count) { + return; + } + popup->set_item_count(p_count); notify_property_list_changed(); } diff --git a/scene/gui/nine_patch_rect.cpp b/scene/gui/nine_patch_rect.cpp index 8fee10b19a..a7e86dd5de 100644 --- a/scene/gui/nine_patch_rect.cpp +++ b/scene/gui/nine_patch_rect.cpp @@ -105,6 +105,11 @@ Ref<Texture2D> NinePatchRect::get_texture() const { void NinePatchRect::set_patch_margin(Side p_side, int p_size) { ERR_FAIL_INDEX((int)p_side, 4); + + if (margin[p_side] == p_size) { + return; + } + margin[p_side] = p_size; update(); update_minimum_size(); @@ -130,6 +135,10 @@ Rect2 NinePatchRect::get_region_rect() const { } void NinePatchRect::set_draw_center(bool p_enabled) { + if (draw_center == p_enabled) { + return; + } + draw_center = p_enabled; update(); } @@ -139,6 +148,10 @@ bool NinePatchRect::is_draw_center_enabled() const { } void NinePatchRect::set_h_axis_stretch_mode(AxisStretchMode p_mode) { + if (axis_h == p_mode) { + return; + } + axis_h = p_mode; update(); } @@ -148,6 +161,10 @@ NinePatchRect::AxisStretchMode NinePatchRect::get_h_axis_stretch_mode() const { } void NinePatchRect::set_v_axis_stretch_mode(AxisStretchMode p_mode) { + if (axis_v == p_mode) { + return; + } + axis_v = p_mode; update(); } diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index a5a6240e27..931dffe3bb 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -204,8 +204,7 @@ void OptionButton::pressed() { // If not triggered by the mouse, start the popup with the checked item selected. if (popup->get_item_count() > 0) { - if ((get_action_mode() == ActionMode::ACTION_MODE_BUTTON_PRESS && Input::get_singleton()->is_action_just_pressed("ui_accept")) || - (get_action_mode() == ActionMode::ACTION_MODE_BUTTON_RELEASE && Input::get_singleton()->is_action_just_released("ui_accept"))) { + if (!_was_pressed_by_mouse()) { popup->set_current_index(current > -1 ? current : 0); } else { popup->scroll_to_item(current > -1 ? current : 0); diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 6ef8158302..4e2aec0278 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -1144,6 +1144,11 @@ void PopupMenu::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) { p_idx += get_item_count(); } ERR_FAIL_INDEX(p_idx, items.size()); + + if (items[p_idx].icon == p_icon) { + return; + } + items.write[p_idx].icon = p_icon; control->update(); @@ -1157,6 +1162,10 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) { } ERR_FAIL_INDEX(p_idx, items.size()); + if (items[p_idx].checked == p_checked) { + return; + } + items.write[p_idx].checked = p_checked; control->update(); @@ -1169,6 +1178,11 @@ void PopupMenu::set_item_id(int p_idx, int p_id) { p_idx += get_item_count(); } ERR_FAIL_INDEX(p_idx, items.size()); + + if (items[p_idx].id == p_id) { + return; + } + items.write[p_idx].id = p_id; control->update(); @@ -1181,6 +1195,11 @@ void PopupMenu::set_item_accelerator(int p_idx, Key p_accel) { p_idx += get_item_count(); } ERR_FAIL_INDEX(p_idx, items.size()); + + if (items[p_idx].accel == p_accel) { + return; + } + items.write[p_idx].accel = p_accel; items.write[p_idx].dirty = true; @@ -1194,6 +1213,11 @@ void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) { p_idx += get_item_count(); } ERR_FAIL_INDEX(p_idx, items.size()); + + if (items[p_idx].metadata == p_meta) { + return; + } + items.write[p_idx].metadata = p_meta; control->update(); child_controls_changed(); @@ -1205,6 +1229,11 @@ void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) { p_idx += get_item_count(); } ERR_FAIL_INDEX(p_idx, items.size()); + + if (items[p_idx].disabled == p_disabled) { + return; + } + items.write[p_idx].disabled = p_disabled; control->update(); child_controls_changed(); @@ -1216,6 +1245,11 @@ void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) { p_idx += get_item_count(); } ERR_FAIL_INDEX(p_idx, items.size()); + + if (items[p_idx].submenu == p_submenu) { + return; + } + items.write[p_idx].submenu = p_submenu; control->update(); child_controls_changed(); @@ -1330,6 +1364,11 @@ void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) { p_idx += get_item_count(); } ERR_FAIL_INDEX(p_idx, items.size()); + + if (items[p_idx].separator == p_separator) { + return; + } + items.write[p_idx].separator = p_separator; control->update(); } @@ -1344,6 +1383,12 @@ void PopupMenu::set_item_as_checkable(int p_idx, bool p_checkable) { p_idx += get_item_count(); } ERR_FAIL_INDEX(p_idx, items.size()); + + int type = (int)(p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE); + if (type == items[p_idx].checkable_type) { + return; + } + items.write[p_idx].checkable_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE; control->update(); _menu_changed(); @@ -1354,6 +1399,12 @@ void PopupMenu::set_item_as_radio_checkable(int p_idx, bool p_radio_checkable) { p_idx += get_item_count(); } ERR_FAIL_INDEX(p_idx, items.size()); + + int type = (int)(p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE); + if (type == items[p_idx].checkable_type) { + return; + } + items.write[p_idx].checkable_type = p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE; control->update(); _menu_changed(); @@ -1364,6 +1415,11 @@ void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) { p_idx += get_item_count(); } ERR_FAIL_INDEX(p_idx, items.size()); + + if (items[p_idx].tooltip == p_tooltip) { + return; + } + items.write[p_idx].tooltip = p_tooltip; control->update(); _menu_changed(); @@ -1374,6 +1430,11 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bo p_idx += get_item_count(); } ERR_FAIL_INDEX(p_idx, items.size()); + + if (items[p_idx].shortcut == p_shortcut && items[p_idx].shortcut_is_global == p_global && items[p_idx].shortcut.is_valid() == p_shortcut.is_valid()) { + return; + } + if (items[p_idx].shortcut.is_valid()) { _unref_shortcut(items[p_idx].shortcut); } @@ -1394,7 +1455,12 @@ void PopupMenu::set_item_indent(int p_idx, int p_indent) { p_idx += get_item_count(); } ERR_FAIL_INDEX(p_idx, items.size()); + + if (items.write[p_idx].indent == p_indent) { + return; + } items.write[p_idx].indent = p_indent; + control->update(); child_controls_changed(); _menu_changed(); @@ -1405,6 +1471,11 @@ void PopupMenu::set_item_multistate(int p_idx, int p_state) { p_idx += get_item_count(); } ERR_FAIL_INDEX(p_idx, items.size()); + + if (items[p_idx].state == p_state) { + return; + } + items.write[p_idx].state = p_state; control->update(); _menu_changed(); @@ -1415,6 +1486,11 @@ void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) { p_idx += get_item_count(); } ERR_FAIL_INDEX(p_idx, items.size()); + + if (items[p_idx].shortcut_is_disabled == p_disabled) { + return; + } + items.write[p_idx].shortcut_is_disabled = p_disabled; control->update(); _menu_changed(); @@ -1457,6 +1533,11 @@ bool PopupMenu::is_item_shortcut_disabled(int p_idx) const { void PopupMenu::set_current_index(int p_idx) { ERR_FAIL_INDEX(p_idx, items.size()); + + if (mouse_over == p_idx) { + return; + } + mouse_over = p_idx; scroll_to_item(mouse_over); control->update(); @@ -1469,6 +1550,11 @@ int PopupMenu::get_current_index() const { void PopupMenu::set_item_count(int p_count) { ERR_FAIL_COND(p_count < 0); int prev_size = items.size(); + + if (prev_size == p_count) { + return; + } + items.resize(p_count); if (prev_size < p_count) { diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index fae6688452..0fb1f27802 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -106,6 +106,10 @@ void Range::set_value(double p_val) { } void Range::set_min(double p_min) { + if (shared->min == p_min) { + return; + } + shared->min = p_min; set_value(shared->val); _validate_values(); @@ -116,6 +120,10 @@ void Range::set_min(double p_min) { } void Range::set_max(double p_max) { + if (shared->max == p_max) { + return; + } + shared->max = p_max; set_value(shared->val); _validate_values(); @@ -124,11 +132,19 @@ void Range::set_max(double p_max) { } void Range::set_step(double p_step) { + if (shared->step == p_step) { + return; + } + shared->step = p_step; shared->emit_changed("step"); } void Range::set_page(double p_page) { + if (shared->page == p_page) { + return; + } + shared->page = p_page; set_value(shared->val); _validate_values(); @@ -300,6 +316,10 @@ bool Range::is_using_rounded_values() const { } void Range::set_exp_ratio(bool p_enable) { + if (shared->exp_ratio == p_enable) { + return; + } + shared->exp_ratio = p_enable; update_configuration_warnings(); diff --git a/scene/gui/reference_rect.cpp b/scene/gui/reference_rect.cpp index 5190a5a7d2..05dfe4b118 100644 --- a/scene/gui/reference_rect.cpp +++ b/scene/gui/reference_rect.cpp @@ -46,6 +46,10 @@ void ReferenceRect::_notification(int p_what) { } void ReferenceRect::set_border_color(const Color &p_color) { + if (border_color == p_color) { + return; + } + border_color = p_color; update(); } @@ -55,7 +59,12 @@ Color ReferenceRect::get_border_color() const { } void ReferenceRect::set_border_width(float p_width) { - border_width = MAX(0.0, p_width); + float width_max = MAX(0.0, p_width); + if (border_width == width_max) { + return; + } + + border_width = width_max; update(); } @@ -64,6 +73,10 @@ float ReferenceRect::get_border_width() const { } void ReferenceRect::set_editor_only(const bool &p_enabled) { + if (editor_only == p_enabled) { + return; + } + editor_only = p_enabled; update(); } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index ab466089a7..6ab3cdcb69 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1346,7 +1346,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o return line_count; } -void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char, bool *r_outside) { +void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char, bool *r_outside, bool p_meta) { if (r_click_item) { *r_click_item = nullptr; } @@ -1369,7 +1369,7 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs); while (ofs.y < size.height && from_line < to_line) { MutexLock lock(main->lines[from_line].text_buf->get_mutex()); - _find_click_in_line(p_frame, from_line, ofs, text_rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char); + _find_click_in_line(p_frame, from_line, ofs, text_rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char, false, p_meta); ofs.y += main->lines[from_line].text_buf->get_size().y + main->lines[from_line].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); if (((r_click_item != nullptr) && ((*r_click_item) != nullptr)) || ((r_click_frame != nullptr) && ((*r_click_frame) != nullptr))) { if (r_outside != nullptr) { @@ -1381,7 +1381,7 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item } } -float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char, bool p_table) { +float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char, bool p_table, bool p_meta) { Vector2 off; bool line_clicked = false; @@ -1479,7 +1479,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V } if (crect.has_point(p_click)) { for (int j = 0; j < (int)frame->lines.size(); j++) { - _find_click_in_line(frame, j, rect.position + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_click, &table_click_frame, &table_click_line, &table_click_item, &table_click_char, true); + _find_click_in_line(frame, j, rect.position + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_click, &table_click_frame, &table_click_line, &table_click_item, &table_click_char, true, p_meta); if (table_click_frame && table_click_item) { // Save cell detected cell hit data. table_range = Vector2i(INT32_MAX, 0); @@ -1512,7 +1512,15 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V if (p_click.y >= rect.position.y && p_click.y <= rect.position.y + rect.size.y) { if ((!rtl && p_click.x >= rect.position.x) || (rtl && p_click.x <= rect.position.x + rect.size.x)) { - char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x); + if (p_meta) { + int64_t glyph_idx = TS->shaped_text_hit_test_grapheme(rid, p_click.x - rect.position.x); + if (glyph_idx >= 0) { + const Glyph *glyphs = TS->shaped_text_get_glyphs(rid); + char_pos = glyphs[glyph_idx].start; + } + } else { + char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x); + } } line_clicked = true; text_rect_begin = rtl ? rect.position.x + rect.size.x : rect.position.x; @@ -1825,7 +1833,7 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const Item *item = nullptr; bool outside = true; - const_cast<RichTextLabel *>(this)->_find_click(main, p_pos, nullptr, nullptr, &item, nullptr, &outside); + const_cast<RichTextLabel *>(this)->_find_click(main, p_pos, nullptr, nullptr, &item, nullptr, &outside, true); if (item && !outside && const_cast<RichTextLabel *>(this)->_find_meta(item, nullptr)) { return CURSOR_POINTING_HAND; @@ -1850,7 +1858,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { selection.drag_attempt = false; - _find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside); + _find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside, false); if (c_item != nullptr) { if (selection.enabled) { selection.click_frame = c_frame; @@ -1888,7 +1896,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { selection.drag_attempt = false; - _find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside); + _find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside, false); if (c_frame) { const Line &l = c_frame->lines[c_line]; @@ -1938,7 +1946,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { Item *c_item = nullptr; bool outside = true; - _find_click(main, b->get_position(), nullptr, nullptr, &c_item, nullptr, &outside); + _find_click(main, b->get_position(), nullptr, nullptr, &c_item, nullptr, &outside, true); if (c_item) { Variant meta; @@ -2044,7 +2052,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { int c_index = 0; bool outside; - _find_click(main, m->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside); + _find_click(main, m->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside, false); if (selection.click_item && c_item) { selection.from_frame = selection.click_frame; selection.from_line = selection.click_line; @@ -2102,7 +2110,7 @@ String RichTextLabel::get_tooltip(const Point2 &p_pos) const { Item *c_item = nullptr; bool outside; - const_cast<RichTextLabel *>(this)->_find_click(main, p_pos, nullptr, nullptr, &c_item, nullptr, &outside); + const_cast<RichTextLabel *>(this)->_find_click(main, p_pos, nullptr, nullptr, &c_item, nullptr, &outside, true); String description; if (c_item && !outside && const_cast<RichTextLabel *>(this)->_find_hint(c_item, &description)) { @@ -3370,6 +3378,10 @@ void RichTextLabel::clear() { } void RichTextLabel::set_tab_size(int p_spaces) { + if (tab_size == p_spaces) { + return; + } + _stop_thread(); tab_size = p_spaces; @@ -3393,6 +3405,10 @@ bool RichTextLabel::is_fit_content_height_enabled() const { } void RichTextLabel::set_meta_underline(bool p_underline) { + if (underline_meta == p_underline) { + return; + } + underline_meta = p_underline; update(); } @@ -4320,6 +4336,8 @@ void RichTextLabel::append_text(const String &p_bbcode) { } void RichTextLabel::scroll_to_paragraph(int p_paragraph) { + _validate_line_caches(); + if (p_paragraph <= 0) { vscroll->set_value(0); } else if (p_paragraph >= main->first_invalid_line.load()) { @@ -4341,6 +4359,8 @@ int RichTextLabel::get_visible_paragraph_count() const { } void RichTextLabel::scroll_to_line(int p_line) { + _validate_line_caches(); + if (p_line <= 0) { vscroll->set_value(0); return; @@ -4405,6 +4425,10 @@ int RichTextLabel::get_visible_line_count() const { } void RichTextLabel::set_selection_enabled(bool p_enabled) { + if (selection.enabled == p_enabled) { + return; + } + selection.enabled = p_enabled; if (!p_enabled) { if (selection.active) { @@ -4417,6 +4441,10 @@ void RichTextLabel::set_selection_enabled(bool p_enabled) { } void RichTextLabel::set_deselect_on_focus_loss_enabled(const bool p_enabled) { + if (deselect_on_focus_loss_enabled == p_enabled) { + return; + } + deselect_on_focus_loss_enabled = p_enabled; if (p_enabled && selection.active && !has_focus()) { deselect(); @@ -4784,6 +4812,10 @@ int RichTextLabel::get_selection_to() const { } void RichTextLabel::set_text(const String &p_bbcode) { + if (text == p_bbcode) { + return; + } + text = p_bbcode; if (use_bbcode) { parse_bbcode(p_bbcode); @@ -4958,6 +4990,8 @@ void RichTextLabel::install_effect(const Variant effect) { } int RichTextLabel::get_content_height() const { + const_cast<RichTextLabel *>(this)->_validate_line_caches(); + int total_height = 0; int to_line = main->first_invalid_line.load(); if (to_line) { @@ -4968,6 +5002,8 @@ int RichTextLabel::get_content_height() const { } int RichTextLabel::get_content_width() const { + const_cast<RichTextLabel *>(this)->_validate_line_caches(); + int total_width = 0; int to_line = main->first_invalid_line.load(); for (int i = 0; i < to_line; i++) { @@ -5316,6 +5352,10 @@ int RichTextLabel::get_total_glyph_count() const { } void RichTextLabel::set_fixed_size_to_width(int p_width) { + if (fixed_width == p_width) { + return; + } + fixed_width = p_width; update_minimum_size(); } diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index e5f0469c01..95e55bf1a1 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -444,7 +444,7 @@ private: TextServer::VisibleCharactersBehavior visible_chars_behavior = TextServer::VC_CHARS_BEFORE_SHAPING; bool _is_click_inside_selection() const; - void _find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr); + void _find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr, bool p_meta = false); String _get_line_text(ItemFrame *p_frame, int p_line, Selection p_sel) const; bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, int p_char_idx, bool p_reverse_search); @@ -455,7 +455,7 @@ private: void _update_line_font(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size); int _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs); - float _find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool p_table = false); + float _find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool p_table = false, bool p_meta = false); String _roman(int p_num, bool p_capitalize) const; String _letters(int p_num, bool p_capitalize) const; diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index 64c07007dc..2695ad1f14 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -227,6 +227,10 @@ double Slider::get_custom_step() const { } void Slider::set_ticks(int p_count) { + if (ticks == p_count) { + return; + } + ticks = p_count; update(); } @@ -240,11 +244,19 @@ bool Slider::get_ticks_on_borders() const { } void Slider::set_ticks_on_borders(bool _tob) { + if (ticks_on_borders == _tob) { + return; + } + ticks_on_borders = _tob; update(); } void Slider::set_editable(bool p_editable) { + if (editable == p_editable) { + return; + } + editable = p_editable; update(); } diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 8a7f52b0d9..517c83545c 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -250,6 +250,10 @@ HorizontalAlignment SpinBox::get_horizontal_alignment() const { } void SpinBox::set_suffix(const String &p_suffix) { + if (suffix == p_suffix) { + return; + } + suffix = p_suffix; _value_changed(0); } @@ -259,6 +263,10 @@ String SpinBox::get_suffix() const { } void SpinBox::set_prefix(const String &p_prefix) { + if (prefix == p_prefix) { + return; + } + prefix = p_prefix; _value_changed(0); } diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index d7aa516ee6..b6073ce265 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -95,14 +95,18 @@ void SplitContainer::_resort() { no_offset_middle_sep = ms_first[axis]; } - // Compute the final middle separation + // Compute the final middle separation. middle_sep = no_offset_middle_sep; + if (prev_no_offset_middle_sep != INT_MAX) { + split_offset -= middle_sep - prev_no_offset_middle_sep; + } + prev_no_offset_middle_sep = middle_sep; + if (!collapsed) { int clamped_split_offset = CLAMP(split_offset, ms_first[axis] - no_offset_middle_sep, (get_size()[axis] - ms_second[axis] - sep) - no_offset_middle_sep); middle_sep += clamped_split_offset; if (should_clamp_split_offset) { split_offset = clamped_split_offset; - should_clamp_split_offset = false; } } @@ -327,6 +331,10 @@ void SplitContainer::set_collapsed(bool p_collapsed) { } void SplitContainer::set_dragger_visibility(DraggerVisibility p_visibility) { + if (dragger_visibility == p_visibility) { + return; + } + dragger_visibility = p_visibility; queue_sort(); update(); diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h index a69ffe4de9..dd15362199 100644 --- a/scene/gui/split_container.h +++ b/scene/gui/split_container.h @@ -47,6 +47,7 @@ private: bool should_clamp_split_offset = false; int split_offset = 0; int middle_sep = 0; + int prev_no_offset_middle_sep = INT_MAX; bool vertical = false; bool dragging = false; int drag_from = 0; diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp index 68281b6a72..869683e427 100644 --- a/scene/gui/subviewport_container.cpp +++ b/scene/gui/subviewport_container.cpp @@ -53,6 +53,10 @@ Size2 SubViewportContainer::get_minimum_size() const { } void SubViewportContainer::set_stretch(bool p_enable) { + if (stretch == p_enable) { + return; + } + stretch = p_enable; update_minimum_size(); queue_sort(); diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index d36a364677..e0739f909f 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -634,6 +634,11 @@ bool TabBar::get_offset_buttons_visible() const { void TabBar::set_tab_title(int p_tab, const String &p_title) { ERR_FAIL_INDEX(p_tab, tabs.size()); + + if (tabs[p_tab].text == p_title) { + return; + } + tabs.write[p_tab].text = p_title; _shape(p_tab); @@ -690,6 +695,11 @@ String TabBar::get_tab_language(int p_tab) const { void TabBar::set_tab_icon(int p_tab, const Ref<Texture2D> &p_icon) { ERR_FAIL_INDEX(p_tab, tabs.size()); + + if (tabs[p_tab].icon == p_icon) { + return; + } + tabs.write[p_tab].icon = p_icon; _update_cache(); @@ -708,6 +718,11 @@ Ref<Texture2D> TabBar::get_tab_icon(int p_tab) const { void TabBar::set_tab_disabled(int p_tab, bool p_disabled) { ERR_FAIL_INDEX(p_tab, tabs.size()); + + if (tabs[p_tab].disabled == p_disabled) { + return; + } + tabs.write[p_tab].disabled = p_disabled; _update_cache(); @@ -726,6 +741,11 @@ bool TabBar::is_tab_disabled(int p_tab) const { void TabBar::set_tab_hidden(int p_tab, bool p_hidden) { ERR_FAIL_INDEX(p_tab, tabs.size()); + + if (tabs[p_tab].hidden == p_hidden) { + return; + } + tabs.write[p_tab].hidden = p_hidden; _update_cache(); @@ -744,6 +764,11 @@ bool TabBar::is_tab_hidden(int p_tab) const { void TabBar::set_tab_button_icon(int p_tab, const Ref<Texture2D> &p_icon) { ERR_FAIL_INDEX(p_tab, tabs.size()); + + if (tabs[p_tab].right_button == p_icon) { + return; + } + tabs.write[p_tab].right_button = p_icon; _update_cache(); @@ -1155,6 +1180,11 @@ int TabBar::get_tab_idx_at_point(const Point2 &p_point) const { void TabBar::set_tab_alignment(AlignmentMode p_alignment) { ERR_FAIL_INDEX(p_alignment, ALIGNMENT_MAX); + + if (tab_alignment == p_alignment) { + return; + } + tab_alignment = p_alignment; _update_cache(); @@ -1374,6 +1404,11 @@ Rect2 TabBar::get_tab_rect(int p_tab) const { void TabBar::set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy) { ERR_FAIL_INDEX(p_policy, CLOSE_BUTTON_MAX); + + if (cb_displaypolicy == p_policy) { + return; + } + cb_displaypolicy = p_policy; _update_cache(); @@ -1391,6 +1426,11 @@ TabBar::CloseButtonDisplayPolicy TabBar::get_tab_close_display_policy() const { void TabBar::set_max_tab_width(int p_width) { ERR_FAIL_COND(p_width < 0); + + if (max_width == p_width) { + return; + } + max_width = p_width; _update_cache(); diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 12f91a9873..10a6d18330 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -618,6 +618,10 @@ int TabContainer::get_tab_idx_from_control(Control *p_child) const { } void TabContainer::set_tab_alignment(TabBar::AlignmentMode p_alignment) { + if (tab_bar->get_tab_alignment() == p_alignment) { + return; + } + tab_bar->set_tab_alignment(p_alignment); _update_margins(); } @@ -679,6 +683,10 @@ void TabContainer::set_tab_title(int p_tab, const String &p_title) { Control *child = get_tab_control(p_tab); ERR_FAIL_COND(!child); + if (tab_bar->get_tab_title(p_tab) == p_title) { + return; + } + tab_bar->set_tab_title(p_tab, p_title); if (p_title == child->get_name()) { @@ -698,6 +706,10 @@ String TabContainer::get_tab_title(int p_tab) const { } void TabContainer::set_tab_icon(int p_tab, const Ref<Texture2D> &p_icon) { + if (tab_bar->get_tab_icon(p_tab) == p_icon) { + return; + } + tab_bar->set_tab_icon(p_tab, p_icon); _update_margins(); @@ -709,6 +721,10 @@ Ref<Texture2D> TabContainer::get_tab_icon(int p_tab) const { } void TabContainer::set_tab_disabled(int p_tab, bool p_disabled) { + if (tab_bar->is_tab_disabled(p_tab) == p_disabled) { + return; + } + tab_bar->set_tab_disabled(p_tab, p_disabled); _update_margins(); @@ -725,6 +741,10 @@ void TabContainer::set_tab_hidden(int p_tab, bool p_hidden) { Control *child = get_tab_control(p_tab); ERR_FAIL_COND(!child); + if (tab_bar->is_tab_hidden(p_tab) == p_hidden) { + return; + } + tab_bar->set_tab_hidden(p_tab, p_hidden); child->hide(); @@ -811,7 +831,11 @@ void TabContainer::set_popup(Node *p_popup) { bool had_popup = get_popup(); Popup *popup = Object::cast_to<Popup>(p_popup); - popup_obj_id = popup ? popup->get_instance_id() : ObjectID(); + ObjectID popup_id = popup ? popup->get_instance_id() : ObjectID(); + if (popup_obj_id == popup_id) { + return; + } + popup_obj_id = popup_id; if (had_popup != bool(popup)) { update(); @@ -855,6 +879,10 @@ int TabContainer::get_tabs_rearrange_group() const { } void TabContainer::set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs) { + if (use_hidden_tabs_for_min_size == p_use_hidden_tabs) { + return; + } + use_hidden_tabs_for_min_size = p_use_hidden_tabs; update_minimum_size(); } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 3755a8fa34..097eb1fd95 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -2889,6 +2889,10 @@ TextServer::StructuredTextParser TextEdit::get_structured_text_bidi_override() c } void TextEdit::set_structured_text_bidi_override_options(Array p_args) { + if (st_args == p_args) { + return; + } + st_args = p_args; for (int i = 0; i < text.size(); i++) { text.set(i, text[i], structured_text_parser(st_parser, st_args, text[i])); @@ -2917,6 +2921,10 @@ int TextEdit::get_tab_size() const { // User controls void TextEdit::set_overtype_mode_enabled(const bool p_enabled) { + if (overtype_mode == p_enabled) { + return; + } + overtype_mode = p_enabled; update(); } @@ -3036,6 +3044,10 @@ int TextEdit::get_line_count() const { } void TextEdit::set_placeholder(const String &p_text) { + if (placeholder_text == p_text) { + return; + } + placeholder_text = p_text; _update_placeholder(); update(); @@ -3945,6 +3957,10 @@ bool TextEdit::is_mouse_over_selection(bool p_edges) const { /* Caret */ void TextEdit::set_caret_type(CaretType p_type) { + if (caret_type == p_type) { + return; + } + caret_type = p_type; update(); } @@ -3954,6 +3970,10 @@ TextEdit::CaretType TextEdit::get_caret_type() const { } void TextEdit::set_caret_blink_enabled(const bool p_enabled) { + if (caret_blink_enabled == p_enabled) { + return; + } + caret_blink_enabled = p_enabled; if (has_focus()) { @@ -4114,6 +4134,10 @@ String TextEdit::get_word_under_caret() const { /* Selection. */ void TextEdit::set_selecting_enabled(const bool p_enabled) { + if (selecting_enabled == p_enabled) { + return; + } + selecting_enabled = p_enabled; if (!selecting_enabled) { @@ -4126,6 +4150,10 @@ bool TextEdit::is_selecting_enabled() const { } void TextEdit::set_deselect_on_focus_loss_enabled(const bool p_enabled) { + if (deselect_on_focus_loss_enabled == p_enabled) { + return; + } + deselect_on_focus_loss_enabled = p_enabled; if (p_enabled && selection.active && !has_focus()) { deselect(); @@ -4431,6 +4459,10 @@ bool TextEdit::is_smooth_scroll_enabled() const { } void TextEdit::set_scroll_past_end_of_file_enabled(const bool p_enabled) { + if (scroll_past_end_of_file_enabled == p_enabled) { + return; + } + scroll_past_end_of_file_enabled = p_enabled; update(); } @@ -4714,10 +4746,12 @@ void TextEdit::center_viewport_to_caret() { /* Minimap */ void TextEdit::set_draw_minimap(bool p_enabled) { - if (draw_minimap != p_enabled) { - draw_minimap = p_enabled; - _update_wrap_at_column(); + if (draw_minimap == p_enabled) { + return; } + + draw_minimap = p_enabled; + _update_wrap_at_column(); update(); } @@ -4726,10 +4760,12 @@ bool TextEdit::is_drawing_minimap() const { } void TextEdit::set_minimap_width(int p_minimap_width) { - if (minimap_width != p_minimap_width) { - minimap_width = p_minimap_width; - _update_wrap_at_column(); + if (minimap_width == p_minimap_width) { + return; } + + minimap_width = p_minimap_width; + _update_wrap_at_column(); update(); } @@ -4780,6 +4816,11 @@ String TextEdit::get_gutter_name(int p_gutter) const { void TextEdit::set_gutter_type(int p_gutter, GutterType p_type) { ERR_FAIL_INDEX(p_gutter, gutters.size()); + + if (gutters[p_gutter].type == p_type) { + return; + } + gutters.write[p_gutter].type = p_type; update(); } @@ -4823,6 +4864,11 @@ bool TextEdit::is_gutter_drawn(int p_gutter) const { void TextEdit::set_gutter_clickable(int p_gutter, bool p_clickable) { ERR_FAIL_INDEX(p_gutter, gutters.size()); + + if (gutters[p_gutter].clickable == p_clickable) { + return; + } + gutters.write[p_gutter].clickable = p_clickable; update(); } @@ -4878,6 +4924,10 @@ void TextEdit::merge_gutters(int p_from_line, int p_to_line) { void TextEdit::set_gutter_custom_draw(int p_gutter, const Callable &p_draw_callback) { ERR_FAIL_INDEX(p_gutter, gutters.size()); + if (gutters[p_gutter].custom_draw_callback == p_draw_callback) { + return; + } + gutters.write[p_gutter].custom_draw_callback = p_draw_callback; update(); } @@ -4898,6 +4948,11 @@ Variant TextEdit::get_line_gutter_metadata(int p_line, int p_gutter) const { void TextEdit::set_line_gutter_text(int p_line, int p_gutter, const String &p_text) { ERR_FAIL_INDEX(p_line, text.size()); ERR_FAIL_INDEX(p_gutter, gutters.size()); + + if (text.get_line_gutter_text(p_line, p_gutter) == p_text) { + return; + } + text.set_line_gutter_text(p_line, p_gutter, p_text); update(); } @@ -4911,6 +4966,11 @@ String TextEdit::get_line_gutter_text(int p_line, int p_gutter) const { void TextEdit::set_line_gutter_icon(int p_line, int p_gutter, const Ref<Texture2D> &p_icon) { ERR_FAIL_INDEX(p_line, text.size()); ERR_FAIL_INDEX(p_gutter, gutters.size()); + + if (text.get_line_gutter_icon(p_line, p_gutter) == p_icon) { + return; + } + text.set_line_gutter_icon(p_line, p_gutter, p_icon); update(); } @@ -4924,6 +4984,11 @@ Ref<Texture2D> TextEdit::get_line_gutter_icon(int p_line, int p_gutter) const { void TextEdit::set_line_gutter_item_color(int p_line, int p_gutter, const Color &p_color) { ERR_FAIL_INDEX(p_line, text.size()); ERR_FAIL_INDEX(p_gutter, gutters.size()); + + if (text.get_line_gutter_item_color(p_line, p_gutter) == p_color) { + return; + } + text.set_line_gutter_item_color(p_line, p_gutter, p_color); update(); } @@ -4949,6 +5014,11 @@ bool TextEdit::is_line_gutter_clickable(int p_line, int p_gutter) const { // Line style void TextEdit::set_line_background_color(int p_line, const Color &p_color) { ERR_FAIL_INDEX(p_line, text.size()); + + if (text.get_line_background_color(p_line) == p_color) { + return; + } + text.set_line_background_color(p_line, p_color); update(); } @@ -4960,6 +5030,10 @@ Color TextEdit::get_line_background_color(int p_line) const { /* Syntax Highlighting. */ void TextEdit::set_syntax_highlighter(Ref<SyntaxHighlighter> p_syntax_highlighter) { + if (syntax_highlighter == p_syntax_highlighter && syntax_highlighter.is_valid() == p_syntax_highlighter.is_valid()) { + return; + } + syntax_highlighter = p_syntax_highlighter; if (syntax_highlighter.is_valid()) { syntax_highlighter->set_text_edit(this); @@ -4973,6 +5047,10 @@ Ref<SyntaxHighlighter> TextEdit::get_syntax_highlighter() const { /* Visual. */ void TextEdit::set_highlight_current_line(bool p_enabled) { + if (highlight_current_line == p_enabled) { + return; + } + highlight_current_line = p_enabled; update(); } @@ -4982,6 +5060,10 @@ bool TextEdit::is_highlight_current_line_enabled() const { } void TextEdit::set_highlight_all_occurrences(const bool p_enabled) { + if (highlight_all_occurrences == p_enabled) { + return; + } + highlight_all_occurrences = p_enabled; update(); } @@ -5008,6 +5090,10 @@ bool TextEdit::get_draw_control_chars() const { } void TextEdit::set_draw_tabs(bool p_enabled) { + if (draw_tabs == p_enabled) { + return; + } + draw_tabs = p_enabled; update(); } @@ -5017,6 +5103,10 @@ bool TextEdit::is_drawing_tabs() const { } void TextEdit::set_draw_spaces(bool p_enabled) { + if (draw_spaces == p_enabled) { + return; + } + draw_spaces = p_enabled; update(); } @@ -5462,6 +5552,10 @@ void TextEdit::_bind_methods() { /* Internal API for CodeEdit. */ // Line hiding. void TextEdit::_set_hiding_enabled(bool p_enabled) { + if (hiding_enabled == p_enabled) { + return; + } + if (!p_enabled) { _unhide_all_lines(); } @@ -5488,6 +5582,11 @@ void TextEdit::_unhide_all_lines() { void TextEdit::_set_line_as_hidden(int p_line, bool p_hidden) { ERR_FAIL_INDEX(p_line, text.size()); + + if (text.is_hidden(p_line) == p_hidden) { + return; + } + if (_is_hiding_enabled() || !p_hidden) { text.set_hidden(p_line, p_hidden); } @@ -5496,6 +5595,10 @@ void TextEdit::_set_line_as_hidden(int p_line, bool p_hidden) { // Symbol lookup. void TextEdit::_set_symbol_lookup_word(const String &p_symbol) { + if (lookup_symbol_word == p_symbol) { + return; + } + lookup_symbol_word = p_symbol; update(); } diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 6711cf8c7f..f97f99075c 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -195,6 +195,9 @@ private: void set(int p_line, const String &p_text, const Array &p_bidi_override); void set_hidden(int p_line, bool p_hidden) { + if (text[p_line].hidden == p_hidden) { + return; + } text.write[p_line].hidden = p_hidden; if (!p_hidden && text[p_line].width > max_width) { max_width = text[p_line].width; diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index 26acfaaa70..916bb2981e 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -294,29 +294,48 @@ void TextureButton::_bind_methods() { } void TextureButton::set_normal_texture(const Ref<Texture2D> &p_normal) { + if (normal == p_normal) { + return; + } + normal = p_normal; update(); update_minimum_size(); } void TextureButton::set_pressed_texture(const Ref<Texture2D> &p_pressed) { + if (pressed == p_pressed) { + return; + } + pressed = p_pressed; update(); update_minimum_size(); } void TextureButton::set_hover_texture(const Ref<Texture2D> &p_hover) { + if (hover == p_hover) { + return; + } + hover = p_hover; update(); update_minimum_size(); } void TextureButton::set_disabled_texture(const Ref<Texture2D> &p_disabled) { + if (disabled == p_disabled) { + return; + } + disabled = p_disabled; update(); } void TextureButton::set_click_mask(const Ref<BitMap> &p_click_mask) { + if (click_mask == p_click_mask) { + return; + } click_mask = p_click_mask; update(); update_minimum_size(); @@ -355,12 +374,20 @@ bool TextureButton::get_ignore_texture_size() const { } void TextureButton::set_ignore_texture_size(bool p_ignore) { + if (ignore_texture_size == p_ignore) { + return; + } + ignore_texture_size = p_ignore; update_minimum_size(); update(); } void TextureButton::set_stretch_mode(StretchMode p_stretch_mode) { + if (stretch_mode == p_stretch_mode) { + return; + } + stretch_mode = p_stretch_mode; update(); } @@ -370,6 +397,10 @@ TextureButton::StretchMode TextureButton::get_stretch_mode() const { } void TextureButton::set_flip_h(bool p_flip) { + if (hflip == p_flip) { + return; + } + hflip = p_flip; update(); } @@ -379,6 +410,10 @@ bool TextureButton::is_flipped_h() const { } void TextureButton::set_flip_v(bool p_flip) { + if (vflip == p_flip) { + return; + } + vflip = p_flip; update(); } diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp index 94e0a6f226..2a9e1a8990 100644 --- a/scene/gui/texture_progress_bar.cpp +++ b/scene/gui/texture_progress_bar.cpp @@ -33,6 +33,10 @@ #include "core/config/engine.h" void TextureProgressBar::set_under_texture(const Ref<Texture2D> &p_texture) { + if (under == p_texture) { + return; + } + under = p_texture; update(); update_minimum_size(); @@ -43,6 +47,10 @@ Ref<Texture2D> TextureProgressBar::get_under_texture() const { } void TextureProgressBar::set_over_texture(const Ref<Texture2D> &p_texture) { + if (over == p_texture) { + return; + } + over = p_texture; update(); if (under.is_null()) { @@ -56,6 +64,11 @@ Ref<Texture2D> TextureProgressBar::get_over_texture() const { void TextureProgressBar::set_stretch_margin(Side p_side, int p_size) { ERR_FAIL_INDEX((int)p_side, 4); + + if (stretch_margin[p_side] == p_size) { + return; + } + stretch_margin[p_side] = p_size; update(); update_minimum_size(); @@ -67,6 +80,10 @@ int TextureProgressBar::get_stretch_margin(Side p_side) const { } void TextureProgressBar::set_nine_patch_stretch(bool p_stretch) { + if (nine_patch_stretch == p_stretch) { + return; + } + nine_patch_stretch = p_stretch; update(); update_minimum_size(); @@ -91,6 +108,10 @@ Size2 TextureProgressBar::get_minimum_size() const { } void TextureProgressBar::set_progress_texture(const Ref<Texture2D> &p_texture) { + if (progress == p_texture) { + return; + } + progress = p_texture; update(); update_minimum_size(); @@ -101,6 +122,10 @@ Ref<Texture2D> TextureProgressBar::get_progress_texture() const { } void TextureProgressBar::set_progress_offset(Point2 p_offset) { + if (progress_offset == p_offset) { + return; + } + progress_offset = p_offset; update(); } @@ -110,6 +135,10 @@ Point2 TextureProgressBar::get_progress_offset() const { } void TextureProgressBar::set_tint_under(const Color &p_tint) { + if (tint_under == p_tint) { + return; + } + tint_under = p_tint; update(); } @@ -119,6 +148,10 @@ Color TextureProgressBar::get_tint_under() const { } void TextureProgressBar::set_tint_progress(const Color &p_tint) { + if (tint_progress == p_tint) { + return; + } + tint_progress = p_tint; update(); } @@ -128,6 +161,10 @@ Color TextureProgressBar::get_tint_progress() const { } void TextureProgressBar::set_tint_over(const Color &p_tint) { + if (tint_over == p_tint) { + return; + } + tint_over = p_tint; update(); } @@ -548,6 +585,11 @@ void TextureProgressBar::_notification(int p_what) { void TextureProgressBar::set_fill_mode(int p_fill) { ERR_FAIL_INDEX(p_fill, FILL_MODE_MAX); + + if (mode == (FillMode)p_fill) { + return; + } + mode = (FillMode)p_fill; update(); } @@ -563,6 +605,11 @@ void TextureProgressBar::set_radial_initial_angle(float p_angle) { while (p_angle < 0) { p_angle += 360; } + + if (rad_init_angle == p_angle) { + return; + } + rad_init_angle = p_angle; update(); } @@ -572,7 +619,13 @@ float TextureProgressBar::get_radial_initial_angle() { } void TextureProgressBar::set_fill_degrees(float p_angle) { - rad_max_degrees = CLAMP(p_angle, 0, 360); + float angle_clamped = CLAMP(p_angle, 0, 360); + + if (rad_max_degrees == angle_clamped) { + return; + } + + rad_max_degrees = angle_clamped; update(); } @@ -581,6 +634,10 @@ float TextureProgressBar::get_fill_degrees() { } void TextureProgressBar::set_radial_center_offset(const Point2 &p_off) { + if (rad_center_off == p_off) { + return; + } + rad_center_off = p_off; update(); } diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp index ecdf55caf0..4dd1c74c12 100644 --- a/scene/gui/texture_rect.cpp +++ b/scene/gui/texture_rect.cpp @@ -179,6 +179,10 @@ Ref<Texture2D> TextureRect::get_texture() const { } void TextureRect::set_ignore_texture_size(bool p_ignore) { + if (ignore_texture_size == p_ignore) { + return; + } + ignore_texture_size = p_ignore; update(); update_minimum_size(); @@ -189,6 +193,10 @@ bool TextureRect::get_ignore_texture_size() const { } void TextureRect::set_stretch_mode(StretchMode p_mode) { + if (stretch_mode == p_mode) { + return; + } + stretch_mode = p_mode; update(); } @@ -198,6 +206,10 @@ TextureRect::StretchMode TextureRect::get_stretch_mode() const { } void TextureRect::set_flip_h(bool p_flip) { + if (hflip == p_flip) { + return; + } + hflip = p_flip; update(); } @@ -207,6 +219,10 @@ bool TextureRect::is_flipped_h() const { } void TextureRect::set_flip_v(bool p_flip) { + if (vflip == p_flip) { + return; + } + vflip = p_flip; update(); } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index ede7bfb0bf..2b19ee4d0b 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -141,6 +141,10 @@ void TreeItem::_change_tree(Tree *p_tree) { void TreeItem::set_cell_mode(int p_column, TreeCellMode p_mode) { ERR_FAIL_INDEX(p_column, cells.size()); + if (cells[p_column].mode == p_mode) { + return; + } + Cell &c = cells.write[p_column]; c.mode = p_mode; c.min = 0; @@ -166,6 +170,10 @@ TreeItem::TreeCellMode TreeItem::get_cell_mode(int p_column) const { void TreeItem::set_checked(int p_column, bool p_checked) { ERR_FAIL_INDEX(p_column, cells.size()); + if (cells[p_column].checked == p_checked) { + return; + } + cells.write[p_column].checked = p_checked; cells.write[p_column].indeterminate = false; cells.write[p_column].cached_minimum_size_dirty = true; @@ -259,6 +267,11 @@ void TreeItem::_propagate_check_through_parents(int p_column, bool p_emit_signal void TreeItem::set_text(int p_column, String p_text) { ERR_FAIL_INDEX(p_column, cells.size()); + + if (cells[p_column].text == p_text) { + return; + } + cells.write[p_column].text = p_text; cells.write[p_column].dirty = true; @@ -290,11 +303,14 @@ String TreeItem::get_text(int p_column) const { void TreeItem::set_text_direction(int p_column, Control::TextDirection p_text_direction) { ERR_FAIL_INDEX(p_column, cells.size()); ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3); - if (cells[p_column].text_direction != p_text_direction) { - cells.write[p_column].text_direction = p_text_direction; - cells.write[p_column].dirty = true; - _changed_notify(p_column); + + if (cells[p_column].text_direction == p_text_direction) { + return; } + + cells.write[p_column].text_direction = p_text_direction; + cells.write[p_column].dirty = true; + _changed_notify(p_column); cells.write[p_column].cached_minimum_size_dirty = true; } @@ -323,6 +339,10 @@ TextServer::StructuredTextParser TreeItem::get_structured_text_bidi_override(int void TreeItem::set_structured_text_bidi_override_options(int p_column, Array p_args) { ERR_FAIL_INDEX(p_column, cells.size()); + if (cells[p_column].st_args == p_args) { + return; + } + cells.write[p_column].st_args = p_args; cells.write[p_column].dirty = true; cells.write[p_column].cached_minimum_size_dirty = true; @@ -355,6 +375,10 @@ String TreeItem::get_language(int p_column) const { void TreeItem::set_suffix(int p_column, String p_suffix) { ERR_FAIL_INDEX(p_column, cells.size()); + if (cells[p_column].suffix == p_suffix) { + return; + } + cells.write[p_column].suffix = p_suffix; cells.write[p_column].cached_minimum_size_dirty = true; @@ -369,6 +393,10 @@ String TreeItem::get_suffix(int p_column) const { void TreeItem::set_icon(int p_column, const Ref<Texture2D> &p_icon) { ERR_FAIL_INDEX(p_column, cells.size()); + if (cells[p_column].icon == p_icon) { + return; + } + cells.write[p_column].icon = p_icon; cells.write[p_column].cached_minimum_size_dirty = true; @@ -383,6 +411,10 @@ Ref<Texture2D> TreeItem::get_icon(int p_column) const { void TreeItem::set_icon_region(int p_column, const Rect2 &p_icon_region) { ERR_FAIL_INDEX(p_column, cells.size()); + if (cells[p_column].icon_region == p_icon_region) { + return; + } + cells.write[p_column].icon_region = p_icon_region; cells.write[p_column].cached_minimum_size_dirty = true; @@ -396,6 +428,11 @@ Rect2 TreeItem::get_icon_region(int p_column) const { void TreeItem::set_icon_modulate(int p_column, const Color &p_modulate) { ERR_FAIL_INDEX(p_column, cells.size()); + + if (cells[p_column].icon_color == p_modulate) { + return; + } + cells.write[p_column].icon_color = p_modulate; _changed_notify(p_column); } @@ -408,6 +445,10 @@ Color TreeItem::get_icon_modulate(int p_column) const { void TreeItem::set_icon_max_width(int p_column, int p_max) { ERR_FAIL_INDEX(p_column, cells.size()); + if (cells[p_column].icon_max_w == p_max) { + return; + } + cells.write[p_column].icon_max_w = p_max; cells.write[p_column].cached_minimum_size_dirty = true; @@ -432,6 +473,10 @@ void TreeItem::set_range(int p_column, double p_value) { p_value = cells[p_column].max; } + if (cells[p_column].val == p_value) { + return; + } + cells.write[p_column].val = p_value; cells.write[p_column].dirty = true; _changed_notify(p_column); @@ -449,6 +494,11 @@ bool TreeItem::is_range_exponential(int p_column) const { void TreeItem::set_range_config(int p_column, double p_min, double p_max, double p_step, bool p_exp) { ERR_FAIL_INDEX(p_column, cells.size()); + + if (cells[p_column].min == p_min && cells[p_column].max == p_max && cells[p_column].step == p_step && cells[p_column].expr == p_exp) { + return; + } + cells.write[p_column].min = p_min; cells.write[p_column].max = p_max; cells.write[p_column].step = p_step; @@ -537,6 +587,10 @@ void TreeItem::uncollapse_tree() { } void TreeItem::set_custom_minimum_height(int p_height) { + if (custom_min_height == p_height) { + return; + } + custom_min_height = p_height; for (Cell &c : cells) { @@ -748,10 +802,10 @@ int TreeItem::get_child_count() { return children_cache.size(); } -Array TreeItem::get_children() { +TypedArray<TreeItem> TreeItem::get_children() { // Don't need to explicitly create children cache, because get_child_count creates it. int size = get_child_count(); - Array arr; + TypedArray<TreeItem> arr; arr.resize(size); for (int i = 0; i < size; i++) { arr[i] = children_cache[i]; @@ -913,6 +967,9 @@ void TreeItem::set_as_cursor(int p_column) { if (tree->select_mode != Tree::SELECT_MULTI) { return; } + if (tree->selected_col == p_column) { + return; + } tree->selected_item = this; tree->selected_col = p_column; tree->update(); @@ -990,6 +1047,11 @@ void TreeItem::set_button(int p_column, int p_idx, const Ref<Texture2D> &p_butto ERR_FAIL_COND(p_button.is_null()); ERR_FAIL_INDEX(p_column, cells.size()); ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size()); + + if (cells[p_column].buttons[p_idx].texture == p_button) { + return; + } + cells.write[p_column].buttons.write[p_idx].texture = p_button; cells.write[p_column].cached_minimum_size_dirty = true; @@ -999,6 +1061,11 @@ void TreeItem::set_button(int p_column, int p_idx, const Ref<Texture2D> &p_butto void TreeItem::set_button_color(int p_column, int p_idx, const Color &p_color) { ERR_FAIL_INDEX(p_column, cells.size()); ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size()); + + if (cells[p_column].buttons[p_idx].color == p_color) { + return; + } + cells.write[p_column].buttons.write[p_idx].color = p_color; _changed_notify(p_column); } @@ -1007,6 +1074,10 @@ void TreeItem::set_button_disabled(int p_column, int p_idx, bool p_disabled) { ERR_FAIL_INDEX(p_column, cells.size()); ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size()); + if (cells[p_column].buttons[p_idx].disabled == p_disabled) { + return; + } + cells.write[p_column].buttons.write[p_idx].disabled = p_disabled; cells.write[p_column].cached_minimum_size_dirty = true; @@ -1023,6 +1094,10 @@ bool TreeItem::is_button_disabled(int p_column, int p_idx) const { void TreeItem::set_editable(int p_column, bool p_editable) { ERR_FAIL_INDEX(p_column, cells.size()); + if (cells[p_column].editable == p_editable) { + return; + } + cells.write[p_column].editable = p_editable; cells.write[p_column].cached_minimum_size_dirty = true; @@ -1036,6 +1111,11 @@ bool TreeItem::is_editable(int p_column) { void TreeItem::set_custom_color(int p_column, const Color &p_color) { ERR_FAIL_INDEX(p_column, cells.size()); + + if (cells[p_column].custom_color == true) { + return; + } + cells.write[p_column].custom_color = true; cells.write[p_column].color = p_color; _changed_notify(p_column); @@ -1092,6 +1172,11 @@ String TreeItem::get_tooltip(int p_column) const { void TreeItem::set_custom_bg_color(int p_column, const Color &p_color, bool p_bg_outline) { ERR_FAIL_INDEX(p_column, cells.size()); + + if (cells[p_column].custom_bg_color && cells[p_column].custom_bg_outline == p_bg_outline && cells[p_column].bg_color == p_color) { + return; + } + cells.write[p_column].custom_bg_color = true; cells.write[p_column].custom_bg_outline = p_bg_outline; cells.write[p_column].bg_color = p_color; @@ -1128,6 +1213,10 @@ bool TreeItem::is_custom_set_as_button(int p_column) const { void TreeItem::set_text_alignment(int p_column, HorizontalAlignment p_alignment) { ERR_FAIL_INDEX(p_column, cells.size()); + if (cells[p_column].text_alignment == p_alignment) { + return; + } + cells.write[p_column].text_alignment = p_alignment; cells.write[p_column].cached_minimum_size_dirty = true; @@ -1142,6 +1231,10 @@ HorizontalAlignment TreeItem::get_text_alignment(int p_column) const { void TreeItem::set_expand_right(int p_column, bool p_enable) { ERR_FAIL_INDEX(p_column, cells.size()); + if (cells[p_column].expand_right == p_enable) { + return; + } + cells.write[p_column].expand_right = p_enable; cells.write[p_column].cached_minimum_size_dirty = true; @@ -1154,6 +1247,10 @@ bool TreeItem::get_expand_right(int p_column) const { } void TreeItem::set_disable_folding(bool p_disable) { + if (disable_folding == p_disable) { + return; + } + disable_folding = p_disable; for (Cell &c : cells) { @@ -3340,7 +3437,8 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { bool rtl = is_layout_rtl(); if (!mb->is_pressed()) { - if (mb->get_button_index() == MouseButton::LEFT) { + if (mb->get_button_index() == MouseButton::LEFT || + mb->get_button_index() == MouseButton::RIGHT) { Point2 pos = mb->get_position(); if (rtl) { pos.x = get_size().width - pos.x; @@ -3354,14 +3452,16 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { int len = 0; for (int i = 0; i < columns.size(); i++) { len += get_column_width(i); - if (pos.x < len) { - emit_signal(SNAME("column_title_pressed"), i); + if (pos.x < static_cast<real_t>(len)) { + emit_signal(SNAME("column_title_clicked"), i, mb->get_button_index()); break; } } } } + } + if (mb->get_button_index() == MouseButton::LEFT) { if (single_select_defer) { select_single_item(single_select_defer, root, single_select_defer_column); single_select_defer = nullptr; @@ -3449,18 +3549,15 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { pos.y -= _get_title_button_height(); if (pos.y < 0) { - if (mb->get_button_index() == MouseButton::LEFT) { - pos.x += cache.offset.x; - int len = 0; - for (int i = 0; i < columns.size(); i++) { - len += get_column_width(i); - if (pos.x < len) { - cache.click_type = Cache::CLICK_TITLE; - cache.click_index = i; - //cache.click_id=; - update(); - break; - } + pos.x += cache.offset.x; + int len = 0; + for (int i = 0; i < columns.size(); i++) { + len += get_column_width(i); + if (pos.x < static_cast<real_t>(len)) { + cache.click_type = Cache::CLICK_TITLE; + cache.click_index = i; + update(); + break; } } break; @@ -3621,12 +3718,17 @@ bool Tree::edit_selected() { } else if (c.mode == TreeItem::CELL_MODE_STRING || c.mode == TreeItem::CELL_MODE_RANGE) { Rect2 popup_rect; - Vector2 ofs(0, (text_editor->get_size().height - rect.size.height) / 2); + Vector2 ofs(0, Math::floor((text_editor->get_size().height - rect.size.height) / 2)); // "floor()" centers vertically. Point2i textedpos = get_screen_position() + rect.position - ofs; cache.text_editor_position = textedpos; popup_rect.position = textedpos; popup_rect.size = rect.size; + + // Account for icon. + popup_rect.position.x += c.get_icon_size().x; + popup_rect.size.x -= c.get_icon_size().x; + text_editor->clear(); text_editor->set_text(c.mode == TreeItem::CELL_MODE_STRING ? c.text : String::num(c.val, Math::range_step_decimals(c.step))); text_editor->select_all(); @@ -4098,6 +4200,10 @@ void Tree::clear() { }; void Tree::set_hide_root(bool p_enabled) { + if (hide_root == p_enabled) { + return; + } + hide_root = p_enabled; update(); } @@ -4109,6 +4215,10 @@ bool Tree::is_root_hidden() const { void Tree::set_column_custom_minimum_width(int p_column, int p_min_width) { ERR_FAIL_INDEX(p_column, columns.size()); + if (columns[p_column].custom_min_width == p_min_width) { + return; + } + if (p_min_width < 0) { return; } @@ -4119,12 +4229,21 @@ void Tree::set_column_custom_minimum_width(int p_column, int p_min_width) { void Tree::set_column_expand(int p_column, bool p_expand) { ERR_FAIL_INDEX(p_column, columns.size()); + if (columns[p_column].expand == p_expand) { + return; + } + columns.write[p_column].expand = p_expand; update(); } void Tree::set_column_expand_ratio(int p_column, int p_ratio) { ERR_FAIL_INDEX(p_column, columns.size()); + + if (columns[p_column].expand_ratio == p_ratio) { + return; + } + columns.write[p_column].expand_ratio = p_ratio; update(); } @@ -4132,6 +4251,10 @@ void Tree::set_column_expand_ratio(int p_column, int p_ratio) { void Tree::set_column_clip_content(int p_column, bool p_fit) { ERR_FAIL_INDEX(p_column, columns.size()); + if (columns[p_column].clip_content == p_fit) { + return; + } + columns.write[p_column].clip_content = p_fit; update(); } @@ -4454,6 +4577,10 @@ Rect2 Tree::get_item_rect(TreeItem *p_item, int p_column, int p_button) const { } void Tree::set_column_titles_visible(bool p_show) { + if (show_column_titles == p_show) { + return; + } + show_column_titles = p_show; update(); } @@ -4464,6 +4591,11 @@ bool Tree::are_column_titles_visible() const { void Tree::set_column_title(int p_column, const String &p_title) { ERR_FAIL_INDEX(p_column, columns.size()); + + if (columns[p_column].title == p_title) { + return; + } + if (cache.font.is_null()) { // avoid a strange case that may corrupt stuff update_cache(); } @@ -4545,6 +4677,10 @@ void Tree::scroll_to_item(TreeItem *p_item, bool p_center_on_item) { } void Tree::set_h_scroll_enabled(bool p_enable) { + if (h_scroll_enabled == p_enable) { + return; + } + h_scroll_enabled = p_enable; update_minimum_size(); } @@ -4554,6 +4690,10 @@ bool Tree::is_h_scroll_enabled() const { } void Tree::set_v_scroll_enabled(bool p_enable) { + if (v_scroll_enabled == p_enable) { + return; + } + v_scroll_enabled = p_enable; update_minimum_size(); } @@ -4882,6 +5022,10 @@ void Tree::set_cursor_can_exit_tree(bool p_enable) { } void Tree::set_hide_folding(bool p_hide) { + if (hide_folding == p_hide) { + return; + } + hide_folding = p_hide; update(); } @@ -5027,7 +5171,7 @@ void Tree::_bind_methods() { ADD_SIGNAL(MethodInfo("button_clicked", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "mouse_button_index"))); ADD_SIGNAL(MethodInfo("custom_popup_edited", PropertyInfo(Variant::BOOL, "arrow_clicked"))); ADD_SIGNAL(MethodInfo("item_activated")); - ADD_SIGNAL(MethodInfo("column_title_pressed", PropertyInfo(Variant::INT, "column"))); + ADD_SIGNAL(MethodInfo("column_title_clicked", PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::INT, "mouse_button_index"))); ADD_SIGNAL(MethodInfo("nothing_selected")); BIND_ENUM_CONSTANT(SELECT_SINGLE); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index bcc2419b80..7f9c00b1b9 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -339,7 +339,7 @@ public: TreeItem *get_child(int p_idx); int get_visible_child_count(); int get_child_count(); - Array get_children(); + TypedArray<TreeItem> get_children(); int get_index(); #ifdef DEV_ENABLED diff --git a/scene/gui/video_stream_player.cpp b/scene/gui/video_stream_player.cpp index f20a2ad67b..7baa4d44aa 100644 --- a/scene/gui/video_stream_player.cpp +++ b/scene/gui/video_stream_player.cpp @@ -208,6 +208,10 @@ Size2 VideoStreamPlayer::get_minimum_size() const { } void VideoStreamPlayer::set_expand(bool p_expand) { + if (expand == p_expand) { + return; + } + expand = p_expand; update(); update_minimum_size(); @@ -306,6 +310,10 @@ bool VideoStreamPlayer::is_playing() const { } void VideoStreamPlayer::set_paused(bool p_paused) { + if (paused == p_paused) { + return; + } + paused = p_paused; if (!p_paused && !can_process()) { paused_from_tree = true; diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 1bc0daef99..515f4d88a6 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -993,7 +993,7 @@ void CanvasItem::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask"); ADD_GROUP("Texture", "texture_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Aniso.,Linear Mipmap Aniso."), "set_texture_filter", "get_texture_filter"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter"); ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Inherit,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat"); ADD_GROUP("Material", ""); @@ -1333,7 +1333,7 @@ void CanvasTexture::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "specular_shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_specular_shininess", "get_specular_shininess"); ADD_GROUP("Texture", "texture_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Aniso.,Linear Mipmap Aniso."), "set_texture_filter", "get_texture_filter"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter"); ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Inherit,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat"); } diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index 8f40f257f9..4890db995a 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -335,7 +335,7 @@ void CanvasLayer::_bind_methods() { ADD_GROUP("", ""); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", PROPERTY_USAGE_NONE), "set_custom_viewport", "get_custom_viewport"); ADD_GROUP("Follow Viewport", "follow_viewport"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_viewport_enable"), "set_follow_viewport", "is_following_viewport"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_viewport_enabled"), "set_follow_viewport", "is_following_viewport"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "follow_viewport_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001,or_greater,or_lesser"), "set_follow_viewport_scale", "get_follow_viewport_scale"); ADD_SIGNAL(MethodInfo("visibility_changed")); diff --git a/scene/main/multiplayer_api.cpp b/scene/main/multiplayer_api.cpp index 95574042a8..2d2103f031 100644 --- a/scene/main/multiplayer_api.cpp +++ b/scene/main/multiplayer_api.cpp @@ -59,18 +59,18 @@ Ref<MultiplayerAPI> MultiplayerAPI::create_default_interface() { // The variant is compressed and encoded; The first byte contains all the meta // information and the format is: -// - The first LSB 5 bits are used for the variant type. +// - The first LSB 6 bits are used for the variant type. // - The next two bits are used to store the encoding mode. -// - The most significant is used to store the boolean value. -#define VARIANT_META_TYPE_MASK 0x1F -#define VARIANT_META_EMODE_MASK 0x60 +// - Boolean values uses the encoding mode to store the value. +#define VARIANT_META_TYPE_MASK 0x3F +#define VARIANT_META_EMODE_MASK 0xC0 #define VARIANT_META_BOOL_MASK 0x80 -#define ENCODE_8 0 << 5 -#define ENCODE_16 1 << 5 -#define ENCODE_32 2 << 5 -#define ENCODE_64 3 << 5 +#define ENCODE_8 0 << 6 +#define ENCODE_16 1 << 6 +#define ENCODE_32 2 << 6 +#define ENCODE_64 3 << 6 Error MultiplayerAPI::encode_and_compress_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_allow_object_decoding) { - // Unreachable because `VARIANT_MAX` == 27 and `ENCODE_VARIANT_MASK` == 31 + // Unreachable because `VARIANT_MAX` == 38 and `ENCODE_VARIANT_MASK` == 77 CRASH_COND(p_variant.get_type() > VARIANT_META_TYPE_MASK); uint8_t *buf = r_buffer; @@ -80,9 +80,9 @@ Error MultiplayerAPI::encode_and_compress_variant(const Variant &p_variant, uint switch (p_variant.get_type()) { case Variant::BOOL: { if (buf) { - // We still have 1 free bit in the meta, so let's use it. + // We don't use encode_mode for booleans, so we can use it to store the value. buf[0] = (p_variant.operator bool()) ? (1 << 7) : 0; - buf[0] |= encode_mode | p_variant.get_type(); + buf[0] |= p_variant.get_type(); } r_len += 1; } break; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index ea9788de27..cc3d14e5be 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -948,6 +948,21 @@ String Node::validate_child_name(Node *p_child) { } #endif +String Node::adjust_name_casing(const String &p_name) { + switch (GLOBAL_GET("editor/node_naming/name_casing").operator int()) { + case NAME_CASING_PASCAL_CASE: + return p_name.capitalize().replace(" ", ""); + case NAME_CASING_CAMEL_CASE: { + String name = p_name.capitalize().replace(" ", ""); + name[0] = name.to_lower()[0]; + return name; + } + case NAME_CASING_SNAKE_CASE: + return p_name.capitalize().replace(" ", "_").to_lower(); + } + return p_name; +} + void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) { /* Make sure the name is unique */ @@ -1021,19 +1036,8 @@ void Node::_generate_serial_child_name(const Node *p_child, StringName &name) co //no name and a new name is needed, create one. name = p_child->get_class(); - // Adjust casing according to project setting. The current type name is expected to be in PascalCase. - switch (ProjectSettings::get_singleton()->get("editor/node_naming/name_casing").operator int()) { - case NAME_CASING_PASCAL_CASE: - break; - case NAME_CASING_CAMEL_CASE: { - String n = name; - n[0] = n.to_lower()[0]; - name = n; - } break; - case NAME_CASING_SNAKE_CASE: - name = String(name).camelcase_to_underscore(true); - break; - } + // Adjust casing according to project setting. + name = adjust_name_casing(name); } //quickly test if proposed name exists @@ -1778,8 +1782,8 @@ void Node::remove_from_group(const StringName &p_identifier) { data.grouped.remove(E); } -Array Node::_get_groups() const { - Array groups; +TypedArray<StringName> Node::_get_groups() const { + TypedArray<StringName> groups; List<GroupInfo> gi; get_groups(&gi); for (const GroupInfo &E : gi) { diff --git a/scene/main/node.h b/scene/main/node.h index ccd1d561d2..703c580d3f 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -181,7 +181,7 @@ private: Node *_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap = nullptr) const; TypedArray<Node> _get_children(bool p_include_internal = true) const; - Array _get_groups() const; + TypedArray<StringName> _get_groups() const; Error _rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); Error _rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); @@ -459,6 +459,7 @@ public: #ifdef TOOLS_ENABLED String validate_child_name(Node *p_child); #endif + static String adjust_name_casing(const String &p_name); void queue_delete(); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 644fb3e9cc..109799e23a 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1000,8 +1000,8 @@ int64_t SceneTree::get_frame() const { return current_frame; } -Array SceneTree::_get_nodes_in_group(const StringName &p_group) { - Array ret; +TypedArray<Node> SceneTree::_get_nodes_in_group(const StringName &p_group) { + TypedArray<Node> ret; HashMap<StringName, Group>::Iterator E = group_map.find(p_group); if (!E) { return ret; @@ -1171,8 +1171,8 @@ Ref<Tween> SceneTree::create_tween() { return tween; } -Array SceneTree::get_processed_tweens() { - Array ret; +TypedArray<Tween> SceneTree::get_processed_tweens() { + TypedArray<Tween> ret; ret.resize(tweens.size()); int i = 0; diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index a512feacc8..e66363ab33 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -141,7 +141,7 @@ private: _FORCE_INLINE_ void _update_group_order(Group &g, bool p_use_priority = false); - Array _get_nodes_in_group(const StringName &p_group); + TypedArray<Node> _get_nodes_in_group(const StringName &p_group); Node *current_scene = nullptr; @@ -367,7 +367,7 @@ public: Ref<SceneTreeTimer> create_timer(double p_delay_sec, bool p_process_always = true); Ref<Tween> create_tween(); - Array get_processed_tweens(); + TypedArray<Tween> get_processed_tweens(); //used by Main::start, don't use otherwise void add_current_scene(Node *p_current); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index cc356e513c..36cc8ebfa2 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -798,6 +798,7 @@ void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override, RS::get_singleton()->viewport_set_size(viewport, 0, 0); } _update_global_transform(); + update_configuration_warnings(); update_canvas_items(); @@ -1875,7 +1876,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } } - DisplayServer::get_singleton()->cursor_set_shape(ds_cursor_shape); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CURSOR_SHAPE)) { + DisplayServer::get_singleton()->cursor_set_shape(ds_cursor_shape); + } } Ref<InputEventScreenTouch> touch_event = p_event; @@ -2684,7 +2687,9 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) { DisplayServer::CURSOR_FDIAGSIZE }; - DisplayServer::get_singleton()->cursor_set_shape(shapes[resize]); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CURSOR_SHAPE)) { + DisplayServer::get_singleton()->cursor_set_shape(shapes[resize]); + } return true; // Reserved for showing the resize cursor. } @@ -2849,8 +2854,8 @@ Variant Viewport::gui_get_drag_data() const { TypedArray<String> Viewport::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); - if (size.x == 0 || size.y == 0) { - warnings.push_back(RTR("Viewport size must be greater than 0 to render anything.")); + if (size.x <= 1 || size.y <= 1) { + warnings.push_back(RTR("The Viewport size must be greater than or equal to 2 pixels on both dimensions to render anything.")); } return warnings; } diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 63cc535e26..68037a1211 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -349,7 +349,9 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) { _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_ENTER); emit_signal(SNAME("mouse_entered")); notification(NOTIFICATION_VP_MOUSE_ENTER); - DisplayServer::get_singleton()->cursor_set_shape(DisplayServer::CURSOR_ARROW); //restore cursor shape + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CURSOR_SHAPE)) { + DisplayServer::get_singleton()->cursor_set_shape(DisplayServer::CURSOR_ARROW); //restore cursor shape + } } break; case DisplayServer::WINDOW_EVENT_MOUSE_EXIT: { notification(NOTIFICATION_VP_MOUSE_EXIT); @@ -846,21 +848,13 @@ void Window::_notification(int p_what) { RS::get_singleton()->viewport_set_active(get_viewport_rid(), true); } - if (theme.is_null()) { - Control *parent_c = cast_to<Control>(get_parent()); - if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) { - theme_owner = parent_c->data.theme_owner; - theme_owner_window = parent_c->data.theme_owner_window; - notification(NOTIFICATION_THEME_CHANGED); - } else { - Window *parent_w = cast_to<Window>(get_parent()); - if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) { - theme_owner = parent_w->theme_owner; - theme_owner_window = parent_w->theme_owner_window; - notification(NOTIFICATION_THEME_CHANGED); - } - } - } + // Need to defer here, because theme owner information might be set in + // add_child_notify, which doesn't get called until right after this. + call_deferred(SNAME("notification"), NOTIFICATION_THEME_CHANGED); + } break; + + case NOTIFICATION_THEME_CHANGED: { + emit_signal(SceneStringNames::get_singleton()->theme_changed); } break; case NOTIFICATION_READY: { @@ -1248,16 +1242,10 @@ Rect2i Window::get_usable_parent_rect() const { } void Window::add_child_notify(Node *p_child) { - Control *child_c = Object::cast_to<Control>(p_child); - - if (child_c && child_c->data.theme.is_null() && (theme_owner || theme_owner_window)) { - Control::_propagate_theme_changed(child_c, theme_owner, theme_owner_window); //need to propagate here, since many controls may require setting up stuff - } - - Window *child_w = Object::cast_to<Window>(p_child); - - if (child_w && child_w->theme.is_null() && (theme_owner || theme_owner_window)) { - Control::_propagate_theme_changed(child_w, theme_owner, theme_owner_window); //need to propagate here, since many controls may require setting up stuff + // We propagate when this node uses a custom theme, so it can pass it on to its children. + if (theme_owner || theme_owner_window) { + // `p_notify` is false here as `NOTIFICATION_THEME_CHANGED` will be handled by `NOTIFICATION_ENTER_TREE`. + Control::_propagate_theme_changed(this, theme_owner, theme_owner_window, false, true); } if (is_inside_tree() && wrap_controls) { @@ -1266,16 +1254,9 @@ void Window::add_child_notify(Node *p_child) { } void Window::remove_child_notify(Node *p_child) { - Control *child_c = Object::cast_to<Control>(p_child); - - if (child_c && (child_c->data.theme_owner || child_c->data.theme_owner_window) && child_c->data.theme.is_null()) { - Control::_propagate_theme_changed(child_c, nullptr, nullptr); - } - - Window *child_w = Object::cast_to<Window>(p_child); - - if (child_w && (child_w->theme_owner || child_w->theme_owner_window) && child_w->theme.is_null()) { - Control::_propagate_theme_changed(child_w, nullptr, nullptr); + // If the removed child isn't inheriting any theme items through this node, then there's no need to propagate. + if (theme_owner || theme_owner_window) { + Control::_propagate_theme_changed(this, nullptr, nullptr, false, true); } if (is_inside_tree() && wrap_controls) { @@ -1288,34 +1269,47 @@ void Window::set_theme(const Ref<Theme> &p_theme) { return; } + if (theme.is_valid()) { + theme->disconnect("changed", callable_mp(this, &Window::_theme_changed)); + } + theme = p_theme; + if (theme.is_valid()) { + Control::_propagate_theme_changed(this, nullptr, this, is_inside_tree(), true); + theme->connect("changed", callable_mp(this, &Window::_theme_changed), CONNECT_DEFERRED); + return; + } - if (!p_theme.is_null()) { - theme_owner = nullptr; - theme_owner_window = this; - Control::_propagate_theme_changed(this, nullptr, this); - } else { - Control *parent_c = cast_to<Control>(get_parent()); - if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) { - Control::_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window); - } else { - Window *parent_w = cast_to<Window>(get_parent()); - if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) { - Control::_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window); - } else { - Control::_propagate_theme_changed(this, nullptr, nullptr); - } - } + Control *parent_c = Object::cast_to<Control>(get_parent()); + if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) { + Control::_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window, is_inside_tree(), true); + return; } + + Window *parent_w = cast_to<Window>(get_parent()); + if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) { + Control::_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window, is_inside_tree(), true); + return; + } + + Control::_propagate_theme_changed(this, nullptr, nullptr, is_inside_tree(), true); } Ref<Theme> Window::get_theme() const { return theme; } +void Window::_theme_changed() { + if (is_inside_tree()) { + Control::_propagate_theme_changed(this, nullptr, this, true, false); + } +} + void Window::set_theme_type_variation(const StringName &p_theme_type) { theme_type_variation = p_theme_type; - Control::_propagate_theme_changed(this, theme_owner, theme_owner_window); + if (is_inside_tree()) { + notification(NOTIFICATION_THEME_CHANGED); + } } StringName Window::get_theme_type_variation() const { @@ -1710,6 +1704,7 @@ void Window::_bind_methods() { ADD_SIGNAL(MethodInfo("theme_changed")); BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED); + BIND_CONSTANT(NOTIFICATION_THEME_CHANGED); BIND_ENUM_CONSTANT(MODE_WINDOWED); BIND_ENUM_CONSTANT(MODE_MINIMIZED); diff --git a/scene/main/window.h b/scene/main/window.h index aa32edbb04..b1ae633997 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -253,6 +253,7 @@ public: void set_theme(const Ref<Theme> &p_theme); Ref<Theme> get_theme() const; + void _theme_changed(); void set_theme_type_variation(const StringName &p_theme_type); StringName get_theme_type_variation() const; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 265ee04bc8..9665873dce 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -50,6 +50,7 @@ #include "scene/2d/light_2d.h" #include "scene/2d/light_occluder_2d.h" #include "scene/2d/line_2d.h" +#include "scene/2d/marker_2d.h" #include "scene/2d/mesh_instance_2d.h" #include "scene/2d/multimesh_instance_2d.h" #include "scene/2d/navigation_agent_2d.h" @@ -60,7 +61,6 @@ #include "scene/2d/physical_bone_2d.h" #include "scene/2d/physics_body_2d.h" #include "scene/2d/polygon_2d.h" -#include "scene/2d/position_2d.h" #include "scene/2d/ray_cast_2d.h" #include "scene/2d/remote_transform_2d.h" #include "scene/2d/shape_cast_2d.h" @@ -162,7 +162,7 @@ #include "scene/resources/multimesh.h" #include "scene/resources/navigation_mesh.h" #include "scene/resources/packed_scene.h" -#include "scene/resources/particles_material.h" +#include "scene/resources/particle_process_material.h" #include "scene/resources/physics_material.h" #include "scene/resources/polygon_path_finder.h" #include "scene/resources/primitive_meshes.h" @@ -232,6 +232,7 @@ #include "scene/3d/light_3d.h" #include "scene/3d/lightmap_gi.h" #include "scene/3d/lightmap_probe.h" +#include "scene/3d/marker_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/multimesh_instance_3d.h" #include "scene/3d/navigation_agent_3d.h" @@ -241,7 +242,6 @@ #include "scene/3d/occluder_instance_3d.h" #include "scene/3d/path_3d.h" #include "scene/3d/physics_body_3d.h" -#include "scene/3d/position_3d.h" #include "scene/3d/ray_cast_3d.h" #include "scene/3d/reflection_probe.h" #include "scene/3d/remote_transform_3d.h" @@ -524,7 +524,7 @@ void register_scene_types() { GDREGISTER_CLASS(GPUParticlesAttractorSphere3D); GDREGISTER_CLASS(GPUParticlesAttractorVectorField3D); GDREGISTER_CLASS(CPUParticles3D); - GDREGISTER_CLASS(Position3D); + GDREGISTER_CLASS(Marker3D); GDREGISTER_CLASS(RootMotionView); OS::get_singleton()->yield(); // may take time to init @@ -696,7 +696,7 @@ void register_scene_types() { GDREGISTER_CLASS(Sprite2D); GDREGISTER_CLASS(SpriteFrames); GDREGISTER_CLASS(AnimatedSprite2D); - GDREGISTER_CLASS(Position2D); + GDREGISTER_CLASS(Marker2D); GDREGISTER_CLASS(Line2D); GDREGISTER_CLASS(MeshInstance2D); GDREGISTER_CLASS(MultiMeshInstance2D); @@ -761,9 +761,9 @@ void register_scene_types() { /* REGISTER RESOURCES */ GDREGISTER_ABSTRACT_CLASS(Shader); - GDREGISTER_CLASS(ParticlesMaterial); - SceneTree::add_idle_callback(ParticlesMaterial::flush_changes); - ParticlesMaterial::init_shaders(); + GDREGISTER_CLASS(ParticleProcessMaterial); + SceneTree::add_idle_callback(ParticleProcessMaterial::flush_changes); + ParticleProcessMaterial::init_shaders(); GDREGISTER_VIRTUAL_CLASS(Mesh); GDREGISTER_CLASS(ArrayMesh); @@ -780,7 +780,6 @@ void register_scene_types() { GDREGISTER_CLASS(CylinderMesh); GDREGISTER_CLASS(PlaneMesh); GDREGISTER_CLASS(PrismMesh); - GDREGISTER_CLASS(QuadMesh); GDREGISTER_CLASS(SphereMesh); GDREGISTER_CLASS(TextMesh); GDREGISTER_CLASS(TorusMesh); @@ -943,6 +942,7 @@ void register_scene_types() { ClassDB::add_compatibility_class("Navigation3D", "Node3D"); ClassDB::add_compatibility_class("Navigation2D", "Node2D"); ClassDB::add_compatibility_class("OpenSimplexNoise", "FastNoiseLite"); + ClassDB::add_compatibility_class("QuadMesh", "PlaneMesh"); ClassDB::add_compatibility_class("ToolButton", "Button"); ClassDB::add_compatibility_class("YSort", "Node2D"); // Portal and room occlusion was replaced by raster occlusion (OccluderInstance3D node). @@ -1019,6 +1019,7 @@ void register_scene_types() { ClassDB::add_compatibility_class("PanoramaSky", "Sky"); ClassDB::add_compatibility_class("Particles", "GPUParticles3D"); ClassDB::add_compatibility_class("Particles2D", "GPUParticles2D"); + ClassDB::add_compatibility_class("ParticlesMaterial", "ParticleProcessMaterial"); ClassDB::add_compatibility_class("Path", "Path3D"); ClassDB::add_compatibility_class("PathFollow", "PathFollow3D"); ClassDB::add_compatibility_class("PhysicalBone", "PhysicalBone3D"); @@ -1034,6 +1035,8 @@ void register_scene_types() { ClassDB::add_compatibility_class("PhysicsShapeQueryParameters", "PhysicsShapeQueryParameters3D"); ClassDB::add_compatibility_class("PinJoint", "PinJoint3D"); ClassDB::add_compatibility_class("PlaneShape", "WorldBoundaryShape3D"); + ClassDB::add_compatibility_class("Position2D", "Marker2D"); + ClassDB::add_compatibility_class("Position3D", "Marker3D"); ClassDB::add_compatibility_class("ProceduralSky", "Sky"); ClassDB::add_compatibility_class("RayCast", "RayCast3D"); ClassDB::add_compatibility_class("RayShape", "SeparationRayShape3D"); @@ -1211,7 +1214,7 @@ void unregister_scene_types() { ProceduralSkyMaterial::cleanup_shader(); #endif // _3D_DISABLED - ParticlesMaterial::finish_shaders(); + ParticleProcessMaterial::finish_shaders(); CanvasItemMaterial::finish_shaders(); ColorPicker::finish_shaders(); SceneStringNames::free(); diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 0782f779b5..980968497d 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -313,29 +313,37 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { Dictionary d = p_value; ERR_FAIL_COND_V(!d.has("times"), false); ERR_FAIL_COND_V(!d.has("points"), false); - Vector<real_t> times = d["times"]; Vector<real_t> values = d["points"]; +#ifdef TOOLS_ENABLED + ERR_FAIL_COND_V(!d.has("handle_modes"), false); + Vector<int> handle_modes = d["handle_modes"]; +#endif // TOOLS_ENABLED - ERR_FAIL_COND_V(times.size() * 6 != values.size(), false); + ERR_FAIL_COND_V(times.size() * 5 != values.size(), false); if (times.size()) { int valcount = times.size(); const real_t *rt = times.ptr(); const real_t *rv = values.ptr(); +#ifdef TOOLS_ENABLED + const int *rh = handle_modes.ptr(); +#endif // TOOLS_ENABLED bt->values.resize(valcount); for (int i = 0; i < valcount; i++) { bt->values.write[i].time = rt[i]; bt->values.write[i].transition = 0; //unused in bezier - bt->values.write[i].value.value = rv[i * 6 + 0]; - bt->values.write[i].value.in_handle.x = rv[i * 6 + 1]; - bt->values.write[i].value.in_handle.y = rv[i * 6 + 2]; - bt->values.write[i].value.out_handle.x = rv[i * 6 + 3]; - bt->values.write[i].value.out_handle.y = rv[i * 6 + 4]; - bt->values.write[i].value.handle_mode = static_cast<HandleMode>((int)rv[i * 6 + 5]); + bt->values.write[i].value.value = rv[i * 5 + 0]; + bt->values.write[i].value.in_handle.x = rv[i * 5 + 1]; + bt->values.write[i].value.in_handle.y = rv[i * 5 + 2]; + bt->values.write[i].value.out_handle.x = rv[i * 5 + 3]; + bt->values.write[i].value.out_handle.y = rv[i * 5 + 4]; +#ifdef TOOLS_ENABLED + bt->values.write[i].value.handle_mode = static_cast<HandleMode>(rh[i]); +#endif // TOOLS_ENABLED } } @@ -699,28 +707,39 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { int kk = bt->values.size(); key_times.resize(kk); - key_points.resize(kk * 6); + key_points.resize(kk * 5); real_t *wti = key_times.ptrw(); real_t *wpo = key_points.ptrw(); +#ifdef TOOLS_ENABLED + Vector<int> handle_modes; + handle_modes.resize(kk); + int *whm = handle_modes.ptrw(); +#endif // TOOLS_ENABLED + int idx = 0; const TKey<BezierKey> *vls = bt->values.ptr(); for (int i = 0; i < kk; i++) { wti[idx] = vls[i].time; - wpo[idx * 6 + 0] = vls[i].value.value; - wpo[idx * 6 + 1] = vls[i].value.in_handle.x; - wpo[idx * 6 + 2] = vls[i].value.in_handle.y; - wpo[idx * 6 + 3] = vls[i].value.out_handle.x; - wpo[idx * 6 + 4] = vls[i].value.out_handle.y; - wpo[idx * 6 + 5] = (double)vls[i].value.handle_mode; + wpo[idx * 5 + 0] = vls[i].value.value; + wpo[idx * 5 + 1] = vls[i].value.in_handle.x; + wpo[idx * 5 + 2] = vls[i].value.in_handle.y; + wpo[idx * 5 + 3] = vls[i].value.out_handle.x; + wpo[idx * 5 + 4] = vls[i].value.out_handle.y; +#ifdef TOOLS_ENABLED + whm[idx] = static_cast<int>(vls[i].value.handle_mode); +#endif // TOOLS_ENABLED idx++; } d["times"] = key_times; d["points"] = key_points; +#ifdef TOOLS_ENABLED + d["handle_modes"] = handle_modes; +#endif // TOOLS_ENABLED r_ret = d; @@ -1626,7 +1645,7 @@ int Animation::track_insert_key(int p_track, double p_time, const Variant &p_key BezierTrack *bt = static_cast<BezierTrack *>(t); Array arr = p_key; - ERR_FAIL_COND_V(arr.size() != 6, -1); + ERR_FAIL_COND_V(arr.size() != 5, -1); TKey<BezierKey> k; k.time = p_time; @@ -1635,9 +1654,16 @@ int Animation::track_insert_key(int p_track, double p_time, const Variant &p_key k.value.in_handle.y = arr[2]; k.value.out_handle.x = arr[3]; k.value.out_handle.y = arr[4]; - k.value.handle_mode = static_cast<HandleMode>((int)arr[5]); ret = _insert(p_time, bt->values, k); + Vector<int> key_neighborhood; + key_neighborhood.push_back(ret); + if (ret > 0) { + key_neighborhood.push_back(ret - 1); + } + if (ret < track_get_key_count(p_track) - 1) { + key_neighborhood.push_back(ret + 1); + } } break; case TYPE_AUDIO: { AudioTrack *at = static_cast<AudioTrack *>(t); @@ -1776,13 +1802,12 @@ Variant Animation::track_get_key_value(int p_track, int p_key_idx) const { ERR_FAIL_INDEX_V(p_key_idx, bt->values.size(), Variant()); Array arr; - arr.resize(6); + arr.resize(5); arr[0] = bt->values[p_key_idx].value.value; arr[1] = bt->values[p_key_idx].value.in_handle.x; arr[2] = bt->values[p_key_idx].value.in_handle.y; arr[3] = bt->values[p_key_idx].value.out_handle.x; arr[4] = bt->values[p_key_idx].value.out_handle.y; - arr[5] = (double)bt->values[p_key_idx].value.handle_mode; return arr; } break; @@ -2151,14 +2176,13 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p ERR_FAIL_INDEX(p_key_idx, bt->values.size()); Array arr = p_value; - ERR_FAIL_COND(arr.size() != 6); + ERR_FAIL_COND(arr.size() != 5); bt->values.write[p_key_idx].value.value = arr[0]; bt->values.write[p_key_idx].value.in_handle.x = arr[1]; bt->values.write[p_key_idx].value.in_handle.y = arr[2]; bt->values.write[p_key_idx].value.out_handle.x = arr[3]; bt->values.write[p_key_idx].value.out_handle.y = arr[4]; - bt->values.write[p_key_idx].value.handle_mode = static_cast<HandleMode>((int)arr[5]); } break; case TYPE_AUDIO: { @@ -2304,96 +2328,6 @@ real_t Animation::_interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) // Cubic interpolation for anytype. -Vector3 Animation::_cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c) const { - return p_a.cubic_interpolate(p_b, p_pre_a, p_post_b, p_c); -} - -Quaternion Animation::_cubic_interpolate(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c) const { - return p_a.spherical_cubic_interpolate(p_b, p_pre_a, p_post_b, p_c); -} - -Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c) const { - Variant::Type type_a = p_a.get_type(); - Variant::Type type_b = p_b.get_type(); - Variant::Type type_pa = p_pre_a.get_type(); - Variant::Type type_pb = p_post_b.get_type(); - - //make int and real play along - - uint32_t vformat = 1 << type_a; - vformat |= 1 << type_b; - vformat |= 1 << type_pa; - vformat |= 1 << type_pb; - - if (vformat == ((1 << Variant::INT) | (1 << Variant::FLOAT)) || vformat == (1 << Variant::FLOAT)) { - //mix of real and int - real_t a = p_a; - real_t b = p_b; - real_t pa = p_pre_a; - real_t pb = p_post_b; - - return Math::cubic_interpolate(a, b, pa, pb, p_c); - } else if ((vformat & (vformat - 1))) { - return p_a; //can't interpolate, mix of types - } - - switch (type_a) { - case Variant::VECTOR2: { - Vector2 a = p_a; - Vector2 b = p_b; - Vector2 pa = p_pre_a; - Vector2 pb = p_post_b; - - return a.cubic_interpolate(b, pa, pb, p_c); - } - case Variant::RECT2: { - Rect2 a = p_a; - Rect2 b = p_b; - Rect2 pa = p_pre_a; - Rect2 pb = p_post_b; - - return Rect2( - a.position.cubic_interpolate(b.position, pa.position, pb.position, p_c), - a.size.cubic_interpolate(b.size, pa.size, pb.size, p_c)); - } - case Variant::VECTOR3: { - Vector3 a = p_a; - Vector3 b = p_b; - Vector3 pa = p_pre_a; - Vector3 pb = p_post_b; - - return a.cubic_interpolate(b, pa, pb, p_c); - } - case Variant::QUATERNION: { - Quaternion a = p_a; - Quaternion b = p_b; - Quaternion pa = p_pre_a; - Quaternion pb = p_post_b; - - return a.spherical_cubic_interpolate(b, pa, pb, p_c); - } - case Variant::AABB: { - AABB a = p_a; - AABB b = p_b; - AABB pa = p_pre_a; - AABB pb = p_post_b; - - return AABB( - a.position.cubic_interpolate(b.position, pa.position, pb.position, p_c), - a.size.cubic_interpolate(b.size, pa.size, pb.size, p_c)); - } - default: { - return _interpolate(p_a, p_b, p_c); - } - } -} - -real_t Animation::_cubic_interpolate(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c) const { - return _interpolate(p_a, p_b, p_c); -} - -// Cubic interpolation in time for anytype. - Vector3 Animation::_cubic_interpolate_in_time(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const { return p_a.cubic_interpolate_in_time(p_b, p_pre_a, p_post_b, p_c, p_b_t, p_pre_a_t, p_post_b_t); } @@ -2661,8 +2595,7 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol case INTERPOLATION_LINEAR: { return _interpolate(p_keys[idx].value, p_keys[next].value, c); } break; - case INTERPOLATION_CUBIC: - case INTERPOLATION_CUBIC_IN_TIME: { + case INTERPOLATION_CUBIC: { int pre = 0; int post = 0; if (!p_backward) { @@ -2702,9 +2635,6 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol } if (loop_mode == LOOP_LINEAR && p_loop_wrap) { - if (p_interp == INTERPOLATION_CUBIC) { - return _cubic_interpolate(p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c); - } return _cubic_interpolate_in_time( p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c, pre > idx ? -length + p_keys[pre].time - p_keys[idx].time : p_keys[pre].time - p_keys[idx].time, @@ -2712,9 +2642,6 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol next < idx || post <= idx ? length + p_keys[post].time - p_keys[idx].time : p_keys[post].time - p_keys[idx].time); } - if (p_interp == INTERPOLATION_CUBIC) { - return _cubic_interpolate(p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c); - } return _cubic_interpolate_in_time( p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c, p_keys[pre].time - p_keys[idx].time, @@ -3347,7 +3274,7 @@ StringName Animation::method_track_get_name(int p_track, int p_key_idx) const { return pm->methods[p_key_idx].method; } -int Animation::bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const HandleMode p_handle_mode) { +int Animation::bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle) { ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); Track *t = tracks[p_track]; ERR_FAIL_COND_V(t->type != TYPE_BEZIER, -1); @@ -3365,7 +3292,6 @@ int Animation::bezier_track_insert_key(int p_track, double p_time, real_t p_valu if (k.value.out_handle.x < 0) { k.value.out_handle.x = 0; } - k.value.handle_mode = p_handle_mode; int key = _insert(p_time, bt->values, k); @@ -3374,30 +3300,6 @@ int Animation::bezier_track_insert_key(int p_track, double p_time, real_t p_valu return key; } -void Animation::bezier_track_set_key_handle_mode(int p_track, int p_index, HandleMode p_mode, double p_balanced_value_time_ratio) { - ERR_FAIL_INDEX(p_track, tracks.size()); - Track *t = tracks[p_track]; - ERR_FAIL_COND(t->type != TYPE_BEZIER); - - BezierTrack *bt = static_cast<BezierTrack *>(t); - - ERR_FAIL_INDEX(p_index, bt->values.size()); - - bt->values.write[p_index].value.handle_mode = p_mode; - - if (p_mode == HANDLE_MODE_BALANCED) { - Transform2D xform; - xform.set_scale(Vector2(1.0, 1.0 / p_balanced_value_time_ratio)); - - Vector2 vec_in = xform.xform(bt->values[p_index].value.in_handle); - Vector2 vec_out = xform.xform(bt->values[p_index].value.out_handle); - - bt->values.write[p_index].value.in_handle = xform.affine_inverse().xform(-vec_out.normalized() * vec_in.length()); - } - - emit_changed(); -} - void Animation::bezier_track_set_key_value(int p_track, int p_index, real_t p_value) { ERR_FAIL_INDEX(p_track, tracks.size()); Track *t = tracks[p_track]; @@ -3408,10 +3310,11 @@ void Animation::bezier_track_set_key_value(int p_track, int p_index, real_t p_va ERR_FAIL_INDEX(p_index, bt->values.size()); bt->values.write[p_index].value.value = p_value; + emit_changed(); } -void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle, double p_balanced_value_time_ratio) { +void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle, real_t p_balanced_value_time_ratio) { ERR_FAIL_INDEX(p_track, tracks.size()); Track *t = tracks[p_track]; ERR_FAIL_COND(t->type != TYPE_BEZIER); @@ -3426,7 +3329,11 @@ void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const V } bt->values.write[p_index].value.in_handle = in_handle; - if (bt->values[p_index].value.handle_mode == HANDLE_MODE_BALANCED) { +#ifdef TOOLS_ENABLED + if (bt->values[p_index].value.handle_mode == HANDLE_MODE_LINEAR) { + bt->values.write[p_index].value.in_handle = Vector2(); + bt->values.write[p_index].value.out_handle = Vector2(); + } else if (bt->values[p_index].value.handle_mode == HANDLE_MODE_BALANCED) { Transform2D xform; xform.set_scale(Vector2(1.0, 1.0 / p_balanced_value_time_ratio)); @@ -3434,12 +3341,15 @@ void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const V Vector2 vec_in = xform.xform(in_handle); bt->values.write[p_index].value.out_handle = xform.affine_inverse().xform(-vec_in.normalized() * vec_out.length()); + } else if (bt->values[p_index].value.handle_mode == HANDLE_MODE_MIRRORED) { + bt->values.write[p_index].value.out_handle = -in_handle; } +#endif // TOOLS_ENABLED emit_changed(); } -void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle, double p_balanced_value_time_ratio) { +void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle, real_t p_balanced_value_time_ratio) { ERR_FAIL_INDEX(p_track, tracks.size()); Track *t = tracks[p_track]; ERR_FAIL_COND(t->type != TYPE_BEZIER); @@ -3454,7 +3364,11 @@ void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const } bt->values.write[p_index].value.out_handle = out_handle; - if (bt->values[p_index].value.handle_mode == HANDLE_MODE_BALANCED) { +#ifdef TOOLS_ENABLED + if (bt->values[p_index].value.handle_mode == HANDLE_MODE_LINEAR) { + bt->values.write[p_index].value.in_handle = Vector2(); + bt->values.write[p_index].value.out_handle = Vector2(); + } else if (bt->values[p_index].value.handle_mode == HANDLE_MODE_BALANCED) { Transform2D xform; xform.set_scale(Vector2(1.0, 1.0 / p_balanced_value_time_ratio)); @@ -3462,7 +3376,10 @@ void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 vec_out = xform.xform(out_handle); bt->values.write[p_index].value.in_handle = xform.affine_inverse().xform(-vec_out.normalized() * vec_in.length()); + } else if (bt->values[p_index].value.handle_mode == HANDLE_MODE_MIRRORED) { + bt->values.write[p_index].value.in_handle = -out_handle; } +#endif // TOOLS_ENABLED emit_changed(); } @@ -3479,18 +3396,6 @@ real_t Animation::bezier_track_get_key_value(int p_track, int p_index) const { return bt->values[p_index].value.value; } -int Animation::bezier_track_get_key_handle_mode(int p_track, int p_index) const { - ERR_FAIL_INDEX_V(p_track, tracks.size(), 0); - Track *t = tracks[p_track]; - ERR_FAIL_COND_V(t->type != TYPE_BEZIER, 0); - - BezierTrack *bt = static_cast<BezierTrack *>(t); - - ERR_FAIL_INDEX_V(p_index, bt->values.size(), 0); - - return bt->values[p_index].value.handle_mode; -} - Vector2 Animation::bezier_track_get_key_in_handle(int p_track, int p_index) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), Vector2()); Track *t = tracks[p_track]; @@ -3515,6 +3420,109 @@ Vector2 Animation::bezier_track_get_key_out_handle(int p_track, int p_index) con return bt->values[p_index].value.out_handle; } +#ifdef TOOLS_ENABLED +void Animation::bezier_track_set_key_handle_mode(int p_track, int p_index, HandleMode p_mode, HandleSetMode p_set_mode) { + ERR_FAIL_INDEX(p_track, tracks.size()); + Track *t = tracks[p_track]; + ERR_FAIL_COND(t->type != TYPE_BEZIER); + + BezierTrack *bt = static_cast<BezierTrack *>(t); + + ERR_FAIL_INDEX(p_index, bt->values.size()); + + bt->values.write[p_index].value.handle_mode = p_mode; + + switch (p_mode) { + case HANDLE_MODE_LINEAR: { + bt->values.write[p_index].value.in_handle = Vector2(0, 0); + bt->values.write[p_index].value.out_handle = Vector2(0, 0); + } break; + case HANDLE_MODE_BALANCED: + case HANDLE_MODE_MIRRORED: { + int prev_key = MAX(0, p_index - 1); + int next_key = MIN(bt->values.size() - 1, p_index + 1); + if (prev_key == next_key) { + break; // Exists only one key. + } + real_t in_handle_x = 0; + real_t in_handle_y = 0; + real_t out_handle_x = 0; + real_t out_handle_y = 0; + if (p_mode == HANDLE_MODE_BALANCED) { + // Note: + // If p_set_mode == HANDLE_SET_MODE_NONE, I don't know if it should change the Tangent implicitly. + // At the least, we need to avoid corrupting the handles when loading animation from the resource. + // However, changes made by the Inspector do not go through the BezierEditor, + // so if you change from Free to Balanced or Mirrored in Inspector, there is no guarantee that + // it is Balanced or Mirrored until there is a handle operation. + if (p_set_mode == HANDLE_SET_MODE_RESET) { + real_t handle_length = 1.0 / 3.0; + in_handle_x = (bt->values[prev_key].time - bt->values[p_index].time) * handle_length; + in_handle_y = 0; + out_handle_x = (bt->values[next_key].time - bt->values[p_index].time) * handle_length; + out_handle_y = 0; + bt->values.write[p_index].value.in_handle = Vector2(in_handle_x, in_handle_y); + bt->values.write[p_index].value.out_handle = Vector2(out_handle_x, out_handle_y); + } else if (p_set_mode == HANDLE_SET_MODE_AUTO) { + real_t handle_length = 1.0 / 6.0; + real_t tangent = (bt->values[next_key].value.value - bt->values[prev_key].value.value) / (bt->values[next_key].time - bt->values[prev_key].time); + in_handle_x = (bt->values[prev_key].time - bt->values[p_index].time) * handle_length; + in_handle_y = in_handle_x * tangent; + out_handle_x = (bt->values[next_key].time - bt->values[p_index].time) * handle_length; + out_handle_y = out_handle_x * tangent; + bt->values.write[p_index].value.in_handle = Vector2(in_handle_x, in_handle_y); + bt->values.write[p_index].value.out_handle = Vector2(out_handle_x, out_handle_y); + } + } else { + real_t handle_length = 1.0 / 4.0; + real_t prev_interval = Math::abs(bt->values[p_index].time - bt->values[prev_key].time); + real_t next_interval = Math::abs(bt->values[p_index].time - bt->values[next_key].time); + real_t min_time = 0; + if (Math::is_zero_approx(prev_interval)) { + min_time = next_interval; + } else if (Math::is_zero_approx(next_interval)) { + min_time = prev_interval; + } else { + min_time = MIN(prev_interval, next_interval); + } + if (p_set_mode == HANDLE_SET_MODE_RESET) { + in_handle_x = -min_time * handle_length; + in_handle_y = 0; + out_handle_x = min_time * handle_length; + out_handle_y = 0; + bt->values.write[p_index].value.in_handle = Vector2(in_handle_x, in_handle_y); + bt->values.write[p_index].value.out_handle = Vector2(out_handle_x, out_handle_y); + } else if (p_set_mode == HANDLE_SET_MODE_AUTO) { + real_t tangent = (bt->values[next_key].value.value - bt->values[prev_key].value.value) / min_time; + in_handle_x = -min_time * handle_length; + in_handle_y = in_handle_x * tangent; + out_handle_x = min_time * handle_length; + out_handle_y = out_handle_x * tangent; + bt->values.write[p_index].value.in_handle = Vector2(in_handle_x, in_handle_y); + bt->values.write[p_index].value.out_handle = Vector2(out_handle_x, out_handle_y); + } + } + } break; + default: { + } break; + } + + emit_changed(); +} + +Animation::HandleMode Animation::bezier_track_get_key_handle_mode(int p_track, int p_index) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), HANDLE_MODE_FREE); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_BEZIER, HANDLE_MODE_FREE); + + BezierTrack *bt = static_cast<BezierTrack *>(t); + + ERR_FAIL_INDEX_V(p_index, bt->values.size(), HANDLE_MODE_FREE); + + return bt->values[p_index].value.handle_mode; +} +#endif // TOOLS_ENABLED + real_t Animation::bezier_track_interpolate(int p_track, double p_time) const { //this uses a different interpolation scheme ERR_FAIL_INDEX_V(p_track, tracks.size(), 0); @@ -3911,7 +3919,7 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("method_track_get_name", "track_idx", "key_idx"), &Animation::method_track_get_name); ClassDB::bind_method(D_METHOD("method_track_get_params", "track_idx", "key_idx"), &Animation::method_track_get_params); - ClassDB::bind_method(D_METHOD("bezier_track_insert_key", "track_idx", "time", "value", "in_handle", "out_handle", "handle_mode"), &Animation::bezier_track_insert_key, DEFVAL(Vector2()), DEFVAL(Vector2()), DEFVAL(Animation::HandleMode::HANDLE_MODE_BALANCED)); + ClassDB::bind_method(D_METHOD("bezier_track_insert_key", "track_idx", "time", "value", "in_handle", "out_handle"), &Animation::bezier_track_insert_key, DEFVAL(Vector2()), DEFVAL(Vector2())); ClassDB::bind_method(D_METHOD("bezier_track_set_key_value", "track_idx", "key_idx", "value"), &Animation::bezier_track_set_key_value); ClassDB::bind_method(D_METHOD("bezier_track_set_key_in_handle", "track_idx", "key_idx", "in_handle", "balanced_value_time_ratio"), &Animation::bezier_track_set_key_in_handle, DEFVAL(1.0)); @@ -3931,9 +3939,6 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("audio_track_get_key_start_offset", "track_idx", "key_idx"), &Animation::audio_track_get_key_start_offset); ClassDB::bind_method(D_METHOD("audio_track_get_key_end_offset", "track_idx", "key_idx"), &Animation::audio_track_get_key_end_offset); - ClassDB::bind_method(D_METHOD("bezier_track_set_key_handle_mode", "track_idx", "key_idx", "key_handle_mode", "balanced_value_time_ratio"), &Animation::bezier_track_set_key_handle_mode, DEFVAL(1.0)); - ClassDB::bind_method(D_METHOD("bezier_track_get_key_handle_mode", "track_idx", "key_idx"), &Animation::bezier_track_get_key_handle_mode); - ClassDB::bind_method(D_METHOD("animation_track_insert_key", "track_idx", "time", "animation"), &Animation::animation_track_insert_key); ClassDB::bind_method(D_METHOD("animation_track_set_key_animation", "track_idx", "key_idx", "animation"), &Animation::animation_track_set_key_animation); ClassDB::bind_method(D_METHOD("animation_track_get_key_animation", "track_idx", "key_idx"), &Animation::animation_track_get_key_animation); @@ -3971,7 +3976,6 @@ void Animation::_bind_methods() { BIND_ENUM_CONSTANT(INTERPOLATION_NEAREST); BIND_ENUM_CONSTANT(INTERPOLATION_LINEAR); BIND_ENUM_CONSTANT(INTERPOLATION_CUBIC); - BIND_ENUM_CONSTANT(INTERPOLATION_CUBIC_IN_TIME); BIND_ENUM_CONSTANT(UPDATE_CONTINUOUS); BIND_ENUM_CONSTANT(UPDATE_DISCRETE); @@ -3981,9 +3985,6 @@ void Animation::_bind_methods() { BIND_ENUM_CONSTANT(LOOP_NONE); BIND_ENUM_CONSTANT(LOOP_LINEAR); BIND_ENUM_CONSTANT(LOOP_PINGPONG); - - BIND_ENUM_CONSTANT(HANDLE_MODE_FREE); - BIND_ENUM_CONSTANT(HANDLE_MODE_BALANCED); } void Animation::clear() { diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 367134b94c..f5eadd2646 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -57,7 +57,6 @@ public: INTERPOLATION_NEAREST, INTERPOLATION_LINEAR, INTERPOLATION_CUBIC, - INTERPOLATION_CUBIC_IN_TIME, }; enum UpdateMode { @@ -73,10 +72,19 @@ public: LOOP_PINGPONG, }; +#ifdef TOOLS_ENABLED enum HandleMode { HANDLE_MODE_FREE, + HANDLE_MODE_LINEAR, HANDLE_MODE_BALANCED, + HANDLE_MODE_MIRRORED, }; + enum HandleSetMode { + HANDLE_SET_MODE_NONE, + HANDLE_SET_MODE_RESET, + HANDLE_SET_MODE_AUTO, + }; +#endif // TOOLS_ENABLED private: struct Track { @@ -166,8 +174,10 @@ private: struct BezierKey { Vector2 in_handle; //relative (x always <0) Vector2 out_handle; //relative (x always >0) - HandleMode handle_mode = HANDLE_MODE_BALANCED; real_t value = 0.0; +#ifdef TOOLS_ENABLED + HandleMode handle_mode = HANDLE_MODE_FREE; +#endif // TOOLS_ENABLED }; struct BezierTrack : public Track { @@ -227,11 +237,6 @@ private: _FORCE_INLINE_ Variant _interpolate(const Variant &p_a, const Variant &p_b, real_t p_c) const; _FORCE_INLINE_ real_t _interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) const; - _FORCE_INLINE_ Vector3 _cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c) const; - _FORCE_INLINE_ Quaternion _cubic_interpolate(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c) const; - _FORCE_INLINE_ Variant _cubic_interpolate(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c) const; - _FORCE_INLINE_ real_t _cubic_interpolate(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c) const; - _FORCE_INLINE_ Vector3 _cubic_interpolate_in_time(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const; _FORCE_INLINE_ Quaternion _cubic_interpolate_in_time(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const; _FORCE_INLINE_ Variant _cubic_interpolate_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const; @@ -429,15 +434,17 @@ public: void track_set_interpolation_type(int p_track, InterpolationType p_interp); InterpolationType track_get_interpolation_type(int p_track) const; - int bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const HandleMode p_handle_mode = HandleMode::HANDLE_MODE_BALANCED); - void bezier_track_set_key_handle_mode(int p_track, int p_index, HandleMode p_mode, double p_balanced_value_time_ratio = 1.0); + int bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle); void bezier_track_set_key_value(int p_track, int p_index, real_t p_value); - void bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle, double p_balanced_value_time_ratio = 1.0); - void bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle, double p_balanced_value_time_ratio = 1.0); + void bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle, real_t p_balanced_value_time_ratio = 1.0); + void bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle, real_t p_balanced_value_time_ratio = 1.0); real_t bezier_track_get_key_value(int p_track, int p_index) const; - int bezier_track_get_key_handle_mode(int p_track, int p_index) const; Vector2 bezier_track_get_key_in_handle(int p_track, int p_index) const; Vector2 bezier_track_get_key_out_handle(int p_track, int p_index) const; +#ifdef TOOLS_ENABLED + void bezier_track_set_key_handle_mode(int p_track, int p_index, HandleMode p_mode, HandleSetMode p_set_mode = HANDLE_SET_MODE_NONE); + HandleMode bezier_track_get_key_handle_mode(int p_track, int p_index) const; +#endif // TOOLS_ENABLED real_t bezier_track_interpolate(int p_track, double p_time) const; @@ -490,7 +497,10 @@ public: VARIANT_ENUM_CAST(Animation::TrackType); VARIANT_ENUM_CAST(Animation::InterpolationType); VARIANT_ENUM_CAST(Animation::UpdateMode); -VARIANT_ENUM_CAST(Animation::HandleMode); VARIANT_ENUM_CAST(Animation::LoopMode); +#ifdef TOOLS_ENABLED +VARIANT_ENUM_CAST(Animation::HandleMode); +VARIANT_ENUM_CAST(Animation::HandleSetMode); +#endif // TOOLS_ENABLED #endif // ANIMATION_H diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp index bef431e980..9b1adde00a 100644 --- a/scene/resources/bit_map.cpp +++ b/scene/resources/bit_map.cpp @@ -31,6 +31,7 @@ #include "bit_map.h" #include "core/io/image_loader.h" +#include "core/variant/typed_array.h" void BitMap::create(const Size2 &p_size) { ERR_FAIL_COND(p_size.width < 1); @@ -576,12 +577,12 @@ void BitMap::shrink_mask(int p_pixels, const Rect2 &p_rect) { grow_mask(-p_pixels, p_rect); } -Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const { +TypedArray<PackedVector2Array> BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const { Vector<Vector<Vector2>> result = clip_opaque_to_polygons(p_rect, p_epsilon); // Convert result to bindable types - Array result_array; + TypedArray<PackedVector2Array> result_array; result_array.resize(result.size()); for (int i = 0; i < result.size(); i++) { const Vector<Vector2> &polygon = result[i]; diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h index 0d0d779c32..d8507dfa8b 100644 --- a/scene/resources/bit_map.h +++ b/scene/resources/bit_map.h @@ -35,6 +35,9 @@ #include "core/io/resource.h" #include "core/io/resource_loader.h" +template <typename T> +class TypedArray; + class BitMap : public Resource { GDCLASS(BitMap, Resource); OBJ_SAVE_TYPE(BitMap); @@ -45,7 +48,7 @@ class BitMap : public Resource { Vector<Vector2> _march_square(const Rect2i &rect, const Point2i &start) const; - Array _opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const; + TypedArray<PackedVector2Array> _opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const; protected: void _set_data(const Dictionary &p_d); diff --git a/scene/resources/bone_map.cpp b/scene/resources/bone_map.cpp index f4697a09b8..dfaf82f36a 100644 --- a/scene/resources/bone_map.cpp +++ b/scene/resources/bone_map.cpp @@ -82,9 +82,13 @@ StringName BoneMap::get_skeleton_bone_name(StringName p_profile_bone_name) const return bone_map.get(p_profile_bone_name); } -void BoneMap::set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name) { +void BoneMap::_set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name) { ERR_FAIL_COND(!bone_map.has(p_profile_bone_name)); bone_map.insert(p_profile_bone_name, p_skeleton_bone_name); +} + +void BoneMap::set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name) { + _set_skeleton_bone_name(p_profile_bone_name, p_skeleton_bone_name); emit_signal("bone_map_updated"); } @@ -167,8 +171,10 @@ void BoneMap::_bind_methods() { ADD_SIGNAL(MethodInfo("profile_updated")); } -void BoneMap::_validate_property(PropertyInfo &p_property) const { - // +void BoneMap::_validate_property(PropertyInfo &property) const { + if (property.name == "bonemap" || property.name == "profile") { + property.usage = PROPERTY_USAGE_NO_EDITOR; + } } BoneMap::BoneMap() { diff --git a/scene/resources/bone_map.h b/scene/resources/bone_map.h index e1bb571df9..a07a776e27 100644 --- a/scene/resources/bone_map.h +++ b/scene/resources/bone_map.h @@ -50,9 +50,6 @@ protected: static void _bind_methods(); public: - int get_profile_type() const; - void set_profile_type(const int p_profile_type); - Ref<SkeletonProfile> get_profile() const; void set_profile(const Ref<SkeletonProfile> &p_profile); @@ -60,6 +57,7 @@ public: StringName get_skeleton_bone_name(StringName p_profile_bone_name) const; void set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name); + void _set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name); // Avoid to emit signal for editor. StringName find_profile_bone_name(StringName p_skeleton_bone_name) const; diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 55325979e2..5bfa1adfe5 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -84,7 +84,7 @@ static Ref<ImageTexture> generate_icon(int p_index) { // with integer scales. const bool upsample = !Math::is_equal_approx(Math::round(scale), scale); ImageLoaderSVG img_loader; - img_loader.create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, false); + img_loader.create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, HashMap<Color, Color>()); #endif return ImageTexture::create_from_image(img); diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index be8e4cef7c..be57d9c965 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -1267,7 +1267,7 @@ void FontFile::_get_property_list(List<PropertyInfo> *p_list) const { } for (int i = 0; i < cache.size(); i++) { String prefix = "cache/" + itos(i) + "/"; - Array sizes = get_size_cache_list(i); + TypedArray<Vector2i> sizes = get_size_cache_list(i); p_list->push_back(PropertyInfo(Variant::DICTIONARY, prefix + "variation_coordinates", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE)); p_list->push_back(PropertyInfo(Variant::INT, "face_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE)); p_list->push_back(PropertyInfo(Variant::FLOAT, "embolden", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE)); @@ -1289,7 +1289,7 @@ void FontFile::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, prefix_sz + "textures/" + itos(k) + "/offsets", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE)); p_list->push_back(PropertyInfo(Variant::OBJECT, prefix_sz + "textures/" + itos(k) + "/image", PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT)); } - Array glyphs = get_glyph_list(i, sz); + PackedInt32Array glyphs = get_glyph_list(i, sz); for (int k = 0; k < glyphs.size(); k++) { const int32_t &gl = glyphs[k]; if (sz.y == 0) { @@ -1301,7 +1301,7 @@ void FontFile::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::INT, prefix_sz + "glyphs/" + itos(gl) + "/texture_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE)); } if (sz.y == 0) { - Array kerning_map = get_kerning_list(i, sz.x); + TypedArray<Vector2i> kerning_map = get_kerning_list(i, sz.x); for (int k = 0; k < kerning_map.size(); k++) { const Vector2i &gl_pair = kerning_map[k]; p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "kerning_overrides/" + itos(gl_pair.x) + "/" + itos(gl_pair.y), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE)); @@ -1817,11 +1817,9 @@ void FontFile::set_data_ptr(const uint8_t *p_data, size_t p_size) { data_ptr = p_data; data_size = p_size; - if (data_ptr != nullptr) { - for (int i = 0; i < cache.size(); i++) { - if (cache[i].is_valid()) { - TS->font_set_data_ptr(cache[i], data_ptr, data_size); - } + for (int i = 0; i < cache.size(); i++) { + if (cache[i].is_valid()) { + TS->font_set_data_ptr(cache[i], data_ptr, data_size); } } } @@ -1831,11 +1829,9 @@ void FontFile::set_data(const PackedByteArray &p_data) { data_ptr = data.ptr(); data_size = data.size(); - if (data_ptr != nullptr) { - for (int i = 0; i < cache.size(); i++) { - if (cache[i].is_valid()) { - TS->font_set_data_ptr(cache[i], data_ptr, data_size); - } + for (int i = 0; i < cache.size(); i++) { + if (cache[i].is_valid()) { + TS->font_set_data_ptr(cache[i], data_ptr, data_size); } } } @@ -2089,7 +2085,7 @@ void FontFile::remove_cache(int p_cache_index) { emit_changed(); } -Array FontFile::get_size_cache_list(int p_cache_index) const { +TypedArray<Vector2i> FontFile::get_size_cache_list(int p_cache_index) const { ERR_FAIL_COND_V(p_cache_index < 0, Array()); _ensure_rid(p_cache_index); return TS->font_get_size_cache_list(cache[p_cache_index]); @@ -2260,8 +2256,8 @@ PackedInt32Array FontFile::get_texture_offsets(int p_cache_index, const Vector2i return TS->font_get_texture_offsets(cache[p_cache_index], p_size, p_texture_index); } -Array FontFile::get_glyph_list(int p_cache_index, const Vector2i &p_size) const { - ERR_FAIL_COND_V(p_cache_index < 0, Array()); +PackedInt32Array FontFile::get_glyph_list(int p_cache_index, const Vector2i &p_size) const { + ERR_FAIL_COND_V(p_cache_index < 0, PackedInt32Array()); _ensure_rid(p_cache_index); return TS->font_get_glyph_list(cache[p_cache_index], p_size); } @@ -2338,7 +2334,7 @@ int FontFile::get_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, i return TS->font_get_glyph_texture_idx(cache[p_cache_index], p_size, p_glyph); } -Array FontFile::get_kerning_list(int p_cache_index, int p_size) const { +TypedArray<Vector2i> FontFile::get_kerning_list(int p_cache_index, int p_size) const { ERR_FAIL_COND_V(p_cache_index < 0, Array()); _ensure_rid(p_cache_index); return TS->font_get_kerning_list(cache[p_cache_index], p_size); diff --git a/scene/resources/font.h b/scene/resources/font.h index 75482400f3..5cf596b41d 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -230,7 +230,7 @@ public: virtual void clear_cache(); virtual void remove_cache(int p_cache_index); - virtual Array get_size_cache_list(int p_cache_index) const; + virtual TypedArray<Vector2i> get_size_cache_list(int p_cache_index) const; virtual void clear_size_cache(int p_cache_index); virtual void remove_size_cache(int p_cache_index, const Vector2i &p_size); @@ -271,7 +271,7 @@ public: virtual void set_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset); virtual PackedInt32Array get_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index) const; - virtual Array get_glyph_list(int p_cache_index, const Vector2i &p_size) const; + virtual PackedInt32Array get_glyph_list(int p_cache_index, const Vector2i &p_size) const; virtual void clear_glyphs(int p_cache_index, const Vector2i &p_size); virtual void remove_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_glyph); @@ -290,7 +290,7 @@ public: virtual void set_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx); virtual int get_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const; - virtual Array get_kerning_list(int p_cache_index, int p_size) const; + virtual TypedArray<Vector2i> get_kerning_list(int p_cache_index, int p_size) const; virtual void clear_kerning_map(int p_cache_index, int p_size); virtual void remove_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair); diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp index 044477e744..90cc3ea5f4 100644 --- a/scene/resources/immediate_mesh.cpp +++ b/scene/resources/immediate_mesh.cpp @@ -340,8 +340,8 @@ Array ImmediateMesh::surface_get_arrays(int p_surface) const { ERR_FAIL_INDEX_V(p_surface, int(surfaces.size()), Array()); return RS::get_singleton()->mesh_surface_get_arrays(mesh, p_surface); } -Array ImmediateMesh::surface_get_blend_shape_arrays(int p_surface) const { - return Array(); +TypedArray<Array> ImmediateMesh::surface_get_blend_shape_arrays(int p_surface) const { + return TypedArray<Array>(); } Dictionary ImmediateMesh::surface_get_lods(int p_surface) const { return Dictionary(); diff --git a/scene/resources/immediate_mesh.h b/scene/resources/immediate_mesh.h index de10fdbfbe..0dad62f555 100644 --- a/scene/resources/immediate_mesh.h +++ b/scene/resources/immediate_mesh.h @@ -97,7 +97,7 @@ public: virtual int surface_get_array_len(int p_idx) const override; virtual int surface_get_array_index_len(int p_idx) const override; virtual Array surface_get_arrays(int p_surface) const override; - virtual Array surface_get_blend_shape_arrays(int p_surface) const override; + virtual TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const override; virtual Dictionary surface_get_lods(int p_surface) const override; virtual uint32_t surface_get_format(int p_idx) const override; virtual PrimitiveType surface_get_primitive_type(int p_idx) const override; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 1f75d4a323..7f318af899 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -71,13 +71,13 @@ Array Mesh::surface_get_arrays(int p_surface) const { return Array(); } -Array Mesh::surface_get_blend_shape_arrays(int p_surface) const { - Array ret; +TypedArray<Array> Mesh::surface_get_blend_shape_arrays(int p_surface) const { + TypedArray<Array> ret; if (GDVIRTUAL_REQUIRED_CALL(_surface_get_blend_shape_arrays, p_surface, ret)) { return ret; } - return Array(); + return TypedArray<Array>(); } Dictionary Mesh::surface_get_lods(int p_surface) const { @@ -1640,8 +1640,8 @@ Array ArrayMesh::surface_get_arrays(int p_surface) const { return RenderingServer::get_singleton()->mesh_surface_get_arrays(mesh, p_surface); } -Array ArrayMesh::surface_get_blend_shape_arrays(int p_surface) const { - ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array()); +TypedArray<Array> ArrayMesh::surface_get_blend_shape_arrays(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), TypedArray<Array>()); return RenderingServer::get_singleton()->mesh_surface_get_blend_shape_arrays(mesh, p_surface); } diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 491a383416..fd3c2c4fa4 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -63,7 +63,7 @@ protected: GDVIRTUAL1RC(int, _surface_get_array_len, int) GDVIRTUAL1RC(int, _surface_get_array_index_len, int) GDVIRTUAL1RC(Array, _surface_get_arrays, int) - GDVIRTUAL1RC(Array, _surface_get_blend_shape_arrays, int) + GDVIRTUAL1RC(TypedArray<Array>, _surface_get_blend_shape_arrays, int) GDVIRTUAL1RC(Dictionary, _surface_get_lods, int) GDVIRTUAL1RC(uint32_t, _surface_get_format, int) GDVIRTUAL1RC(uint32_t, _surface_get_primitive_type, int) @@ -151,7 +151,7 @@ public: virtual int surface_get_array_len(int p_idx) const; virtual int surface_get_array_index_len(int p_idx) const; virtual Array surface_get_arrays(int p_surface) const; - virtual Array surface_get_blend_shape_arrays(int p_surface) const; + virtual TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const; virtual Dictionary surface_get_lods(int p_surface) const; virtual uint32_t surface_get_format(int p_idx) const; virtual PrimitiveType surface_get_primitive_type(int p_idx) const; @@ -270,7 +270,7 @@ public: void add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data = Vector<uint8_t>(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>(), const Vector<RS::SurfaceData::LOD> &p_lods = Vector<RS::SurfaceData::LOD>()); Array surface_get_arrays(int p_surface) const override; - Array surface_get_blend_shape_arrays(int p_surface) const override; + TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const override; Dictionary surface_get_lods(int p_surface) const override; void add_blend_shape(const StringName &p_name); @@ -345,7 +345,7 @@ public: virtual int surface_get_array_len(int p_idx) const override { return 0; } virtual int surface_get_array_index_len(int p_idx) const override { return 0; } virtual Array surface_get_arrays(int p_surface) const override { return Array(); } - virtual Array surface_get_blend_shape_arrays(int p_surface) const override { return Array(); } + virtual TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const override { return TypedArray<Array>(); } virtual Dictionary surface_get_lods(int p_surface) const override { return Dictionary(); } virtual uint32_t surface_get_format(int p_idx) const override { return 0; } virtual PrimitiveType surface_get_primitive_type(int p_idx) const override { return PRIMITIVE_TRIANGLES; } diff --git a/scene/resources/particles_material.cpp b/scene/resources/particle_process_material.cpp index 0fe5c8f2db..ed19101de4 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particle_process_material.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* particles_material.cpp */ +/* particle_process_material.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,17 +28,17 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "particles_material.h" +#include "particle_process_material.h" #include "core/version.h" -Mutex ParticlesMaterial::material_mutex; -SelfList<ParticlesMaterial>::List *ParticlesMaterial::dirty_materials = nullptr; -HashMap<ParticlesMaterial::MaterialKey, ParticlesMaterial::ShaderData, ParticlesMaterial::MaterialKey> ParticlesMaterial::shader_map; -ParticlesMaterial::ShaderNames *ParticlesMaterial::shader_names = nullptr; +Mutex ParticleProcessMaterial::material_mutex; +SelfList<ParticleProcessMaterial>::List *ParticleProcessMaterial::dirty_materials = nullptr; +HashMap<ParticleProcessMaterial::MaterialKey, ParticleProcessMaterial::ShaderData, ParticleProcessMaterial::MaterialKey> ParticleProcessMaterial::shader_map; +ParticleProcessMaterial::ShaderNames *ParticleProcessMaterial::shader_names = nullptr; -void ParticlesMaterial::init_shaders() { - dirty_materials = memnew(SelfList<ParticlesMaterial>::List); +void ParticleProcessMaterial::init_shaders() { + dirty_materials = memnew(SelfList<ParticleProcessMaterial>::List); shader_names = memnew(ShaderNames); @@ -121,14 +121,14 @@ void ParticlesMaterial::init_shaders() { shader_names->collision_bounce = "collision_bounce"; } -void ParticlesMaterial::finish_shaders() { +void ParticleProcessMaterial::finish_shaders() { memdelete(dirty_materials); dirty_materials = nullptr; memdelete(shader_names); } -void ParticlesMaterial::_update_shader() { +void ParticleProcessMaterial::_update_shader() { dirty_materials->remove(&element); MaterialKey mk = _compute_key(); @@ -155,7 +155,7 @@ void ParticlesMaterial::_update_shader() { //must create a shader! // Add a comment to describe the shader origin (useful when converting to ShaderMaterial). - String code = "// NOTE: Shader automatically converted from " VERSION_NAME " " VERSION_FULL_CONFIG "'s ParticlesMaterial.\n\n"; + String code = "// NOTE: Shader automatically converted from " VERSION_NAME " " VERSION_FULL_CONFIG "'s ParticleProcessMaterial.\n\n"; code += "shader_type particles;\n"; @@ -287,7 +287,7 @@ void ParticlesMaterial::_update_shader() { code += "uniform sampler2D anim_offset_texture : repeat_disable;\n"; } - if (collision_enabled) { + if (collision_mode == COLLISION_RIGID) { code += "uniform float collision_friction;\n"; code += "uniform float collision_bounce;\n"; } @@ -695,8 +695,10 @@ void ParticlesMaterial::_update_shader() { } code += " vec3 noise_direction = get_noise_direction(TRANSFORM[3].xyz, EMISSION_TRANSFORM[3].xyz, time_noise);\n"; // If collision happened, turbulence is no longer applied. + // We don't need this check when the collision mode is "hide on contact", + // as the particle will be hidden anyway. String extra_tab = ""; - if (collision_enabled) { + if (collision_mode != COLLISION_RIGID) { code += " if (!COLLIDED) {\n"; extra_tab = " "; } @@ -704,7 +706,7 @@ void ParticlesMaterial::_update_shader() { code += extra_tab + " float vel_mag = length(VELOCITY);\n"; code += extra_tab + " float vel_infl = clamp(mix(turbulence_influence_min, turbulence_influence_max, rand_from_seed(alt_seed)) * turbulence_influence, 0.0, 1.0);\n"; code += extra_tab + " VELOCITY = mix(VELOCITY, normalize(noise_direction) * vel_mag * (1.0 + (1.0 - vel_infl) * 0.2), vel_infl);\n"; - if (collision_enabled) { + if (collision_mode != COLLISION_RIGID) { code += " }"; } } @@ -828,7 +830,7 @@ void ParticlesMaterial::_update_shader() { code += " TRANSFORM[3].z = 0.0;\n"; } - if (collision_enabled) { + if (collision_mode == COLLISION_RIGID) { code += " if (COLLIDED) {\n"; code += " if (length(VELOCITY) > 3.0) {\n"; code += " TRANSFORM[3].xyz += COLLISION_NORMAL * COLLISION_DEPTH;\n"; @@ -851,6 +853,18 @@ void ParticlesMaterial::_update_shader() { code += " TRANSFORM[1].xyz *= base_scale * sign(tex_scale.g) * max(abs(tex_scale.g), 0.001);\n"; code += " TRANSFORM[2].xyz *= base_scale * sign(tex_scale.b) * max(abs(tex_scale.b), 0.001);\n"; + if (collision_mode == COLLISION_RIGID) { + code += " if (COLLIDED) {\n"; + code += " TRANSFORM[3].xyz+=COLLISION_NORMAL * COLLISION_DEPTH;\n"; + code += " VELOCITY -= COLLISION_NORMAL * dot(COLLISION_NORMAL, VELOCITY) * (1.0 + collision_bounce);\n"; + code += " VELOCITY = mix(VELOCITY,vec3(0.0),collision_friction * DELTA * 100.0);\n"; + code += " }\n"; + } else if (collision_mode == COLLISION_HIDE_ON_CONTACT) { + code += " if (COLLIDED) {\n"; + code += " ACTIVE = false;\n"; + code += " }\n"; + } + if (sub_emitter_mode != SUB_EMITTER_DISABLED) { code += " int emit_count = 0;\n"; switch (sub_emitter_mode) { @@ -894,7 +908,7 @@ void ParticlesMaterial::_update_shader() { RS::get_singleton()->material_set_shader(_get_material(), shader_data.shader); } -void ParticlesMaterial::flush_changes() { +void ParticleProcessMaterial::flush_changes() { MutexLock lock(material_mutex); while (dirty_materials->first()) { @@ -902,7 +916,7 @@ void ParticlesMaterial::flush_changes() { } } -void ParticlesMaterial::_queue_shader_change() { +void ParticleProcessMaterial::_queue_shader_change() { MutexLock lock(material_mutex); if (is_initialized && !element.in_list()) { @@ -910,40 +924,40 @@ void ParticlesMaterial::_queue_shader_change() { } } -bool ParticlesMaterial::_is_shader_dirty() const { +bool ParticleProcessMaterial::_is_shader_dirty() const { MutexLock lock(material_mutex); return element.in_list(); } -void ParticlesMaterial::set_direction(Vector3 p_direction) { +void ParticleProcessMaterial::set_direction(Vector3 p_direction) { direction = p_direction; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->direction, direction); } -Vector3 ParticlesMaterial::get_direction() const { +Vector3 ParticleProcessMaterial::get_direction() const { return direction; } -void ParticlesMaterial::set_spread(float p_spread) { +void ParticleProcessMaterial::set_spread(float p_spread) { spread = p_spread; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->spread, p_spread); } -float ParticlesMaterial::get_spread() const { +float ParticleProcessMaterial::get_spread() const { return spread; } -void ParticlesMaterial::set_flatness(float p_flatness) { +void ParticleProcessMaterial::set_flatness(float p_flatness) { flatness = p_flatness; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->flatness, p_flatness); } -float ParticlesMaterial::get_flatness() const { +float ParticleProcessMaterial::get_flatness() const { return flatness; } -void ParticlesMaterial::set_param_min(Parameter p_param, float p_value) { +void ParticleProcessMaterial::set_param_min(Parameter p_param, float p_value) { ERR_FAIL_INDEX(p_param, PARAM_MAX); params_min[p_param] = p_value; @@ -1002,13 +1016,13 @@ void ParticlesMaterial::set_param_min(Parameter p_param, float p_value) { } } -float ParticlesMaterial::get_param_min(Parameter p_param) const { +float ParticleProcessMaterial::get_param_min(Parameter p_param) const { ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); return params_min[p_param]; } -void ParticlesMaterial::set_param_max(Parameter p_param, float p_value) { +void ParticleProcessMaterial::set_param_max(Parameter p_param, float p_value) { ERR_FAIL_INDEX(p_param, PARAM_MAX); params_max[p_param] = p_value; @@ -1067,7 +1081,7 @@ void ParticlesMaterial::set_param_max(Parameter p_param, float p_value) { } } -float ParticlesMaterial::get_param_max(Parameter p_param) const { +float ParticleProcessMaterial::get_param_max(Parameter p_param) const { ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); return params_max[p_param]; @@ -1082,7 +1096,7 @@ static void _adjust_curve_range(const Ref<Texture2D> &p_texture, float p_min, fl curve_tex->ensure_default_setup(p_min, p_max); } -void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture2D> &p_texture) { +void ParticleProcessMaterial::set_param_texture(Parameter p_param, const Ref<Texture2D> &p_texture) { ERR_FAIL_INDEX(p_param, PARAM_MAX); tex_parameters[p_param] = p_texture; @@ -1153,22 +1167,22 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture2D _queue_shader_change(); } -Ref<Texture2D> ParticlesMaterial::get_param_texture(Parameter p_param) const { +Ref<Texture2D> ParticleProcessMaterial::get_param_texture(Parameter p_param) const { ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref<Texture2D>()); return tex_parameters[p_param]; } -void ParticlesMaterial::set_color(const Color &p_color) { +void ParticleProcessMaterial::set_color(const Color &p_color) { RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color, p_color); color = p_color; } -Color ParticlesMaterial::get_color() const { +Color ParticleProcessMaterial::get_color() const { return color; } -void ParticlesMaterial::set_color_ramp(const Ref<Texture2D> &p_texture) { +void ParticleProcessMaterial::set_color_ramp(const Ref<Texture2D> &p_texture) { color_ramp = p_texture; RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, tex_rid); @@ -1176,11 +1190,11 @@ void ParticlesMaterial::set_color_ramp(const Ref<Texture2D> &p_texture) { notify_property_list_changed(); } -Ref<Texture2D> ParticlesMaterial::get_color_ramp() const { +Ref<Texture2D> ParticleProcessMaterial::get_color_ramp() const { return color_ramp; } -void ParticlesMaterial::set_color_initial_ramp(const Ref<Texture2D> &p_texture) { +void ParticleProcessMaterial::set_color_initial_ramp(const Ref<Texture2D> &p_texture) { color_initial_ramp = p_texture; RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_initial_ramp, tex_rid); @@ -1188,11 +1202,11 @@ void ParticlesMaterial::set_color_initial_ramp(const Ref<Texture2D> &p_texture) notify_property_list_changed(); } -Ref<Texture2D> ParticlesMaterial::get_color_initial_ramp() const { +Ref<Texture2D> ParticleProcessMaterial::get_color_initial_ramp() const { return color_initial_ramp; } -void ParticlesMaterial::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) { +void ParticleProcessMaterial::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) { ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX); particle_flags[p_particle_flag] = p_enable; _queue_shader_change(); @@ -1201,165 +1215,165 @@ void ParticlesMaterial::set_particle_flag(ParticleFlags p_particle_flag, bool p_ } } -bool ParticlesMaterial::get_particle_flag(ParticleFlags p_particle_flag) const { +bool ParticleProcessMaterial::get_particle_flag(ParticleFlags p_particle_flag) const { ERR_FAIL_INDEX_V(p_particle_flag, PARTICLE_FLAG_MAX, false); return particle_flags[p_particle_flag]; } -void ParticlesMaterial::set_emission_shape(EmissionShape p_shape) { +void ParticleProcessMaterial::set_emission_shape(EmissionShape p_shape) { ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX); emission_shape = p_shape; notify_property_list_changed(); _queue_shader_change(); } -void ParticlesMaterial::set_emission_sphere_radius(real_t p_radius) { +void ParticleProcessMaterial::set_emission_sphere_radius(real_t p_radius) { emission_sphere_radius = p_radius; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_sphere_radius, p_radius); } -void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) { +void ParticleProcessMaterial::set_emission_box_extents(Vector3 p_extents) { emission_box_extents = p_extents; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_box_extents, p_extents); } -void ParticlesMaterial::set_emission_point_texture(const Ref<Texture2D> &p_points) { +void ParticleProcessMaterial::set_emission_point_texture(const Ref<Texture2D> &p_points) { emission_point_texture = p_points; RID tex_rid = p_points.is_valid() ? p_points->get_rid() : RID(); RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, tex_rid); } -void ParticlesMaterial::set_emission_normal_texture(const Ref<Texture2D> &p_normals) { +void ParticleProcessMaterial::set_emission_normal_texture(const Ref<Texture2D> &p_normals) { emission_normal_texture = p_normals; RID tex_rid = p_normals.is_valid() ? p_normals->get_rid() : RID(); RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, tex_rid); } -void ParticlesMaterial::set_emission_color_texture(const Ref<Texture2D> &p_colors) { +void ParticleProcessMaterial::set_emission_color_texture(const Ref<Texture2D> &p_colors) { emission_color_texture = p_colors; RID tex_rid = p_colors.is_valid() ? p_colors->get_rid() : RID(); RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, tex_rid); _queue_shader_change(); } -void ParticlesMaterial::set_emission_point_count(int p_count) { +void ParticleProcessMaterial::set_emission_point_count(int p_count) { emission_point_count = p_count; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_point_count, p_count); } -void ParticlesMaterial::set_emission_ring_axis(Vector3 p_axis) { +void ParticleProcessMaterial::set_emission_ring_axis(Vector3 p_axis) { emission_ring_axis = p_axis; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_axis, p_axis); } -void ParticlesMaterial::set_emission_ring_height(real_t p_height) { +void ParticleProcessMaterial::set_emission_ring_height(real_t p_height) { emission_ring_height = p_height; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_height, p_height); } -void ParticlesMaterial::set_emission_ring_radius(real_t p_radius) { +void ParticleProcessMaterial::set_emission_ring_radius(real_t p_radius) { emission_ring_radius = p_radius; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_radius, p_radius); } -void ParticlesMaterial::set_emission_ring_inner_radius(real_t p_radius) { +void ParticleProcessMaterial::set_emission_ring_inner_radius(real_t p_radius) { emission_ring_inner_radius = p_radius; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_inner_radius, p_radius); } -ParticlesMaterial::EmissionShape ParticlesMaterial::get_emission_shape() const { +ParticleProcessMaterial::EmissionShape ParticleProcessMaterial::get_emission_shape() const { return emission_shape; } -real_t ParticlesMaterial::get_emission_sphere_radius() const { +real_t ParticleProcessMaterial::get_emission_sphere_radius() const { return emission_sphere_radius; } -Vector3 ParticlesMaterial::get_emission_box_extents() const { +Vector3 ParticleProcessMaterial::get_emission_box_extents() const { return emission_box_extents; } -Ref<Texture2D> ParticlesMaterial::get_emission_point_texture() const { +Ref<Texture2D> ParticleProcessMaterial::get_emission_point_texture() const { return emission_point_texture; } -Ref<Texture2D> ParticlesMaterial::get_emission_normal_texture() const { +Ref<Texture2D> ParticleProcessMaterial::get_emission_normal_texture() const { return emission_normal_texture; } -Ref<Texture2D> ParticlesMaterial::get_emission_color_texture() const { +Ref<Texture2D> ParticleProcessMaterial::get_emission_color_texture() const { return emission_color_texture; } -int ParticlesMaterial::get_emission_point_count() const { +int ParticleProcessMaterial::get_emission_point_count() const { return emission_point_count; } -Vector3 ParticlesMaterial::get_emission_ring_axis() const { +Vector3 ParticleProcessMaterial::get_emission_ring_axis() const { return emission_ring_axis; } -real_t ParticlesMaterial::get_emission_ring_height() const { +real_t ParticleProcessMaterial::get_emission_ring_height() const { return emission_ring_height; } -real_t ParticlesMaterial::get_emission_ring_radius() const { +real_t ParticleProcessMaterial::get_emission_ring_radius() const { return emission_ring_radius; } -real_t ParticlesMaterial::get_emission_ring_inner_radius() const { +real_t ParticleProcessMaterial::get_emission_ring_inner_radius() const { return emission_ring_inner_radius; } -void ParticlesMaterial::set_turbulence_enabled(const bool p_turbulence_enabled) { +void ParticleProcessMaterial::set_turbulence_enabled(const bool p_turbulence_enabled) { turbulence_enabled = p_turbulence_enabled; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_enabled, turbulence_enabled); _queue_shader_change(); notify_property_list_changed(); } -bool ParticlesMaterial::get_turbulence_enabled() const { +bool ParticleProcessMaterial::get_turbulence_enabled() const { return turbulence_enabled; } -void ParticlesMaterial::set_turbulence_noise_strength(float p_turbulence_noise_strength) { +void ParticleProcessMaterial::set_turbulence_noise_strength(float p_turbulence_noise_strength) { turbulence_noise_strength = p_turbulence_noise_strength; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_strength, p_turbulence_noise_strength); } -float ParticlesMaterial::get_turbulence_noise_strength() const { +float ParticleProcessMaterial::get_turbulence_noise_strength() const { return turbulence_noise_strength; } -void ParticlesMaterial::set_turbulence_noise_scale(float p_turbulence_noise_scale) { +void ParticleProcessMaterial::set_turbulence_noise_scale(float p_turbulence_noise_scale) { turbulence_noise_scale = p_turbulence_noise_scale; float shader_turbulence_noise_scale = (pow(p_turbulence_noise_scale, 0.25) * 5.6234 / 10.0) * 4.0 - 3.0; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_scale, shader_turbulence_noise_scale); } -float ParticlesMaterial::get_turbulence_noise_scale() const { +float ParticleProcessMaterial::get_turbulence_noise_scale() const { return turbulence_noise_scale; } -void ParticlesMaterial::set_turbulence_noise_speed_random(float p_turbulence_noise_speed_random) { +void ParticleProcessMaterial::set_turbulence_noise_speed_random(float p_turbulence_noise_speed_random) { turbulence_noise_speed_random = p_turbulence_noise_speed_random; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_speed_random, p_turbulence_noise_speed_random); } -float ParticlesMaterial::get_turbulence_noise_speed_random() const { +float ParticleProcessMaterial::get_turbulence_noise_speed_random() const { return turbulence_noise_speed_random; } -void ParticlesMaterial::set_turbulence_noise_speed(const Vector3 &p_turbulence_noise_speed) { +void ParticleProcessMaterial::set_turbulence_noise_speed(const Vector3 &p_turbulence_noise_speed) { turbulence_noise_speed = p_turbulence_noise_speed; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_speed, turbulence_noise_speed); } -Vector3 ParticlesMaterial::get_turbulence_noise_speed() const { +Vector3 ParticleProcessMaterial::get_turbulence_noise_speed() const { return turbulence_noise_speed; } -void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) { +void ParticleProcessMaterial::set_gravity(const Vector3 &p_gravity) { gravity = p_gravity; Vector3 gset = gravity; if (gset == Vector3()) { @@ -1368,25 +1382,25 @@ void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) { RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->gravity, gset); } -Vector3 ParticlesMaterial::get_gravity() const { +Vector3 ParticleProcessMaterial::get_gravity() const { return gravity; } -void ParticlesMaterial::set_lifetime_randomness(double p_lifetime) { +void ParticleProcessMaterial::set_lifetime_randomness(double p_lifetime) { lifetime_randomness = p_lifetime; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->lifetime_randomness, lifetime_randomness); } -double ParticlesMaterial::get_lifetime_randomness() const { +double ParticleProcessMaterial::get_lifetime_randomness() const { return lifetime_randomness; } -RID ParticlesMaterial::get_shader_rid() const { +RID ParticleProcessMaterial::get_shader_rid() const { ERR_FAIL_COND_V(!shader_map.has(current_key), RID()); return shader_map[current_key].shader; } -void ParticlesMaterial::_validate_property(PropertyInfo &p_property) const { +void ParticleProcessMaterial::_validate_property(PropertyInfo &p_property) const { if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) { p_property.usage = PROPERTY_USAGE_NONE; } @@ -1436,204 +1450,213 @@ void ParticlesMaterial::_validate_property(PropertyInfo &p_property) const { p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } + + if (p_property.name == "collision_friction" && collision_mode != COLLISION_RIGID) { + p_property.usage = PROPERTY_USAGE_NONE; + } + + if (p_property.name == "collision_bounce" && collision_mode != COLLISION_RIGID) { + p_property.usage = PROPERTY_USAGE_NONE; + } } -void ParticlesMaterial::set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode) { +void ParticleProcessMaterial::set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode) { sub_emitter_mode = p_sub_emitter_mode; _queue_shader_change(); notify_property_list_changed(); } -ParticlesMaterial::SubEmitterMode ParticlesMaterial::get_sub_emitter_mode() const { +ParticleProcessMaterial::SubEmitterMode ParticleProcessMaterial::get_sub_emitter_mode() const { return sub_emitter_mode; } -void ParticlesMaterial::set_sub_emitter_frequency(double p_frequency) { +void ParticleProcessMaterial::set_sub_emitter_frequency(double p_frequency) { sub_emitter_frequency = p_frequency; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_frequency, 1.0 / p_frequency); //pass delta instead of frequency, since its easier to compute } -double ParticlesMaterial::get_sub_emitter_frequency() const { +double ParticleProcessMaterial::get_sub_emitter_frequency() const { return sub_emitter_frequency; } -void ParticlesMaterial::set_sub_emitter_amount_at_end(int p_amount) { +void ParticleProcessMaterial::set_sub_emitter_amount_at_end(int p_amount) { sub_emitter_amount_at_end = p_amount; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_amount_at_end, p_amount); } -int ParticlesMaterial::get_sub_emitter_amount_at_end() const { +int ParticleProcessMaterial::get_sub_emitter_amount_at_end() const { return sub_emitter_amount_at_end; } -void ParticlesMaterial::set_sub_emitter_keep_velocity(bool p_enable) { +void ParticleProcessMaterial::set_sub_emitter_keep_velocity(bool p_enable) { sub_emitter_keep_velocity = p_enable; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_keep_velocity, p_enable); } -bool ParticlesMaterial::get_sub_emitter_keep_velocity() const { +bool ParticleProcessMaterial::get_sub_emitter_keep_velocity() const { return sub_emitter_keep_velocity; } -void ParticlesMaterial::set_attractor_interaction_enabled(bool p_enable) { +void ParticleProcessMaterial::set_attractor_interaction_enabled(bool p_enable) { attractor_interaction_enabled = p_enable; _queue_shader_change(); } -bool ParticlesMaterial::is_attractor_interaction_enabled() const { +bool ParticleProcessMaterial::is_attractor_interaction_enabled() const { return attractor_interaction_enabled; } -void ParticlesMaterial::set_collision_enabled(bool p_enabled) { - collision_enabled = p_enabled; +void ParticleProcessMaterial::set_collision_mode(CollisionMode p_collision_mode) { + collision_mode = p_collision_mode; _queue_shader_change(); + notify_property_list_changed(); } -bool ParticlesMaterial::is_collision_enabled() const { - return collision_enabled; +ParticleProcessMaterial::CollisionMode ParticleProcessMaterial::get_collision_mode() const { + return collision_mode; } -void ParticlesMaterial::set_collision_use_scale(bool p_scale) { +void ParticleProcessMaterial::set_collision_use_scale(bool p_scale) { collision_scale = p_scale; _queue_shader_change(); } -bool ParticlesMaterial::is_collision_using_scale() const { +bool ParticleProcessMaterial::is_collision_using_scale() const { return collision_scale; } -void ParticlesMaterial::set_collision_friction(float p_friction) { +void ParticleProcessMaterial::set_collision_friction(float p_friction) { collision_friction = p_friction; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->collision_friction, p_friction); } -float ParticlesMaterial::get_collision_friction() const { +float ParticleProcessMaterial::get_collision_friction() const { return collision_friction; } -void ParticlesMaterial::set_collision_bounce(float p_bounce) { +void ParticleProcessMaterial::set_collision_bounce(float p_bounce) { collision_bounce = p_bounce; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->collision_bounce, p_bounce); } -float ParticlesMaterial::get_collision_bounce() const { +float ParticleProcessMaterial::get_collision_bounce() const { return collision_bounce; } -Shader::Mode ParticlesMaterial::get_shader_mode() const { +Shader::Mode ParticleProcessMaterial::get_shader_mode() const { return Shader::MODE_PARTICLES; } -void ParticlesMaterial::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_direction", "degrees"), &ParticlesMaterial::set_direction); - ClassDB::bind_method(D_METHOD("get_direction"), &ParticlesMaterial::get_direction); +void ParticleProcessMaterial::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_direction", "degrees"), &ParticleProcessMaterial::set_direction); + ClassDB::bind_method(D_METHOD("get_direction"), &ParticleProcessMaterial::get_direction); - ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &ParticlesMaterial::set_spread); - ClassDB::bind_method(D_METHOD("get_spread"), &ParticlesMaterial::get_spread); + ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &ParticleProcessMaterial::set_spread); + ClassDB::bind_method(D_METHOD("get_spread"), &ParticleProcessMaterial::get_spread); - ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &ParticlesMaterial::set_flatness); - ClassDB::bind_method(D_METHOD("get_flatness"), &ParticlesMaterial::get_flatness); + ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &ParticleProcessMaterial::set_flatness); + ClassDB::bind_method(D_METHOD("get_flatness"), &ParticleProcessMaterial::get_flatness); - ClassDB::bind_method(D_METHOD("set_param_min", "param", "value"), &ParticlesMaterial::set_param_min); - ClassDB::bind_method(D_METHOD("get_param_min", "param"), &ParticlesMaterial::get_param_min); + ClassDB::bind_method(D_METHOD("set_param_min", "param", "value"), &ParticleProcessMaterial::set_param_min); + ClassDB::bind_method(D_METHOD("get_param_min", "param"), &ParticleProcessMaterial::get_param_min); - ClassDB::bind_method(D_METHOD("set_param_max", "param", "value"), &ParticlesMaterial::set_param_max); - ClassDB::bind_method(D_METHOD("get_param_max", "param"), &ParticlesMaterial::get_param_max); + ClassDB::bind_method(D_METHOD("set_param_max", "param", "value"), &ParticleProcessMaterial::set_param_max); + ClassDB::bind_method(D_METHOD("get_param_max", "param"), &ParticleProcessMaterial::get_param_max); - ClassDB::bind_method(D_METHOD("set_param_texture", "param", "texture"), &ParticlesMaterial::set_param_texture); - ClassDB::bind_method(D_METHOD("get_param_texture", "param"), &ParticlesMaterial::get_param_texture); + ClassDB::bind_method(D_METHOD("set_param_texture", "param", "texture"), &ParticleProcessMaterial::set_param_texture); + ClassDB::bind_method(D_METHOD("get_param_texture", "param"), &ParticleProcessMaterial::get_param_texture); - ClassDB::bind_method(D_METHOD("set_color", "color"), &ParticlesMaterial::set_color); - ClassDB::bind_method(D_METHOD("get_color"), &ParticlesMaterial::get_color); + ClassDB::bind_method(D_METHOD("set_color", "color"), &ParticleProcessMaterial::set_color); + ClassDB::bind_method(D_METHOD("get_color"), &ParticleProcessMaterial::get_color); - ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &ParticlesMaterial::set_color_ramp); - ClassDB::bind_method(D_METHOD("get_color_ramp"), &ParticlesMaterial::get_color_ramp); + ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &ParticleProcessMaterial::set_color_ramp); + ClassDB::bind_method(D_METHOD("get_color_ramp"), &ParticleProcessMaterial::get_color_ramp); - ClassDB::bind_method(D_METHOD("set_color_initial_ramp", "ramp"), &ParticlesMaterial::set_color_initial_ramp); - ClassDB::bind_method(D_METHOD("get_color_initial_ramp"), &ParticlesMaterial::get_color_initial_ramp); + ClassDB::bind_method(D_METHOD("set_color_initial_ramp", "ramp"), &ParticleProcessMaterial::set_color_initial_ramp); + ClassDB::bind_method(D_METHOD("get_color_initial_ramp"), &ParticleProcessMaterial::get_color_initial_ramp); - ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &ParticlesMaterial::set_particle_flag); - ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &ParticlesMaterial::get_particle_flag); + ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &ParticleProcessMaterial::set_particle_flag); + ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &ParticleProcessMaterial::get_particle_flag); - ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &ParticlesMaterial::set_emission_shape); - ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticlesMaterial::get_emission_shape); + ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &ParticleProcessMaterial::set_emission_shape); + ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticleProcessMaterial::get_emission_shape); - ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &ParticlesMaterial::set_emission_sphere_radius); - ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &ParticlesMaterial::get_emission_sphere_radius); + ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &ParticleProcessMaterial::set_emission_sphere_radius); + ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &ParticleProcessMaterial::get_emission_sphere_radius); - ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &ParticlesMaterial::set_emission_box_extents); - ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &ParticlesMaterial::get_emission_box_extents); + ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &ParticleProcessMaterial::set_emission_box_extents); + ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &ParticleProcessMaterial::get_emission_box_extents); - ClassDB::bind_method(D_METHOD("set_emission_point_texture", "texture"), &ParticlesMaterial::set_emission_point_texture); - ClassDB::bind_method(D_METHOD("get_emission_point_texture"), &ParticlesMaterial::get_emission_point_texture); + ClassDB::bind_method(D_METHOD("set_emission_point_texture", "texture"), &ParticleProcessMaterial::set_emission_point_texture); + ClassDB::bind_method(D_METHOD("get_emission_point_texture"), &ParticleProcessMaterial::get_emission_point_texture); - ClassDB::bind_method(D_METHOD("set_emission_normal_texture", "texture"), &ParticlesMaterial::set_emission_normal_texture); - ClassDB::bind_method(D_METHOD("get_emission_normal_texture"), &ParticlesMaterial::get_emission_normal_texture); + ClassDB::bind_method(D_METHOD("set_emission_normal_texture", "texture"), &ParticleProcessMaterial::set_emission_normal_texture); + ClassDB::bind_method(D_METHOD("get_emission_normal_texture"), &ParticleProcessMaterial::get_emission_normal_texture); - ClassDB::bind_method(D_METHOD("set_emission_color_texture", "texture"), &ParticlesMaterial::set_emission_color_texture); - ClassDB::bind_method(D_METHOD("get_emission_color_texture"), &ParticlesMaterial::get_emission_color_texture); + ClassDB::bind_method(D_METHOD("set_emission_color_texture", "texture"), &ParticleProcessMaterial::set_emission_color_texture); + ClassDB::bind_method(D_METHOD("get_emission_color_texture"), &ParticleProcessMaterial::get_emission_color_texture); - ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticlesMaterial::set_emission_point_count); - ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticlesMaterial::get_emission_point_count); + ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticleProcessMaterial::set_emission_point_count); + ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticleProcessMaterial::get_emission_point_count); - ClassDB::bind_method(D_METHOD("set_emission_ring_axis", "axis"), &ParticlesMaterial::set_emission_ring_axis); - ClassDB::bind_method(D_METHOD("get_emission_ring_axis"), &ParticlesMaterial::get_emission_ring_axis); + ClassDB::bind_method(D_METHOD("set_emission_ring_axis", "axis"), &ParticleProcessMaterial::set_emission_ring_axis); + ClassDB::bind_method(D_METHOD("get_emission_ring_axis"), &ParticleProcessMaterial::get_emission_ring_axis); - ClassDB::bind_method(D_METHOD("set_emission_ring_height", "height"), &ParticlesMaterial::set_emission_ring_height); - ClassDB::bind_method(D_METHOD("get_emission_ring_height"), &ParticlesMaterial::get_emission_ring_height); + ClassDB::bind_method(D_METHOD("set_emission_ring_height", "height"), &ParticleProcessMaterial::set_emission_ring_height); + ClassDB::bind_method(D_METHOD("get_emission_ring_height"), &ParticleProcessMaterial::get_emission_ring_height); - ClassDB::bind_method(D_METHOD("set_emission_ring_radius", "radius"), &ParticlesMaterial::set_emission_ring_radius); - ClassDB::bind_method(D_METHOD("get_emission_ring_radius"), &ParticlesMaterial::get_emission_ring_radius); + ClassDB::bind_method(D_METHOD("set_emission_ring_radius", "radius"), &ParticleProcessMaterial::set_emission_ring_radius); + ClassDB::bind_method(D_METHOD("get_emission_ring_radius"), &ParticleProcessMaterial::get_emission_ring_radius); - ClassDB::bind_method(D_METHOD("set_emission_ring_inner_radius", "inner_radius"), &ParticlesMaterial::set_emission_ring_inner_radius); - ClassDB::bind_method(D_METHOD("get_emission_ring_inner_radius"), &ParticlesMaterial::get_emission_ring_inner_radius); + ClassDB::bind_method(D_METHOD("set_emission_ring_inner_radius", "inner_radius"), &ParticleProcessMaterial::set_emission_ring_inner_radius); + ClassDB::bind_method(D_METHOD("get_emission_ring_inner_radius"), &ParticleProcessMaterial::get_emission_ring_inner_radius); - ClassDB::bind_method(D_METHOD("get_turbulence_enabled"), &ParticlesMaterial::get_turbulence_enabled); - ClassDB::bind_method(D_METHOD("set_turbulence_enabled", "turbulence_enabled"), &ParticlesMaterial::set_turbulence_enabled); + ClassDB::bind_method(D_METHOD("get_turbulence_enabled"), &ParticleProcessMaterial::get_turbulence_enabled); + ClassDB::bind_method(D_METHOD("set_turbulence_enabled", "turbulence_enabled"), &ParticleProcessMaterial::set_turbulence_enabled); - ClassDB::bind_method(D_METHOD("get_turbulence_noise_strength"), &ParticlesMaterial::get_turbulence_noise_strength); - ClassDB::bind_method(D_METHOD("set_turbulence_noise_strength", "turbulence_noise_strength"), &ParticlesMaterial::set_turbulence_noise_strength); + ClassDB::bind_method(D_METHOD("get_turbulence_noise_strength"), &ParticleProcessMaterial::get_turbulence_noise_strength); + ClassDB::bind_method(D_METHOD("set_turbulence_noise_strength", "turbulence_noise_strength"), &ParticleProcessMaterial::set_turbulence_noise_strength); - ClassDB::bind_method(D_METHOD("get_turbulence_noise_scale"), &ParticlesMaterial::get_turbulence_noise_scale); - ClassDB::bind_method(D_METHOD("set_turbulence_noise_scale", "turbulence_noise_scale"), &ParticlesMaterial::set_turbulence_noise_scale); + ClassDB::bind_method(D_METHOD("get_turbulence_noise_scale"), &ParticleProcessMaterial::get_turbulence_noise_scale); + ClassDB::bind_method(D_METHOD("set_turbulence_noise_scale", "turbulence_noise_scale"), &ParticleProcessMaterial::set_turbulence_noise_scale); - ClassDB::bind_method(D_METHOD("get_turbulence_noise_speed_random"), &ParticlesMaterial::get_turbulence_noise_speed_random); - ClassDB::bind_method(D_METHOD("set_turbulence_noise_speed_random", "turbulence_noise_speed_random"), &ParticlesMaterial::set_turbulence_noise_speed_random); + ClassDB::bind_method(D_METHOD("get_turbulence_noise_speed_random"), &ParticleProcessMaterial::get_turbulence_noise_speed_random); + ClassDB::bind_method(D_METHOD("set_turbulence_noise_speed_random", "turbulence_noise_speed_random"), &ParticleProcessMaterial::set_turbulence_noise_speed_random); - ClassDB::bind_method(D_METHOD("get_turbulence_noise_speed"), &ParticlesMaterial::get_turbulence_noise_speed); - ClassDB::bind_method(D_METHOD("set_turbulence_noise_speed", "turbulence_noise_speed"), &ParticlesMaterial::set_turbulence_noise_speed); + ClassDB::bind_method(D_METHOD("get_turbulence_noise_speed"), &ParticleProcessMaterial::get_turbulence_noise_speed); + ClassDB::bind_method(D_METHOD("set_turbulence_noise_speed", "turbulence_noise_speed"), &ParticleProcessMaterial::set_turbulence_noise_speed); - ClassDB::bind_method(D_METHOD("get_gravity"), &ParticlesMaterial::get_gravity); - ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &ParticlesMaterial::set_gravity); + ClassDB::bind_method(D_METHOD("get_gravity"), &ParticleProcessMaterial::get_gravity); + ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &ParticleProcessMaterial::set_gravity); - ClassDB::bind_method(D_METHOD("set_lifetime_randomness", "randomness"), &ParticlesMaterial::set_lifetime_randomness); - ClassDB::bind_method(D_METHOD("get_lifetime_randomness"), &ParticlesMaterial::get_lifetime_randomness); + ClassDB::bind_method(D_METHOD("set_lifetime_randomness", "randomness"), &ParticleProcessMaterial::set_lifetime_randomness); + ClassDB::bind_method(D_METHOD("get_lifetime_randomness"), &ParticleProcessMaterial::get_lifetime_randomness); - ClassDB::bind_method(D_METHOD("get_sub_emitter_mode"), &ParticlesMaterial::get_sub_emitter_mode); - ClassDB::bind_method(D_METHOD("set_sub_emitter_mode", "mode"), &ParticlesMaterial::set_sub_emitter_mode); + ClassDB::bind_method(D_METHOD("get_sub_emitter_mode"), &ParticleProcessMaterial::get_sub_emitter_mode); + ClassDB::bind_method(D_METHOD("set_sub_emitter_mode", "mode"), &ParticleProcessMaterial::set_sub_emitter_mode); - ClassDB::bind_method(D_METHOD("get_sub_emitter_frequency"), &ParticlesMaterial::get_sub_emitter_frequency); - ClassDB::bind_method(D_METHOD("set_sub_emitter_frequency", "hz"), &ParticlesMaterial::set_sub_emitter_frequency); + ClassDB::bind_method(D_METHOD("get_sub_emitter_frequency"), &ParticleProcessMaterial::get_sub_emitter_frequency); + ClassDB::bind_method(D_METHOD("set_sub_emitter_frequency", "hz"), &ParticleProcessMaterial::set_sub_emitter_frequency); - ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_end"), &ParticlesMaterial::get_sub_emitter_amount_at_end); - ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_end", "amount"), &ParticlesMaterial::set_sub_emitter_amount_at_end); + ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_end"), &ParticleProcessMaterial::get_sub_emitter_amount_at_end); + ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_end", "amount"), &ParticleProcessMaterial::set_sub_emitter_amount_at_end); - ClassDB::bind_method(D_METHOD("get_sub_emitter_keep_velocity"), &ParticlesMaterial::get_sub_emitter_keep_velocity); - ClassDB::bind_method(D_METHOD("set_sub_emitter_keep_velocity", "enable"), &ParticlesMaterial::set_sub_emitter_keep_velocity); + ClassDB::bind_method(D_METHOD("get_sub_emitter_keep_velocity"), &ParticleProcessMaterial::get_sub_emitter_keep_velocity); + ClassDB::bind_method(D_METHOD("set_sub_emitter_keep_velocity", "enable"), &ParticleProcessMaterial::set_sub_emitter_keep_velocity); - ClassDB::bind_method(D_METHOD("set_attractor_interaction_enabled", "enabled"), &ParticlesMaterial::set_attractor_interaction_enabled); - ClassDB::bind_method(D_METHOD("is_attractor_interaction_enabled"), &ParticlesMaterial::is_attractor_interaction_enabled); + ClassDB::bind_method(D_METHOD("set_attractor_interaction_enabled", "enabled"), &ParticleProcessMaterial::set_attractor_interaction_enabled); + ClassDB::bind_method(D_METHOD("is_attractor_interaction_enabled"), &ParticleProcessMaterial::is_attractor_interaction_enabled); - ClassDB::bind_method(D_METHOD("set_collision_enabled", "enabled"), &ParticlesMaterial::set_collision_enabled); - ClassDB::bind_method(D_METHOD("is_collision_enabled"), &ParticlesMaterial::is_collision_enabled); + ClassDB::bind_method(D_METHOD("set_collision_mode", "mode"), &ParticleProcessMaterial::set_collision_mode); + ClassDB::bind_method(D_METHOD("get_collision_mode"), &ParticleProcessMaterial::get_collision_mode); - ClassDB::bind_method(D_METHOD("set_collision_use_scale", "radius"), &ParticlesMaterial::set_collision_use_scale); - ClassDB::bind_method(D_METHOD("is_collision_using_scale"), &ParticlesMaterial::is_collision_using_scale); + ClassDB::bind_method(D_METHOD("set_collision_use_scale", "radius"), &ParticleProcessMaterial::set_collision_use_scale); + ClassDB::bind_method(D_METHOD("is_collision_using_scale"), &ParticleProcessMaterial::is_collision_using_scale); - ClassDB::bind_method(D_METHOD("set_collision_friction", "friction"), &ParticlesMaterial::set_collision_friction); - ClassDB::bind_method(D_METHOD("get_collision_friction"), &ParticlesMaterial::get_collision_friction); + ClassDB::bind_method(D_METHOD("set_collision_friction", "friction"), &ParticleProcessMaterial::set_collision_friction); + ClassDB::bind_method(D_METHOD("get_collision_friction"), &ParticleProcessMaterial::get_collision_friction); - ClassDB::bind_method(D_METHOD("set_collision_bounce", "bounce"), &ParticlesMaterial::set_collision_bounce); - ClassDB::bind_method(D_METHOD("get_collision_bounce"), &ParticlesMaterial::get_collision_bounce); + ClassDB::bind_method(D_METHOD("set_collision_bounce", "bounce"), &ParticleProcessMaterial::set_collision_bounce); + ClassDB::bind_method(D_METHOD("get_collision_bounce"), &ParticleProcessMaterial::get_collision_bounce); ADD_GROUP("Time", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness"); @@ -1734,7 +1757,7 @@ void ParticlesMaterial::_bind_methods() { ADD_GROUP("Attractor Interaction", "attractor_interaction_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "attractor_interaction_enabled"), "set_attractor_interaction_enabled", "is_attractor_interaction_enabled"); ADD_GROUP("Collision", "collision_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_enabled"), "set_collision_enabled", "is_collision_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mode", PROPERTY_HINT_ENUM, "Disabled,Rigid,Hide On Contact"), "set_collision_mode", "get_collision_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_friction", "get_collision_friction"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_bounce", "get_collision_bounce"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_use_scale"), "set_collision_use_scale", "is_collision_using_scale"); @@ -1776,9 +1799,14 @@ void ParticlesMaterial::_bind_methods() { BIND_ENUM_CONSTANT(SUB_EMITTER_AT_END); BIND_ENUM_CONSTANT(SUB_EMITTER_AT_COLLISION); BIND_ENUM_CONSTANT(SUB_EMITTER_MAX); + + BIND_ENUM_CONSTANT(COLLISION_DISABLED); + BIND_ENUM_CONSTANT(COLLISION_RIGID); + BIND_ENUM_CONSTANT(COLLISION_HIDE_ON_CONTACT); + BIND_ENUM_CONSTANT(COLLISION_MAX); } -ParticlesMaterial::ParticlesMaterial() : +ParticleProcessMaterial::ParticleProcessMaterial() : element(this) { set_direction(Vector3(1, 0, 0)); set_spread(45); @@ -1834,7 +1862,7 @@ ParticlesMaterial::ParticlesMaterial() : set_sub_emitter_keep_velocity(false); set_attractor_interaction_enabled(true); - set_collision_enabled(false); + set_collision_mode(COLLISION_DISABLED); set_collision_bounce(0.0); set_collision_friction(0.0); set_collision_use_scale(false); @@ -1851,7 +1879,7 @@ ParticlesMaterial::ParticlesMaterial() : _queue_shader_change(); } -ParticlesMaterial::~ParticlesMaterial() { +ParticleProcessMaterial::~ParticleProcessMaterial() { MutexLock lock(material_mutex); if (shader_map.has(current_key)) { diff --git a/scene/resources/particles_material.h b/scene/resources/particle_process_material.h index 116d8b7d06..fe4741d6e5 100644 --- a/scene/resources/particles_material.h +++ b/scene/resources/particle_process_material.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* particles_material.h */ +/* particle_process_material.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -31,8 +31,8 @@ #include "core/templates/rid.h" #include "scene/resources/material.h" -#ifndef PARTICLES_MATERIAL_H -#define PARTICLES_MATERIAL_H +#ifndef PARTICLE_PROCESS_MATERIAL_H +#define PARTICLE_PROCESS_MATERIAL_H /* TODO: @@ -41,8 +41,8 @@ -Proper trails */ -class ParticlesMaterial : public Material { - GDCLASS(ParticlesMaterial, Material); +class ParticleProcessMaterial : public Material { + GDCLASS(ParticleProcessMaterial, Material); public: enum Parameter { @@ -93,6 +93,14 @@ public: SUB_EMITTER_MAX }; + // When extending, make sure not to overflow the size of the MaterialKey below. + enum CollisionMode { + COLLISION_DISABLED, + COLLISION_RIGID, + COLLISION_HIDE_ON_CONTACT, + COLLISION_MAX + }; + private: union MaterialKey { // The bit size of the struct must be kept below or equal to 32 bits. @@ -106,7 +114,7 @@ private: uint32_t has_emission_color : 1; uint32_t sub_emitter : 2; uint32_t attractor_enabled : 1; - uint32_t collision_enabled : 1; + uint32_t collision_mode : 2; uint32_t collision_scale : 1; uint32_t turbulence_enabled : 1; }; @@ -153,7 +161,7 @@ private: mk.emission_shape = emission_shape; mk.has_emission_color = emission_shape >= EMISSION_SHAPE_POINTS && emission_color_texture.is_valid(); mk.sub_emitter = sub_emitter_mode; - mk.collision_enabled = collision_enabled; + mk.collision_mode = collision_mode; mk.attractor_enabled = attractor_interaction_enabled; mk.collision_scale = collision_scale; mk.turbulence_enabled = turbulence_enabled; @@ -162,7 +170,7 @@ private: } static Mutex material_mutex; - static SelfList<ParticlesMaterial>::List *dirty_materials; + static SelfList<ParticleProcessMaterial>::List *dirty_materials; struct ShaderNames { StringName direction; @@ -246,7 +254,7 @@ private: static ShaderNames *shader_names; - SelfList<ParticlesMaterial> element; + SelfList<ParticleProcessMaterial> element; void _update_shader(); _FORCE_INLINE_ void _queue_shader_change(); @@ -300,7 +308,7 @@ private: //do not save emission points here bool attractor_interaction_enabled = false; - bool collision_enabled = false; + CollisionMode collision_mode; bool collision_scale = false; float collision_friction = 0.0f; float collision_bounce = 0.0f; @@ -385,8 +393,8 @@ public: void set_attractor_interaction_enabled(bool p_enable); bool is_attractor_interaction_enabled() const; - void set_collision_enabled(bool p_enabled); - bool is_collision_enabled() const; + void set_collision_mode(CollisionMode p_collision_mode); + CollisionMode get_collision_mode() const; void set_collision_use_scale(bool p_scale); bool is_collision_using_scale() const; @@ -417,13 +425,14 @@ public: virtual Shader::Mode get_shader_mode() const override; - ParticlesMaterial(); - ~ParticlesMaterial(); + ParticleProcessMaterial(); + ~ParticleProcessMaterial(); }; -VARIANT_ENUM_CAST(ParticlesMaterial::Parameter) -VARIANT_ENUM_CAST(ParticlesMaterial::ParticleFlags) -VARIANT_ENUM_CAST(ParticlesMaterial::EmissionShape) -VARIANT_ENUM_CAST(ParticlesMaterial::SubEmitterMode) +VARIANT_ENUM_CAST(ParticleProcessMaterial::Parameter) +VARIANT_ENUM_CAST(ParticleProcessMaterial::ParticleFlags) +VARIANT_ENUM_CAST(ParticleProcessMaterial::EmissionShape) +VARIANT_ENUM_CAST(ParticleProcessMaterial::SubEmitterMode) +VARIANT_ENUM_CAST(ParticleProcessMaterial::CollisionMode) -#endif // PARTICLES_MATERIAL_H +#endif // PARTICLE_PROCESS_MATERIAL_H diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index f038a79b8f..e993936350 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -152,8 +152,8 @@ Dictionary PrimitiveMesh::surface_get_lods(int p_surface) const { return Dictionary(); //not really supported } -Array PrimitiveMesh::surface_get_blend_shape_arrays(int p_surface) const { - return Array(); //not really supported +TypedArray<Array> PrimitiveMesh::surface_get_blend_shape_arrays(int p_surface) const { + return TypedArray<Array>(); //not really supported } uint32_t PrimitiveMesh::surface_get_format(int p_idx) const { @@ -990,6 +990,13 @@ void PlaneMesh::_create_mesh_array(Array &p_arr) const { Size2 start_pos = size * -0.5; + Vector3 normal = Vector3(0.0, 1.0, 0.0); + if (orientation == FACE_X) { + normal = Vector3(1.0, 0.0, 0.0); + } else if (orientation == FACE_Z) { + normal = Vector3(0.0, 0.0, 1.0); + } + Vector<Vector3> points; Vector<Vector3> normals; Vector<float> tangents; @@ -1015,8 +1022,14 @@ void PlaneMesh::_create_mesh_array(Array &p_arr) const { u /= (subdivide_w + 1.0); v /= (subdivide_d + 1.0); - points.push_back(Vector3(-x, 0.0, -z) + center_offset); - normals.push_back(Vector3(0.0, 1.0, 0.0)); + if (orientation == FACE_X) { + points.push_back(Vector3(0.0, z, x) + center_offset); + } else if (orientation == FACE_Y) { + points.push_back(Vector3(-x, 0.0, -z) + center_offset); + } else if (orientation == FACE_Z) { + points.push_back(Vector3(-x, z, 0.0) + center_offset); + } + normals.push_back(normal); ADD_TANGENT(1.0, 0.0, 0.0, 1.0); uvs.push_back(Vector2(1.0 - u, 1.0 - v)); /* 1.0 - uv to match orientation with Quad */ point++; @@ -1053,13 +1066,22 @@ void PlaneMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("get_subdivide_width"), &PlaneMesh::get_subdivide_width); ClassDB::bind_method(D_METHOD("set_subdivide_depth", "subdivide"), &PlaneMesh::set_subdivide_depth); ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &PlaneMesh::get_subdivide_depth); + ClassDB::bind_method(D_METHOD("set_center_offset", "offset"), &PlaneMesh::set_center_offset); ClassDB::bind_method(D_METHOD("get_center_offset"), &PlaneMesh::get_center_offset); + ClassDB::bind_method(D_METHOD("set_orientation", "orientation"), &PlaneMesh::set_orientation); + ClassDB::bind_method(D_METHOD("get_orientation"), &PlaneMesh::get_orientation); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width"); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_center_offset", "get_center_offset"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "orientation", PROPERTY_HINT_ENUM, "Face X, Face Y, Face Z"), "set_orientation", "get_orientation"); + + BIND_ENUM_CONSTANT(FACE_X) + BIND_ENUM_CONSTANT(FACE_Y) + BIND_ENUM_CONSTANT(FACE_Z) } void PlaneMesh::set_size(const Size2 &p_size) { @@ -1098,6 +1120,15 @@ Vector3 PlaneMesh::get_center_offset() const { return center_offset; } +void PlaneMesh::set_orientation(const Orientation p_orientation) { + orientation = p_orientation; + _request_update(); +} + +PlaneMesh::Orientation PlaneMesh::get_orientation() const { + return orientation; +} + PlaneMesh::PlaneMesh() {} /** @@ -1381,98 +1412,6 @@ int PrismMesh::get_subdivide_depth() const { PrismMesh::PrismMesh() {} /** - QuadMesh -*/ - -void QuadMesh::_create_mesh_array(Array &p_arr) const { - Vector<Vector3> faces; - Vector<Vector3> normals; - Vector<float> tangents; - Vector<Vector2> uvs; - - faces.resize(6); - normals.resize(6); - tangents.resize(6 * 4); - uvs.resize(6); - - Vector2 _size = Vector2(size.x / 2.0f, size.y / 2.0f); - - Vector3 quad_faces[4] = { - Vector3(-_size.x, -_size.y, 0) + center_offset, - Vector3(-_size.x, _size.y, 0) + center_offset, - Vector3(_size.x, _size.y, 0) + center_offset, - Vector3(_size.x, -_size.y, 0) + center_offset, - }; - - static const int indices[6] = { - 0, 1, 2, - 0, 2, 3 - }; - - for (int i = 0; i < 6; i++) { - int j = indices[i]; - faces.set(i, quad_faces[j]); - normals.set(i, Vector3(0, 0, 1)); - tangents.set(i * 4 + 0, 1.0); - tangents.set(i * 4 + 1, 0.0); - tangents.set(i * 4 + 2, 0.0); - tangents.set(i * 4 + 3, 1.0); - - static const Vector2 quad_uv[4] = { - Vector2(0, 1), - Vector2(0, 0), - Vector2(1, 0), - Vector2(1, 1), - }; - - uvs.set(i, quad_uv[j]); - } - - p_arr[RS::ARRAY_VERTEX] = faces; - p_arr[RS::ARRAY_NORMAL] = normals; - p_arr[RS::ARRAY_TANGENT] = tangents; - p_arr[RS::ARRAY_TEX_UV] = uvs; -} - -void QuadMesh::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_size", "size"), &QuadMesh::set_size); - ClassDB::bind_method(D_METHOD("get_size"), &QuadMesh::get_size); - ClassDB::bind_method(D_METHOD("set_center_offset", "center_offset"), &QuadMesh::set_center_offset); - ClassDB::bind_method(D_METHOD("get_center_offset"), &QuadMesh::get_center_offset); - - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_center_offset", "get_center_offset"); -} - -uint32_t QuadMesh::surface_get_format(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, 1, 0); - - return RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_TANGENT | RS::ARRAY_FORMAT_TEX_UV; -} - -QuadMesh::QuadMesh() { - primitive_type = PRIMITIVE_TRIANGLES; -} - -void QuadMesh::set_size(const Size2 &p_size) { - size = p_size; - _request_update(); -} - -Size2 QuadMesh::get_size() const { - return size; -} - -void QuadMesh::set_center_offset(Vector3 p_center_offset) { - center_offset = p_center_offset; - _request_update(); -} - -Vector3 QuadMesh::get_center_offset() const { - return center_offset; -} - -/** SphereMesh */ @@ -2519,9 +2458,7 @@ void TextMesh::_create_mesh_array(Array &p_arr) const { dirty_text = false; dirty_font = false; - if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) { - TS->shaped_text_fit_to_width(text_rid, width, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA); - } + dirty_lines = true; } else if (dirty_font) { int spans = TS->shaped_get_span_count(text_rid); for (int i = 0; i < spans; i++) { @@ -2532,81 +2469,138 @@ void TextMesh::_create_mesh_array(Array &p_arr) const { } dirty_font = false; + dirty_lines = true; + } + + if (dirty_lines) { + for (int i = 0; i < lines_rid.size(); i++) { + TS->free_rid(lines_rid[i]); + } + lines_rid.clear(); + + BitField<TextServer::LineBreakFlag> autowrap_flags = TextServer::BREAK_MANDATORY; + switch (autowrap_mode) { + case TextServer::AUTOWRAP_WORD_SMART: + autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_ADAPTIVE | TextServer::BREAK_MANDATORY; + break; + case TextServer::AUTOWRAP_WORD: + autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_MANDATORY; + break; + case TextServer::AUTOWRAP_ARBITRARY: + autowrap_flags = TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_MANDATORY; + break; + case TextServer::AUTOWRAP_OFF: + break; + } + PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags); + + float max_line_w = 0.0; + for (int i = 0; i < line_breaks.size(); i = i + 2) { + RID line = TS->shaped_text_substr(text_rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]); + max_line_w = MAX(max_line_w, TS->shaped_text_get_width(line)); + lines_rid.push_back(line); + } + if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) { - TS->shaped_text_fit_to_width(text_rid, width, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA); + for (int i = 0; i < lines_rid.size() - 1; i++) { + TS->shaped_text_fit_to_width(lines_rid[i], (width > 0) ? width : max_line_w, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA); + } } + dirty_lines = false; } - Vector2 offset; - const Glyph *glyphs = TS->shaped_text_get_glyphs(text_rid); - int gl_size = TS->shaped_text_get_glyph_count(text_rid); - float line_width = TS->shaped_text_get_width(text_rid) * pixel_size; - - switch (horizontal_alignment) { - case HORIZONTAL_ALIGNMENT_LEFT: - offset.x = 0.0; - break; - case HORIZONTAL_ALIGNMENT_FILL: - case HORIZONTAL_ALIGNMENT_CENTER: { - offset.x = -line_width / 2.0; + float total_h = 0.0; + for (int i = 0; i < lines_rid.size(); i++) { + total_h += (TS->shaped_text_get_size(lines_rid[i]).y + line_spacing) * pixel_size; + } + + float vbegin = 0.0; + switch (vertical_alignment) { + case VERTICAL_ALIGNMENT_FILL: + case VERTICAL_ALIGNMENT_TOP: { + // Nothing. + } break; + case VERTICAL_ALIGNMENT_CENTER: { + vbegin = (total_h - line_spacing * pixel_size) / 2.0; } break; - case HORIZONTAL_ALIGNMENT_RIGHT: { - offset.x = -line_width; + case VERTICAL_ALIGNMENT_BOTTOM: { + vbegin = (total_h - line_spacing * pixel_size); } break; } - bool has_depth = !Math::is_zero_approx(depth); - - // Generate glyph data, precalculate size of the arrays and mesh bounds for UV. - int64_t p_size = 0; - int64_t i_size = 0; + Vector<Vector3> vertices; + Vector<Vector3> normals; + Vector<float> tangents; + Vector<Vector2> uvs; + Vector<int32_t> indices; Vector2 min_p = Vector2(INFINITY, INFINITY); Vector2 max_p = Vector2(-INFINITY, -INFINITY); - Vector2 offset_pre = offset; - for (int i = 0; i < gl_size; i++) { - if (glyphs[i].index == 0) { - offset.x += glyphs[i].advance * pixel_size * glyphs[i].repeat; - continue; + int32_t p_size = 0; + int32_t i_size = 0; + + Vector2 offset = Vector2(0, vbegin + lbl_offset.y * pixel_size); + for (int i = 0; i < lines_rid.size(); i++) { + const Glyph *glyphs = TS->shaped_text_get_glyphs(lines_rid[i]); + int gl_size = TS->shaped_text_get_glyph_count(lines_rid[i]); + float line_width = TS->shaped_text_get_width(lines_rid[i]) * pixel_size; + + switch (horizontal_alignment) { + case HORIZONTAL_ALIGNMENT_LEFT: + offset.x = 0.0; + break; + case HORIZONTAL_ALIGNMENT_FILL: + case HORIZONTAL_ALIGNMENT_CENTER: { + offset.x = -line_width / 2.0; + } break; + case HORIZONTAL_ALIGNMENT_RIGHT: { + offset.x = -line_width; + } break; } - if (glyphs[i].font_rid != RID()) { - GlyphMeshKey key = GlyphMeshKey(glyphs[i].font_rid.get_id(), glyphs[i].index); - _generate_glyph_mesh_data(key, glyphs[i]); - GlyphMeshData &gl_data = cache[key]; - - p_size += glyphs[i].repeat * gl_data.triangles.size() * ((has_depth) ? 2 : 1); - i_size += glyphs[i].repeat * gl_data.triangles.size() * ((has_depth) ? 2 : 1); - - if (has_depth) { - for (int j = 0; j < gl_data.contours.size(); j++) { - p_size += glyphs[i].repeat * gl_data.contours[j].size() * 4; - i_size += glyphs[i].repeat * gl_data.contours[j].size() * 6; - } - } + offset.x += lbl_offset.x * pixel_size; + offset.y -= TS->shaped_text_get_ascent(lines_rid[i]) * pixel_size; - for (int j = 0; j < glyphs[i].repeat; j++) { - min_p.x = MIN(gl_data.min_p.x + offset_pre.x, min_p.x); - min_p.y = MIN(gl_data.min_p.y + offset_pre.y, min_p.y); - max_p.x = MAX(gl_data.max_p.x + offset_pre.x, max_p.x); - max_p.y = MAX(gl_data.max_p.y + offset_pre.y, max_p.y); + bool has_depth = !Math::is_zero_approx(depth); - offset_pre.x += glyphs[i].advance * pixel_size; + for (int j = 0; j < gl_size; j++) { + if (glyphs[j].index == 0) { + offset.x += glyphs[j].advance * pixel_size * glyphs[j].repeat; + continue; } - } else { - p_size += glyphs[i].repeat * 4; - i_size += glyphs[i].repeat * 6; + if (glyphs[j].font_rid != RID()) { + GlyphMeshKey key = GlyphMeshKey(glyphs[j].font_rid.get_id(), glyphs[j].index); + _generate_glyph_mesh_data(key, glyphs[j]); + GlyphMeshData &gl_data = cache[key]; + + p_size += glyphs[j].repeat * gl_data.triangles.size() * ((has_depth) ? 2 : 1); + i_size += glyphs[j].repeat * gl_data.triangles.size() * ((has_depth) ? 2 : 1); - offset_pre.x += glyphs[i].advance * pixel_size * glyphs[i].repeat; + if (has_depth) { + for (int k = 0; k < gl_data.contours.size(); k++) { + p_size += glyphs[j].repeat * gl_data.contours[k].size() * 4; + i_size += glyphs[j].repeat * gl_data.contours[k].size() * 6; + } + } + + for (int r = 0; r < glyphs[j].repeat; r++) { + min_p.x = MIN(gl_data.min_p.x + offset.x, min_p.x); + min_p.y = MIN(gl_data.min_p.y - offset.y, min_p.y); + max_p.x = MAX(gl_data.max_p.x + offset.x, max_p.x); + max_p.y = MAX(gl_data.max_p.y - offset.y, max_p.y); + + offset.x += glyphs[j].advance * pixel_size; + } + } else { + p_size += glyphs[j].repeat * 4; + i_size += glyphs[j].repeat * 6; + + offset.x += glyphs[j].advance * pixel_size * glyphs[j].repeat; + } } + offset.y -= (TS->shaped_text_get_descent(lines_rid[i]) + line_spacing) * pixel_size; } - Vector<Vector3> vertices; - Vector<Vector3> normals; - Vector<float> tangents; - Vector<Vector2> uvs; - Vector<int32_t> indices; - vertices.resize(p_size); normals.resize(p_size); uvs.resize(p_size); @@ -2622,149 +2616,176 @@ void TextMesh::_create_mesh_array(Array &p_arr) const { // Generate mesh. int32_t p_idx = 0; int32_t i_idx = 0; - for (int i = 0; i < gl_size; i++) { - if (glyphs[i].index == 0) { - offset.x += glyphs[i].advance * pixel_size * glyphs[i].repeat; - continue; + + offset = Vector2(0, vbegin + lbl_offset.y * pixel_size); + for (int i = 0; i < lines_rid.size(); i++) { + const Glyph *glyphs = TS->shaped_text_get_glyphs(lines_rid[i]); + int gl_size = TS->shaped_text_get_glyph_count(lines_rid[i]); + float line_width = TS->shaped_text_get_width(lines_rid[i]) * pixel_size; + + switch (horizontal_alignment) { + case HORIZONTAL_ALIGNMENT_LEFT: + offset.x = 0.0; + break; + case HORIZONTAL_ALIGNMENT_FILL: + case HORIZONTAL_ALIGNMENT_CENTER: { + offset.x = -line_width / 2.0; + } break; + case HORIZONTAL_ALIGNMENT_RIGHT: { + offset.x = -line_width; + } break; } - if (glyphs[i].font_rid != RID()) { - GlyphMeshKey key = GlyphMeshKey(glyphs[i].font_rid.get_id(), glyphs[i].index); - _generate_glyph_mesh_data(key, glyphs[i]); - const GlyphMeshData &gl_data = cache[key]; - - int64_t ts = gl_data.triangles.size(); - const Vector2 *ts_ptr = gl_data.triangles.ptr(); - - for (int j = 0; j < glyphs[i].repeat; j++) { - for (int k = 0; k < ts; k += 3) { - // Add front face. - for (int l = 0; l < 3; l++) { - Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, depth / 2.0); - vertices_ptr[p_idx] = point; - normals_ptr[p_idx] = Vector3(0.0, 0.0, 1.0); - if (has_depth) { - uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -min_p.y, -max_p.y, real_t(0.0), real_t(0.4))); - } else { - uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -min_p.y, -max_p.y, real_t(0.0), real_t(1.0))); - } - tangents_ptr[p_idx * 4 + 0] = 1.0; - tangents_ptr[p_idx * 4 + 1] = 0.0; - tangents_ptr[p_idx * 4 + 2] = 0.0; - tangents_ptr[p_idx * 4 + 3] = 1.0; - indices_ptr[i_idx++] = p_idx; - p_idx++; - } - if (has_depth) { - // Add back face. - for (int l = 2; l >= 0; l--) { - Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, -depth / 2.0); + offset.x += lbl_offset.x * pixel_size; + offset.y -= TS->shaped_text_get_ascent(lines_rid[i]) * pixel_size; + + bool has_depth = !Math::is_zero_approx(depth); + + // Generate glyph data, precalculate size of the arrays and mesh bounds for UV. + for (int j = 0; j < gl_size; j++) { + if (glyphs[j].index == 0) { + offset.x += glyphs[j].advance * pixel_size * glyphs[j].repeat; + continue; + } + if (glyphs[j].font_rid != RID()) { + GlyphMeshKey key = GlyphMeshKey(glyphs[j].font_rid.get_id(), glyphs[j].index); + _generate_glyph_mesh_data(key, glyphs[j]); + const GlyphMeshData &gl_data = cache[key]; + + int64_t ts = gl_data.triangles.size(); + const Vector2 *ts_ptr = gl_data.triangles.ptr(); + + for (int r = 0; r < glyphs[j].repeat; r++) { + for (int k = 0; k < ts; k += 3) { + // Add front face. + for (int l = 0; l < 3; l++) { + Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, depth / 2.0); vertices_ptr[p_idx] = point; - normals_ptr[p_idx] = Vector3(0.0, 0.0, -1.0); - uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -min_p.y, -max_p.y, real_t(0.4), real_t(0.8))); - tangents_ptr[p_idx * 4 + 0] = -1.0; + normals_ptr[p_idx] = Vector3(0.0, 0.0, 1.0); + if (has_depth) { + uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -max_p.y, -min_p.y, real_t(0.4), real_t(0.0))); + } else { + uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -max_p.y, -min_p.y, real_t(1.0), real_t(0.0))); + } + tangents_ptr[p_idx * 4 + 0] = 1.0; tangents_ptr[p_idx * 4 + 1] = 0.0; tangents_ptr[p_idx * 4 + 2] = 0.0; tangents_ptr[p_idx * 4 + 3] = 1.0; indices_ptr[i_idx++] = p_idx; p_idx++; } - } - } - // Add sides. - if (has_depth) { - for (int k = 0; k < gl_data.contours.size(); k++) { - int64_t ps = gl_data.contours[k].size(); - const ContourPoint *ps_ptr = gl_data.contours[k].ptr(); - const ContourInfo &ps_info = gl_data.contours_info[k]; - real_t length = 0.0; - for (int l = 0; l < ps; l++) { - int prev = (l == 0) ? (ps - 1) : (l - 1); - int next = (l + 1 == ps) ? 0 : (l + 1); - Vector2 d1; - Vector2 d2 = (ps_ptr[next].point - ps_ptr[l].point).normalized(); - if (ps_ptr[l].sharp) { - d1 = d2; - } else { - d1 = (ps_ptr[l].point - ps_ptr[prev].point).normalized(); + if (has_depth) { + // Add back face. + for (int l = 2; l >= 0; l--) { + Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, -depth / 2.0); + vertices_ptr[p_idx] = point; + normals_ptr[p_idx] = Vector3(0.0, 0.0, -1.0); + uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -max_p.y, -min_p.y, real_t(0.8), real_t(0.4))); + tangents_ptr[p_idx * 4 + 0] = -1.0; + tangents_ptr[p_idx * 4 + 1] = 0.0; + tangents_ptr[p_idx * 4 + 2] = 0.0; + tangents_ptr[p_idx * 4 + 3] = 1.0; + indices_ptr[i_idx++] = p_idx; + p_idx++; } - real_t seg_len = (ps_ptr[next].point - ps_ptr[l].point).length(); - - Vector3 quad_faces[4] = { - Vector3(ps_ptr[l].point.x + offset.x, -ps_ptr[l].point.y + offset.y, -depth / 2.0), - Vector3(ps_ptr[next].point.x + offset.x, -ps_ptr[next].point.y + offset.y, -depth / 2.0), - Vector3(ps_ptr[l].point.x + offset.x, -ps_ptr[l].point.y + offset.y, depth / 2.0), - Vector3(ps_ptr[next].point.x + offset.x, -ps_ptr[next].point.y + offset.y, depth / 2.0), - }; - for (int m = 0; m < 4; m++) { - const Vector2 &d = ((m % 2) == 0) ? d1 : d2; - real_t u_pos = ((m % 2) == 0) ? length : length + seg_len; - vertices_ptr[p_idx + m] = quad_faces[m]; - normals_ptr[p_idx + m] = Vector3(d.y, d.x, 0.0); - if (m < 2) { - uvs_ptr[p_idx + m] = Vector2(Math::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.8 : 0.9); + } + } + // Add sides. + if (has_depth) { + for (int k = 0; k < gl_data.contours.size(); k++) { + int64_t ps = gl_data.contours[k].size(); + const ContourPoint *ps_ptr = gl_data.contours[k].ptr(); + const ContourInfo &ps_info = gl_data.contours_info[k]; + real_t length = 0.0; + for (int l = 0; l < ps; l++) { + int prev = (l == 0) ? (ps - 1) : (l - 1); + int next = (l + 1 == ps) ? 0 : (l + 1); + Vector2 d1; + Vector2 d2 = (ps_ptr[next].point - ps_ptr[l].point).normalized(); + if (ps_ptr[l].sharp) { + d1 = d2; } else { - uvs_ptr[p_idx + m] = Vector2(Math::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.9 : 1.0); + d1 = (ps_ptr[l].point - ps_ptr[prev].point).normalized(); + } + real_t seg_len = (ps_ptr[next].point - ps_ptr[l].point).length(); + + Vector3 quad_faces[4] = { + Vector3(ps_ptr[l].point.x + offset.x, -ps_ptr[l].point.y + offset.y, -depth / 2.0), + Vector3(ps_ptr[next].point.x + offset.x, -ps_ptr[next].point.y + offset.y, -depth / 2.0), + Vector3(ps_ptr[l].point.x + offset.x, -ps_ptr[l].point.y + offset.y, depth / 2.0), + Vector3(ps_ptr[next].point.x + offset.x, -ps_ptr[next].point.y + offset.y, depth / 2.0), + }; + for (int m = 0; m < 4; m++) { + const Vector2 &d = ((m % 2) == 0) ? d1 : d2; + real_t u_pos = ((m % 2) == 0) ? length : length + seg_len; + vertices_ptr[p_idx + m] = quad_faces[m]; + normals_ptr[p_idx + m] = Vector3(d.y, d.x, 0.0); + if (m < 2) { + uvs_ptr[p_idx + m] = Vector2(Math::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.8 : 0.9); + } else { + uvs_ptr[p_idx + m] = Vector2(Math::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.9 : 1.0); + } + tangents_ptr[(p_idx + m) * 4 + 0] = d.x; + tangents_ptr[(p_idx + m) * 4 + 1] = -d.y; + tangents_ptr[(p_idx + m) * 4 + 2] = 0.0; + tangents_ptr[(p_idx + m) * 4 + 3] = 1.0; } - tangents_ptr[(p_idx + m) * 4 + 0] = d.x; - tangents_ptr[(p_idx + m) * 4 + 1] = -d.y; - tangents_ptr[(p_idx + m) * 4 + 2] = 0.0; - tangents_ptr[(p_idx + m) * 4 + 3] = 1.0; - } - indices_ptr[i_idx++] = p_idx; - indices_ptr[i_idx++] = p_idx + 1; - indices_ptr[i_idx++] = p_idx + 2; + indices_ptr[i_idx++] = p_idx; + indices_ptr[i_idx++] = p_idx + 1; + indices_ptr[i_idx++] = p_idx + 2; - indices_ptr[i_idx++] = p_idx + 1; - indices_ptr[i_idx++] = p_idx + 3; - indices_ptr[i_idx++] = p_idx + 2; + indices_ptr[i_idx++] = p_idx + 1; + indices_ptr[i_idx++] = p_idx + 3; + indices_ptr[i_idx++] = p_idx + 2; - length += seg_len; - p_idx += 4; + length += seg_len; + p_idx += 4; + } } } + offset.x += glyphs[j].advance * pixel_size; } - offset.x += glyphs[i].advance * pixel_size; - } - } else { - // Add fallback quad for missing glyphs. - for (int j = 0; j < glyphs[i].repeat; j++) { - Size2 sz = TS->get_hex_code_box_size(glyphs[i].font_size, glyphs[i].index) * pixel_size; - Vector3 quad_faces[4] = { - Vector3(offset.x, offset.y, 0.0), - Vector3(offset.x, sz.y + offset.y, 0.0), - Vector3(sz.x + offset.x, sz.y + offset.y, 0.0), - Vector3(sz.x + offset.x, offset.y, 0.0), - }; - for (int k = 0; k < 4; k++) { - vertices_ptr[p_idx + k] = quad_faces[k]; - normals_ptr[p_idx + k] = Vector3(0.0, 0.0, 1.0); - if (has_depth) { - uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -min_p.y, -max_p.y, real_t(0.0), real_t(0.4))); - } else { - uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -min_p.y, -max_p.y, real_t(0.0), real_t(1.0))); + } else { + // Add fallback quad for missing glyphs. + for (int r = 0; r < glyphs[j].repeat; r++) { + Size2 sz = TS->get_hex_code_box_size(glyphs[j].font_size, glyphs[j].index) * pixel_size; + Vector3 quad_faces[4] = { + Vector3(offset.x, offset.y, 0.0), + Vector3(offset.x, sz.y + offset.y, 0.0), + Vector3(sz.x + offset.x, sz.y + offset.y, 0.0), + Vector3(sz.x + offset.x, offset.y, 0.0), + }; + for (int k = 0; k < 4; k++) { + vertices_ptr[p_idx + k] = quad_faces[k]; + normals_ptr[p_idx + k] = Vector3(0.0, 0.0, 1.0); + if (has_depth) { + uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -max_p.y, -min_p.y, real_t(0.4), real_t(0.0))); + } else { + uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -max_p.y, -min_p.y, real_t(1.0), real_t(0.0))); + } + tangents_ptr[(p_idx + k) * 4 + 0] = 1.0; + tangents_ptr[(p_idx + k) * 4 + 1] = 0.0; + tangents_ptr[(p_idx + k) * 4 + 2] = 0.0; + tangents_ptr[(p_idx + k) * 4 + 3] = 1.0; } - tangents_ptr[(p_idx + k) * 4 + 0] = 1.0; - tangents_ptr[(p_idx + k) * 4 + 1] = 0.0; - tangents_ptr[(p_idx + k) * 4 + 2] = 0.0; - tangents_ptr[(p_idx + k) * 4 + 3] = 1.0; - } - indices_ptr[i_idx++] = p_idx; - indices_ptr[i_idx++] = p_idx + 1; - indices_ptr[i_idx++] = p_idx + 2; + indices_ptr[i_idx++] = p_idx; + indices_ptr[i_idx++] = p_idx + 1; + indices_ptr[i_idx++] = p_idx + 2; - indices_ptr[i_idx++] = p_idx + 0; - indices_ptr[i_idx++] = p_idx + 2; - indices_ptr[i_idx++] = p_idx + 3; - p_idx += 4; + indices_ptr[i_idx++] = p_idx + 0; + indices_ptr[i_idx++] = p_idx + 2; + indices_ptr[i_idx++] = p_idx + 3; + p_idx += 4; - offset.x += glyphs[i].advance * pixel_size; + offset.x += glyphs[j].advance * pixel_size; + } } } + offset.y -= (TS->shaped_text_get_descent(lines_rid[i]) + line_spacing) * pixel_size; } - if (p_size == 0) { + if (indices.is_empty()) { // If empty, add single triangle to suppress errors. vertices.push_back(Vector3()); normals.push_back(Vector3()); @@ -2789,6 +2810,9 @@ void TextMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_horizontal_alignment", "alignment"), &TextMesh::set_horizontal_alignment); ClassDB::bind_method(D_METHOD("get_horizontal_alignment"), &TextMesh::get_horizontal_alignment); + ClassDB::bind_method(D_METHOD("set_vertical_alignment", "alignment"), &TextMesh::set_vertical_alignment); + ClassDB::bind_method(D_METHOD("get_vertical_alignment"), &TextMesh::get_vertical_alignment); + ClassDB::bind_method(D_METHOD("set_text", "text"), &TextMesh::set_text); ClassDB::bind_method(D_METHOD("get_text"), &TextMesh::get_text); @@ -2798,6 +2822,12 @@ void TextMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_font_size", "font_size"), &TextMesh::set_font_size); ClassDB::bind_method(D_METHOD("get_font_size"), &TextMesh::get_font_size); + ClassDB::bind_method(D_METHOD("set_line_spacing", "line_spacing"), &TextMesh::set_line_spacing); + ClassDB::bind_method(D_METHOD("get_line_spacing"), &TextMesh::get_line_spacing); + + ClassDB::bind_method(D_METHOD("set_autowrap_mode", "autowrap_mode"), &TextMesh::set_autowrap_mode); + ClassDB::bind_method(D_METHOD("get_autowrap_mode"), &TextMesh::get_autowrap_mode); + ClassDB::bind_method(D_METHOD("set_depth", "depth"), &TextMesh::set_depth); ClassDB::bind_method(D_METHOD("get_depth"), &TextMesh::get_depth); @@ -2807,6 +2837,9 @@ void TextMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pixel_size", "pixel_size"), &TextMesh::set_pixel_size); ClassDB::bind_method(D_METHOD("get_pixel_size"), &TextMesh::get_pixel_size); + ClassDB::bind_method(D_METHOD("set_offset", "offset"), &TextMesh::set_offset); + ClassDB::bind_method(D_METHOD("get_offset"), &TextMesh::get_offset); + ClassDB::bind_method(D_METHOD("set_curve_step", "curve_step"), &TextMesh::set_curve_step); ClassDB::bind_method(D_METHOD("get_curve_step"), &TextMesh::get_curve_step); @@ -2829,17 +2862,21 @@ void TextMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("_request_update"), &TextMesh::_request_update); ADD_GROUP("Text", ""); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT, ""), "set_text", "get_text"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_font", "get_font"); ADD_PROPERTY(PropertyInfo(Variant::INT, "font_size", PROPERTY_HINT_RANGE, "1,256,1,or_greater,suffix:px"), "set_font_size", "get_font_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "horizontal_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_horizontal_alignment", "get_horizontal_alignment"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "vertical_alignment", PROPERTY_HINT_ENUM, "Top,Center,Bottom"), "set_vertical_alignment", "get_vertical_alignment"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uppercase"), "set_uppercase", "is_uppercase"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "line_spacing", PROPERTY_HINT_NONE, "suffix:px"), "set_line_spacing", "get_line_spacing"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Off,Arbitrary,Word,Word (Smart)"), "set_autowrap_mode", "get_autowrap_mode"); ADD_GROUP("Mesh", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pixel_size", PROPERTY_HINT_RANGE, "0.0001,128,0.0001,suffix:m"), "set_pixel_size", "get_pixel_size"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "curve_step", PROPERTY_HINT_RANGE, "0.1,10,0.1,suffix:px"), "set_curve_step", "get_curve_step"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_RANGE, "0.0,100.0,0.001,or_greater,suffix:m"), "set_depth", "get_depth"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "width", PROPERTY_HINT_NONE, "suffix:m"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset", PROPERTY_HINT_NONE, "suffix:px"), "set_offset", "get_offset"); ADD_GROUP("BiDi", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left"), "set_text_direction", "get_text_direction"); @@ -2868,6 +2905,11 @@ TextMesh::TextMesh() { } TextMesh::~TextMesh() { + for (int i = 0; i < lines_rid.size(); i++) { + TS->free_rid(lines_rid[i]); + } + lines_rid.clear(); + TS->free_rid(text_rid); } @@ -2875,7 +2917,7 @@ void TextMesh::set_horizontal_alignment(HorizontalAlignment p_alignment) { ERR_FAIL_INDEX((int)p_alignment, 4); if (horizontal_alignment != p_alignment) { if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL || p_alignment == HORIZONTAL_ALIGNMENT_FILL) { - dirty_text = true; + dirty_lines = true; } horizontal_alignment = p_alignment; _request_update(); @@ -2886,6 +2928,18 @@ HorizontalAlignment TextMesh::get_horizontal_alignment() const { return horizontal_alignment; } +void TextMesh::set_vertical_alignment(VerticalAlignment p_alignment) { + ERR_FAIL_INDEX((int)p_alignment, 4); + if (vertical_alignment != p_alignment) { + vertical_alignment = p_alignment; + _request_update(); + } +} + +VerticalAlignment TextMesh::get_vertical_alignment() const { + return vertical_alignment; +} + void TextMesh::set_text(const String &p_string) { if (text != p_string) { text = p_string; @@ -2970,6 +3024,29 @@ int TextMesh::get_font_size() const { return font_size; } +void TextMesh::set_line_spacing(float p_line_spacing) { + if (line_spacing != p_line_spacing) { + line_spacing = p_line_spacing; + _request_update(); + } +} + +float TextMesh::get_line_spacing() const { + return line_spacing; +} + +void TextMesh::set_autowrap_mode(TextServer::AutowrapMode p_mode) { + if (autowrap_mode != p_mode) { + autowrap_mode = p_mode; + dirty_lines = true; + _request_update(); + } +} + +TextServer::AutowrapMode TextMesh::get_autowrap_mode() const { + return autowrap_mode; +} + void TextMesh::set_depth(real_t p_depth) { if (depth != p_depth) { depth = MAX(p_depth, 0.0); @@ -2984,9 +3061,7 @@ real_t TextMesh::get_depth() const { void TextMesh::set_width(real_t p_width) { if (width != p_width) { width = p_width; - if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) { - dirty_text = true; - } + dirty_lines = true; _request_update(); } } @@ -3007,6 +3082,17 @@ real_t TextMesh::get_pixel_size() const { return pixel_size; } +void TextMesh::set_offset(const Point2 &p_offset) { + if (lbl_offset != p_offset) { + lbl_offset = p_offset; + _request_update(); + } +} + +Point2 TextMesh::get_offset() const { + return lbl_offset; +} + void TextMesh::set_curve_step(real_t p_step) { if (curve_step != p_step) { curve_step = CLAMP(p_step, 0.1, 10.0); diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index 64eefd2c07..280477ebfa 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -75,7 +75,7 @@ public: virtual int surface_get_array_len(int p_idx) const override; virtual int surface_get_array_index_len(int p_idx) const override; virtual Array surface_get_arrays(int p_surface) const override; - virtual Array surface_get_blend_shape_arrays(int p_surface) const override; + virtual TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const override; virtual Dictionary surface_get_lods(int p_surface) const override; virtual uint32_t surface_get_format(int p_idx) const override; virtual Mesh::PrimitiveType surface_get_primitive_type(int p_idx) const override; @@ -217,17 +217,25 @@ public: CylinderMesh(); }; -/** - Similar to quadmesh but with tessellation support +/* + A flat rectangle, can be used as quad or heightmap. */ class PlaneMesh : public PrimitiveMesh { GDCLASS(PlaneMesh, PrimitiveMesh); +public: + enum Orientation { + FACE_X, + FACE_Y, + FACE_Z, + }; + private: Size2 size = Size2(2.0, 2.0); int subdivide_w = 0; int subdivide_d = 0; Vector3 center_offset; + Orientation orientation = FACE_Y; protected: static void _bind_methods(); @@ -246,9 +254,14 @@ public: void set_center_offset(const Vector3 p_offset); Vector3 get_center_offset() const; + void set_orientation(const Orientation p_orientation); + Orientation get_orientation() const; + PlaneMesh(); }; +VARIANT_ENUM_CAST(PlaneMesh::Orientation) + /** A prism shapen, handy for ramps, triangles, etc. */ @@ -286,33 +299,6 @@ public: }; /** - Our original quadmesh... -*/ - -class QuadMesh : public PrimitiveMesh { - GDCLASS(QuadMesh, PrimitiveMesh); - -private: - Size2 size = Size2(1.0, 1.0); - Vector3 center_offset; - -protected: - static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr) const override; - -public: - virtual uint32_t surface_get_format(int p_idx) const override; - - QuadMesh(); - - void set_size(const Size2 &p_size); - Size2 get_size() const; - - void set_center_offset(const Vector3 p_offset); - Vector3 get_center_offset() const; -}; - -/** A sphere.. */ class SphereMesh : public PrimitiveMesh { @@ -548,14 +534,21 @@ private: mutable HashMap<GlyphMeshKey, GlyphMeshData, GlyphMeshKeyHasher> cache; RID text_rid; + mutable Vector<RID> lines_rid; + String text; String xl_text; int font_size = 16; Ref<Font> font_override; + + TextServer::AutowrapMode autowrap_mode = TextServer::AUTOWRAP_OFF; float width = 500.0; + float line_spacing = 0.f; + Point2 lbl_offset; HorizontalAlignment horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER; + VerticalAlignment vertical_alignment = VERTICAL_ALIGNMENT_CENTER; bool uppercase = false; String language; TextServer::Direction text_direction = TextServer::DIRECTION_AUTO; @@ -566,6 +559,7 @@ private: real_t pixel_size = 0.01; real_t curve_step = 0.5; + mutable bool dirty_lines = true; mutable bool dirty_text = true; mutable bool dirty_font = true; mutable bool dirty_cache = true; @@ -588,6 +582,9 @@ public: void set_horizontal_alignment(HorizontalAlignment p_alignment); HorizontalAlignment get_horizontal_alignment() const; + void set_vertical_alignment(VerticalAlignment p_alignment); + VerticalAlignment get_vertical_alignment() const; + void set_text(const String &p_string); String get_text() const; @@ -598,6 +595,12 @@ public: void set_font_size(int p_size); int get_font_size() const; + void set_line_spacing(float p_size); + float get_line_spacing() const; + + void set_autowrap_mode(TextServer::AutowrapMode p_mode); + TextServer::AutowrapMode get_autowrap_mode() const; + void set_text_direction(TextServer::Direction p_text_direction); TextServer::Direction get_text_direction() const; @@ -624,6 +627,9 @@ public: void set_pixel_size(real_t p_amount); real_t get_pixel_size() const; + + void set_offset(const Point2 &p_offset); + Point2 get_offset() const; }; VARIANT_ENUM_CAST(RibbonTrailMesh::Shape) diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp index 16ef45829f..fe43f345d4 100644 --- a/scene/resources/shape_2d.cpp +++ b/scene/resources/shape_2d.cpp @@ -59,39 +59,39 @@ bool Shape2D::collide(const Transform2D &p_local_xform, const Ref<Shape2D> &p_sh return PhysicsServer2D::get_singleton()->shape_collide(get_rid(), p_local_xform, Vector2(), p_shape->get_rid(), p_shape_xform, Vector2(), nullptr, 0, r); } -Array Shape2D::collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion) { - ERR_FAIL_COND_V(p_shape.is_null(), Array()); +PackedVector2Array Shape2D::collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion) { + ERR_FAIL_COND_V(p_shape.is_null(), PackedVector2Array()); const int max_contacts = 16; Vector2 result[max_contacts * 2]; int contacts = 0; if (!PhysicsServer2D::get_singleton()->shape_collide(get_rid(), p_local_xform, p_local_motion, p_shape->get_rid(), p_shape_xform, p_shape_motion, result, max_contacts, contacts)) { - return Array(); + return PackedVector2Array(); } - Array results; + PackedVector2Array results; results.resize(contacts * 2); for (int i = 0; i < contacts * 2; i++) { - results[i] = result[i]; + results.write[i] = result[i]; } return results; } -Array Shape2D::collide_and_get_contacts(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform) { - ERR_FAIL_COND_V(p_shape.is_null(), Array()); +PackedVector2Array Shape2D::collide_and_get_contacts(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform) { + ERR_FAIL_COND_V(p_shape.is_null(), PackedVector2Array()); const int max_contacts = 16; Vector2 result[max_contacts * 2]; int contacts = 0; if (!PhysicsServer2D::get_singleton()->shape_collide(get_rid(), p_local_xform, Vector2(), p_shape->get_rid(), p_shape_xform, Vector2(), result, max_contacts, contacts)) { - return Array(); + return PackedVector2Array(); } - Array results; + PackedVector2Array results; results.resize(contacts * 2); for (int i = 0; i < contacts * 2; i++) { - results[i] = result[i]; + results.write[i] = result[i]; } return results; diff --git a/scene/resources/shape_2d.h b/scene/resources/shape_2d.h index e9dc10eeae..a15aecee93 100644 --- a/scene/resources/shape_2d.h +++ b/scene/resources/shape_2d.h @@ -53,8 +53,8 @@ public: bool collide_with_motion(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion); bool collide(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform); - Array collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion); - Array collide_and_get_contacts(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform); + PackedVector2Array collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion); + PackedVector2Array collide_and_get_contacts(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform); virtual void draw(const RID &p_to_rid, const Color &p_color) {} virtual Rect2 get_rect() const { return Rect2(); } diff --git a/scene/resources/skeleton_modification_3d_ccdik.h b/scene/resources/skeleton_modification_3d_ccdik.h index 7098794038..1fe53e94b6 100644 --- a/scene/resources/skeleton_modification_3d_ccdik.h +++ b/scene/resources/skeleton_modification_3d_ccdik.h @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef SKELETON_MODIFICATION_3D_CCDIK_H +#define SKELETON_MODIFICATION_3D_CCDIK_H + #include "core/templates/local_vector.h" #include "scene/3d/skeleton_3d.h" #include "scene/resources/skeleton_modification_3d.h" -#ifndef SKELETON_MODIFICATION_3D_CCDIK_H -#define SKELETON_MODIFICATION_3D_CCDIK_H - class SkeletonModification3DCCDIK : public SkeletonModification3D { GDCLASS(SkeletonModification3DCCDIK, SkeletonModification3D); diff --git a/scene/resources/skeleton_modification_3d_fabrik.h b/scene/resources/skeleton_modification_3d_fabrik.h index 3d66bb6d99..e2e490d636 100644 --- a/scene/resources/skeleton_modification_3d_fabrik.h +++ b/scene/resources/skeleton_modification_3d_fabrik.h @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef SKELETON_MODIFICATION_3D_FABRIK_H +#define SKELETON_MODIFICATION_3D_FABRIK_H + #include "core/templates/local_vector.h" #include "scene/3d/skeleton_3d.h" #include "scene/resources/skeleton_modification_3d.h" -#ifndef SKELETON_MODIFICATION_3D_FABRIK_H -#define SKELETON_MODIFICATION_3D_FABRIK_H - class SkeletonModification3DFABRIK : public SkeletonModification3D { GDCLASS(SkeletonModification3DFABRIK, SkeletonModification3D); diff --git a/scene/resources/skeleton_modification_3d_jiggle.h b/scene/resources/skeleton_modification_3d_jiggle.h index f41ffcd58d..bd1ee51d93 100644 --- a/scene/resources/skeleton_modification_3d_jiggle.h +++ b/scene/resources/skeleton_modification_3d_jiggle.h @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef SKELETON_MODIFICATION_3D_JIGGLE_H +#define SKELETON_MODIFICATION_3D_JIGGLE_H + #include "core/templates/local_vector.h" #include "scene/3d/skeleton_3d.h" #include "scene/resources/skeleton_modification_3d.h" -#ifndef SKELETON_MODIFICATION_3D_JIGGLE_H -#define SKELETON_MODIFICATION_3D_JIGGLE_H - class SkeletonModification3DJiggle : public SkeletonModification3D { GDCLASS(SkeletonModification3DJiggle, SkeletonModification3D); diff --git a/scene/resources/skeleton_modification_3d_lookat.h b/scene/resources/skeleton_modification_3d_lookat.h index 4e5714b5dc..cea63fc34f 100644 --- a/scene/resources/skeleton_modification_3d_lookat.h +++ b/scene/resources/skeleton_modification_3d_lookat.h @@ -28,12 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/skeleton_modification_3d.h" - #ifndef SKELETON_MODIFICATION_3D_LOOKAT_H #define SKELETON_MODIFICATION_3D_LOOKAT_H +#include "scene/3d/skeleton_3d.h" +#include "scene/resources/skeleton_modification_3d.h" + class SkeletonModification3DLookAt : public SkeletonModification3D { GDCLASS(SkeletonModification3DLookAt, SkeletonModification3D); diff --git a/scene/resources/skeleton_modification_3d_stackholder.h b/scene/resources/skeleton_modification_3d_stackholder.h index ae22099158..2071de5457 100644 --- a/scene/resources/skeleton_modification_3d_stackholder.h +++ b/scene/resources/skeleton_modification_3d_stackholder.h @@ -28,12 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/skeleton_modification_3d.h" - #ifndef SKELETON_MODIFICATION_3D_STACKHOLDER_H #define SKELETON_MODIFICATION_3D_STACKHOLDER_H +#include "scene/3d/skeleton_3d.h" +#include "scene/resources/skeleton_modification_3d.h" + class SkeletonModification3DStackHolder : public SkeletonModification3D { GDCLASS(SkeletonModification3DStackHolder, SkeletonModification3D); diff --git a/scene/resources/skeleton_modification_3d_twoboneik.h b/scene/resources/skeleton_modification_3d_twoboneik.h index 57e8237511..7bd7c8291d 100644 --- a/scene/resources/skeleton_modification_3d_twoboneik.h +++ b/scene/resources/skeleton_modification_3d_twoboneik.h @@ -28,12 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/skeleton_modification_3d.h" - #ifndef SKELETON_MODIFICATION_3D_TWOBONEIK_H #define SKELETON_MODIFICATION_3D_TWOBONEIK_H +#include "scene/3d/skeleton_3d.h" +#include "scene/resources/skeleton_modification_3d.h" + class SkeletonModification3DTwoBoneIK : public SkeletonModification3D { GDCLASS(SkeletonModification3DTwoBoneIK, SkeletonModification3D); diff --git a/scene/resources/skeleton_profile.cpp b/scene/resources/skeleton_profile.cpp index 875d2dcff7..1367ea86dd 100644 --- a/scene/resources/skeleton_profile.cpp +++ b/scene/resources/skeleton_profile.cpp @@ -506,7 +506,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[5].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0); bones.write[5].handle_offset = Vector2(0.5, 0.23); bones.write[5].group = "Body"; - bones.write[5].require = true; + bones.write[5].require = false; bones.write[6].bone_name = "Head"; bones.write[6].bone_parent = "Neck"; diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 0180b2ffcf..90f1a1bff1 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -1036,11 +1036,11 @@ void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_por } } -Array VisualShader::_get_node_connections(Type p_type) const { +TypedArray<Dictionary> VisualShader::_get_node_connections(Type p_type) const { ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Array()); const Graph *g = &graph[p_type]; - Array ret; + TypedArray<Dictionary> ret; for (const Connection &E : g->connections) { Dictionary d; d["from_node"] = E.from_node; @@ -2214,6 +2214,12 @@ void VisualShader::_update_shader() const { case VaryingType::VARYING_TYPE_FLOAT: global_code += "float "; break; + case VaryingType::VARYING_TYPE_INT: + if (E.value.mode == VaryingMode::VARYING_MODE_VERTEX_TO_FRAG_LIGHT) { + global_code += "flat "; + } + global_code += "int "; + break; case VaryingType::VARYING_TYPE_VECTOR_2D: global_code += "vec2 "; break; @@ -2223,8 +2229,11 @@ void VisualShader::_update_shader() const { case VaryingType::VARYING_TYPE_VECTOR_4D: global_code += "vec4 "; break; - case VaryingType::VARYING_TYPE_COLOR: - global_code += "vec4 "; + case VaryingType::VARYING_TYPE_BOOLEAN: + if (E.value.mode == VaryingMode::VARYING_MODE_VERTEX_TO_FRAG_LIGHT) { + global_code += "flat "; + } + global_code += "bool "; break; case VaryingType::VARYING_TYPE_TRANSFORM: global_code += "mat4 "; @@ -2277,6 +2286,9 @@ void VisualShader::_update_shader() const { case VaryingType::VARYING_TYPE_FLOAT: code2 += "0.0"; break; + case VaryingType::VARYING_TYPE_INT: + code2 += "0"; + break; case VaryingType::VARYING_TYPE_VECTOR_2D: code2 += "vec2(0.0)"; break; @@ -2286,8 +2298,8 @@ void VisualShader::_update_shader() const { case VaryingType::VARYING_TYPE_VECTOR_4D: code2 += "vec4(0.0)"; break; - case VaryingType::VARYING_TYPE_COLOR: - code2 += "vec4(0.0)"; + case VaryingType::VARYING_TYPE_BOOLEAN: + code2 += "false"; break; case VaryingType::VARYING_TYPE_TRANSFORM: code2 += "mat4(1.0)"; @@ -2585,10 +2597,11 @@ void VisualShader::_bind_methods() { BIND_ENUM_CONSTANT(VARYING_MODE_MAX); BIND_ENUM_CONSTANT(VARYING_TYPE_FLOAT); + BIND_ENUM_CONSTANT(VARYING_TYPE_INT); BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_2D); BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_3D); BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_4D); - BIND_ENUM_CONSTANT(VARYING_TYPE_COLOR); + BIND_ENUM_CONSTANT(VARYING_TYPE_BOOLEAN); BIND_ENUM_CONSTANT(VARYING_TYPE_TRANSFORM); BIND_ENUM_CONSTANT(VARYING_TYPE_MAX); @@ -4632,21 +4645,23 @@ void VisualShaderNodeVarying::_bind_methods() { ClassDB::bind_method(D_METHOD("get_varying_type"), &VisualShaderNodeVarying::get_varying_type); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "varying_name"), "set_varying_name", "get_varying_name"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "varying_type", PROPERTY_HINT_ENUM, "Float,Vector,Transform"), "set_varying_type", "get_varying_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "varying_type", PROPERTY_HINT_ENUM, "Float,Int,Vector2,Vector3,Vector4,Boolean,Transform"), "set_varying_type", "get_varying_type"); } String VisualShaderNodeVarying::get_type_str() const { switch (varying_type) { case VisualShader::VARYING_TYPE_FLOAT: return "float"; + case VisualShader::VARYING_TYPE_INT: + return "int"; case VisualShader::VARYING_TYPE_VECTOR_2D: return "vec2"; case VisualShader::VARYING_TYPE_VECTOR_3D: return "vec3"; case VisualShader::VARYING_TYPE_VECTOR_4D: return "vec4"; - case VisualShader::VARYING_TYPE_COLOR: - return "vec4"; + case VisualShader::VARYING_TYPE_BOOLEAN: + return "bool"; case VisualShader::VARYING_TYPE_TRANSFORM: return "mat4"; default: @@ -4657,17 +4672,16 @@ String VisualShaderNodeVarying::get_type_str() const { VisualShaderNodeVarying::PortType VisualShaderNodeVarying::get_port_type(VisualShader::VaryingType p_type, int p_port) const { switch (p_type) { + case VisualShader::VARYING_TYPE_INT: + return PORT_TYPE_SCALAR_INT; case VisualShader::VARYING_TYPE_VECTOR_2D: return PORT_TYPE_VECTOR_2D; case VisualShader::VARYING_TYPE_VECTOR_3D: return PORT_TYPE_VECTOR_3D; case VisualShader::VARYING_TYPE_VECTOR_4D: return PORT_TYPE_VECTOR_4D; - case VisualShader::VARYING_TYPE_COLOR: - if (p_port == 1) { - break; // scalar - } - return PORT_TYPE_VECTOR_3D; + case VisualShader::VARYING_TYPE_BOOLEAN: + return PORT_TYPE_BOOLEAN; case VisualShader::VARYING_TYPE_TRANSFORM: return PORT_TYPE_TRANSFORM; default: @@ -4711,9 +4725,6 @@ String VisualShaderNodeVaryingSetter::get_caption() const { } int VisualShaderNodeVaryingSetter::get_input_port_count() const { - if (varying_type == VisualShader::VARYING_TYPE_COLOR) { - return 2; - } return 1; } @@ -4722,13 +4733,6 @@ VisualShaderNodeVaryingSetter::PortType VisualShaderNodeVaryingSetter::get_input } String VisualShaderNodeVaryingSetter::get_input_port_name(int p_port) const { - if (varying_type == VisualShader::VARYING_TYPE_COLOR) { - if (p_port == 0) { - return "color"; - } else { - return "alpha"; - } - } return ""; } @@ -4744,20 +4748,12 @@ String VisualShaderNodeVaryingSetter::get_output_port_name(int p_port) const { return ""; } -String VisualShaderNodeVaryingSetter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - return vformat("varying %s %s;\n", get_type_str(), varying_name); -} - String VisualShaderNodeVaryingSetter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; if (varying_name == "[None]") { return code; } - if (varying_type == VisualShader::VARYING_TYPE_COLOR) { - code += vformat(" %s = vec4(%s, %s);\n", varying_name, p_input_vars[0], p_input_vars[1]); - } else { - code += vformat(" %s = %s;\n", varying_name, p_input_vars[0]); - } + code += vformat(" %s = %s;\n", varying_name, p_input_vars[0]); return code; } @@ -4783,9 +4779,6 @@ String VisualShaderNodeVaryingGetter::get_input_port_name(int p_port) const { } int VisualShaderNodeVaryingGetter::get_output_port_count() const { - if (varying_type == VisualShader::VARYING_TYPE_COLOR) { - return 2; - } return 1; } @@ -4794,13 +4787,6 @@ VisualShaderNodeVaryingGetter::PortType VisualShaderNodeVaryingGetter::get_outpu } String VisualShaderNodeVaryingGetter::get_output_port_name(int p_port) const { - if (varying_type == VisualShader::VARYING_TYPE_COLOR) { - if (p_port == 0) { - return "color"; - } else { - return "alpha"; - } - } return ""; } @@ -4817,6 +4803,9 @@ String VisualShaderNodeVaryingGetter::generate_code(Shader::Mode p_mode, VisualS case VisualShader::VARYING_TYPE_FLOAT: from = "0.0"; break; + case VisualShader::VARYING_TYPE_INT: + from = "0"; + break; case VisualShader::VARYING_TYPE_VECTOR_2D: from = "vec2(0.0)"; break; @@ -4826,9 +4815,8 @@ String VisualShaderNodeVaryingGetter::generate_code(Shader::Mode p_mode, VisualS case VisualShader::VARYING_TYPE_VECTOR_4D: from = "vec4(0.0)"; break; - case VisualShader::VARYING_TYPE_COLOR: - from = "vec3(0.0)"; - from2 = "0.0"; + case VisualShader::VARYING_TYPE_BOOLEAN: + from = "false"; break; case VisualShader::VARYING_TYPE_TRANSFORM: from = "mat4(1.0)"; @@ -4836,16 +4824,6 @@ String VisualShaderNodeVaryingGetter::generate_code(Shader::Mode p_mode, VisualS default: break; } - } else if (varying_type == VisualShader::VARYING_TYPE_COLOR) { - from = varying_name + ".rgb"; - from2 = varying_name + ".a"; - } - - if (varying_type == VisualShader::VARYING_TYPE_COLOR) { - String code; - code += vformat(" %s = %s;\n", p_output_vars[0], from); - code += vformat(" %s = %s;\n", p_output_vars[1], from2); - return code; } return vformat(" %s = %s;\n", p_output_vars[0], from); } diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 527588b6e6..09a3917a16 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -79,10 +79,11 @@ public: enum VaryingType { VARYING_TYPE_FLOAT, + VARYING_TYPE_INT, VARYING_TYPE_VECTOR_2D, VARYING_TYPE_VECTOR_3D, VARYING_TYPE_VECTOR_4D, - VARYING_TYPE_COLOR, + VARYING_TYPE_BOOLEAN, VARYING_TYPE_TRANSFORM, VARYING_TYPE_MAX, }; @@ -132,7 +133,7 @@ private: Shader::Mode shader_mode = Shader::MODE_SPATIAL; mutable String previous_code; - Array _get_node_connections(Type p_type) const; + TypedArray<Dictionary> _get_node_connections(Type p_type) const; Vector2 graph_offset; @@ -828,7 +829,6 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; - virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; VisualShaderNodeVaryingSetter(); diff --git a/servers/audio/audio_driver_dummy.cpp b/servers/audio/audio_driver_dummy.cpp index 60eb657923..729f278d4b 100644 --- a/servers/audio/audio_driver_dummy.cpp +++ b/servers/audio/audio_driver_dummy.cpp @@ -36,9 +36,8 @@ AudioDriverDummy *AudioDriverDummy::singleton = nullptr; Error AudioDriverDummy::init() { - active = false; - thread_exited = false; - exit_thread = false; + active.clear(); + exit_thread.clear(); samples_in = nullptr; if (mix_rate == -1) { @@ -60,23 +59,23 @@ void AudioDriverDummy::thread_func(void *p_udata) { uint64_t usdelay = (ad->buffer_frames / float(ad->mix_rate)) * 1000000; - while (!ad->exit_thread) { - if (ad->active) { + while (!ad->exit_thread.is_set()) { + if (ad->active.is_set()) { ad->lock(); + ad->start_counting_ticks(); ad->audio_server_process(ad->buffer_frames, ad->samples_in); + ad->stop_counting_ticks(); ad->unlock(); }; OS::get_singleton()->delay_usec(usdelay); }; - - ad->thread_exited = true; }; void AudioDriverDummy::start() { - active = true; + active.set(); }; int AudioDriverDummy::get_mix_rate() const { @@ -113,7 +112,7 @@ uint32_t AudioDriverDummy::get_channels() const { } void AudioDriverDummy::mix_audio(int p_frames, int32_t *p_buffer) { - ERR_FAIL_COND(!active); // If not active, should not mix. + ERR_FAIL_COND(!active.is_set()); // If not active, should not mix. ERR_FAIL_COND(use_threads == true); // If using threads, this will not work well. uint32_t todo = p_frames; @@ -136,7 +135,7 @@ void AudioDriverDummy::mix_audio(int p_frames, int32_t *p_buffer) { void AudioDriverDummy::finish() { if (use_threads) { - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); } diff --git a/servers/audio/audio_driver_dummy.h b/servers/audio/audio_driver_dummy.h index 8f47e64d8b..46dd2e1439 100644 --- a/servers/audio/audio_driver_dummy.h +++ b/servers/audio/audio_driver_dummy.h @@ -35,6 +35,7 @@ #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/templates/safe_refcount.h" class AudioDriverDummy : public AudioDriver { Thread thread; @@ -50,9 +51,8 @@ class AudioDriverDummy : public AudioDriver { int channels; - bool active; - bool thread_exited; - mutable bool exit_thread; + SafeFlag active; + SafeFlag exit_thread; bool use_threads = true; diff --git a/servers/audio/effects/audio_effect_delay.cpp b/servers/audio/effects/audio_effect_delay.cpp index 80e7a8223c..ae8c58f654 100644 --- a/servers/audio/effects/audio_effect_delay.cpp +++ b/servers/audio/effects/audio_effect_delay.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "audio_effect_delay.h" + #include "core/math/math_funcs.h" #include "servers/audio_server.h" @@ -286,37 +287,21 @@ void AudioEffectDelay::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dry", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dry", "get_dry"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tap1/active"), "set_tap1_active", "is_tap1_active"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap1/delay_ms", PROPERTY_HINT_RANGE, "0,1500,1,suffix:ms"), "set_tap1_delay_ms", "get_tap1_delay_ms"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap1/level_db", PROPERTY_HINT_RANGE, "-60,0,0.01,suffix:dB"), "set_tap1_level_db", "get_tap1_level_db"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap1/pan", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_tap1_pan", "get_tap1_pan"); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tap2/active"), "set_tap2_active", "is_tap2_active"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap2/delay_ms", PROPERTY_HINT_RANGE, "0,1500,1,suffix:ms"), "set_tap2_delay_ms", "get_tap2_delay_ms"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap2/level_db", PROPERTY_HINT_RANGE, "-60,0,0.01,suffix:dB"), "set_tap2_level_db", "get_tap2_level_db"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap2/pan", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_tap2_pan", "get_tap2_pan"); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "feedback/active"), "set_feedback_active", "is_feedback_active"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "feedback/delay_ms", PROPERTY_HINT_RANGE, "0,1500,1,suffix:ms"), "set_feedback_delay_ms", "get_feedback_delay_ms"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "feedback/level_db", PROPERTY_HINT_RANGE, "-60,0,0.01,suffix:dB"), "set_feedback_level_db", "get_feedback_level_db"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "feedback/lowpass", PROPERTY_HINT_RANGE, "1,16000,1"), "set_feedback_lowpass", "get_feedback_lowpass"); -} - -AudioEffectDelay::AudioEffectDelay() { - tap_1_active = true; - tap_1_delay_ms = 250; - tap_1_level = -6; - tap_1_pan = 0.2; - - tap_2_active = true; - tap_2_delay_ms = 500; - tap_2_level = -12; - tap_2_pan = -0.4; - - feedback_active = false; - feedback_delay_ms = 340; - feedback_level = -6; - feedback_lowpass = 16000; - - dry = 1.0; + ADD_GROUP("Tap 1", "tap1_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tap1_active"), "set_tap1_active", "is_tap1_active"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap1_delay_ms", PROPERTY_HINT_RANGE, "0,1500,1,suffix:ms"), "set_tap1_delay_ms", "get_tap1_delay_ms"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap1_level_db", PROPERTY_HINT_RANGE, "-60,0,0.01,suffix:dB"), "set_tap1_level_db", "get_tap1_level_db"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap1_pan", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_tap1_pan", "get_tap1_pan"); + + ADD_GROUP("Tap 2", "tap2_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tap2_active"), "set_tap2_active", "is_tap2_active"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap2_delay_ms", PROPERTY_HINT_RANGE, "0,1500,1,suffix:ms"), "set_tap2_delay_ms", "get_tap2_delay_ms"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap2_level_db", PROPERTY_HINT_RANGE, "-60,0,0.01,suffix:dB"), "set_tap2_level_db", "get_tap2_level_db"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap2_pan", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_tap2_pan", "get_tap2_pan"); + + ADD_GROUP("Feedback", "feedback_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "feedback_active"), "set_feedback_active", "is_feedback_active"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "feedback_delay_ms", PROPERTY_HINT_RANGE, "0,1500,1,suffix:ms"), "set_feedback_delay_ms", "get_feedback_delay_ms"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "feedback_level_db", PROPERTY_HINT_RANGE, "-60,0,0.01,suffix:dB"), "set_feedback_level_db", "get_feedback_level_db"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "feedback_lowpass", PROPERTY_HINT_RANGE, "1,16000,1"), "set_feedback_lowpass", "get_feedback_lowpass"); } diff --git a/servers/audio/effects/audio_effect_delay.h b/servers/audio/effects/audio_effect_delay.h index 137a4e7dbe..020d45e79b 100644 --- a/servers/audio/effects/audio_effect_delay.h +++ b/servers/audio/effects/audio_effect_delay.h @@ -37,6 +37,7 @@ class AudioEffectDelay; class AudioEffectDelayInstance : public AudioEffectInstance { GDCLASS(AudioEffectDelayInstance, AudioEffectInstance); + friend class AudioEffectDelay; Ref<AudioEffectDelay> base; @@ -66,22 +67,22 @@ class AudioEffectDelay : public AudioEffect { MAX_TAPS = 2 }; - float dry; + float dry = 1.0f; - bool tap_1_active; - float tap_1_delay_ms; - float tap_1_level; - float tap_1_pan; + bool tap_1_active = true; + float tap_1_delay_ms = 250.0f; + float tap_1_level = -6.0f; + float tap_1_pan = 0.2f; - bool tap_2_active; - float tap_2_delay_ms; - float tap_2_level; - float tap_2_pan; + bool tap_2_active = true; + float tap_2_delay_ms = 500.0f; + float tap_2_level = -12.0f; + float tap_2_pan = -0.4f; - bool feedback_active; - float feedback_delay_ms; - float feedback_level; - float feedback_lowpass; + bool feedback_active = false; + float feedback_delay_ms = 340.0f; + float feedback_level = -6.0f; + float feedback_lowpass = 16000.0f; protected: static void _bind_methods(); @@ -128,7 +129,7 @@ public: Ref<AudioEffectInstance> instantiate() override; - AudioEffectDelay(); + AudioEffectDelay() {} }; #endif // AUDIO_EFFECT_DELAY_H diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 9052f8e05e..64695557aa 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -144,8 +144,8 @@ int AudioDriver::get_total_channels_by_speaker_mode(AudioDriver::SpeakerMode p_m ERR_FAIL_V(2); } -Array AudioDriver::get_device_list() { - Array list; +PackedStringArray AudioDriver::get_device_list() { + PackedStringArray list; list.push_back("Default"); @@ -156,8 +156,8 @@ String AudioDriver::get_device() { return "Default"; } -Array AudioDriver::capture_get_device_list() { - Array list; +PackedStringArray AudioDriver::capture_get_device_list() { + PackedStringArray list; list.push_back("Default"); @@ -1637,7 +1637,7 @@ Ref<AudioBusLayout> AudioServer::generate_bus_layout() const { return state; } -Array AudioServer::get_device_list() { +PackedStringArray AudioServer::get_device_list() { return AudioDriver::get_singleton()->get_device_list(); } @@ -1649,7 +1649,7 @@ void AudioServer::set_device(String device) { AudioDriver::get_singleton()->set_device(device); } -Array AudioServer::capture_get_device_list() { +PackedStringArray AudioServer::capture_get_device_list() { return AudioDriver::get_singleton()->capture_get_device_list(); } diff --git a/servers/audio_server.h b/servers/audio_server.h index 5613267909..588107c25d 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -94,7 +94,7 @@ public: virtual void start() = 0; virtual int get_mix_rate() const = 0; virtual SpeakerMode get_speaker_mode() const = 0; - virtual Array get_device_list(); + virtual PackedStringArray get_device_list(); virtual String get_device(); virtual void set_device(String device) {} virtual void lock() = 0; @@ -105,7 +105,7 @@ public: virtual Error capture_stop() { return FAILED; } virtual void capture_set_device(const String &p_name) {} virtual String capture_get_device() { return "Default"; } - virtual Array capture_get_device_list(); // TODO: convert this and get_device_list to PackedStringArray + virtual PackedStringArray capture_get_device_list(); virtual float get_latency() { return 0; } @@ -419,11 +419,11 @@ public: void set_bus_layout(const Ref<AudioBusLayout> &p_bus_layout); Ref<AudioBusLayout> generate_bus_layout() const; - Array get_device_list(); + PackedStringArray get_device_list(); String get_device(); void set_device(String device); - Array capture_get_device_list(); + PackedStringArray capture_get_device_list(); String capture_get_device(); void capture_set_device(const String &p_name); diff --git a/servers/camera_server.cpp b/servers/camera_server.cpp index 91df3afadd..b83b41a571 100644 --- a/servers/camera_server.cpp +++ b/servers/camera_server.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "camera_server.h" +#include "core/variant/typed_array.h" #include "rendering_server.h" #include "servers/camera/camera_feed.h" @@ -143,8 +144,8 @@ int CameraServer::get_feed_count() { return feeds.size(); }; -Array CameraServer::get_feeds() { - Array return_feeds; +TypedArray<CameraFeed> CameraServer::get_feeds() { + TypedArray<CameraFeed> return_feeds; int cc = get_feed_count(); return_feeds.resize(cc); diff --git a/servers/camera_server.h b/servers/camera_server.h index b70938c34f..c6fb906b3c 100644 --- a/servers/camera_server.h +++ b/servers/camera_server.h @@ -43,6 +43,8 @@ **/ class CameraFeed; +template <typename T> +class TypedArray; class CameraServer : public Object { GDCLASS(CameraServer, Object); @@ -100,7 +102,7 @@ public: // Get our feeds. Ref<CameraFeed> get_feed(int p_index); int get_feed_count(); - Array get_feeds(); + TypedArray<CameraFeed> get_feeds(); // Intended for use with custom CameraServer implementation. RID feed_texture(int p_id, FeedImage p_texture); diff --git a/servers/display_server.cpp b/servers/display_server.cpp index ff6d769a86..0c05570b23 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -256,14 +256,14 @@ void DisplayServer::tts_resume() { WARN_PRINT("TTS is not supported by this display server."); } -Array DisplayServer::tts_get_voices() const { +TypedArray<Dictionary> DisplayServer::tts_get_voices() const { WARN_PRINT("TTS is not supported by this display server."); - return Array(); + return TypedArray<Dictionary>(); } PackedStringArray DisplayServer::tts_get_voices_for_language(const String &p_language) const { PackedStringArray ret; - Array voices = tts_get_voices(); + TypedArray<Dictionary> voices = tts_get_voices(); for (int i = 0; i < voices.size(); i++) { const Dictionary &voice = voices[i]; if (voice.has("id") && voice.has("language") && voice["language"].operator String().begins_with(p_language)) { diff --git a/servers/display_server.h b/servers/display_server.h index a5c42617af..4e52c58633 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -198,7 +198,7 @@ private: public: virtual bool tts_is_speaking() const; virtual bool tts_is_paused() const; - virtual Array tts_get_voices() const; + virtual TypedArray<Dictionary> tts_get_voices() const; virtual PackedStringArray tts_get_voices_for_language(const String &p_language) const; virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false); @@ -230,7 +230,7 @@ public: virtual void clipboard_set_primary(const String &p_text); virtual String clipboard_get_primary() const; - virtual Array get_display_cutouts() const { return Array(); } + virtual TypedArray<Rect2> get_display_cutouts() const { return TypedArray<Rect2>(); } virtual Rect2i get_display_safe_area() const { return screen_get_usable_rect(); } enum { diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp index 27b49014d8..0f73df8894 100644 --- a/servers/navigation_server_2d.cpp +++ b/servers/navigation_server_2d.cpp @@ -237,7 +237,7 @@ void NavigationServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("agent_create"), &NavigationServer2D::agent_create); ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer2D::agent_set_map); ClassDB::bind_method(D_METHOD("agent_get_map", "agent"), &NavigationServer2D::agent_get_map); - ClassDB::bind_method(D_METHOD("agent_set_neighbor_dist", "agent", "dist"), &NavigationServer2D::agent_set_neighbor_dist); + ClassDB::bind_method(D_METHOD("agent_set_neighbor_distance", "agent", "distance"), &NavigationServer2D::agent_set_neighbor_distance); ClassDB::bind_method(D_METHOD("agent_set_max_neighbors", "agent", "count"), &NavigationServer2D::agent_set_max_neighbors); ClassDB::bind_method(D_METHOD("agent_set_time_horizon", "agent", "time"), &NavigationServer2D::agent_set_time_horizon); ClassDB::bind_method(D_METHOD("agent_set_radius", "agent", "radius"), &NavigationServer2D::agent_set_radius); @@ -263,11 +263,11 @@ NavigationServer2D::~NavigationServer2D() { singleton = nullptr; } -Array FORWARD_0_C(get_maps); +TypedArray<RID> FORWARD_0_C(get_maps); -Array FORWARD_1_C(map_get_regions, RID, p_map, rid_to_rid); +TypedArray<RID> FORWARD_1_C(map_get_regions, RID, p_map, rid_to_rid); -Array FORWARD_1_C(map_get_agents, RID, p_map, rid_to_rid); +TypedArray<RID> FORWARD_1_C(map_get_agents, RID, p_map, rid_to_rid); RID FORWARD_1_C(region_get_map, RID, p_region, rid_to_rid); @@ -323,7 +323,7 @@ RID NavigationServer2D::agent_create() const { void FORWARD_2_C(agent_set_map, RID, p_agent, RID, p_map, rid_to_rid, rid_to_rid); -void FORWARD_2_C(agent_set_neighbor_dist, RID, p_agent, real_t, p_dist, rid_to_rid, real_to_real); +void FORWARD_2_C(agent_set_neighbor_distance, RID, p_agent, real_t, p_dist, rid_to_rid, real_to_real); void FORWARD_2_C(agent_set_max_neighbors, RID, p_agent, int, p_count, rid_to_rid, int_to_int); diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h index 83271f990e..5e96466d66 100644 --- a/servers/navigation_server_2d.h +++ b/servers/navigation_server_2d.h @@ -53,7 +53,7 @@ public: /// MUST be used in single thread! static NavigationServer2D *get_singleton_mut() { return singleton; } - virtual Array get_maps() const; + virtual TypedArray<RID> get_maps() const; /// Create a new map. virtual RID map_create() const; @@ -82,8 +82,8 @@ public: virtual Vector2 map_get_closest_point(RID p_map, const Vector2 &p_point) const; virtual RID map_get_closest_point_owner(RID p_map, const Vector2 &p_point) const; - virtual Array map_get_regions(RID p_map) const; - virtual Array map_get_agents(RID p_map) const; + virtual TypedArray<RID> map_get_regions(RID p_map) const; + virtual TypedArray<RID> map_get_agents(RID p_map) const; virtual void map_force_update(RID p_map); @@ -133,7 +133,7 @@ public: /// time of the simulation. If the number is too /// low, the simulation will not be safe. /// Must be non-negative. - virtual void agent_set_neighbor_dist(RID p_agent, real_t p_dist) const; + virtual void agent_set_neighbor_distance(RID p_agent, real_t p_distance) const; /// The maximum number of other agents this /// agent takes into account in the navigation. diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index 206698f97c..466b74bc64 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -79,7 +79,7 @@ void NavigationServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("agent_create"), &NavigationServer3D::agent_create); ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer3D::agent_set_map); ClassDB::bind_method(D_METHOD("agent_get_map", "agent"), &NavigationServer3D::agent_get_map); - ClassDB::bind_method(D_METHOD("agent_set_neighbor_dist", "agent", "dist"), &NavigationServer3D::agent_set_neighbor_dist); + ClassDB::bind_method(D_METHOD("agent_set_neighbor_distance", "agent", "distance"), &NavigationServer3D::agent_set_neighbor_distance); ClassDB::bind_method(D_METHOD("agent_set_max_neighbors", "agent", "count"), &NavigationServer3D::agent_set_max_neighbors); ClassDB::bind_method(D_METHOD("agent_set_time_horizon", "agent", "time"), &NavigationServer3D::agent_set_time_horizon); ClassDB::bind_method(D_METHOD("agent_set_radius", "agent", "radius"), &NavigationServer3D::agent_set_radius); diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h index f24c0117d1..3213da3d84 100644 --- a/servers/navigation_server_3d.h +++ b/servers/navigation_server_3d.h @@ -56,7 +56,7 @@ public: /// MUST be used in single thread! static NavigationServer3D *get_singleton_mut(); - virtual Array get_maps() const = 0; + virtual TypedArray<RID> get_maps() const = 0; /// Create a new map. virtual RID map_create() const = 0; @@ -93,8 +93,8 @@ public: virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const = 0; virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const = 0; - virtual Array map_get_regions(RID p_map) const = 0; - virtual Array map_get_agents(RID p_map) const = 0; + virtual TypedArray<RID> map_get_regions(RID p_map) const = 0; + virtual TypedArray<RID> map_get_agents(RID p_map) const = 0; virtual void map_force_update(RID p_map) = 0; @@ -147,7 +147,7 @@ public: /// time of the simulation. If the number is too /// low, the simulation will not be safe. /// Must be non-negative. - virtual void agent_set_neighbor_dist(RID p_agent, real_t p_dist) const = 0; + virtual void agent_set_neighbor_distance(RID p_agent, real_t p_distance) const = 0; /// The maximum number of other agents this /// agent takes into account in the navigation. diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index ee6764d8e1..bfb5cd8106 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/string/print_string.h" +#include "core/variant/typed_array.h" PhysicsServer2D *PhysicsServer2D::singleton = nullptr; @@ -347,7 +348,7 @@ Dictionary PhysicsDirectSpaceState2D::_intersect_ray(const Ref<PhysicsRayQueryPa return d; } -Array PhysicsDirectSpaceState2D::_intersect_point(const Ref<PhysicsPointQueryParameters2D> &p_point_query, int p_max_results) { +TypedArray<Dictionary> PhysicsDirectSpaceState2D::_intersect_point(const Ref<PhysicsPointQueryParameters2D> &p_point_query, int p_max_results) { ERR_FAIL_COND_V(p_point_query.is_null(), Array()); Vector<ShapeResult> ret; @@ -356,10 +357,10 @@ Array PhysicsDirectSpaceState2D::_intersect_point(const Ref<PhysicsPointQueryPar int rc = intersect_point(p_point_query->get_parameters(), ret.ptrw(), ret.size()); if (rc == 0) { - return Array(); + return TypedArray<Dictionary>(); } - Array r; + TypedArray<Dictionary> r; r.resize(rc); for (int i = 0; i < rc; i++) { Dictionary d; @@ -372,13 +373,13 @@ Array PhysicsDirectSpaceState2D::_intersect_point(const Ref<PhysicsPointQueryPar return r; } -Array PhysicsDirectSpaceState2D::_intersect_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results) { - ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array()); +TypedArray<Dictionary> PhysicsDirectSpaceState2D::_intersect_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results) { + ERR_FAIL_COND_V(!p_shape_query.is_valid(), TypedArray<Dictionary>()); Vector<ShapeResult> sr; sr.resize(p_max_results); int rc = intersect_shape(p_shape_query->get_parameters(), sr.ptrw(), sr.size()); - Array ret; + TypedArray<Dictionary> ret; ret.resize(rc); for (int i = 0; i < rc; i++) { Dictionary d; @@ -392,22 +393,22 @@ Array PhysicsDirectSpaceState2D::_intersect_shape(const Ref<PhysicsShapeQueryPar return ret; } -Array PhysicsDirectSpaceState2D::_cast_motion(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query) { - ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array()); +Vector<real_t> PhysicsDirectSpaceState2D::_cast_motion(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query) { + ERR_FAIL_COND_V(!p_shape_query.is_valid(), Vector<real_t>()); real_t closest_safe, closest_unsafe; bool res = cast_motion(p_shape_query->get_parameters(), closest_safe, closest_unsafe); if (!res) { - return Array(); + return Vector<real_t>(); } - Array ret; + Vector<real_t> ret; ret.resize(2); - ret[0] = closest_safe; - ret[1] = closest_unsafe; + ret.write[0] = closest_safe; + ret.write[1] = closest_unsafe; return ret; } -Array PhysicsDirectSpaceState2D::_collide_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results) { +TypedArray<PackedVector2Array> PhysicsDirectSpaceState2D::_collide_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results) { ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array()); Vector<Vector2> ret; @@ -415,9 +416,9 @@ Array PhysicsDirectSpaceState2D::_collide_shape(const Ref<PhysicsShapeQueryParam int rc = 0; bool res = collide_shape(p_shape_query->get_parameters(), ret.ptrw(), p_max_results, rc); if (!res) { - return Array(); + return TypedArray<PackedVector2Array>(); } - Array r; + TypedArray<PackedVector2Array> r; r.resize(rc * 2); for (int i = 0; i < rc * 2; i++) { r[i] = ret[i]; diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index df8b641ffc..d0c5a7189b 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -36,6 +36,8 @@ #include "core/object/ref_counted.h" class PhysicsDirectSpaceState2D; +template <typename T> +class TypedArray; class PhysicsDirectBodyState2D : public Object { GDCLASS(PhysicsDirectBodyState2D, Object); @@ -114,10 +116,10 @@ class PhysicsDirectSpaceState2D : public Object { GDCLASS(PhysicsDirectSpaceState2D, Object); Dictionary _intersect_ray(const Ref<PhysicsRayQueryParameters2D> &p_ray_query); - Array _intersect_point(const Ref<PhysicsPointQueryParameters2D> &p_point_query, int p_max_results = 32); - Array _intersect_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results = 32); - Array _cast_motion(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query); - Array _collide_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results = 32); + TypedArray<Dictionary> _intersect_point(const Ref<PhysicsPointQueryParameters2D> &p_point_query, int p_max_results = 32); + TypedArray<Dictionary> _intersect_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results = 32); + Vector<real_t> _cast_motion(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query); + TypedArray<PackedVector2Array> _collide_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results = 32); Dictionary _get_rest_info(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query); protected: diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index c985df83b2..6dd5be9ea8 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/string/print_string.h" +#include "core/variant/typed_array.h" void PhysicsServer3DRenderingServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) { GDVIRTUAL_REQUIRED_CALL(_set_vertex, p_vertex_id, p_vector3); @@ -366,8 +367,8 @@ Dictionary PhysicsDirectSpaceState3D::_intersect_ray(const Ref<PhysicsRayQueryPa return d; } -Array PhysicsDirectSpaceState3D::_intersect_point(const Ref<PhysicsPointQueryParameters3D> &p_point_query, int p_max_results) { - ERR_FAIL_COND_V(p_point_query.is_null(), Array()); +TypedArray<Dictionary> PhysicsDirectSpaceState3D::_intersect_point(const Ref<PhysicsPointQueryParameters3D> &p_point_query, int p_max_results) { + ERR_FAIL_COND_V(p_point_query.is_null(), TypedArray<Dictionary>()); Vector<ShapeResult> ret; ret.resize(p_max_results); @@ -375,10 +376,10 @@ Array PhysicsDirectSpaceState3D::_intersect_point(const Ref<PhysicsPointQueryPar int rc = intersect_point(p_point_query->get_parameters(), ret.ptrw(), ret.size()); if (rc == 0) { - return Array(); + return TypedArray<Dictionary>(); } - Array r; + TypedArray<Dictionary> r; r.resize(rc); for (int i = 0; i < rc; i++) { Dictionary d; @@ -391,13 +392,13 @@ Array PhysicsDirectSpaceState3D::_intersect_point(const Ref<PhysicsPointQueryPar return r; } -Array PhysicsDirectSpaceState3D::_intersect_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results) { - ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array()); +TypedArray<Dictionary> PhysicsDirectSpaceState3D::_intersect_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results) { + ERR_FAIL_COND_V(!p_shape_query.is_valid(), TypedArray<Dictionary>()); Vector<ShapeResult> sr; sr.resize(p_max_results); int rc = intersect_shape(p_shape_query->get_parameters(), sr.ptrw(), sr.size()); - Array ret; + TypedArray<Dictionary> ret; ret.resize(rc); for (int i = 0; i < rc; i++) { Dictionary d; @@ -411,22 +412,22 @@ Array PhysicsDirectSpaceState3D::_intersect_shape(const Ref<PhysicsShapeQueryPar return ret; } -Array PhysicsDirectSpaceState3D::_cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query) { - ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array()); +Vector<real_t> PhysicsDirectSpaceState3D::_cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query) { + ERR_FAIL_COND_V(!p_shape_query.is_valid(), Vector<real_t>()); real_t closest_safe = 1.0f, closest_unsafe = 1.0f; bool res = cast_motion(p_shape_query->get_parameters(), closest_safe, closest_unsafe); if (!res) { - return Array(); + return Vector<real_t>(); } - Array ret; + Vector<real_t> ret; ret.resize(2); - ret[0] = closest_safe; - ret[1] = closest_unsafe; + ret.write[0] = closest_safe; + ret.write[1] = closest_unsafe; return ret; } -Array PhysicsDirectSpaceState3D::_collide_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results) { +TypedArray<PackedVector2Array> PhysicsDirectSpaceState3D::_collide_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results) { ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array()); Vector<Vector3> ret; @@ -434,9 +435,9 @@ Array PhysicsDirectSpaceState3D::_collide_shape(const Ref<PhysicsShapeQueryParam int rc = 0; bool res = collide_shape(p_shape_query->get_parameters(), ret.ptrw(), p_max_results, rc); if (!res) { - return Array(); + return TypedArray<PackedVector2Array>(); } - Array r; + TypedArray<PackedVector2Array> r; r.resize(rc * 2); for (int i = 0; i < rc * 2; i++) { r[i] = ret[i]; diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index 01324be0f5..d5c4d9713b 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -38,6 +38,8 @@ #include "core/variant/native_ptr.h" class PhysicsDirectSpaceState3D; +template <typename T> +class TypedArray; class PhysicsDirectBodyState3D : public Object { GDCLASS(PhysicsDirectBodyState3D, Object); @@ -120,10 +122,10 @@ class PhysicsDirectSpaceState3D : public Object { private: Dictionary _intersect_ray(const Ref<PhysicsRayQueryParameters3D> &p_ray_query); - Array _intersect_point(const Ref<PhysicsPointQueryParameters3D> &p_point_query, int p_max_results = 32); - Array _intersect_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results = 32); - Array _cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query); - Array _collide_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results = 32); + TypedArray<Dictionary> _intersect_point(const Ref<PhysicsPointQueryParameters3D> &p_point_query, int p_max_results = 32); + TypedArray<Dictionary> _intersect_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results = 32); + Vector<real_t> _cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query); + TypedArray<PackedVector2Array> _collide_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results = 32); Dictionary _get_rest_info(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query); protected: diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index ba644e7eb9..022b027644 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -134,7 +134,7 @@ void process() { material_storage->material_initialize(particles_shader.default_material); material_storage->material_set_shader(particles_shader.default_material, particles_shader.default_shader); - ParticlesMaterialData *md = static_cast<ParticlesMaterialData *>(material_storage->material_get_data(particles_shader.default_material, MaterialStorage::SHADER_TYPE_PARTICLES)); + ParticleProcessMaterialData *md = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(particles_shader.default_material, MaterialStorage::SHADER_TYPE_PARTICLES)); particles_shader.default_shader_rd = particles_shader.shader.version_get_shader(md->shader_data->version, 0); Vector<RD::Uniform> uniforms; @@ -1072,9 +1072,9 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta RD::get_singleton()->buffer_update(p_particles->frame_params_buffer, 0, sizeof(ParticlesFrameParams) * p_particles->trail_params.size(), p_particles->trail_params.ptr()); - ParticlesMaterialData *m = static_cast<ParticlesMaterialData *>(material_storage->material_get_data(p_particles->process_material, MaterialStorage::SHADER_TYPE_PARTICLES)); + ParticleProcessMaterialData *m = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(p_particles->process_material, MaterialStorage::SHADER_TYPE_PARTICLES)); if (!m) { - m = static_cast<ParticlesMaterialData *>(material_storage->material_get_data(particles_shader.default_material, MaterialStorage::SHADER_TYPE_PARTICLES)); + m = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(particles_shader.default_material, MaterialStorage::SHADER_TYPE_PARTICLES)); } ERR_FAIL_COND(!m); @@ -1696,16 +1696,16 @@ MaterialStorage::ShaderData *ParticlesStorage::_create_particles_shader_func() { return shader_data; } -bool ParticlesStorage::ParticlesMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { +bool ParticlesStorage::ParticleProcessMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, ParticlesStorage::get_singleton()->particles_shader.shader.version_get_shader(shader_data->version, 0), 3); } -ParticlesStorage::ParticlesMaterialData::~ParticlesMaterialData() { +ParticlesStorage::ParticleProcessMaterialData::~ParticleProcessMaterialData() { free_parameters_uniform_set(uniform_set); } MaterialStorage::MaterialData *ParticlesStorage::_create_particles_material_func(ParticlesShaderData *p_shader) { - ParticlesMaterialData *material_data = memnew(ParticlesMaterialData); + ParticleProcessMaterialData *material_data = memnew(ParticleProcessMaterialData); material_data->shader_data = p_shader; //update will happen later anyway so do nothing. return material_data; diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h index 97d100e2da..299fdc6ec8 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h @@ -354,14 +354,14 @@ private: return ParticlesStorage::get_singleton()->_create_particles_shader_func(); } - struct ParticlesMaterialData : public MaterialStorage::MaterialData { + struct ParticleProcessMaterialData : public MaterialStorage::MaterialData { ParticlesShaderData *shader_data = nullptr; RID uniform_set; virtual void set_render_priority(int p_priority) {} virtual void set_next_pass(RID p_pass) {} virtual bool update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); - virtual ~ParticlesMaterialData(); + virtual ~ParticleProcessMaterialData(); }; MaterialStorage::MaterialData *_create_particles_material_func(ParticlesShaderData *p_shader); diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 0b20bb372a..9f5eb85c2f 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -506,7 +506,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { } if (instance->mesh_instance.is_valid()) { - RSG::mesh_storage->mesh_free(instance->mesh_instance); + RSG::mesh_storage->mesh_instance_free(instance->mesh_instance); instance->mesh_instance = RID(); // no need to set instance data flag here, as it was freed above } diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 73b03966c5..bfb81925bc 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -72,6 +72,41 @@ static Transform2D _canvas_get_transform(RendererViewport::Viewport *p_viewport, return xf; } +Vector<RendererViewport::Viewport *> RendererViewport::_sort_active_viewports() { + // We need to sort the viewports in a "topological order", + // children first and parents last, we use the Kahn's algorithm to achieve that. + + Vector<Viewport *> result; + List<Viewport *> nodes; + + for (Viewport *viewport : active_viewports) { + if (viewport->parent.is_valid()) { + continue; + } + + nodes.push_back(viewport); + } + + while (!nodes.is_empty()) { + Viewport *node = nodes[0]; + nodes.pop_front(); + + result.insert(0, node); + + for (Viewport *child : active_viewports) { + if (child->parent != node->self) { + continue; + } + + if (!nodes.find(child)) { + nodes.push_back(child); + } + } + } + + return result; +} + void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { if (p_viewport->render_buffers.is_valid()) { if (p_viewport->size.width == 0 || p_viewport->size.height == 0) { @@ -548,8 +583,10 @@ void RendererViewport::draw_viewports() { set_default_clear_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color")); } - //sort viewports - active_viewports.sort_custom<ViewportSort>(); + if (sorted_active_viewports_dirty) { + sorted_active_viewports = _sort_active_viewports(); + sorted_active_viewports_dirty = false; + } HashMap<DisplayServer::WindowID, Vector<BlitToScreen>> blit_to_screen_list; //draw viewports @@ -558,9 +595,9 @@ void RendererViewport::draw_viewports() { //determine what is visible draw_viewports_pass++; - for (int i = active_viewports.size() - 1; i >= 0; i--) { //to compute parent dependency, must go in reverse draw order + for (int i = sorted_active_viewports.size() - 1; i >= 0; i--) { //to compute parent dependency, must go in reverse draw order - Viewport *vp = active_viewports[i]; + Viewport *vp = sorted_active_viewports[i]; if (vp->update_mode == RS::VIEWPORT_UPDATE_DISABLED) { continue; @@ -621,8 +658,8 @@ void RendererViewport::draw_viewports() { int objects_drawn = 0; int draw_calls_used = 0; - for (int i = 0; i < active_viewports.size(); i++) { - Viewport *vp = active_viewports[i]; + for (int i = 0; i < sorted_active_viewports.size(); i++) { + Viewport *vp = sorted_active_viewports[i]; if (vp->last_pass != draw_viewports_pass) { continue; //should not draw @@ -814,6 +851,8 @@ void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) { } else { active_viewports.erase(viewport); } + + sorted_active_viewports_dirty = true; } void RendererViewport::viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) { @@ -1243,6 +1282,7 @@ bool RendererViewport::free(RID p_rid) { viewport_set_scenario(p_rid, RID()); active_viewports.erase(viewport); + sorted_active_viewports_dirty = true; if (viewport->use_occlusion_culling) { RendererSceneOcclusionCull::get_singleton()->remove_buffer(p_rid); diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index 5e37c96336..ab4893a908 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -185,25 +185,16 @@ public: mutable RID_Owner<Viewport, true> viewport_owner; - struct ViewportSort { - _FORCE_INLINE_ bool operator()(const Viewport *p_left, const Viewport *p_right) const { - bool left_to_screen = p_left->viewport_to_screen_rect.size != Size2(); - bool right_to_screen = p_right->viewport_to_screen_rect.size != Size2(); - - if (left_to_screen == right_to_screen) { - return p_right->parent == p_left->self; - } - return (right_to_screen ? 0 : 1) < (left_to_screen ? 0 : 1); - } - }; - Vector<Viewport *> active_viewports; + Vector<Viewport *> sorted_active_viewports; + bool sorted_active_viewports_dirty = false; int total_objects_drawn = 0; int total_vertices_drawn = 0; int total_draw_calls_used = 0; private: + Vector<Viewport *> _sort_active_viewports(); void _configure_3d_render_buffers(Viewport *p_viewport); void _draw_3d(Viewport *p_viewport); void _draw_viewport(Viewport *p_viewport); diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h index 8bdd3deea1..a56b7eb241 100644 --- a/servers/rendering/rendering_device_binds.h +++ b/servers/rendering/rendering_device_binds.h @@ -443,8 +443,8 @@ public: void add_id(const RID &p_id) { base.append_id(p_id); } void clear_ids() { base.clear_ids(); } - Array get_ids() const { - Array ids; + TypedArray<RID> get_ids() const { + TypedArray<RID> ids; for (uint32_t i = 0; i < base.get_id_count(); i++) { ids.push_back(base.get_id(i)); } @@ -452,7 +452,7 @@ public: } protected: - void _set_ids(const Array &p_ids) { + void _set_ids(const TypedArray<RID> &p_ids) { base.clear_ids(); for (int i = 0; i < p_ids.size(); i++) { RID id = p_ids[i]; diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index cab92e6e20..2bbc5e4dfb 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -5377,6 +5377,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } _set_tkpos(prev_pos); + ShaderNode::Varying &var = shader->varyings[identifier]; String error; if (is_token_operator_assign(next_token.type)) { if (!_validate_varying_assign(shader->varyings[identifier], &error)) { @@ -5384,8 +5385,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons return nullptr; } } else { - ShaderNode::Varying &var = shader->varyings[identifier]; - switch (var.stage) { case ShaderNode::Varying::STAGE_VERTEX: if (current_function == varying_function_names.fragment || current_function == varying_function_names.light) { @@ -5401,6 +5400,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons break; } } + + if ((var.stage != ShaderNode::Varying::STAGE_FRAGMENT && var.stage != ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT) && var.type < TYPE_FLOAT && var.interpolation != INTERPOLATION_FLAT) { + _set_tkpos(var.tkpos); + _set_error(RTR("Varying with integer data type must be declared with `flat` interpolation qualifier.")); + return nullptr; + } } if (ident_type == IDENTIFIER_FUNCTION) { @@ -8299,8 +8304,8 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f return ERR_PARSE_ERROR; } - if (!is_uniform && (type < TYPE_FLOAT || type > TYPE_MAT4)) { - _set_error(RTR("Invalid type for varying, only 'float', 'vec2', 'vec3', 'vec4', 'mat2', 'mat3', 'mat4', or arrays of these types are allowed.")); + if (!is_uniform && type > TYPE_MAT4) { + _set_error(RTR("Invalid data type for varying.")); return ERR_PARSE_ERROR; } diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index cba75effc9..30b6faa360 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -31,6 +31,7 @@ #include "rendering_server.h" #include "core/config/project_settings.h" +#include "core/variant/typed_array.h" #include "servers/rendering/rendering_server_globals.h" #include "servers/rendering/shader_language.h" @@ -69,44 +70,44 @@ Array RenderingServer::_texture_debug_usage_bind() { return arr; } -static Array to_array(const Vector<ObjectID> &ids) { - Array a; +static PackedInt64Array to_int_array(const Vector<ObjectID> &ids) { + PackedInt64Array a; a.resize(ids.size()); for (int i = 0; i < ids.size(); ++i) { - a[i] = ids[i]; + a.write[i] = ids[i]; } return a; } -Array RenderingServer::_instances_cull_aabb_bind(const AABB &p_aabb, RID p_scenario) const { +PackedInt64Array RenderingServer::_instances_cull_aabb_bind(const AABB &p_aabb, RID p_scenario) const { if (RSG::threaded) { WARN_PRINT_ONCE("Using this function with a threaded renderer hurts performance, as it causes a server stall."); } Vector<ObjectID> ids = instances_cull_aabb(p_aabb, p_scenario); - return to_array(ids); + return to_int_array(ids); } -Array RenderingServer::_instances_cull_ray_bind(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const { +PackedInt64Array RenderingServer::_instances_cull_ray_bind(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const { if (RSG::threaded) { WARN_PRINT_ONCE("Using this function with a threaded renderer hurts performance, as it causes a server stall."); } Vector<ObjectID> ids = instances_cull_ray(p_from, p_to, p_scenario); - return to_array(ids); + return to_int_array(ids); } -Array RenderingServer::_instances_cull_convex_bind(const Array &p_convex, RID p_scenario) const { +PackedInt64Array RenderingServer::_instances_cull_convex_bind(const Array &p_convex, RID p_scenario) const { if (RSG::threaded) { WARN_PRINT_ONCE("Using this function with a threaded renderer hurts performance, as it causes a server stall."); } Vector<Plane> planes; for (int i = 0; i < p_convex.size(); ++i) { Variant v = p_convex[i]; - ERR_FAIL_COND_V(v.get_type() != Variant::PLANE, Array()); + ERR_FAIL_COND_V(v.get_type() != Variant::PLANE, PackedInt64Array()); planes.push_back(v); } Vector<ObjectID> ids = instances_cull_convex(planes, p_scenario); - return to_array(ids); + return to_int_array(ids); } RID RenderingServer::get_test_texture() { @@ -1337,7 +1338,7 @@ Dictionary RenderingServer::mesh_surface_get_lods(RID p_mesh, int p_surface) con return ret; } -Array RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const { +TypedArray<Array> RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const { SurfaceData sd = mesh_get_surface(p_mesh, p_surface); ERR_FAIL_COND_V(sd.vertex_count == 0, Array()); @@ -1359,7 +1360,7 @@ Array RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_sur ERR_FAIL_COND_V(blend_shape_count != (uint32_t)mesh_get_blend_shape_count(p_mesh), Array()); - Array blend_shape_array; + TypedArray<Array> blend_shape_array; blend_shape_array.resize(mesh_get_blend_shape_count(p_mesh)); for (uint32_t i = 0; i < blend_shape_count; i++) { Vector<uint8_t> bs_data = blend_shape_data.slice(i * divisor, (i + 1) * divisor); @@ -1369,7 +1370,7 @@ Array RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_sur return blend_shape_array; } else { - return Array(); + return TypedArray<Array>(); } } @@ -1625,7 +1626,7 @@ Dictionary RenderingServer::_mesh_get_surface(RID p_mesh, int p_idx) { return d; } -Array RenderingServer::_instance_geometry_get_shader_uniform_list(RID p_instance) const { +TypedArray<Dictionary> RenderingServer::_instance_geometry_get_shader_uniform_list(RID p_instance) const { List<PropertyInfo> params; instance_geometry_get_shader_uniform_list(p_instance, ¶ms); return convert_property_list(¶ms); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 572b08092e..56295a2c5f 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -42,6 +42,9 @@ #include "servers/display_server.h" #include "servers/rendering/rendering_device.h" +template <typename T> +class TypedArray; + class RenderingServer : public Object { GDCLASS(RenderingServer, Object); @@ -325,7 +328,7 @@ public: virtual Error mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = 0); Array mesh_create_arrays_from_surface_data(const SurfaceData &p_data) const; Array mesh_surface_get_arrays(RID p_mesh, int p_surface) const; - Array mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const; + TypedArray<Array> mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const; Dictionary mesh_surface_get_lods(RID p_mesh, int p_surface) const; virtual void mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = 0); @@ -1213,9 +1216,9 @@ public: virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const = 0; virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario = RID()) const = 0; - Array _instances_cull_aabb_bind(const AABB &p_aabb, RID p_scenario = RID()) const; - Array _instances_cull_ray_bind(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const; - Array _instances_cull_convex_bind(const Array &p_convex, RID p_scenario = RID()) const; + PackedInt64Array _instances_cull_aabb_bind(const AABB &p_aabb, RID p_scenario = RID()) const; + PackedInt64Array _instances_cull_ray_bind(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const; + PackedInt64Array _instances_cull_convex_bind(const Array &p_convex, RID p_scenario = RID()) const; enum InstanceFlags { INSTANCE_FLAG_USE_BAKED_LIGHT, @@ -1579,7 +1582,7 @@ private: RID _mesh_create_from_surfaces(const TypedArray<Dictionary> &p_surfaces, int p_blend_shape_count); void _mesh_add_surface(RID p_mesh, const Dictionary &p_surface); Dictionary _mesh_get_surface(RID p_mesh, int p_idx); - Array _instance_geometry_get_shader_uniform_list(RID p_instance) const; + TypedArray<Dictionary> _instance_geometry_get_shader_uniform_list(RID p_instance) const; TypedArray<Image> _bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size); void _particles_set_trail_bind_poses(RID p_particles, const TypedArray<Transform3D> &p_bind_poses); }; diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index 23bd0e8936..74ae2bfff0 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -634,12 +634,12 @@ double TextServerExtension::font_get_oversampling(const RID &p_font_rid) const { return 0.0; } -Array TextServerExtension::font_get_size_cache_list(const RID &p_font_rid) const { - Array ret; +TypedArray<Vector2i> TextServerExtension::font_get_size_cache_list(const RID &p_font_rid) const { + TypedArray<Vector2i> ret; if (GDVIRTUAL_CALL(font_get_size_cache_list, p_font_rid, ret)) { return ret; } - return Array(); + return TypedArray<Vector2i>(); } void TextServerExtension::font_clear_size_cache(const RID &p_font_rid) { @@ -750,12 +750,12 @@ PackedInt32Array TextServerExtension::font_get_texture_offsets(const RID &p_font return PackedInt32Array(); } -Array TextServerExtension::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const { - Array ret; +PackedInt32Array TextServerExtension::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const { + PackedInt32Array ret; if (GDVIRTUAL_CALL(font_get_glyph_list, p_font_rid, p_size, ret)) { return ret; } - return Array(); + return PackedInt32Array(); } void TextServerExtension::font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) { @@ -850,12 +850,12 @@ Dictionary TextServerExtension::font_get_glyph_contours(const RID &p_font_rid, i return Dictionary(); } -Array TextServerExtension::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const { - Array ret; +TypedArray<Vector2i> TextServerExtension::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const { + TypedArray<Vector2i> ret; if (GDVIRTUAL_CALL(font_get_kerning_list, p_font_rid, p_size, ret)) { return ret; } - return Array(); + return TypedArray<Vector2i>(); } void TextServerExtension::font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) { @@ -1534,12 +1534,12 @@ String TextServerExtension::string_to_lower(const String &p_string, const String return p_string; } -Array TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { - Array ret; +TypedArray<Vector2i> TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { + TypedArray<Vector2i> ret; if (GDVIRTUAL_CALL(parse_structured_text, p_parser_type, p_args, p_text, ret)) { return ret; } - return Array(); + return TypedArray<Vector2i>(); } PackedInt32Array TextServerExtension::string_get_word_breaks(const String &p_string, const String &p_language) const { diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index d6b1c8ac0a..6a2c199898 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -35,6 +35,7 @@ #include "core/object/script_language.h" #include "core/os/thread_safe.h" #include "core/variant/native_ptr.h" +#include "core/variant/typed_array.h" #include "servers/text_server.h" class TextServerExtension : public TextServer { @@ -172,10 +173,10 @@ public: GDVIRTUAL2(font_set_oversampling, RID, double); GDVIRTUAL1RC(double, font_get_oversampling, RID); - virtual Array font_get_size_cache_list(const RID &p_font_rid) const override; + virtual TypedArray<Vector2i> font_get_size_cache_list(const RID &p_font_rid) const override; virtual void font_clear_size_cache(const RID &p_font_rid) override; virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) override; - GDVIRTUAL1RC(Array, font_get_size_cache_list, RID); + GDVIRTUAL1RC(TypedArray<Vector2i>, font_get_size_cache_list, RID); GDVIRTUAL1(font_clear_size_cache, RID); GDVIRTUAL2(font_remove_size_cache, RID, const Vector2i &); @@ -221,10 +222,10 @@ public: GDVIRTUAL4(font_set_texture_offsets, RID, const Vector2i &, int64_t, const PackedInt32Array &); GDVIRTUAL3RC(PackedInt32Array, font_get_texture_offsets, RID, const Vector2i &, int64_t); - virtual Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override; + virtual PackedInt32Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override; virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) override; virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) override; - GDVIRTUAL2RC(Array, font_get_glyph_list, RID, const Vector2i &); + GDVIRTUAL2RC(PackedInt32Array, font_get_glyph_list, RID, const Vector2i &); GDVIRTUAL2(font_clear_glyphs, RID, const Vector2i &); GDVIRTUAL3(font_remove_glyph, RID, const Vector2i &, int64_t); @@ -262,10 +263,10 @@ public: virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const override; GDVIRTUAL3RC(Dictionary, font_get_glyph_contours, RID, int64_t, int64_t); - virtual Array font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override; + virtual TypedArray<Vector2i> font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override; virtual void font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) override; virtual void font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) override; - GDVIRTUAL2RC(Array, font_get_kerning_list, RID, int64_t); + GDVIRTUAL2RC(TypedArray<Vector2i>, font_get_kerning_list, RID, int64_t); GDVIRTUAL2(font_clear_kerning_map, RID, int64_t); GDVIRTUAL3(font_remove_kerning, RID, int64_t, const Vector2i &); @@ -504,8 +505,8 @@ public: GDVIRTUAL2RC(String, string_to_upper, const String &, const String &); GDVIRTUAL2RC(String, string_to_lower, const String &, const String &); - Array parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; - GDVIRTUAL3RC(Array, parse_structured_text, StructuredTextParser, const Array &, const String &); + TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; + GDVIRTUAL3RC(TypedArray<Vector2i>, parse_structured_text, StructuredTextParser, const Array &, const String &); virtual int is_confusable(const String &p_string, const PackedStringArray &p_dict) const override; virtual bool spoof_check(const String &p_string) const override; diff --git a/servers/text_server.cpp b/servers/text_server.cpp index ab5221582d..393160fe9e 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "servers/text_server.h" +#include "core/variant/typed_array.h" #include "servers/rendering_server.h" TextServerManager *TextServerManager::singleton = nullptr; @@ -103,8 +104,8 @@ Ref<TextServer> TextServerManager::find_interface(const String &p_name) const { return interfaces[idx]; } -Array TextServerManager::get_interfaces() const { - Array ret; +TypedArray<Dictionary> TextServerManager::get_interfaces() const { + TypedArray<Dictionary> ret; for (int i = 0; i < interfaces.size(); i++) { Dictionary iface_info; @@ -1596,8 +1597,8 @@ String TextServer::strip_diacritics(const String &p_string) const { return result; } -Array TextServer::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { - Array ret; +TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { + TypedArray<Vector2i> ret; switch (p_parser_type) { case STRUCTURED_TEXT_URI: { int prev = 0; @@ -1638,7 +1639,7 @@ Array TextServer::parse_structured_text(StructuredTextParser p_parser_type, cons ret.push_back(Vector2i(prev, i)); ret.push_back(Vector2i(i, i + 1)); prev = i + 1; - } else if (!local & (p_text[i] == '.')) { // Add each dot separated "domain" part as context. + } else if (!local && (p_text[i] == '.')) { // Add each dot separated "domain" part as context. if (prev != i) { ret.push_back(Vector2i(prev, i)); } @@ -1673,8 +1674,8 @@ Array TextServer::parse_structured_text(StructuredTextParser p_parser_type, cons return ret; } -Array TextServer::_shaped_text_get_glyphs_wrapper(const RID &p_shaped) const { - Array ret; +TypedArray<Dictionary> TextServer::_shaped_text_get_glyphs_wrapper(const RID &p_shaped) const { + TypedArray<Dictionary> ret; const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); int gl_size = shaped_text_get_glyph_count(p_shaped); @@ -1698,7 +1699,7 @@ Array TextServer::_shaped_text_get_glyphs_wrapper(const RID &p_shaped) const { return ret; } -Array TextServer::_shaped_text_sort_logical_wrapper(const RID &p_shaped) { +TypedArray<Dictionary> TextServer::_shaped_text_sort_logical_wrapper(const RID &p_shaped) { Array ret; const Glyph *glyphs = shaped_text_sort_logical(p_shaped); @@ -1723,8 +1724,8 @@ Array TextServer::_shaped_text_sort_logical_wrapper(const RID &p_shaped) { return ret; } -Array TextServer::_shaped_text_get_ellipsis_glyphs_wrapper(const RID &p_shaped) const { - Array ret; +TypedArray<Dictionary> TextServer::_shaped_text_get_ellipsis_glyphs_wrapper(const RID &p_shaped) const { + TypedArray<Dictionary> ret; const Glyph *glyphs = shaped_text_get_ellipsis_glyphs(p_shaped); int gl_size = shaped_text_get_ellipsis_glyph_count(p_shaped); diff --git a/servers/text_server.h b/servers/text_server.h index 22d48335d3..9304771d1b 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -37,6 +37,9 @@ #include "core/variant/native_ptr.h" #include "core/variant/variant.h" +template <typename T> +class TypedArray; + struct Glyph; struct CaretInfo; @@ -284,7 +287,7 @@ public: virtual void font_set_oversampling(const RID &p_font_rid, double p_oversampling) = 0; virtual double font_get_oversampling(const RID &p_font_rid) const = 0; - virtual Array font_get_size_cache_list(const RID &p_font_rid) const = 0; + virtual TypedArray<Vector2i> font_get_size_cache_list(const RID &p_font_rid) const = 0; virtual void font_clear_size_cache(const RID &p_font_rid) = 0; virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) = 0; @@ -313,7 +316,7 @@ public: virtual void font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) = 0; virtual PackedInt32Array font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const = 0; - virtual Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const = 0; + virtual PackedInt32Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const = 0; virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) = 0; virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) = 0; @@ -336,7 +339,7 @@ public: virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const = 0; - virtual Array font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const = 0; + virtual TypedArray<Vector2i> font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const = 0; virtual void font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) = 0; virtual void font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) = 0; @@ -426,9 +429,9 @@ public: virtual bool shaped_text_is_ready(const RID &p_shaped) const = 0; virtual const Glyph *shaped_text_get_glyphs(const RID &p_shaped) const = 0; - Array _shaped_text_get_glyphs_wrapper(const RID &p_shaped) const; + TypedArray<Dictionary> _shaped_text_get_glyphs_wrapper(const RID &p_shaped) const; virtual const Glyph *shaped_text_sort_logical(const RID &p_shaped) = 0; - Array _shaped_text_sort_logical_wrapper(const RID &p_shaped); + TypedArray<Dictionary> _shaped_text_sort_logical_wrapper(const RID &p_shaped); virtual int64_t shaped_text_get_glyph_count(const RID &p_shaped) const = 0; virtual Vector2i shaped_text_get_range(const RID &p_shaped) const = 0; @@ -440,7 +443,7 @@ public: virtual int64_t shaped_text_get_trim_pos(const RID &p_shaped) const = 0; virtual int64_t shaped_text_get_ellipsis_pos(const RID &p_shaped) const = 0; virtual const Glyph *shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const = 0; - Array _shaped_text_get_ellipsis_glyphs_wrapper(const RID &p_shaped) const; + TypedArray<Dictionary> _shaped_text_get_ellipsis_glyphs_wrapper(const RID &p_shaped) const; virtual int64_t shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const = 0; virtual void shaped_text_overrun_trim_to_width(const RID &p_shaped, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) = 0; @@ -491,7 +494,7 @@ public: virtual String string_to_upper(const String &p_string, const String &p_language = "") const = 0; virtual String string_to_lower(const String &p_string, const String &p_language = "") const = 0; - Array parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; + TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; TextServer(); ~TextServer(); @@ -553,7 +556,7 @@ public: int get_interface_count() const; Ref<TextServer> get_interface(int p_index) const; Ref<TextServer> find_interface(const String &p_name) const; - Array get_interfaces() const; + TypedArray<Dictionary> get_interfaces() const; _FORCE_INLINE_ Ref<TextServer> get_primary_interface() const { return primary_interface; diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index 990281d96d..e26212ada1 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -226,7 +226,7 @@ Ref<XRInterface> XRServer::find_interface(const String &p_name) const { return interfaces[idx]; }; -Array XRServer::get_interfaces() const { +TypedArray<Dictionary> XRServer::get_interfaces() const { Array ret; for (int i = 0; i < interfaces.size(); i++) { diff --git a/servers/xr_server.h b/servers/xr_server.h index 74128bfb54..57e42deccb 100644 --- a/servers/xr_server.h +++ b/servers/xr_server.h @@ -157,7 +157,7 @@ public: int get_interface_count() const; Ref<XRInterface> get_interface(int p_index) const; Ref<XRInterface> find_interface(const String &p_name) const; - Array get_interfaces() const; + TypedArray<Dictionary> get_interfaces() const; /* note, more then one interface can technically be active, especially on mobile, but only one interface is used for diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h index 8914dbfd9a..62d2051eee 100644 --- a/tests/core/string/test_string.h +++ b/tests/core/string/test_string.h @@ -619,7 +619,7 @@ TEST_CASE("[String] sprintf") { output = format.sprintf(args, &error); REQUIRE(error == false); CHECK(output == String("fish % frog")); - //////// INTS + ///// Ints // Int format = "fish %d frog"; @@ -727,7 +727,7 @@ TEST_CASE("[String] sprintf") { REQUIRE(error == false); CHECK(output == String("fish 143 frog")); - ////// REALS + ///// Reals // Real format = "fish %f frog"; @@ -737,7 +737,7 @@ TEST_CASE("[String] sprintf") { REQUIRE(error == false); CHECK(output == String("fish 99.990000 frog")); - // Real left-padded + // Real left-padded. format = "fish %11f frog"; args.clear(); args.push_back(99.99); @@ -745,7 +745,7 @@ TEST_CASE("[String] sprintf") { REQUIRE(error == false); CHECK(output == String("fish 99.990000 frog")); - // Real right-padded + // Real right-padded. format = "fish %-11f frog"; args.clear(); args.push_back(99.99); @@ -769,7 +769,7 @@ TEST_CASE("[String] sprintf") { REQUIRE(error == false); CHECK(output == String("fish +99.990000 frog")); - // Real with 1 decimals. + // Real with 1 decimal. format = "fish %.1f frog"; args.clear(); args.push_back(99.99); @@ -803,7 +803,97 @@ TEST_CASE("[String] sprintf") { REQUIRE(error == false); CHECK(output == String("fish -99.990000 frog")); - /////// Strings. + ///// Vectors + + // Vector2 + format = "fish %v frog"; + args.clear(); + args.push_back(Variant(Vector2(19.99, 1.00))); + output = format.sprintf(args, &error); + REQUIRE(error == false); + CHECK(output == String("fish (19.990000, 1.000000) frog")); + + // Vector3 + format = "fish %v frog"; + args.clear(); + args.push_back(Variant(Vector3(19.99, 1.00, -2.05))); + output = format.sprintf(args, &error); + REQUIRE(error == false); + CHECK(output == String("fish (19.990000, 1.000000, -2.050000) frog")); + + // Vector4 + format = "fish %v frog"; + args.clear(); + args.push_back(Variant(Vector4(19.99, 1.00, -2.05, 5.5))); + output = format.sprintf(args, &error); + REQUIRE(error == false); + CHECK(output == String("fish (19.990000, 1.000000, -2.050000, 5.500000) frog")); + + // Vector with negative values. + format = "fish %v frog"; + args.clear(); + args.push_back(Variant(Vector2(-19.99, -1.00))); + output = format.sprintf(args, &error); + REQUIRE(error == false); + CHECK(output == String("fish (-19.990000, -1.000000) frog")); + + // Vector left-padded. + format = "fish %11v frog"; + args.clear(); + args.push_back(Variant(Vector3(19.99, 1.00, -2.05))); + output = format.sprintf(args, &error); + REQUIRE(error == false); + CHECK(output == String("fish ( 19.990000, 1.000000, -2.050000) frog")); + + // Vector right-padded. + format = "fish %-11v frog"; + args.clear(); + args.push_back(Variant(Vector3(19.99, 1.00, -2.05))); + output = format.sprintf(args, &error); + REQUIRE(error == false); + CHECK(output == String("fish (19.990000 , 1.000000 , -2.050000 ) frog")); + + // Vector left-padded with zeros. + format = "fish %011v frog"; + args.clear(); + args.push_back(Variant(Vector3(19.99, 1.00, -2.05))); + output = format.sprintf(args, &error); + REQUIRE(error == false); + CHECK(output == String("fish (0019.990000, 0001.000000, -002.050000) frog")); + + // Vector given Vector3i. + format = "fish %v frog"; + args.clear(); + args.push_back(Variant(Vector3i(19, 1, -2))); + output = format.sprintf(args, &error); + REQUIRE(error == false); + CHECK(output == String("fish (19.000000, 1.000000, -2.000000) frog")); + + // Vector with 1 decimal. + format = "fish %.1v frog"; + args.clear(); + args.push_back(Variant(Vector3(19.99, 1.00, -2.05))); + output = format.sprintf(args, &error); + REQUIRE(error == false); + CHECK(output == String("fish (20.0, 1.0, -2.0) frog")); + + // Vector with 12 decimals. + format = "fish %.12v frog"; + args.clear(); + args.push_back(Variant(Vector3(19.00, 1.00, -2.00))); + output = format.sprintf(args, &error); + REQUIRE(error == false); + CHECK(output == String("fish (19.000000000000, 1.000000000000, -2.000000000000) frog")); + + // Vector with no decimals. + format = "fish %.v frog"; + args.clear(); + args.push_back(Variant(Vector3(19.99, 1.00, -2.05))); + output = format.sprintf(args, &error); + REQUIRE(error == false); + CHECK(output == String("fish (20, 1, -2) frog")); + + ///// Strings // String format = "fish %s frog"; @@ -813,7 +903,7 @@ TEST_CASE("[String] sprintf") { REQUIRE(error == false); CHECK(output == String("fish cheese frog")); - // String left-padded + // String left-padded. format = "fish %10s frog"; args.clear(); args.push_back("cheese"); @@ -821,7 +911,7 @@ TEST_CASE("[String] sprintf") { REQUIRE(error == false); CHECK(output == String("fish cheese frog")); - // String right-padded + // String right-padded. format = "fish %-10s frog"; args.clear(); args.push_back("cheese"); @@ -849,7 +939,7 @@ TEST_CASE("[String] sprintf") { ///// Dynamic width - // String dynamic width + // String dynamic width. format = "fish %*s frog"; args.clear(); args.push_back(10); @@ -858,7 +948,7 @@ TEST_CASE("[String] sprintf") { REQUIRE(error == false); REQUIRE(output == String("fish cheese frog")); - // Int dynamic width + // Int dynamic width. format = "fish %*d frog"; args.clear(); args.push_back(10); @@ -867,7 +957,7 @@ TEST_CASE("[String] sprintf") { REQUIRE(error == false); REQUIRE(output == String("fish 99 frog")); - // Float dynamic width + // Float dynamic width. format = "fish %*.*f frog"; args.clear(); args.push_back(10); @@ -904,7 +994,7 @@ TEST_CASE("[String] sprintf") { REQUIRE(error); CHECK(output == "incomplete format"); - // Bad character in format string + // Bad character in format string. format = "fish %&f frog"; args.clear(); args.push_back("cheese"); @@ -920,14 +1010,14 @@ TEST_CASE("[String] sprintf") { REQUIRE(error); CHECK(output == "too many decimal points in format"); - // * not a number + // * not a number or vector. format = "fish %*f frog"; args.clear(); args.push_back("cheese"); args.push_back(99.99); output = format.sprintf(args, &error); REQUIRE(error); - CHECK(output == "* wants number"); + CHECK(output == "* wants number or vector"); // Character too long. format = "fish %c frog"; diff --git a/tests/create_test.py b/tests/create_test.py new file mode 100644 index 0000000000..5a0439084f --- /dev/null +++ b/tests/create_test.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 + +import argparse +import os +import re +import sys +from subprocess import call + + +def main(): + # Change to the directory where the script is located, + # so that the script can be run from any location. + os.chdir(os.path.dirname(os.path.realpath(__file__))) + + parser = argparse.ArgumentParser(description="Creates a new unit test file.") + parser.add_argument("name", type=str, help="The unit test name in PascalCase notation") + parser.add_argument( + "path", + type=str, + nargs="?", + help="The path to the unit test file relative to the tests folder (default: .)", + default=".", + ) + parser.add_argument( + "-i", + "--invasive", + action="store_true", + help="if set, the script will automatically insert the include directive in test_main.cpp. Use with caution!", + ) + args = parser.parse_args() + + snake_case_regex = re.compile(r"(?<!^)(?=[A-Z])") + name_snake_case = snake_case_regex.sub("_", args.name).lower() + + file_path = os.path.normpath(os.path.join(args.path, f"test_{name_snake_case}.h")) + + print(file_path) + if os.path.isfile(file_path): + print(f'ERROR: The file "{file_path}" already exists.') + sys.exit(1) + with open(file_path, "w") as file: + file.write( + """/*************************************************************************/ +/* test_{name_snake_case}.h {padding} */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 TEST_{name_upper_snake_case}_H +#define TEST_{name_upper_snake_case}_H + +#include "tests/test_macros.h" + +namespace Test{name_pascal_case} {{ + +TEST_CASE("[{name_pascal_case}] Example test case") {{ + // TODO: Remove this comment and write your test code here. +}} + +}} // namespace Test{name_pascal_case} + +#endif // TEST_{name_upper_snake_case}_H +""".format( + name_snake_case=name_snake_case, + # Capitalize the first letter but keep capitalization for the rest of the string. + # This is done in case the user passes a camelCase string instead of PascalCase. + name_pascal_case=args.name[0].upper() + args.name[1:], + name_upper_snake_case=name_snake_case.upper(), + # The padding length depends on the test name length. + padding=" " * (60 - len(name_snake_case)), + ) + ) + + # Print an absolute path so it can be Ctrl + clicked in some IDEs and terminal emulators. + print("Test header file created:") + print(os.path.abspath(file_path)) + + if args.invasive: + print("Trying to insert include directive in test_main.cpp...") + with open("test_main.cpp", "r") as file: + contents = file.read() + match = re.search(r'#include "tests.*\n', contents) + + if match: + new_string = contents[: match.start()] + f'#include "tests/{file_path}"\n' + contents[match.start() :] + + with open("test_main.cpp", "w") as file: + file.write(new_string) + print("Done.") + # Use clang format to sort include directives afster insertion. + clang_format_args = ["clang-format", "test_main.cpp", "-i"] + retcode = call(clang_format_args) + if retcode != 0: + print( + "Include directives in test_main.cpp could not be sorted automatically using clang-format. Please sort them manually." + ) + else: + print("Could not find a valid position in test_main.cpp to insert the include directive.") + + else: + print("\nRemember to #include the new test header in this file (following alphabetical order):") + print(os.path.abspath("test_main.cpp")) + print("Insert the following line in the appropriate place:") + print(f'#include "tests/{file_path}"') + + +if __name__ == "__main__": + main() diff --git a/tests/scene/test_code_edit.h b/tests/scene/test_code_edit.h index 7605f24cf8..4fc88f398f 100644 --- a/tests/scene/test_code_edit.h +++ b/tests/scene/test_code_edit.h @@ -74,7 +74,7 @@ TEST_CASE("[SceneTree][CodeEdit] line gutters") { code_edit->set_line_as_breakpoint(0, true); CHECK(code_edit->is_line_breakpointed(0)); - CHECK(code_edit->get_breakpointed_lines()[0] == Variant(0)); + CHECK(code_edit->get_breakpointed_lines()[0] == 0); SIGNAL_CHECK("breakpoint_toggled", args); code_edit->set_line_as_breakpoint(0, false); @@ -451,7 +451,7 @@ TEST_CASE("[SceneTree][CodeEdit] line gutters") { ERR_PRINT_ON; code_edit->set_line_as_bookmarked(0, true); - CHECK(code_edit->get_bookmarked_lines()[0] == Variant(0)); + CHECK(code_edit->get_bookmarked_lines()[0] == 0); CHECK(code_edit->is_line_bookmarked(0)); code_edit->set_line_as_bookmarked(0, false); @@ -657,7 +657,7 @@ TEST_CASE("[SceneTree][CodeEdit] line gutters") { ERR_PRINT_ON; code_edit->set_line_as_executing(0, true); - CHECK(code_edit->get_executing_lines()[0] == Variant(0)); + CHECK(code_edit->get_executing_lines()[0] == 0); CHECK(code_edit->is_line_executing(0)); code_edit->set_line_as_executing(0, false); diff --git a/tests/scene/test_path_follow_2d.h b/tests/scene/test_path_follow_2d.h index abd12fe862..57261116a2 100644 --- a/tests/scene/test_path_follow_2d.h +++ b/tests/scene/test_path_follow_2d.h @@ -37,7 +37,7 @@ namespace TestPathFollow2D { -TEST_CASE("[PathFollow2D] Sampling with unit offset") { +TEST_CASE("[PathFollow2D] Sampling with progress ratio") { const Ref<Curve2D> &curve = memnew(Curve2D()); curve->add_point(Vector2(0, 0)); curve->add_point(Vector2(100, 0)); @@ -49,37 +49,37 @@ TEST_CASE("[PathFollow2D] Sampling with unit offset") { const PathFollow2D *path_follow_2d = memnew(PathFollow2D); path->add_child(path_follow_2d); - path_follow_2d->set_unit_offset(0); + path_follow_2d->set_progress_ratio(0); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 0))); - path_follow_2d->set_unit_offset(0.125); + path_follow_2d->set_progress_ratio(0.125); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 0))); - path_follow_2d->set_unit_offset(0.25); + path_follow_2d->set_progress_ratio(0.25); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 0))); - path_follow_2d->set_unit_offset(0.375); + path_follow_2d->set_progress_ratio(0.375); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 50))); - path_follow_2d->set_unit_offset(0.5); + path_follow_2d->set_progress_ratio(0.5); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 100))); - path_follow_2d->set_unit_offset(0.625); + path_follow_2d->set_progress_ratio(0.625); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 100))); - path_follow_2d->set_unit_offset(0.75); + path_follow_2d->set_progress_ratio(0.75); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 100))); - path_follow_2d->set_unit_offset(0.875); + path_follow_2d->set_progress_ratio(0.875); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 50))); - path_follow_2d->set_unit_offset(1); + path_follow_2d->set_progress_ratio(1); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 0))); memdelete(path); } -TEST_CASE("[PathFollow2D] Sampling with offset") { +TEST_CASE("[PathFollow2D] Sampling with progress") { const Ref<Curve2D> &curve = memnew(Curve2D()); curve->add_point(Vector2(0, 0)); curve->add_point(Vector2(100, 0)); @@ -91,31 +91,31 @@ TEST_CASE("[PathFollow2D] Sampling with offset") { const PathFollow2D *path_follow_2d = memnew(PathFollow2D); path->add_child(path_follow_2d); - path_follow_2d->set_offset(0); + path_follow_2d->set_progress(0); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 0))); - path_follow_2d->set_offset(50); + path_follow_2d->set_progress(50); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 0))); - path_follow_2d->set_offset(100); + path_follow_2d->set_progress(100); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 0))); - path_follow_2d->set_offset(150); + path_follow_2d->set_progress(150); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 50))); - path_follow_2d->set_offset(200); + path_follow_2d->set_progress(200); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 100))); - path_follow_2d->set_offset(250); + path_follow_2d->set_progress(250); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 100))); - path_follow_2d->set_offset(300); + path_follow_2d->set_progress(300); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 100))); - path_follow_2d->set_offset(350); + path_follow_2d->set_progress(350); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 50))); - path_follow_2d->set_offset(400); + path_follow_2d->set_progress(400); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 0))); memdelete(path); @@ -131,7 +131,7 @@ TEST_CASE("[PathFollow2D] Removal of a point in curve") { const PathFollow2D *path_follow_2d = memnew(PathFollow2D); path->add_child(path_follow_2d); - path_follow_2d->set_unit_offset(0.5); + path_follow_2d->set_progress_ratio(0.5); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 0))); curve->remove_point(1); @@ -152,7 +152,7 @@ TEST_CASE("[PathFollow2D] Setting h_offset and v_offset") { const PathFollow2D *path_follow_2d = memnew(PathFollow2D); path->add_child(path_follow_2d); - path_follow_2d->set_unit_offset(0.5); + path_follow_2d->set_progress_ratio(0.5); CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 0))); path_follow_2d->set_h_offset(25); @@ -175,32 +175,32 @@ TEST_CASE("[PathFollow2D] Unit offset out of range") { path_follow_2d->set_loop(true); - path_follow_2d->set_unit_offset(-0.3); + path_follow_2d->set_progress_ratio(-0.3); CHECK_MESSAGE( - path_follow_2d->get_unit_offset() == 0.7, - "Unit Offset should loop back from the end in the opposite direction"); + path_follow_2d->get_progress_ratio() == 0.7, + "Progress Ratio should loop back from the end in the opposite direction"); - path_follow_2d->set_unit_offset(1.3); + path_follow_2d->set_progress_ratio(1.3); CHECK_MESSAGE( - path_follow_2d->get_unit_offset() == 0.3, - "Unit Offset should loop back from the end in the opposite direction"); + path_follow_2d->get_progress_ratio() == 0.3, + "Progress Ratio should loop back from the end in the opposite direction"); path_follow_2d->set_loop(false); - path_follow_2d->set_unit_offset(-0.3); + path_follow_2d->set_progress_ratio(-0.3); CHECK_MESSAGE( - path_follow_2d->get_unit_offset() == 0, - "Unit Offset should be clamped at 0"); + path_follow_2d->get_progress_ratio() == 0, + "Progress Ratio should be clamped at 0"); - path_follow_2d->set_unit_offset(1.3); + path_follow_2d->set_progress_ratio(1.3); CHECK_MESSAGE( - path_follow_2d->get_unit_offset() == 1, - "Unit Offset should be clamped at 1"); + path_follow_2d->get_progress_ratio() == 1, + "Progress Ratio should be clamped at 1"); memdelete(path); } -TEST_CASE("[PathFollow2D] Offset out of range") { +TEST_CASE("[PathFollow2D] Progress out of range") { const Ref<Curve2D> &curve = memnew(Curve2D()); curve->add_point(Vector2(0, 0)); curve->add_point(Vector2(100, 0)); @@ -211,27 +211,27 @@ TEST_CASE("[PathFollow2D] Offset out of range") { path_follow_2d->set_loop(true); - path_follow_2d->set_offset(-50); + path_follow_2d->set_progress(-50); CHECK_MESSAGE( - path_follow_2d->get_offset() == 50, - "Offset should loop back from the end in the opposite direction"); + path_follow_2d->get_progress() == 50, + "Progress should loop back from the end in the opposite direction"); - path_follow_2d->set_offset(150); + path_follow_2d->set_progress(150); CHECK_MESSAGE( - path_follow_2d->get_offset() == 50, - "Offset should loop back from the end in the opposite direction"); + path_follow_2d->get_progress() == 50, + "Progress should loop back from the end in the opposite direction"); path_follow_2d->set_loop(false); - path_follow_2d->set_offset(-50); + path_follow_2d->set_progress(-50); CHECK_MESSAGE( - path_follow_2d->get_offset() == 0, - "Offset should be clamped at 0"); + path_follow_2d->get_progress() == 0, + "Progress should be clamped at 0"); - path_follow_2d->set_offset(150); + path_follow_2d->set_progress(150); CHECK_MESSAGE( - path_follow_2d->get_offset() == 100, - "Offset should be clamped at 1"); + path_follow_2d->get_progress() == 100, + "Progress should be clamped at 1"); memdelete(path); } diff --git a/tests/scene/test_path_follow_3d.h b/tests/scene/test_path_follow_3d.h index 9ffe49e3d6..6334fa56de 100644 --- a/tests/scene/test_path_follow_3d.h +++ b/tests/scene/test_path_follow_3d.h @@ -37,7 +37,7 @@ namespace TestPathFollow3D { -TEST_CASE("[PathFollow3D] Sampling with unit offset") { +TEST_CASE("[PathFollow3D] Sampling with progress ratio") { const Ref<Curve3D> &curve = memnew(Curve3D()); curve->add_point(Vector3(0, 0, 0)); curve->add_point(Vector3(100, 0, 0)); @@ -49,37 +49,37 @@ TEST_CASE("[PathFollow3D] Sampling with unit offset") { const PathFollow3D *path_follow_3d = memnew(PathFollow3D); path->add_child(path_follow_3d); - path_follow_3d->set_unit_offset(0); + path_follow_3d->set_progress_ratio(0); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(0, 0, 0)); - path_follow_3d->set_unit_offset(0.125); + path_follow_3d->set_progress_ratio(0.125); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(50, 0, 0)); - path_follow_3d->set_unit_offset(0.25); + path_follow_3d->set_progress_ratio(0.25); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 0, 0); - path_follow_3d->set_unit_offset(0.375); + path_follow_3d->set_progress_ratio(0.375); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 50, 0))); - path_follow_3d->set_unit_offset(0.5); + path_follow_3d->set_progress_ratio(0.5); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 0))); - path_follow_3d->set_unit_offset(0.625); + path_follow_3d->set_progress_ratio(0.625); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 50))); - path_follow_3d->set_unit_offset(0.75); + path_follow_3d->set_progress_ratio(0.75); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 100))); - path_follow_3d->set_unit_offset(0.875); + path_follow_3d->set_progress_ratio(0.875); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 50, 100))); - path_follow_3d->set_unit_offset(1); + path_follow_3d->set_progress_ratio(1); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 0, 100))); memdelete(path); } -TEST_CASE("[PathFollow3D] Sampling with offset") { +TEST_CASE("[PathFollow3D] Sampling with progress") { const Ref<Curve3D> &curve = memnew(Curve3D()); curve->add_point(Vector3(0, 0, 0)); curve->add_point(Vector3(100, 0, 0)); @@ -91,31 +91,31 @@ TEST_CASE("[PathFollow3D] Sampling with offset") { const PathFollow3D *path_follow_3d = memnew(PathFollow3D); path->add_child(path_follow_3d); - path_follow_3d->set_offset(0); + path_follow_3d->set_progress(0); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(0, 0, 0)); - path_follow_3d->set_offset(50); + path_follow_3d->set_progress(50); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(50, 0, 0)); - path_follow_3d->set_offset(100); + path_follow_3d->set_progress(100); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 0, 0); - path_follow_3d->set_offset(150); + path_follow_3d->set_progress(150); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 50, 0))); - path_follow_3d->set_offset(200); + path_follow_3d->set_progress(200); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 0))); - path_follow_3d->set_offset(250); + path_follow_3d->set_progress(250); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 50))); - path_follow_3d->set_offset(300); + path_follow_3d->set_progress(300); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 100))); - path_follow_3d->set_offset(350); + path_follow_3d->set_progress(350); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 50, 100))); - path_follow_3d->set_offset(400); + path_follow_3d->set_progress(400); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 0, 100))); memdelete(path); @@ -131,7 +131,7 @@ TEST_CASE("[PathFollow3D] Removal of a point in curve") { const PathFollow3D *path_follow_3d = memnew(PathFollow3D); path->add_child(path_follow_3d); - path_follow_3d->set_unit_offset(0.5); + path_follow_3d->set_progress_ratio(0.5); CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector2(100, 0, 0))); curve->remove_point(1); @@ -143,7 +143,7 @@ TEST_CASE("[PathFollow3D] Removal of a point in curve") { memdelete(path); } -TEST_CASE("[PathFollow3D] Unit offset out of range") { +TEST_CASE("[PathFollow3D] Progress ratio out of range") { const Ref<Curve3D> &curve = memnew(Curve3D()); curve->add_point(Vector3(0, 0, 0)); curve->add_point(Vector3(100, 0, 0)); @@ -154,32 +154,32 @@ TEST_CASE("[PathFollow3D] Unit offset out of range") { path_follow_3d->set_loop(true); - path_follow_3d->set_unit_offset(-0.3); + path_follow_3d->set_progress_ratio(-0.3); CHECK_MESSAGE( - path_follow_3d->get_unit_offset() == 0.7, - "Unit Offset should loop back from the end in the opposite direction"); + path_follow_3d->get_progress_ratio() == 0.7, + "Progress Ratio should loop back from the end in the opposite direction"); - path_follow_3d->set_unit_offset(1.3); + path_follow_3d->set_progress_ratio(1.3); CHECK_MESSAGE( - path_follow_3d->get_unit_offset() == 0.3, - "Unit Offset should loop back from the end in the opposite direction"); + path_follow_3d->get_progress_ratio() == 0.3, + "Progress Ratio should loop back from the end in the opposite direction"); path_follow_3d->set_loop(false); - path_follow_3d->set_unit_offset(-0.3); + path_follow_3d->set_progress_ratio(-0.3); CHECK_MESSAGE( - path_follow_3d->get_unit_offset() == 0, - "Unit Offset should be clamped at 0"); + path_follow_3d->get_progress_ratio() == 0, + "Progress Ratio should be clamped at 0"); - path_follow_3d->set_unit_offset(1.3); + path_follow_3d->set_progress_ratio(1.3); CHECK_MESSAGE( - path_follow_3d->get_unit_offset() == 1, - "Unit Offset should be clamped at 1"); + path_follow_3d->get_progress_ratio() == 1, + "Progress Ratio should be clamped at 1"); memdelete(path); } -TEST_CASE("[PathFollow3D] Offset out of range") { +TEST_CASE("[PathFollow3D] Progress out of range") { const Ref<Curve3D> &curve = memnew(Curve3D()); curve->add_point(Vector3(0, 0, 0)); curve->add_point(Vector3(100, 0, 0)); @@ -190,27 +190,27 @@ TEST_CASE("[PathFollow3D] Offset out of range") { path_follow_3d->set_loop(true); - path_follow_3d->set_offset(-50); + path_follow_3d->set_progress(-50); CHECK_MESSAGE( - path_follow_3d->get_offset() == 50, - "Offset should loop back from the end in the opposite direction"); + path_follow_3d->get_progress() == 50, + "Progress should loop back from the end in the opposite direction"); - path_follow_3d->set_offset(150); + path_follow_3d->set_progress(150); CHECK_MESSAGE( - path_follow_3d->get_offset() == 50, - "Offset should loop back from the end in the opposite direction"); + path_follow_3d->get_progress() == 50, + "Progress should loop back from the end in the opposite direction"); path_follow_3d->set_loop(false); - path_follow_3d->set_offset(-50); + path_follow_3d->set_progress(-50); CHECK_MESSAGE( - path_follow_3d->get_offset() == 0, - "Offset should be clamped at 0"); + path_follow_3d->get_progress() == 0, + "Progress should be clamped at 0"); - path_follow_3d->set_offset(150); + path_follow_3d->set_progress(150); CHECK_MESSAGE( - path_follow_3d->get_offset() == 100, - "Offset should be clamped at max value of curve"); + path_follow_3d->get_progress() == 100, + "Progress should be clamped at max value of curve"); memdelete(path); } diff --git a/thirdparty/README.md b/thirdparty/README.md index 664401fca6..4514217dd8 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -195,6 +195,7 @@ Files extracted from upstream source: to `glslang/build_info.h` - `LICENSE.txt` - Unnecessary files like `CMakeLists.txt`, `*.m4` and `updateGrammar` removed. +- Patch in `patches/unused_cleanup.diff` must be applied. ## graphite @@ -319,12 +320,12 @@ Files extracted from upstream source: ## libwebp - Upstream: https://chromium.googlesource.com/webm/libwebp/ -- Version: 1.2.2 (b0a860891dcd4c0c2d7c6149e5cccb6eb881cc21, 2022) +- Version: 1.2.4 (0d1f12546bd803099a60c070517a552483f3790e, 2022) - License: BSD-3-Clause Files extracted from upstream source: -- `src/*` except from: `.am`, `.rc` and `.in` files +- `src/` and `sharpyuv/` except from: `.am`, `.rc` and `.in` files - `AUTHORS`, `COPYING`, `PATENTS` diff --git a/thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp b/thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp index 81da99c2c4..1cbd616e98 100644 --- a/thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp +++ b/thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp @@ -66,43 +66,6 @@ static void DetachThreadLinux(void *) } // -// Registers cleanup handler, sets cancel type and state, and executes the thread specific -// cleanup handler. This function will be called in the Standalone.cpp for regression -// testing. When OpenGL applications are run with the driver code, Linux OS does the -// thread cleanup. -// -void OS_CleanupThreadData(void) -{ -#if defined(__ANDROID__) || defined(__Fuchsia__) - DetachThreadLinux(NULL); -#else - int old_cancel_state, old_cancel_type; - void *cleanupArg = NULL; - - // - // Set thread cancel state and push cleanup handler. - // - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancel_state); - pthread_cleanup_push(DetachThreadLinux, (void *) cleanupArg); - - // - // Put the thread in deferred cancellation mode. - // - pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old_cancel_type); - - // - // Pop cleanup handler and execute it prior to unregistering the cleanup handler. - // - pthread_cleanup_pop(1); - - // - // Restore the thread's previous cancellation mode. - // - pthread_setcanceltype(old_cancel_state, NULL); -#endif -} - -// // Thread Local Storage Operations // inline OS_TLSIndex PthreadKeyToTLSIndex(pthread_key_t key) diff --git a/thirdparty/glslang/glslang/OSDependent/osinclude.h b/thirdparty/glslang/glslang/OSDependent/osinclude.h index 218abe4f23..fcfeff2cc4 100644 --- a/thirdparty/glslang/glslang/OSDependent/osinclude.h +++ b/thirdparty/glslang/glslang/OSDependent/osinclude.h @@ -54,8 +54,6 @@ void ReleaseGlobalLock(); typedef unsigned int (*TThreadEntrypoint)(void*); -void OS_CleanupThreadData(void); - void OS_DumpMemoryCounters(); } // end namespace glslang diff --git a/thirdparty/glslang/patches/unused_cleanup.diff b/thirdparty/glslang/patches/unused_cleanup.diff new file mode 100644 index 0000000000..3e9a9c23f9 --- /dev/null +++ b/thirdparty/glslang/patches/unused_cleanup.diff @@ -0,0 +1,61 @@ +diff --git a/thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp b/thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp +index 81da99c2c4..1cbd616e98 100644 +--- a/thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp ++++ b/thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp +@@ -65,43 +65,6 @@ static void DetachThreadLinux(void *) + DetachThread(); + } + +-// +-// Registers cleanup handler, sets cancel type and state, and executes the thread specific +-// cleanup handler. This function will be called in the Standalone.cpp for regression +-// testing. When OpenGL applications are run with the driver code, Linux OS does the +-// thread cleanup. +-// +-void OS_CleanupThreadData(void) +-{ +-#if defined(__ANDROID__) || defined(__Fuchsia__) +- DetachThreadLinux(NULL); +-#else +- int old_cancel_state, old_cancel_type; +- void *cleanupArg = NULL; +- +- // +- // Set thread cancel state and push cleanup handler. +- // +- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancel_state); +- pthread_cleanup_push(DetachThreadLinux, (void *) cleanupArg); +- +- // +- // Put the thread in deferred cancellation mode. +- // +- pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old_cancel_type); +- +- // +- // Pop cleanup handler and execute it prior to unregistering the cleanup handler. +- // +- pthread_cleanup_pop(1); +- +- // +- // Restore the thread's previous cancellation mode. +- // +- pthread_setcanceltype(old_cancel_state, NULL); +-#endif +-} +- + // + // Thread Local Storage Operations + // +diff --git a/thirdparty/glslang/glslang/OSDependent/osinclude.h b/thirdparty/glslang/glslang/OSDependent/osinclude.h +index 218abe4f23..fcfeff2cc4 100644 +--- a/thirdparty/glslang/glslang/OSDependent/osinclude.h ++++ b/thirdparty/glslang/glslang/OSDependent/osinclude.h +@@ -54,8 +54,6 @@ void ReleaseGlobalLock(); + + typedef unsigned int (*TThreadEntrypoint)(void*); + +-void OS_CleanupThreadData(void); +- + void OS_DumpMemoryCounters(); + + } // end namespace glslang diff --git a/thirdparty/libwebp/AUTHORS b/thirdparty/libwebp/AUTHORS index 8307c2099d..3efcbe25b6 100644 --- a/thirdparty/libwebp/AUTHORS +++ b/thirdparty/libwebp/AUTHORS @@ -1,12 +1,15 @@ Contributors: - Aidan O'Loan (aidanol at gmail dot com) - Alan Browning (browning at google dot com) +- Alexandru Ardelean (ardeleanalex at gmail dot com) +- Brian Ledger (brianpl at google dot com) - Charles Munger (clm at google dot com) - Cheng Yi (cyi at google dot com) - Christian Duvivier (cduvivier at google dot com) - Christopher Degawa (ccom at randomderp dot com) - Clement Courbet (courbet at google dot com) - Djordje Pesut (djordje dot pesut at imgtec dot com) +- Frank Barchard (fbarchard at google dot com) - Hui Su (huisu at google dot com) - Ilya Kurdyukov (jpegqs at gmail dot com) - Ingvar Stepanyan (rreverser at google dot com) @@ -22,6 +25,7 @@ Contributors: - Mans Rullgard (mans at mansr dot com) - Marcin Kowalczyk (qrczak at google dot com) - Martin Olsson (mnemo at minimum dot se) +- Maryla Ustarroz-Calonge (maryla at google dot com) - MikoÅ‚aj Zalewski (mikolajz at google dot com) - Mislav Bradac (mislavm at google dot com) - Nico Weber (thakis at chromium dot org) diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv.c b/thirdparty/libwebp/sharpyuv/sharpyuv.c new file mode 100644 index 0000000000..8b3ab7216b --- /dev/null +++ b/thirdparty/libwebp/sharpyuv/sharpyuv.c @@ -0,0 +1,498 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Sharp RGB to YUV conversion. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "sharpyuv/sharpyuv.h" + +#include <assert.h> +#include <limits.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> + +#include "src/webp/types.h" +#include "src/dsp/cpu.h" +#include "sharpyuv/sharpyuv_dsp.h" +#include "sharpyuv/sharpyuv_gamma.h" + +//------------------------------------------------------------------------------ +// Sharp RGB->YUV conversion + +static const int kNumIterations = 4; + +#define YUV_FIX 16 // fixed-point precision for RGB->YUV +static const int kYuvHalf = 1 << (YUV_FIX - 1); + +// Max bit depth so that intermediate calculations fit in 16 bits. +static const int kMaxBitDepth = 14; + +// Returns the precision shift to use based on the input rgb_bit_depth. +static int GetPrecisionShift(int rgb_bit_depth) { + // Try to add 2 bits of precision if it fits in kMaxBitDepth. Otherwise remove + // bits if needed. + return ((rgb_bit_depth + 2) <= kMaxBitDepth) ? 2 + : (kMaxBitDepth - rgb_bit_depth); +} + +typedef int16_t fixed_t; // signed type with extra precision for UV +typedef uint16_t fixed_y_t; // unsigned type with extra precision for W + +//------------------------------------------------------------------------------ + +static uint8_t clip_8b(fixed_t v) { + return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u; +} + +static uint16_t clip(fixed_t v, int max) { + return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v; +} + +static fixed_y_t clip_bit_depth(int y, int bit_depth) { + const int max = (1 << bit_depth) - 1; + return (!(y & ~max)) ? (fixed_y_t)y : (y < 0) ? 0 : max; +} + +//------------------------------------------------------------------------------ + +static int RGBToGray(int64_t r, int64_t g, int64_t b) { + const int64_t luma = 13933 * r + 46871 * g + 4732 * b + kYuvHalf; + return (int)(luma >> YUV_FIX); +} + +static uint32_t ScaleDown(uint16_t a, uint16_t b, uint16_t c, uint16_t d, + int rgb_bit_depth) { + const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth); + const uint32_t A = SharpYuvGammaToLinear(a, bit_depth); + const uint32_t B = SharpYuvGammaToLinear(b, bit_depth); + const uint32_t C = SharpYuvGammaToLinear(c, bit_depth); + const uint32_t D = SharpYuvGammaToLinear(d, bit_depth); + return SharpYuvLinearToGamma((A + B + C + D + 2) >> 2, bit_depth); +} + +static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w, + int rgb_bit_depth) { + const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth); + int i; + for (i = 0; i < w; ++i) { + const uint32_t R = SharpYuvGammaToLinear(src[0 * w + i], bit_depth); + const uint32_t G = SharpYuvGammaToLinear(src[1 * w + i], bit_depth); + const uint32_t B = SharpYuvGammaToLinear(src[2 * w + i], bit_depth); + const uint32_t Y = RGBToGray(R, G, B); + dst[i] = (fixed_y_t)SharpYuvLinearToGamma(Y, bit_depth); + } +} + +static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2, + fixed_t* dst, int uv_w, int rgb_bit_depth) { + int i; + for (i = 0; i < uv_w; ++i) { + const int r = + ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1], src2[0 * uv_w + 0], + src2[0 * uv_w + 1], rgb_bit_depth); + const int g = + ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1], src2[2 * uv_w + 0], + src2[2 * uv_w + 1], rgb_bit_depth); + const int b = + ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1], src2[4 * uv_w + 0], + src2[4 * uv_w + 1], rgb_bit_depth); + const int W = RGBToGray(r, g, b); + dst[0 * uv_w] = (fixed_t)(r - W); + dst[1 * uv_w] = (fixed_t)(g - W); + dst[2 * uv_w] = (fixed_t)(b - W); + dst += 1; + src1 += 2; + src2 += 2; + } +} + +static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) { + int i; + assert(w > 0); + for (i = 0; i < w; ++i) { + y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]); + } +} + +//------------------------------------------------------------------------------ + +static WEBP_INLINE fixed_y_t Filter2(int A, int B, int W0, int bit_depth) { + const int v0 = (A * 3 + B + 2) >> 2; + return clip_bit_depth(v0 + W0, bit_depth); +} + +//------------------------------------------------------------------------------ + +static WEBP_INLINE int Shift(int v, int shift) { + return (shift >= 0) ? (v << shift) : (v >> -shift); +} + +static void ImportOneRow(const uint8_t* const r_ptr, + const uint8_t* const g_ptr, + const uint8_t* const b_ptr, + int rgb_step, + int rgb_bit_depth, + int pic_width, + fixed_y_t* const dst) { + // Convert the rgb_step from a number of bytes to a number of uint8_t or + // uint16_t values depending the bit depth. + const int step = (rgb_bit_depth > 8) ? rgb_step / 2 : rgb_step; + int i; + const int w = (pic_width + 1) & ~1; + for (i = 0; i < pic_width; ++i) { + const int off = i * step; + const int shift = GetPrecisionShift(rgb_bit_depth); + if (rgb_bit_depth == 8) { + dst[i + 0 * w] = Shift(r_ptr[off], shift); + dst[i + 1 * w] = Shift(g_ptr[off], shift); + dst[i + 2 * w] = Shift(b_ptr[off], shift); + } else { + dst[i + 0 * w] = Shift(((uint16_t*)r_ptr)[off], shift); + dst[i + 1 * w] = Shift(((uint16_t*)g_ptr)[off], shift); + dst[i + 2 * w] = Shift(((uint16_t*)b_ptr)[off], shift); + } + } + if (pic_width & 1) { // replicate rightmost pixel + dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1]; + dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1]; + dst[pic_width + 2 * w] = dst[pic_width + 2 * w - 1]; + } +} + +static void InterpolateTwoRows(const fixed_y_t* const best_y, + const fixed_t* prev_uv, + const fixed_t* cur_uv, + const fixed_t* next_uv, + int w, + fixed_y_t* out1, + fixed_y_t* out2, + int rgb_bit_depth) { + const int uv_w = w >> 1; + const int len = (w - 1) >> 1; // length to filter + int k = 3; + const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth); + while (k-- > 0) { // process each R/G/B segments in turn + // special boundary case for i==0 + out1[0] = Filter2(cur_uv[0], prev_uv[0], best_y[0], bit_depth); + out2[0] = Filter2(cur_uv[0], next_uv[0], best_y[w], bit_depth); + + SharpYuvFilterRow(cur_uv, prev_uv, len, best_y + 0 + 1, out1 + 1, + bit_depth); + SharpYuvFilterRow(cur_uv, next_uv, len, best_y + w + 1, out2 + 1, + bit_depth); + + // special boundary case for i == w - 1 when w is even + if (!(w & 1)) { + out1[w - 1] = Filter2(cur_uv[uv_w - 1], prev_uv[uv_w - 1], + best_y[w - 1 + 0], bit_depth); + out2[w - 1] = Filter2(cur_uv[uv_w - 1], next_uv[uv_w - 1], + best_y[w - 1 + w], bit_depth); + } + out1 += w; + out2 += w; + prev_uv += uv_w; + cur_uv += uv_w; + next_uv += uv_w; + } +} + +static WEBP_INLINE int RGBToYUVComponent(int r, int g, int b, + const int coeffs[4], int sfix) { + const int srounder = 1 << (YUV_FIX + sfix - 1); + const int luma = coeffs[0] * r + coeffs[1] * g + coeffs[2] * b + + coeffs[3] + srounder; + return (luma >> (YUV_FIX + sfix)); +} + +static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv, + uint8_t* y_ptr, int y_stride, uint8_t* u_ptr, + int u_stride, uint8_t* v_ptr, int v_stride, + int rgb_bit_depth, + int yuv_bit_depth, int width, int height, + const SharpYuvConversionMatrix* yuv_matrix) { + int i, j; + const fixed_t* const best_uv_base = best_uv; + const int w = (width + 1) & ~1; + const int h = (height + 1) & ~1; + const int uv_w = w >> 1; + const int uv_h = h >> 1; + const int sfix = GetPrecisionShift(rgb_bit_depth); + const int yuv_max = (1 << yuv_bit_depth) - 1; + + for (best_uv = best_uv_base, j = 0; j < height; ++j) { + for (i = 0; i < width; ++i) { + const int off = (i >> 1); + const int W = best_y[i]; + const int r = best_uv[off + 0 * uv_w] + W; + const int g = best_uv[off + 1 * uv_w] + W; + const int b = best_uv[off + 2 * uv_w] + W; + const int y = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_y, sfix); + if (yuv_bit_depth <= 8) { + y_ptr[i] = clip_8b(y); + } else { + ((uint16_t*)y_ptr)[i] = clip(y, yuv_max); + } + } + best_y += w; + best_uv += (j & 1) * 3 * uv_w; + y_ptr += y_stride; + } + for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) { + for (i = 0; i < uv_w; ++i) { + const int off = i; + // Note r, g and b values here are off by W, but a constant offset on all + // 3 components doesn't change the value of u and v with a YCbCr matrix. + const int r = best_uv[off + 0 * uv_w]; + const int g = best_uv[off + 1 * uv_w]; + const int b = best_uv[off + 2 * uv_w]; + const int u = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_u, sfix); + const int v = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_v, sfix); + if (yuv_bit_depth <= 8) { + u_ptr[i] = clip_8b(u); + v_ptr[i] = clip_8b(v); + } else { + ((uint16_t*)u_ptr)[i] = clip(u, yuv_max); + ((uint16_t*)v_ptr)[i] = clip(v, yuv_max); + } + } + best_uv += 3 * uv_w; + u_ptr += u_stride; + v_ptr += v_stride; + } + return 1; +} + +//------------------------------------------------------------------------------ +// Main function + +static void* SafeMalloc(uint64_t nmemb, size_t size) { + const uint64_t total_size = nmemb * (uint64_t)size; + if (total_size != (size_t)total_size) return NULL; + return malloc((size_t)total_size); +} + +#define SAFE_ALLOC(W, H, T) ((T*)SafeMalloc((W) * (H), sizeof(T))) + +static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr, + const uint8_t* b_ptr, int rgb_step, int rgb_stride, + int rgb_bit_depth, uint8_t* y_ptr, int y_stride, + uint8_t* u_ptr, int u_stride, uint8_t* v_ptr, + int v_stride, int yuv_bit_depth, int width, + int height, + const SharpYuvConversionMatrix* yuv_matrix) { + // we expand the right/bottom border if needed + const int w = (width + 1) & ~1; + const int h = (height + 1) & ~1; + const int uv_w = w >> 1; + const int uv_h = h >> 1; + uint64_t prev_diff_y_sum = ~0; + int j, iter; + + // TODO(skal): allocate one big memory chunk. But for now, it's easier + // for valgrind debugging to have several chunks. + fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch + fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t); + fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t); + fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t); + fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); + fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); + fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t); + fixed_y_t* best_y = best_y_base; + fixed_y_t* target_y = target_y_base; + fixed_t* best_uv = best_uv_base; + fixed_t* target_uv = target_uv_base; + const uint64_t diff_y_threshold = (uint64_t)(3.0 * w * h); + int ok; + assert(w > 0); + assert(h > 0); + + if (best_y_base == NULL || best_uv_base == NULL || + target_y_base == NULL || target_uv_base == NULL || + best_rgb_y == NULL || best_rgb_uv == NULL || + tmp_buffer == NULL) { + ok = 0; + goto End; + } + + // Import RGB samples to W/RGB representation. + for (j = 0; j < height; j += 2) { + const int is_last_row = (j == height - 1); + fixed_y_t* const src1 = tmp_buffer + 0 * w; + fixed_y_t* const src2 = tmp_buffer + 3 * w; + + // prepare two rows of input + ImportOneRow(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth, width, + src1); + if (!is_last_row) { + ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride, + rgb_step, rgb_bit_depth, width, src2); + } else { + memcpy(src2, src1, 3 * w * sizeof(*src2)); + } + StoreGray(src1, best_y + 0, w); + StoreGray(src2, best_y + w, w); + + UpdateW(src1, target_y, w, rgb_bit_depth); + UpdateW(src2, target_y + w, w, rgb_bit_depth); + UpdateChroma(src1, src2, target_uv, uv_w, rgb_bit_depth); + memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv)); + best_y += 2 * w; + best_uv += 3 * uv_w; + target_y += 2 * w; + target_uv += 3 * uv_w; + r_ptr += 2 * rgb_stride; + g_ptr += 2 * rgb_stride; + b_ptr += 2 * rgb_stride; + } + + // Iterate and resolve clipping conflicts. + for (iter = 0; iter < kNumIterations; ++iter) { + const fixed_t* cur_uv = best_uv_base; + const fixed_t* prev_uv = best_uv_base; + uint64_t diff_y_sum = 0; + + best_y = best_y_base; + best_uv = best_uv_base; + target_y = target_y_base; + target_uv = target_uv_base; + for (j = 0; j < h; j += 2) { + fixed_y_t* const src1 = tmp_buffer + 0 * w; + fixed_y_t* const src2 = tmp_buffer + 3 * w; + { + const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0); + InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w, + src1, src2, rgb_bit_depth); + prev_uv = cur_uv; + cur_uv = next_uv; + } + + UpdateW(src1, best_rgb_y + 0 * w, w, rgb_bit_depth); + UpdateW(src2, best_rgb_y + 1 * w, w, rgb_bit_depth); + UpdateChroma(src1, src2, best_rgb_uv, uv_w, rgb_bit_depth); + + // update two rows of Y and one row of RGB + diff_y_sum += + SharpYuvUpdateY(target_y, best_rgb_y, best_y, 2 * w, + rgb_bit_depth + GetPrecisionShift(rgb_bit_depth)); + SharpYuvUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w); + + best_y += 2 * w; + best_uv += 3 * uv_w; + target_y += 2 * w; + target_uv += 3 * uv_w; + } + // test exit condition + if (iter > 0) { + if (diff_y_sum < diff_y_threshold) break; + if (diff_y_sum > prev_diff_y_sum) break; + } + prev_diff_y_sum = diff_y_sum; + } + + // final reconstruction + ok = ConvertWRGBToYUV(best_y_base, best_uv_base, y_ptr, y_stride, u_ptr, + u_stride, v_ptr, v_stride, rgb_bit_depth, yuv_bit_depth, + width, height, yuv_matrix); + + End: + free(best_y_base); + free(best_uv_base); + free(target_y_base); + free(target_uv_base); + free(best_rgb_y); + free(best_rgb_uv); + free(tmp_buffer); + return ok; +} +#undef SAFE_ALLOC + +// Hidden exported init function. +// By default SharpYuvConvert calls it with NULL. If needed, users can declare +// it as extern and call it with a VP8CPUInfo function. +extern void SharpYuvInit(VP8CPUInfo cpu_info_func); +void SharpYuvInit(VP8CPUInfo cpu_info_func) { + static volatile VP8CPUInfo sharpyuv_last_cpuinfo_used = + (VP8CPUInfo)&sharpyuv_last_cpuinfo_used; + const int initialized = + (sharpyuv_last_cpuinfo_used != (VP8CPUInfo)&sharpyuv_last_cpuinfo_used); + if (cpu_info_func == NULL && initialized) return; + if (sharpyuv_last_cpuinfo_used == cpu_info_func) return; + + SharpYuvInitDsp(cpu_info_func); + if (!initialized) { + SharpYuvInitGammaTables(); + } + + sharpyuv_last_cpuinfo_used = cpu_info_func; +} + +int SharpYuvConvert(const void* r_ptr, const void* g_ptr, + const void* b_ptr, int rgb_step, int rgb_stride, + int rgb_bit_depth, void* y_ptr, int y_stride, + void* u_ptr, int u_stride, void* v_ptr, + int v_stride, int yuv_bit_depth, int width, + int height, const SharpYuvConversionMatrix* yuv_matrix) { + SharpYuvConversionMatrix scaled_matrix; + const int rgb_max = (1 << rgb_bit_depth) - 1; + const int rgb_round = 1 << (rgb_bit_depth - 1); + const int yuv_max = (1 << yuv_bit_depth) - 1; + const int sfix = GetPrecisionShift(rgb_bit_depth); + + if (width < 1 || height < 1 || width == INT_MAX || height == INT_MAX || + r_ptr == NULL || g_ptr == NULL || b_ptr == NULL || y_ptr == NULL || + u_ptr == NULL || v_ptr == NULL) { + return 0; + } + if (rgb_bit_depth != 8 && rgb_bit_depth != 10 && rgb_bit_depth != 12 && + rgb_bit_depth != 16) { + return 0; + } + if (yuv_bit_depth != 8 && yuv_bit_depth != 10 && yuv_bit_depth != 12) { + return 0; + } + if (rgb_bit_depth > 8 && (rgb_step % 2 != 0 || rgb_stride %2 != 0)) { + // Step/stride should be even for uint16_t buffers. + return 0; + } + if (yuv_bit_depth > 8 && + (y_stride % 2 != 0 || u_stride % 2 != 0 || v_stride % 2 != 0)) { + // Stride should be even for uint16_t buffers. + return 0; + } + SharpYuvInit(NULL); + + // Add scaling factor to go from rgb_bit_depth to yuv_bit_depth, to the + // rgb->yuv conversion matrix. + if (rgb_bit_depth == yuv_bit_depth) { + memcpy(&scaled_matrix, yuv_matrix, sizeof(scaled_matrix)); + } else { + int i; + for (i = 0; i < 3; ++i) { + scaled_matrix.rgb_to_y[i] = + (yuv_matrix->rgb_to_y[i] * yuv_max + rgb_round) / rgb_max; + scaled_matrix.rgb_to_u[i] = + (yuv_matrix->rgb_to_u[i] * yuv_max + rgb_round) / rgb_max; + scaled_matrix.rgb_to_v[i] = + (yuv_matrix->rgb_to_v[i] * yuv_max + rgb_round) / rgb_max; + } + } + // Also incorporate precision change scaling. + scaled_matrix.rgb_to_y[3] = Shift(yuv_matrix->rgb_to_y[3], sfix); + scaled_matrix.rgb_to_u[3] = Shift(yuv_matrix->rgb_to_u[3], sfix); + scaled_matrix.rgb_to_v[3] = Shift(yuv_matrix->rgb_to_v[3], sfix); + + return DoSharpArgbToYuv(r_ptr, g_ptr, b_ptr, rgb_step, rgb_stride, + rgb_bit_depth, y_ptr, y_stride, u_ptr, u_stride, + v_ptr, v_stride, yuv_bit_depth, width, height, + &scaled_matrix); +} + +//------------------------------------------------------------------------------ diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv.h b/thirdparty/libwebp/sharpyuv/sharpyuv.h new file mode 100644 index 0000000000..9386ea2185 --- /dev/null +++ b/thirdparty/libwebp/sharpyuv/sharpyuv.h @@ -0,0 +1,81 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Sharp RGB to YUV conversion. + +#ifndef WEBP_SHARPYUV_SHARPYUV_H_ +#define WEBP_SHARPYUV_SHARPYUV_H_ + +#include <inttypes.h> + +#ifdef __cplusplus +extern "C" { +#endif + +// SharpYUV API version following the convention from semver.org +#define SHARPYUV_VERSION_MAJOR 0 +#define SHARPYUV_VERSION_MINOR 1 +#define SHARPYUV_VERSION_PATCH 0 +// Version as a uint32_t. The major number is the high 8 bits. +// The minor number is the middle 8 bits. The patch number is the low 16 bits. +#define SHARPYUV_MAKE_VERSION(MAJOR, MINOR, PATCH) \ + (((MAJOR) << 24) | ((MINOR) << 16) | (PATCH)) +#define SHARPYUV_VERSION \ + SHARPYUV_MAKE_VERSION(SHARPYUV_VERSION_MAJOR, SHARPYUV_VERSION_MINOR, \ + SHARPYUV_VERSION_PATCH) + +// RGB to YUV conversion matrix, in 16 bit fixed point. +// y = rgb_to_y[0] * r + rgb_to_y[1] * g + rgb_to_y[2] * b + rgb_to_y[3] +// u = rgb_to_u[0] * r + rgb_to_u[1] * g + rgb_to_u[2] * b + rgb_to_u[3] +// v = rgb_to_v[0] * r + rgb_to_v[1] * g + rgb_to_v[2] * b + rgb_to_v[3] +// Then y, u and v values are divided by 1<<16 and rounded. +typedef struct { + int rgb_to_y[4]; + int rgb_to_u[4]; + int rgb_to_v[4]; +} SharpYuvConversionMatrix; + +// Converts RGB to YUV420 using a downsampling algorithm that minimizes +// artefacts caused by chroma subsampling. +// This is slower than standard downsampling (averaging of 4 UV values). +// Assumes that the image will be upsampled using a bilinear filter. If nearest +// neighbor is used instead, the upsampled image might look worse than with +// standard downsampling. +// r_ptr, g_ptr, b_ptr: pointers to the source r, g and b channels. Should point +// to uint8_t buffers if rgb_bit_depth is 8, or uint16_t buffers otherwise. +// rgb_step: distance in bytes between two horizontally adjacent pixels on the +// r, g and b channels. If rgb_bit_depth is > 8, it should be a +// multiple of 2. +// rgb_stride: distance in bytes between two vertically adjacent pixels on the +// r, g, and b channels. If rgb_bit_depth is > 8, it should be a +// multiple of 2. +// rgb_bit_depth: number of bits for each r/g/b value. One of: 8, 10, 12, 16. +// Note: 16 bit input is truncated to 14 bits before conversion to yuv. +// yuv_bit_depth: number of bits for each y/u/v value. One of: 8, 10, 12. +// y_ptr, u_ptr, v_ptr: pointers to the destination y, u and v channels. Should +// point to uint8_t buffers if yuv_bit_depth is 8, or uint16_t buffers +// otherwise. +// y_stride, u_stride, v_stride: distance in bytes between two vertically +// adjacent pixels on the y, u and v channels. If yuv_bit_depth > 8, they +// should be multiples of 2. +// width, height: width and height of the image in pixels +int SharpYuvConvert(const void* r_ptr, const void* g_ptr, const void* b_ptr, + int rgb_step, int rgb_stride, int rgb_bit_depth, + void* y_ptr, int y_stride, void* u_ptr, int u_stride, + void* v_ptr, int v_stride, int yuv_bit_depth, int width, + int height, const SharpYuvConversionMatrix* yuv_matrix); + +// TODO(b/194336375): Add YUV444 to YUV420 conversion. Maybe also add 422 +// support (it's rarely used in practice, especially for images). + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_SHARPYUV_SHARPYUV_H_ diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv_csp.c b/thirdparty/libwebp/sharpyuv/sharpyuv_csp.c new file mode 100644 index 0000000000..5334fa64fa --- /dev/null +++ b/thirdparty/libwebp/sharpyuv/sharpyuv_csp.c @@ -0,0 +1,110 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Colorspace utilities. + +#include "sharpyuv/sharpyuv_csp.h" + +#include <assert.h> +#include <math.h> +#include <string.h> + +static int ToFixed16(float f) { return (int)floor(f * (1 << 16) + 0.5f); } + +void SharpYuvComputeConversionMatrix(const SharpYuvColorSpace* yuv_color_space, + SharpYuvConversionMatrix* matrix) { + const float kr = yuv_color_space->kr; + const float kb = yuv_color_space->kb; + const float kg = 1.0f - kr - kb; + const float cr = 0.5f / (1.0f - kb); + const float cb = 0.5f / (1.0f - kr); + + const int shift = yuv_color_space->bit_depth - 8; + + const float denom = (float)((1 << yuv_color_space->bit_depth) - 1); + float scale_y = 1.0f; + float add_y = 0.0f; + float scale_u = cr; + float scale_v = cb; + float add_uv = (float)(128 << shift); + assert(yuv_color_space->bit_depth >= 8); + + if (yuv_color_space->range == kSharpYuvRangeLimited) { + scale_y *= (219 << shift) / denom; + scale_u *= (224 << shift) / denom; + scale_v *= (224 << shift) / denom; + add_y = (float)(16 << shift); + } + + matrix->rgb_to_y[0] = ToFixed16(kr * scale_y); + matrix->rgb_to_y[1] = ToFixed16(kg * scale_y); + matrix->rgb_to_y[2] = ToFixed16(kb * scale_y); + matrix->rgb_to_y[3] = ToFixed16(add_y); + + matrix->rgb_to_u[0] = ToFixed16(-kr * scale_u); + matrix->rgb_to_u[1] = ToFixed16(-kg * scale_u); + matrix->rgb_to_u[2] = ToFixed16((1 - kb) * scale_u); + matrix->rgb_to_u[3] = ToFixed16(add_uv); + + matrix->rgb_to_v[0] = ToFixed16((1 - kr) * scale_v); + matrix->rgb_to_v[1] = ToFixed16(-kg * scale_v); + matrix->rgb_to_v[2] = ToFixed16(-kb * scale_v); + matrix->rgb_to_v[3] = ToFixed16(add_uv); +} + +// Matrices are in YUV_FIX fixed point precision. +// WebP's matrix, similar but not identical to kRec601LimitedMatrix. +static const SharpYuvConversionMatrix kWebpMatrix = { + {16839, 33059, 6420, 16 << 16}, + {-9719, -19081, 28800, 128 << 16}, + {28800, -24116, -4684, 128 << 16}, +}; +// Kr=0.2990f Kb=0.1140f bits=8 range=kSharpYuvRangeLimited +static const SharpYuvConversionMatrix kRec601LimitedMatrix = { + {16829, 33039, 6416, 16 << 16}, + {-9714, -19071, 28784, 128 << 16}, + {28784, -24103, -4681, 128 << 16}, +}; +// Kr=0.2990f Kb=0.1140f bits=8 range=kSharpYuvRangeFull +static const SharpYuvConversionMatrix kRec601FullMatrix = { + {19595, 38470, 7471, 0}, + {-11058, -21710, 32768, 128 << 16}, + {32768, -27439, -5329, 128 << 16}, +}; +// Kr=0.2126f Kb=0.0722f bits=8 range=kSharpYuvRangeLimited +static const SharpYuvConversionMatrix kRec709LimitedMatrix = { + {11966, 40254, 4064, 16 << 16}, + {-6596, -22189, 28784, 128 << 16}, + {28784, -26145, -2639, 128 << 16}, +}; +// Kr=0.2126f Kb=0.0722f bits=8 range=kSharpYuvRangeFull +static const SharpYuvConversionMatrix kRec709FullMatrix = { + {13933, 46871, 4732, 0}, + {-7509, -25259, 32768, 128 << 16}, + {32768, -29763, -3005, 128 << 16}, +}; + +const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix( + SharpYuvMatrixType matrix_type) { + switch (matrix_type) { + case kSharpYuvMatrixWebp: + return &kWebpMatrix; + case kSharpYuvMatrixRec601Limited: + return &kRec601LimitedMatrix; + case kSharpYuvMatrixRec601Full: + return &kRec601FullMatrix; + case kSharpYuvMatrixRec709Limited: + return &kRec709LimitedMatrix; + case kSharpYuvMatrixRec709Full: + return &kRec709FullMatrix; + case kSharpYuvMatrixNum: + return NULL; + } + return NULL; +} diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv_csp.h b/thirdparty/libwebp/sharpyuv/sharpyuv_csp.h new file mode 100644 index 0000000000..63c99ef5cd --- /dev/null +++ b/thirdparty/libwebp/sharpyuv/sharpyuv_csp.h @@ -0,0 +1,59 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Colorspace utilities. + +#ifndef WEBP_SHARPYUV_SHARPYUV_CSP_H_ +#define WEBP_SHARPYUV_SHARPYUV_CSP_H_ + +#include "sharpyuv/sharpyuv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Range of YUV values. +typedef enum { + kSharpYuvRangeFull, // YUV values between [0;255] (for 8 bit) + kSharpYuvRangeLimited // Y in [16;235], YUV in [16;240] (for 8 bit) +} SharpYuvRange; + +// Constants that define a YUV color space. +typedef struct { + // Kr and Kb are defined such that: + // Y = Kr * r + Kg * g + Kb * b where Kg = 1 - Kr - Kb. + float kr; + float kb; + int bit_depth; // 8, 10 or 12 + SharpYuvRange range; +} SharpYuvColorSpace; + +// Fills in 'matrix' for the given YUVColorSpace. +void SharpYuvComputeConversionMatrix(const SharpYuvColorSpace* yuv_color_space, + SharpYuvConversionMatrix* matrix); + +// Enums for precomputed conversion matrices. +typedef enum { + kSharpYuvMatrixWebp = 0, + kSharpYuvMatrixRec601Limited, + kSharpYuvMatrixRec601Full, + kSharpYuvMatrixRec709Limited, + kSharpYuvMatrixRec709Full, + kSharpYuvMatrixNum +} SharpYuvMatrixType; + +// Returns a pointer to a matrix for one of the predefined colorspaces. +const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix( + SharpYuvMatrixType matrix_type); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_SHARPYUV_SHARPYUV_CSP_H_ diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv_dsp.c b/thirdparty/libwebp/sharpyuv/sharpyuv_dsp.c new file mode 100644 index 0000000000..956fa7ce55 --- /dev/null +++ b/thirdparty/libwebp/sharpyuv/sharpyuv_dsp.c @@ -0,0 +1,102 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Speed-critical functions for Sharp YUV. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "sharpyuv/sharpyuv_dsp.h" + +#include <assert.h> +#include <stdlib.h> + +#include "src/dsp/cpu.h" + +//----------------------------------------------------------------------------- + +#if !WEBP_NEON_OMIT_C_CODE +static uint16_t clip(int v, int max) { + return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v; +} + +static uint64_t SharpYuvUpdateY_C(const uint16_t* ref, const uint16_t* src, + uint16_t* dst, int len, int bit_depth) { + uint64_t diff = 0; + int i; + const int max_y = (1 << bit_depth) - 1; + for (i = 0; i < len; ++i) { + const int diff_y = ref[i] - src[i]; + const int new_y = (int)dst[i] + diff_y; + dst[i] = clip(new_y, max_y); + diff += (uint64_t)abs(diff_y); + } + return diff; +} + +static void SharpYuvUpdateRGB_C(const int16_t* ref, const int16_t* src, + int16_t* dst, int len) { + int i; + for (i = 0; i < len; ++i) { + const int diff_uv = ref[i] - src[i]; + dst[i] += diff_uv; + } +} + +static void SharpYuvFilterRow_C(const int16_t* A, const int16_t* B, int len, + const uint16_t* best_y, uint16_t* out, + int bit_depth) { + int i; + const int max_y = (1 << bit_depth) - 1; + for (i = 0; i < len; ++i, ++A, ++B) { + const int v0 = (A[0] * 9 + A[1] * 3 + B[0] * 3 + B[1] + 8) >> 4; + const int v1 = (A[1] * 9 + A[0] * 3 + B[1] * 3 + B[0] + 8) >> 4; + out[2 * i + 0] = clip(best_y[2 * i + 0] + v0, max_y); + out[2 * i + 1] = clip(best_y[2 * i + 1] + v1, max_y); + } +} +#endif // !WEBP_NEON_OMIT_C_CODE + +//----------------------------------------------------------------------------- + +uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref, + uint16_t* dst, int len, int bit_depth); +void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, int16_t* dst, + int len); +void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len, + const uint16_t* best_y, uint16_t* out, + int bit_depth); + +extern void InitSharpYuvSSE2(void); +extern void InitSharpYuvNEON(void); + +void SharpYuvInitDsp(VP8CPUInfo cpu_info_func) { + (void)cpu_info_func; + +#if !WEBP_NEON_OMIT_C_CODE + SharpYuvUpdateY = SharpYuvUpdateY_C; + SharpYuvUpdateRGB = SharpYuvUpdateRGB_C; + SharpYuvFilterRow = SharpYuvFilterRow_C; +#endif + +#if defined(WEBP_HAVE_SSE2) + if (cpu_info_func == NULL || cpu_info_func(kSSE2)) { + InitSharpYuvSSE2(); + } +#endif // WEBP_HAVE_SSE2 + +#if defined(WEBP_HAVE_NEON) + if (WEBP_NEON_OMIT_C_CODE || cpu_info_func == NULL || cpu_info_func(kNEON)) { + InitSharpYuvNEON(); + } +#endif // WEBP_HAVE_NEON + + assert(SharpYuvUpdateY != NULL); + assert(SharpYuvUpdateRGB != NULL); + assert(SharpYuvFilterRow != NULL); +} diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv_dsp.h b/thirdparty/libwebp/sharpyuv/sharpyuv_dsp.h new file mode 100644 index 0000000000..e561d8d3d0 --- /dev/null +++ b/thirdparty/libwebp/sharpyuv/sharpyuv_dsp.h @@ -0,0 +1,29 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Speed-critical functions for Sharp YUV. + +#ifndef WEBP_SHARPYUV_SHARPYUV_DSP_H_ +#define WEBP_SHARPYUV_SHARPYUV_DSP_H_ + +#include <stdint.h> + +#include "src/dsp/cpu.h" + +extern uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref, + uint16_t* dst, int len, int bit_depth); +extern void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, + int16_t* dst, int len); +extern void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len, + const uint16_t* best_y, uint16_t* out, + int bit_depth); + +void SharpYuvInitDsp(VP8CPUInfo cpu_info_func); + +#endif // WEBP_SHARPYUV_SHARPYUV_DSP_H_ diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv_gamma.c b/thirdparty/libwebp/sharpyuv/sharpyuv_gamma.c new file mode 100644 index 0000000000..05b5436f83 --- /dev/null +++ b/thirdparty/libwebp/sharpyuv/sharpyuv_gamma.c @@ -0,0 +1,114 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Gamma correction utilities. + +#include "sharpyuv/sharpyuv_gamma.h" + +#include <assert.h> +#include <math.h> +#include <stdint.h> + +#include "src/webp/types.h" + +// Gamma correction compensates loss of resolution during chroma subsampling. +// Size of pre-computed table for converting from gamma to linear. +#define GAMMA_TO_LINEAR_TAB_BITS 10 +#define GAMMA_TO_LINEAR_TAB_SIZE (1 << GAMMA_TO_LINEAR_TAB_BITS) +static uint32_t kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE + 2]; +#define LINEAR_TO_GAMMA_TAB_BITS 9 +#define LINEAR_TO_GAMMA_TAB_SIZE (1 << LINEAR_TO_GAMMA_TAB_BITS) +static uint32_t kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE + 2]; + +static const double kGammaF = 1. / 0.45; +#define GAMMA_TO_LINEAR_BITS 16 + +static volatile int kGammaTablesSOk = 0; +void SharpYuvInitGammaTables(void) { + assert(GAMMA_TO_LINEAR_BITS <= 16); + if (!kGammaTablesSOk) { + int v; + const double a = 0.09929682680944; + const double thresh = 0.018053968510807; + const double final_scale = 1 << GAMMA_TO_LINEAR_BITS; + // Precompute gamma to linear table. + { + const double norm = 1. / GAMMA_TO_LINEAR_TAB_SIZE; + const double a_rec = 1. / (1. + a); + for (v = 0; v <= GAMMA_TO_LINEAR_TAB_SIZE; ++v) { + const double g = norm * v; + double value; + if (g <= thresh * 4.5) { + value = g / 4.5; + } else { + value = pow(a_rec * (g + a), kGammaF); + } + kGammaToLinearTabS[v] = (uint32_t)(value * final_scale + .5); + } + // to prevent small rounding errors to cause read-overflow: + kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE + 1] = + kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE]; + } + // Precompute linear to gamma table. + { + const double scale = 1. / LINEAR_TO_GAMMA_TAB_SIZE; + for (v = 0; v <= LINEAR_TO_GAMMA_TAB_SIZE; ++v) { + const double g = scale * v; + double value; + if (g <= thresh) { + value = 4.5 * g; + } else { + value = (1. + a) * pow(g, 1. / kGammaF) - a; + } + kLinearToGammaTabS[v] = + (uint32_t)(final_scale * value + 0.5); + } + // to prevent small rounding errors to cause read-overflow: + kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE + 1] = + kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE]; + } + kGammaTablesSOk = 1; + } +} + +static WEBP_INLINE int Shift(int v, int shift) { + return (shift >= 0) ? (v << shift) : (v >> -shift); +} + +static WEBP_INLINE uint32_t FixedPointInterpolation(int v, uint32_t* tab, + int tab_pos_shift_right, + int tab_value_shift) { + const uint32_t tab_pos = Shift(v, -tab_pos_shift_right); + // fractional part, in 'tab_pos_shift' fixed-point precision + const uint32_t x = v - (tab_pos << tab_pos_shift_right); // fractional part + // v0 / v1 are in kGammaToLinearBits fixed-point precision (range [0..1]) + const uint32_t v0 = Shift(tab[tab_pos + 0], tab_value_shift); + const uint32_t v1 = Shift(tab[tab_pos + 1], tab_value_shift); + // Final interpolation. + const uint32_t v2 = (v1 - v0) * x; // note: v1 >= v0. + const int half = + (tab_pos_shift_right > 0) ? 1 << (tab_pos_shift_right - 1) : 0; + const uint32_t result = v0 + ((v2 + half) >> tab_pos_shift_right); + return result; +} + +uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth) { + const int shift = GAMMA_TO_LINEAR_TAB_BITS - bit_depth; + if (shift > 0) { + return kGammaToLinearTabS[v << shift]; + } + return FixedPointInterpolation(v, kGammaToLinearTabS, -shift, 0); +} + +uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth) { + return FixedPointInterpolation( + value, kLinearToGammaTabS, + (GAMMA_TO_LINEAR_BITS - LINEAR_TO_GAMMA_TAB_BITS), + bit_depth - GAMMA_TO_LINEAR_BITS); +} diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv_gamma.h b/thirdparty/libwebp/sharpyuv/sharpyuv_gamma.h new file mode 100644 index 0000000000..2f1a3ff4a0 --- /dev/null +++ b/thirdparty/libwebp/sharpyuv/sharpyuv_gamma.h @@ -0,0 +1,35 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Gamma correction utilities. + +#ifndef WEBP_SHARPYUV_SHARPYUV_GAMMA_H_ +#define WEBP_SHARPYUV_SHARPYUV_GAMMA_H_ + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +// Initializes precomputed tables. Must be called once before calling +// SharpYuvGammaToLinear or SharpYuvLinearToGamma. +void SharpYuvInitGammaTables(void); + +// Converts a gamma color value on 'bit_depth' bits to a 16 bit linear value. +uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth); + +// Converts a 16 bit linear color value to a gamma value on 'bit_depth' bits. +uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_SHARPYUV_SHARPYUV_GAMMA_H_ diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv_neon.c b/thirdparty/libwebp/sharpyuv/sharpyuv_neon.c new file mode 100644 index 0000000000..5cf6aaffb0 --- /dev/null +++ b/thirdparty/libwebp/sharpyuv/sharpyuv_neon.c @@ -0,0 +1,182 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Speed-critical functions for Sharp YUV. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "sharpyuv/sharpyuv_dsp.h" + +#if defined(WEBP_USE_NEON) +#include <assert.h> +#include <stdlib.h> +#include <arm_neon.h> +#endif + +extern void InitSharpYuvNEON(void); + +#if defined(WEBP_USE_NEON) + +static uint16_t clip_NEON(int v, int max) { + return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v; +} + +static uint64_t SharpYuvUpdateY_NEON(const uint16_t* ref, const uint16_t* src, + uint16_t* dst, int len, int bit_depth) { + const int max_y = (1 << bit_depth) - 1; + int i; + const int16x8_t zero = vdupq_n_s16(0); + const int16x8_t max = vdupq_n_s16(max_y); + uint64x2_t sum = vdupq_n_u64(0); + uint64_t diff; + + for (i = 0; i + 8 <= len; i += 8) { + const int16x8_t A = vreinterpretq_s16_u16(vld1q_u16(ref + i)); + const int16x8_t B = vreinterpretq_s16_u16(vld1q_u16(src + i)); + const int16x8_t C = vreinterpretq_s16_u16(vld1q_u16(dst + i)); + const int16x8_t D = vsubq_s16(A, B); // diff_y + const int16x8_t F = vaddq_s16(C, D); // new_y + const uint16x8_t H = + vreinterpretq_u16_s16(vmaxq_s16(vminq_s16(F, max), zero)); + const int16x8_t I = vabsq_s16(D); // abs(diff_y) + vst1q_u16(dst + i, H); + sum = vpadalq_u32(sum, vpaddlq_u16(vreinterpretq_u16_s16(I))); + } + diff = vgetq_lane_u64(sum, 0) + vgetq_lane_u64(sum, 1); + for (; i < len; ++i) { + const int diff_y = ref[i] - src[i]; + const int new_y = (int)(dst[i]) + diff_y; + dst[i] = clip_NEON(new_y, max_y); + diff += (uint64_t)(abs(diff_y)); + } + return diff; +} + +static void SharpYuvUpdateRGB_NEON(const int16_t* ref, const int16_t* src, + int16_t* dst, int len) { + int i; + for (i = 0; i + 8 <= len; i += 8) { + const int16x8_t A = vld1q_s16(ref + i); + const int16x8_t B = vld1q_s16(src + i); + const int16x8_t C = vld1q_s16(dst + i); + const int16x8_t D = vsubq_s16(A, B); // diff_uv + const int16x8_t E = vaddq_s16(C, D); // new_uv + vst1q_s16(dst + i, E); + } + for (; i < len; ++i) { + const int diff_uv = ref[i] - src[i]; + dst[i] += diff_uv; + } +} + +static void SharpYuvFilterRow16_NEON(const int16_t* A, const int16_t* B, + int len, const uint16_t* best_y, + uint16_t* out, int bit_depth) { + const int max_y = (1 << bit_depth) - 1; + int i; + const int16x8_t max = vdupq_n_s16(max_y); + const int16x8_t zero = vdupq_n_s16(0); + for (i = 0; i + 8 <= len; i += 8) { + const int16x8_t a0 = vld1q_s16(A + i + 0); + const int16x8_t a1 = vld1q_s16(A + i + 1); + const int16x8_t b0 = vld1q_s16(B + i + 0); + const int16x8_t b1 = vld1q_s16(B + i + 1); + const int16x8_t a0b1 = vaddq_s16(a0, b1); + const int16x8_t a1b0 = vaddq_s16(a1, b0); + const int16x8_t a0a1b0b1 = vaddq_s16(a0b1, a1b0); // A0+A1+B0+B1 + const int16x8_t a0b1_2 = vaddq_s16(a0b1, a0b1); // 2*(A0+B1) + const int16x8_t a1b0_2 = vaddq_s16(a1b0, a1b0); // 2*(A1+B0) + const int16x8_t c0 = vshrq_n_s16(vaddq_s16(a0b1_2, a0a1b0b1), 3); + const int16x8_t c1 = vshrq_n_s16(vaddq_s16(a1b0_2, a0a1b0b1), 3); + const int16x8_t e0 = vrhaddq_s16(c1, a0); + const int16x8_t e1 = vrhaddq_s16(c0, a1); + const int16x8x2_t f = vzipq_s16(e0, e1); + const int16x8_t g0 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 0)); + const int16x8_t g1 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 8)); + const int16x8_t h0 = vaddq_s16(g0, f.val[0]); + const int16x8_t h1 = vaddq_s16(g1, f.val[1]); + const int16x8_t i0 = vmaxq_s16(vminq_s16(h0, max), zero); + const int16x8_t i1 = vmaxq_s16(vminq_s16(h1, max), zero); + vst1q_u16(out + 2 * i + 0, vreinterpretq_u16_s16(i0)); + vst1q_u16(out + 2 * i + 8, vreinterpretq_u16_s16(i1)); + } + for (; i < len; ++i) { + const int a0b1 = A[i + 0] + B[i + 1]; + const int a1b0 = A[i + 1] + B[i + 0]; + const int a0a1b0b1 = a0b1 + a1b0 + 8; + const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4; + const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4; + out[2 * i + 0] = clip_NEON(best_y[2 * i + 0] + v0, max_y); + out[2 * i + 1] = clip_NEON(best_y[2 * i + 1] + v1, max_y); + } +} + +static void SharpYuvFilterRow32_NEON(const int16_t* A, const int16_t* B, + int len, const uint16_t* best_y, + uint16_t* out, int bit_depth) { + const int max_y = (1 << bit_depth) - 1; + int i; + const uint16x8_t max = vdupq_n_u16(max_y); + for (i = 0; i + 4 <= len; i += 4) { + const int16x4_t a0 = vld1_s16(A + i + 0); + const int16x4_t a1 = vld1_s16(A + i + 1); + const int16x4_t b0 = vld1_s16(B + i + 0); + const int16x4_t b1 = vld1_s16(B + i + 1); + const int32x4_t a0b1 = vaddl_s16(a0, b1); + const int32x4_t a1b0 = vaddl_s16(a1, b0); + const int32x4_t a0a1b0b1 = vaddq_s32(a0b1, a1b0); // A0+A1+B0+B1 + const int32x4_t a0b1_2 = vaddq_s32(a0b1, a0b1); // 2*(A0+B1) + const int32x4_t a1b0_2 = vaddq_s32(a1b0, a1b0); // 2*(A1+B0) + const int32x4_t c0 = vshrq_n_s32(vaddq_s32(a0b1_2, a0a1b0b1), 3); + const int32x4_t c1 = vshrq_n_s32(vaddq_s32(a1b0_2, a0a1b0b1), 3); + const int32x4_t e0 = vrhaddq_s32(c1, vmovl_s16(a0)); + const int32x4_t e1 = vrhaddq_s32(c0, vmovl_s16(a1)); + const int32x4x2_t f = vzipq_s32(e0, e1); + + const int16x8_t g = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i)); + const int32x4_t h0 = vaddw_s16(f.val[0], vget_low_s16(g)); + const int32x4_t h1 = vaddw_s16(f.val[1], vget_high_s16(g)); + const uint16x8_t i_16 = vcombine_u16(vqmovun_s32(h0), vqmovun_s32(h1)); + const uint16x8_t i_clamped = vminq_u16(i_16, max); + vst1q_u16(out + 2 * i + 0, i_clamped); + } + for (; i < len; ++i) { + const int a0b1 = A[i + 0] + B[i + 1]; + const int a1b0 = A[i + 1] + B[i + 0]; + const int a0a1b0b1 = a0b1 + a1b0 + 8; + const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4; + const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4; + out[2 * i + 0] = clip_NEON(best_y[2 * i + 0] + v0, max_y); + out[2 * i + 1] = clip_NEON(best_y[2 * i + 1] + v1, max_y); + } +} + +static void SharpYuvFilterRow_NEON(const int16_t* A, const int16_t* B, int len, + const uint16_t* best_y, uint16_t* out, + int bit_depth) { + if (bit_depth <= 10) { + SharpYuvFilterRow16_NEON(A, B, len, best_y, out, bit_depth); + } else { + SharpYuvFilterRow32_NEON(A, B, len, best_y, out, bit_depth); + } +} + +//------------------------------------------------------------------------------ + +WEBP_TSAN_IGNORE_FUNCTION void InitSharpYuvNEON(void) { + SharpYuvUpdateY = SharpYuvUpdateY_NEON; + SharpYuvUpdateRGB = SharpYuvUpdateRGB_NEON; + SharpYuvFilterRow = SharpYuvFilterRow_NEON; +} + +#else // !WEBP_USE_NEON + +void InitSharpYuvNEON(void) {} + +#endif // WEBP_USE_NEON diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv_sse2.c b/thirdparty/libwebp/sharpyuv/sharpyuv_sse2.c new file mode 100644 index 0000000000..1943873748 --- /dev/null +++ b/thirdparty/libwebp/sharpyuv/sharpyuv_sse2.c @@ -0,0 +1,204 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// Speed-critical functions for Sharp YUV. +// +// Author: Skal (pascal.massimino@gmail.com) + +#include "sharpyuv/sharpyuv_dsp.h" + +#if defined(WEBP_USE_SSE2) +#include <stdlib.h> +#include <emmintrin.h> +#endif + +extern void InitSharpYuvSSE2(void); + +#if defined(WEBP_USE_SSE2) + +static uint16_t clip_SSE2(int v, int max) { + return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v; +} + +static uint64_t SharpYuvUpdateY_SSE2(const uint16_t* ref, const uint16_t* src, + uint16_t* dst, int len, int bit_depth) { + const int max_y = (1 << bit_depth) - 1; + uint64_t diff = 0; + uint32_t tmp[4]; + int i; + const __m128i zero = _mm_setzero_si128(); + const __m128i max = _mm_set1_epi16(max_y); + const __m128i one = _mm_set1_epi16(1); + __m128i sum = zero; + + for (i = 0; i + 8 <= len; i += 8) { + const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i)); + const __m128i B = _mm_loadu_si128((const __m128i*)(src + i)); + const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i)); + const __m128i D = _mm_sub_epi16(A, B); // diff_y + const __m128i E = _mm_cmpgt_epi16(zero, D); // sign (-1 or 0) + const __m128i F = _mm_add_epi16(C, D); // new_y + const __m128i G = _mm_or_si128(E, one); // -1 or 1 + const __m128i H = _mm_max_epi16(_mm_min_epi16(F, max), zero); + const __m128i I = _mm_madd_epi16(D, G); // sum(abs(...)) + _mm_storeu_si128((__m128i*)(dst + i), H); + sum = _mm_add_epi32(sum, I); + } + _mm_storeu_si128((__m128i*)tmp, sum); + diff = tmp[3] + tmp[2] + tmp[1] + tmp[0]; + for (; i < len; ++i) { + const int diff_y = ref[i] - src[i]; + const int new_y = (int)dst[i] + diff_y; + dst[i] = clip_SSE2(new_y, max_y); + diff += (uint64_t)abs(diff_y); + } + return diff; +} + +static void SharpYuvUpdateRGB_SSE2(const int16_t* ref, const int16_t* src, + int16_t* dst, int len) { + int i = 0; + for (i = 0; i + 8 <= len; i += 8) { + const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i)); + const __m128i B = _mm_loadu_si128((const __m128i*)(src + i)); + const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i)); + const __m128i D = _mm_sub_epi16(A, B); // diff_uv + const __m128i E = _mm_add_epi16(C, D); // new_uv + _mm_storeu_si128((__m128i*)(dst + i), E); + } + for (; i < len; ++i) { + const int diff_uv = ref[i] - src[i]; + dst[i] += diff_uv; + } +} + +static void SharpYuvFilterRow16_SSE2(const int16_t* A, const int16_t* B, + int len, const uint16_t* best_y, + uint16_t* out, int bit_depth) { + const int max_y = (1 << bit_depth) - 1; + int i; + const __m128i kCst8 = _mm_set1_epi16(8); + const __m128i max = _mm_set1_epi16(max_y); + const __m128i zero = _mm_setzero_si128(); + for (i = 0; i + 8 <= len; i += 8) { + const __m128i a0 = _mm_loadu_si128((const __m128i*)(A + i + 0)); + const __m128i a1 = _mm_loadu_si128((const __m128i*)(A + i + 1)); + const __m128i b0 = _mm_loadu_si128((const __m128i*)(B + i + 0)); + const __m128i b1 = _mm_loadu_si128((const __m128i*)(B + i + 1)); + const __m128i a0b1 = _mm_add_epi16(a0, b1); + const __m128i a1b0 = _mm_add_epi16(a1, b0); + const __m128i a0a1b0b1 = _mm_add_epi16(a0b1, a1b0); // A0+A1+B0+B1 + const __m128i a0a1b0b1_8 = _mm_add_epi16(a0a1b0b1, kCst8); + const __m128i a0b1_2 = _mm_add_epi16(a0b1, a0b1); // 2*(A0+B1) + const __m128i a1b0_2 = _mm_add_epi16(a1b0, a1b0); // 2*(A1+B0) + const __m128i c0 = _mm_srai_epi16(_mm_add_epi16(a0b1_2, a0a1b0b1_8), 3); + const __m128i c1 = _mm_srai_epi16(_mm_add_epi16(a1b0_2, a0a1b0b1_8), 3); + const __m128i d0 = _mm_add_epi16(c1, a0); + const __m128i d1 = _mm_add_epi16(c0, a1); + const __m128i e0 = _mm_srai_epi16(d0, 1); + const __m128i e1 = _mm_srai_epi16(d1, 1); + const __m128i f0 = _mm_unpacklo_epi16(e0, e1); + const __m128i f1 = _mm_unpackhi_epi16(e0, e1); + const __m128i g0 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0)); + const __m128i g1 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 8)); + const __m128i h0 = _mm_add_epi16(g0, f0); + const __m128i h1 = _mm_add_epi16(g1, f1); + const __m128i i0 = _mm_max_epi16(_mm_min_epi16(h0, max), zero); + const __m128i i1 = _mm_max_epi16(_mm_min_epi16(h1, max), zero); + _mm_storeu_si128((__m128i*)(out + 2 * i + 0), i0); + _mm_storeu_si128((__m128i*)(out + 2 * i + 8), i1); + } + for (; i < len; ++i) { + // (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 = + // = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4 + // We reuse the common sub-expressions. + const int a0b1 = A[i + 0] + B[i + 1]; + const int a1b0 = A[i + 1] + B[i + 0]; + const int a0a1b0b1 = a0b1 + a1b0 + 8; + const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4; + const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4; + out[2 * i + 0] = clip_SSE2(best_y[2 * i + 0] + v0, max_y); + out[2 * i + 1] = clip_SSE2(best_y[2 * i + 1] + v1, max_y); + } +} + +static WEBP_INLINE __m128i s16_to_s32(__m128i in) { + return _mm_srai_epi32(_mm_unpacklo_epi16(in, in), 16); +} + +static void SharpYuvFilterRow32_SSE2(const int16_t* A, const int16_t* B, + int len, const uint16_t* best_y, + uint16_t* out, int bit_depth) { + const int max_y = (1 << bit_depth) - 1; + int i; + const __m128i kCst8 = _mm_set1_epi32(8); + const __m128i max = _mm_set1_epi16(max_y); + const __m128i zero = _mm_setzero_si128(); + for (i = 0; i + 4 <= len; i += 4) { + const __m128i a0 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(A + i + 0))); + const __m128i a1 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(A + i + 1))); + const __m128i b0 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(B + i + 0))); + const __m128i b1 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(B + i + 1))); + const __m128i a0b1 = _mm_add_epi32(a0, b1); + const __m128i a1b0 = _mm_add_epi32(a1, b0); + const __m128i a0a1b0b1 = _mm_add_epi32(a0b1, a1b0); // A0+A1+B0+B1 + const __m128i a0a1b0b1_8 = _mm_add_epi32(a0a1b0b1, kCst8); + const __m128i a0b1_2 = _mm_add_epi32(a0b1, a0b1); // 2*(A0+B1) + const __m128i a1b0_2 = _mm_add_epi32(a1b0, a1b0); // 2*(A1+B0) + const __m128i c0 = _mm_srai_epi32(_mm_add_epi32(a0b1_2, a0a1b0b1_8), 3); + const __m128i c1 = _mm_srai_epi32(_mm_add_epi32(a1b0_2, a0a1b0b1_8), 3); + const __m128i d0 = _mm_add_epi32(c1, a0); + const __m128i d1 = _mm_add_epi32(c0, a1); + const __m128i e0 = _mm_srai_epi32(d0, 1); + const __m128i e1 = _mm_srai_epi32(d1, 1); + const __m128i f0 = _mm_unpacklo_epi32(e0, e1); + const __m128i f1 = _mm_unpackhi_epi32(e0, e1); + const __m128i g = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0)); + const __m128i h_16 = _mm_add_epi16(g, _mm_packs_epi32(f0, f1)); + const __m128i final = _mm_max_epi16(_mm_min_epi16(h_16, max), zero); + _mm_storeu_si128((__m128i*)(out + 2 * i + 0), final); + } + for (; i < len; ++i) { + // (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 = + // = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4 + // We reuse the common sub-expressions. + const int a0b1 = A[i + 0] + B[i + 1]; + const int a1b0 = A[i + 1] + B[i + 0]; + const int a0a1b0b1 = a0b1 + a1b0 + 8; + const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4; + const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4; + out[2 * i + 0] = clip_SSE2(best_y[2 * i + 0] + v0, max_y); + out[2 * i + 1] = clip_SSE2(best_y[2 * i + 1] + v1, max_y); + } +} + +static void SharpYuvFilterRow_SSE2(const int16_t* A, const int16_t* B, int len, + const uint16_t* best_y, uint16_t* out, + int bit_depth) { + if (bit_depth <= 10) { + SharpYuvFilterRow16_SSE2(A, B, len, best_y, out, bit_depth); + } else { + SharpYuvFilterRow32_SSE2(A, B, len, best_y, out, bit_depth); + } +} + +//------------------------------------------------------------------------------ + +extern void InitSharpYuvSSE2(void); + +WEBP_TSAN_IGNORE_FUNCTION void InitSharpYuvSSE2(void) { + SharpYuvUpdateY = SharpYuvUpdateY_SSE2; + SharpYuvUpdateRGB = SharpYuvUpdateRGB_SSE2; + SharpYuvFilterRow = SharpYuvFilterRow_SSE2; +} +#else // !WEBP_USE_SSE2 + +void InitSharpYuvSSE2(void) {} + +#endif // WEBP_USE_SSE2 diff --git a/thirdparty/libwebp/src/dec/vp8i_dec.h b/thirdparty/libwebp/src/dec/vp8i_dec.h index 9af22f8cc6..30c1bd3ef9 100644 --- a/thirdparty/libwebp/src/dec/vp8i_dec.h +++ b/thirdparty/libwebp/src/dec/vp8i_dec.h @@ -32,7 +32,7 @@ extern "C" { // version numbers #define DEC_MAJ_VERSION 1 #define DEC_MIN_VERSION 2 -#define DEC_REV_VERSION 2 +#define DEC_REV_VERSION 4 // YUV-cache parameters. Cache is 32-bytes wide (= one cacheline). // Constraints are: We need to store one 16x16 block of luma samples (y), diff --git a/thirdparty/libwebp/src/dec/vp8l_dec.c b/thirdparty/libwebp/src/dec/vp8l_dec.c index 78db014030..1348055128 100644 --- a/thirdparty/libwebp/src/dec/vp8l_dec.c +++ b/thirdparty/libwebp/src/dec/vp8l_dec.c @@ -178,7 +178,7 @@ static WEBP_INLINE int PlaneCodeToDistance(int xsize, int plane_code) { //------------------------------------------------------------------------------ // Decodes the next Huffman code from bit-stream. -// FillBitWindow(br) needs to be called at minimum every second call +// VP8LFillBitWindow(br) needs to be called at minimum every second call // to ReadSymbol, in order to pre-fetch enough bits. static WEBP_INLINE int ReadSymbol(const HuffmanCode* table, VP8LBitReader* const br) { @@ -321,7 +321,7 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec, // The first code is either 1 bit or 8 bit code. int symbol = VP8LReadBits(br, (first_symbol_len_code == 0) ? 1 : 8); code_lengths[symbol] = 1; - // The second code (if present), is always 8 bit long. + // The second code (if present), is always 8 bits long. if (num_symbols == 2) { symbol = VP8LReadBits(br, 8); code_lengths[symbol] = 1; @@ -1281,7 +1281,7 @@ static int ExpandColorMap(int num_colors, VP8LTransform* const transform) { uint8_t* const new_data = (uint8_t*)new_color_map; new_color_map[0] = transform->data_[0]; for (i = 4; i < 4 * num_colors; ++i) { - // Equivalent to AddPixelEq(), on a byte-basis. + // Equivalent to VP8LAddPixels(), on a byte-basis. new_data[i] = (data[i] + new_data[i - 4]) & 0xff; } for (; i < 4 * final_num_colors; ++i) { diff --git a/thirdparty/libwebp/src/demux/demux.c b/thirdparty/libwebp/src/demux/demux.c index f04a2b8450..41387ec2d6 100644 --- a/thirdparty/libwebp/src/demux/demux.c +++ b/thirdparty/libwebp/src/demux/demux.c @@ -25,7 +25,7 @@ #define DMUX_MAJ_VERSION 1 #define DMUX_MIN_VERSION 2 -#define DMUX_REV_VERSION 2 +#define DMUX_REV_VERSION 4 typedef struct { size_t start_; // start location of the data @@ -614,7 +614,6 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { while (f != NULL) { const int cur_frame_set = f->frame_num_; - int frame_count = 0; // Check frame properties. for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) { @@ -649,8 +648,6 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { dmux->canvas_width_, dmux->canvas_height_)) { return 0; } - - ++frame_count; } } return 1; diff --git a/thirdparty/libwebp/src/dsp/alpha_processing_neon.c b/thirdparty/libwebp/src/dsp/alpha_processing_neon.c index 9e0ace9421..6716fb77f0 100644 --- a/thirdparty/libwebp/src/dsp/alpha_processing_neon.c +++ b/thirdparty/libwebp/src/dsp/alpha_processing_neon.c @@ -83,7 +83,7 @@ static void ApplyAlphaMultiply_NEON(uint8_t* rgba, int alpha_first, static int DispatchAlpha_NEON(const uint8_t* WEBP_RESTRICT alpha, int alpha_stride, int width, int height, uint8_t* WEBP_RESTRICT dst, int dst_stride) { - uint32_t alpha_mask = 0xffffffffu; + uint32_t alpha_mask = 0xffu; uint8x8_t mask8 = vdup_n_u8(0xff); uint32_t tmp[2]; int i, j; @@ -107,6 +107,7 @@ static int DispatchAlpha_NEON(const uint8_t* WEBP_RESTRICT alpha, dst += dst_stride; } vst1_u8((uint8_t*)tmp, mask8); + alpha_mask *= 0x01010101; alpha_mask &= tmp[0]; alpha_mask &= tmp[1]; return (alpha_mask != 0xffffffffu); @@ -135,7 +136,7 @@ static void DispatchAlphaToGreen_NEON(const uint8_t* WEBP_RESTRICT alpha, static int ExtractAlpha_NEON(const uint8_t* WEBP_RESTRICT argb, int argb_stride, int width, int height, uint8_t* WEBP_RESTRICT alpha, int alpha_stride) { - uint32_t alpha_mask = 0xffffffffu; + uint32_t alpha_mask = 0xffu; uint8x8_t mask8 = vdup_n_u8(0xff); uint32_t tmp[2]; int i, j; @@ -157,6 +158,7 @@ static int ExtractAlpha_NEON(const uint8_t* WEBP_RESTRICT argb, int argb_stride, alpha += alpha_stride; } vst1_u8((uint8_t*)tmp, mask8); + alpha_mask *= 0x01010101; alpha_mask &= tmp[0]; alpha_mask &= tmp[1]; return (alpha_mask == 0xffffffffu); diff --git a/thirdparty/libwebp/src/dsp/cpu.c b/thirdparty/libwebp/src/dsp/cpu.c index 3145e190a4..a4ba7f2cb7 100644 --- a/thirdparty/libwebp/src/dsp/cpu.c +++ b/thirdparty/libwebp/src/dsp/cpu.c @@ -11,7 +11,7 @@ // // Author: Christian Duvivier (cduvivier@google.com) -#include "src/dsp/dsp.h" +#include "src/dsp/cpu.h" #if defined(WEBP_HAVE_NEON_RTCD) #include <stdio.h> diff --git a/thirdparty/libwebp/src/dsp/cpu.h b/thirdparty/libwebp/src/dsp/cpu.h new file mode 100644 index 0000000000..57a40d87d4 --- /dev/null +++ b/thirdparty/libwebp/src/dsp/cpu.h @@ -0,0 +1,254 @@ +// Copyright 2022 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// CPU detection functions and macros. +// +// Author: Skal (pascal.massimino@gmail.com) + +#ifndef WEBP_DSP_CPU_H_ +#define WEBP_DSP_CPU_H_ + +#ifdef HAVE_CONFIG_H +#include "src/webp/config.h" +#endif + +#include "src/webp/types.h" + +#if defined(__GNUC__) +#define LOCAL_GCC_VERSION ((__GNUC__ << 8) | __GNUC_MINOR__) +#define LOCAL_GCC_PREREQ(maj, min) (LOCAL_GCC_VERSION >= (((maj) << 8) | (min))) +#else +#define LOCAL_GCC_VERSION 0 +#define LOCAL_GCC_PREREQ(maj, min) 0 +#endif + +#if defined(__clang__) +#define LOCAL_CLANG_VERSION ((__clang_major__ << 8) | __clang_minor__) +#define LOCAL_CLANG_PREREQ(maj, min) \ + (LOCAL_CLANG_VERSION >= (((maj) << 8) | (min))) +#else +#define LOCAL_CLANG_VERSION 0 +#define LOCAL_CLANG_PREREQ(maj, min) 0 +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#if !defined(HAVE_CONFIG_H) +#if defined(_MSC_VER) && _MSC_VER > 1310 && \ + (defined(_M_X64) || defined(_M_IX86)) +#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1500 && \ + (defined(_M_X64) || defined(_M_IX86)) +#define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets +#endif +#endif + +// WEBP_HAVE_* are used to indicate the presence of the instruction set in dsp +// files without intrinsics, allowing the corresponding Init() to be called. +// Files containing intrinsics will need to be built targeting the instruction +// set so should succeed on one of the earlier tests. +#if (defined(__SSE2__) || defined(WEBP_MSC_SSE2)) && \ + (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE2)) +#define WEBP_USE_SSE2 +#endif + +#if defined(WEBP_USE_SSE2) && !defined(WEBP_HAVE_SSE2) +#define WEBP_HAVE_SSE2 +#endif + +#if (defined(__SSE4_1__) || defined(WEBP_MSC_SSE41)) && \ + (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE41)) +#define WEBP_USE_SSE41 +#endif + +#if defined(WEBP_USE_SSE41) && !defined(WEBP_HAVE_SSE41) +#define WEBP_HAVE_SSE41 +#endif + +#undef WEBP_MSC_SSE41 +#undef WEBP_MSC_SSE2 + +// The intrinsics currently cause compiler errors with arm-nacl-gcc and the +// inline assembly would need to be modified for use with Native Client. +#if ((defined(__ARM_NEON__) || defined(__aarch64__)) && \ + (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_NEON))) && \ + !defined(__native_client__) +#define WEBP_USE_NEON +#endif + +#if !defined(WEBP_USE_NEON) && defined(__ANDROID__) && \ + defined(__ARM_ARCH_7A__) && defined(HAVE_CPU_FEATURES_H) +#define WEBP_ANDROID_NEON // Android targets that may have NEON +#define WEBP_USE_NEON +#endif + +// Note: ARM64 is supported in Visual Studio 2017, but requires the direct +// inclusion of arm64_neon.h; Visual Studio 2019 includes this file in +// arm_neon.h. Compile errors were seen with Visual Studio 2019 16.4 with +// vtbl4_u8(); a fix was made in 16.6. +#if defined(_MSC_VER) && ((_MSC_VER >= 1700 && defined(_M_ARM)) || \ + (_MSC_VER >= 1926 && defined(_M_ARM64))) +#define WEBP_USE_NEON +#define WEBP_USE_INTRINSICS +#endif + +#if defined(WEBP_USE_NEON) && !defined(WEBP_HAVE_NEON) +#define WEBP_HAVE_NEON +#endif + +#if defined(__mips__) && !defined(__mips64) && defined(__mips_isa_rev) && \ + (__mips_isa_rev >= 1) && (__mips_isa_rev < 6) +#define WEBP_USE_MIPS32 +#if (__mips_isa_rev >= 2) +#define WEBP_USE_MIPS32_R2 +#if defined(__mips_dspr2) || (defined(__mips_dsp_rev) && __mips_dsp_rev >= 2) +#define WEBP_USE_MIPS_DSP_R2 +#endif +#endif +#endif + +#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5) +#define WEBP_USE_MSA +#endif + +#ifndef WEBP_DSP_OMIT_C_CODE +#define WEBP_DSP_OMIT_C_CODE 1 +#endif + +#if defined(WEBP_USE_NEON) && WEBP_DSP_OMIT_C_CODE +#define WEBP_NEON_OMIT_C_CODE 1 +#else +#define WEBP_NEON_OMIT_C_CODE 0 +#endif + +#if !(LOCAL_CLANG_PREREQ(3, 8) || LOCAL_GCC_PREREQ(4, 8) || \ + defined(__aarch64__)) +#define WEBP_NEON_WORK_AROUND_GCC 1 +#else +#define WEBP_NEON_WORK_AROUND_GCC 0 +#endif + +// This macro prevents thread_sanitizer from reporting known concurrent writes. +#define WEBP_TSAN_IGNORE_FUNCTION +#if defined(__has_feature) +#if __has_feature(thread_sanitizer) +#undef WEBP_TSAN_IGNORE_FUNCTION +#define WEBP_TSAN_IGNORE_FUNCTION __attribute__((no_sanitize_thread)) +#endif +#endif + +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) +#define WEBP_MSAN +#endif +#endif + +#if defined(WEBP_USE_THREAD) && !defined(_WIN32) +#include <pthread.h> // NOLINT + +#define WEBP_DSP_INIT(func) \ + do { \ + static volatile VP8CPUInfo func##_last_cpuinfo_used = \ + (VP8CPUInfo)&func##_last_cpuinfo_used; \ + static pthread_mutex_t func##_lock = PTHREAD_MUTEX_INITIALIZER; \ + if (pthread_mutex_lock(&func##_lock)) break; \ + if (func##_last_cpuinfo_used != VP8GetCPUInfo) func(); \ + func##_last_cpuinfo_used = VP8GetCPUInfo; \ + (void)pthread_mutex_unlock(&func##_lock); \ + } while (0) +#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32)) +#define WEBP_DSP_INIT(func) \ + do { \ + static volatile VP8CPUInfo func##_last_cpuinfo_used = \ + (VP8CPUInfo)&func##_last_cpuinfo_used; \ + if (func##_last_cpuinfo_used == VP8GetCPUInfo) break; \ + func(); \ + func##_last_cpuinfo_used = VP8GetCPUInfo; \ + } while (0) +#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32) + +// Defines an Init + helper function that control multiple initialization of +// function pointers / tables. +/* Usage: + WEBP_DSP_INIT_FUNC(InitFunc) { + ...function body + } +*/ +#define WEBP_DSP_INIT_FUNC(name) \ + static WEBP_TSAN_IGNORE_FUNCTION void name##_body(void); \ + WEBP_TSAN_IGNORE_FUNCTION void name(void) { WEBP_DSP_INIT(name##_body); } \ + static WEBP_TSAN_IGNORE_FUNCTION void name##_body(void) + +#define WEBP_UBSAN_IGNORE_UNDEF +#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW +#if defined(__clang__) && defined(__has_attribute) +#if __has_attribute(no_sanitize) +// This macro prevents the undefined behavior sanitizer from reporting +// failures. This is only meant to silence unaligned loads on platforms that +// are known to support them. +#undef WEBP_UBSAN_IGNORE_UNDEF +#define WEBP_UBSAN_IGNORE_UNDEF __attribute__((no_sanitize("undefined"))) + +// This macro prevents the undefined behavior sanitizer from reporting +// failures related to unsigned integer overflows. This is only meant to +// silence cases where this well defined behavior is expected. +#undef WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW +#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW \ + __attribute__((no_sanitize("unsigned-integer-overflow"))) +#endif +#endif + +// If 'ptr' is NULL, returns NULL. Otherwise returns 'ptr + off'. +// Prevents undefined behavior sanitizer nullptr-with-nonzero-offset warning. +#if !defined(WEBP_OFFSET_PTR) +#define WEBP_OFFSET_PTR(ptr, off) (((ptr) == NULL) ? NULL : ((ptr) + (off))) +#endif + +// Regularize the definition of WEBP_SWAP_16BIT_CSP (backward compatibility) +#if !defined(WEBP_SWAP_16BIT_CSP) +#define WEBP_SWAP_16BIT_CSP 0 +#endif + +// some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__) +#if !defined(WORDS_BIGENDIAN) && \ + (defined(__BIG_ENDIAN__) || defined(_M_PPC) || \ + (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) +#define WORDS_BIGENDIAN +#endif + +typedef enum { + kSSE2, + kSSE3, + kSlowSSSE3, // special feature for slow SSSE3 architectures + kSSE4_1, + kAVX, + kAVX2, + kNEON, + kMIPS32, + kMIPSdspR2, + kMSA +} CPUFeature; + +#ifdef __cplusplus +extern "C" { +#endif + +// returns true if the CPU supports the feature. +typedef int (*VP8CPUInfo)(CPUFeature feature); +WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBP_DSP_CPU_H_ diff --git a/thirdparty/libwebp/src/dsp/dsp.h b/thirdparty/libwebp/src/dsp/dsp.h index c4f57e4d5b..d2000b8efc 100644 --- a/thirdparty/libwebp/src/dsp/dsp.h +++ b/thirdparty/libwebp/src/dsp/dsp.h @@ -18,6 +18,7 @@ #include "src/webp/config.h" #endif +#include "src/dsp/cpu.h" #include "src/webp/types.h" #ifdef __cplusplus @@ -43,225 +44,6 @@ extern "C" { #define WEBP_RESTRICT #endif -//------------------------------------------------------------------------------ -// CPU detection - -#if defined(__GNUC__) -# define LOCAL_GCC_VERSION ((__GNUC__ << 8) | __GNUC_MINOR__) -# define LOCAL_GCC_PREREQ(maj, min) \ - (LOCAL_GCC_VERSION >= (((maj) << 8) | (min))) -#else -# define LOCAL_GCC_VERSION 0 -# define LOCAL_GCC_PREREQ(maj, min) 0 -#endif - -#if defined(__clang__) -# define LOCAL_CLANG_VERSION ((__clang_major__ << 8) | __clang_minor__) -# define LOCAL_CLANG_PREREQ(maj, min) \ - (LOCAL_CLANG_VERSION >= (((maj) << 8) | (min))) -#else -# define LOCAL_CLANG_VERSION 0 -# define LOCAL_CLANG_PREREQ(maj, min) 0 -#endif - -#ifndef __has_builtin -# define __has_builtin(x) 0 -#endif - -#if !defined(HAVE_CONFIG_H) -#if defined(_MSC_VER) && _MSC_VER > 1310 && \ - (defined(_M_X64) || defined(_M_IX86)) -#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets -#endif - -#if defined(_MSC_VER) && _MSC_VER >= 1500 && \ - (defined(_M_X64) || defined(_M_IX86)) -#define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets -#endif -#endif - -// WEBP_HAVE_* are used to indicate the presence of the instruction set in dsp -// files without intrinsics, allowing the corresponding Init() to be called. -// Files containing intrinsics will need to be built targeting the instruction -// set so should succeed on one of the earlier tests. -#if (defined(__SSE2__) || defined(WEBP_MSC_SSE2)) && \ - (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE2)) -#define WEBP_USE_SSE2 -#endif - -#if defined(WEBP_USE_SSE2) && !defined(WEBP_HAVE_SSE2) -#define WEBP_HAVE_SSE2 -#endif - -#if (defined(__SSE4_1__) || defined(WEBP_MSC_SSE41)) && \ - (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE41)) -#define WEBP_USE_SSE41 -#endif - -#if defined(WEBP_USE_SSE41) && !defined(WEBP_HAVE_SSE41) -#define WEBP_HAVE_SSE41 -#endif - -#undef WEBP_MSC_SSE41 -#undef WEBP_MSC_SSE2 - -// The intrinsics currently cause compiler errors with arm-nacl-gcc and the -// inline assembly would need to be modified for use with Native Client. -#if ((defined(__ARM_NEON__) || defined(__aarch64__)) && \ - (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_NEON))) && \ - !defined(__native_client__) -#define WEBP_USE_NEON -#endif - -#if !defined(WEBP_USE_NEON) && defined(__ANDROID__) && \ - defined(__ARM_ARCH_7A__) && defined(HAVE_CPU_FEATURES_H) -#define WEBP_ANDROID_NEON // Android targets that may have NEON -#define WEBP_USE_NEON -#endif - -// Note: ARM64 is supported in Visual Studio 2017, but requires the direct -// inclusion of arm64_neon.h; Visual Studio 2019 includes this file in -// arm_neon.h. -#if defined(_MSC_VER) && \ - ((_MSC_VER >= 1700 && defined(_M_ARM)) || \ - (_MSC_VER >= 1920 && defined(_M_ARM64))) -#define WEBP_USE_NEON -#define WEBP_USE_INTRINSICS -#endif - -#if defined(WEBP_USE_NEON) && !defined(WEBP_HAVE_NEON) -#define WEBP_HAVE_NEON -#endif - -#if defined(__mips__) && !defined(__mips64) && \ - defined(__mips_isa_rev) && (__mips_isa_rev >= 1) && (__mips_isa_rev < 6) -#define WEBP_USE_MIPS32 -#if (__mips_isa_rev >= 2) -#define WEBP_USE_MIPS32_R2 -#if defined(__mips_dspr2) || (defined(__mips_dsp_rev) && __mips_dsp_rev >= 2) -#define WEBP_USE_MIPS_DSP_R2 -#endif -#endif -#endif - -#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5) -#define WEBP_USE_MSA -#endif - -#ifndef WEBP_DSP_OMIT_C_CODE -#define WEBP_DSP_OMIT_C_CODE 1 -#endif - -#if defined(WEBP_USE_NEON) && WEBP_DSP_OMIT_C_CODE -#define WEBP_NEON_OMIT_C_CODE 1 -#else -#define WEBP_NEON_OMIT_C_CODE 0 -#endif - -#if !(LOCAL_CLANG_PREREQ(3,8) || LOCAL_GCC_PREREQ(4,8) || defined(__aarch64__)) -#define WEBP_NEON_WORK_AROUND_GCC 1 -#else -#define WEBP_NEON_WORK_AROUND_GCC 0 -#endif - -// This macro prevents thread_sanitizer from reporting known concurrent writes. -#define WEBP_TSAN_IGNORE_FUNCTION -#if defined(__has_feature) -#if __has_feature(thread_sanitizer) -#undef WEBP_TSAN_IGNORE_FUNCTION -#define WEBP_TSAN_IGNORE_FUNCTION __attribute__((no_sanitize_thread)) -#endif -#endif - -#if defined(WEBP_USE_THREAD) && !defined(_WIN32) -#include <pthread.h> // NOLINT - -#define WEBP_DSP_INIT(func) do { \ - static volatile VP8CPUInfo func ## _last_cpuinfo_used = \ - (VP8CPUInfo)&func ## _last_cpuinfo_used; \ - static pthread_mutex_t func ## _lock = PTHREAD_MUTEX_INITIALIZER; \ - if (pthread_mutex_lock(&func ## _lock)) break; \ - if (func ## _last_cpuinfo_used != VP8GetCPUInfo) func(); \ - func ## _last_cpuinfo_used = VP8GetCPUInfo; \ - (void)pthread_mutex_unlock(&func ## _lock); \ -} while (0) -#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32)) -#define WEBP_DSP_INIT(func) do { \ - static volatile VP8CPUInfo func ## _last_cpuinfo_used = \ - (VP8CPUInfo)&func ## _last_cpuinfo_used; \ - if (func ## _last_cpuinfo_used == VP8GetCPUInfo) break; \ - func(); \ - func ## _last_cpuinfo_used = VP8GetCPUInfo; \ -} while (0) -#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32) - -// Defines an Init + helper function that control multiple initialization of -// function pointers / tables. -/* Usage: - WEBP_DSP_INIT_FUNC(InitFunc) { - ...function body - } -*/ -#define WEBP_DSP_INIT_FUNC(name) \ - static WEBP_TSAN_IGNORE_FUNCTION void name ## _body(void); \ - WEBP_TSAN_IGNORE_FUNCTION void name(void) { \ - WEBP_DSP_INIT(name ## _body); \ - } \ - static WEBP_TSAN_IGNORE_FUNCTION void name ## _body(void) - -#define WEBP_UBSAN_IGNORE_UNDEF -#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW -#if defined(__clang__) && defined(__has_attribute) -#if __has_attribute(no_sanitize) -// This macro prevents the undefined behavior sanitizer from reporting -// failures. This is only meant to silence unaligned loads on platforms that -// are known to support them. -#undef WEBP_UBSAN_IGNORE_UNDEF -#define WEBP_UBSAN_IGNORE_UNDEF \ - __attribute__((no_sanitize("undefined"))) - -// This macro prevents the undefined behavior sanitizer from reporting -// failures related to unsigned integer overflows. This is only meant to -// silence cases where this well defined behavior is expected. -#undef WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW -#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW \ - __attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -#endif - -// If 'ptr' is NULL, returns NULL. Otherwise returns 'ptr + off'. -// Prevents undefined behavior sanitizer nullptr-with-nonzero-offset warning. -#if !defined(WEBP_OFFSET_PTR) -#define WEBP_OFFSET_PTR(ptr, off) (((ptr) == NULL) ? NULL : ((ptr) + (off))) -#endif - -// Regularize the definition of WEBP_SWAP_16BIT_CSP (backward compatibility) -#if !defined(WEBP_SWAP_16BIT_CSP) -#define WEBP_SWAP_16BIT_CSP 0 -#endif - -// some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__) -#if !defined(WORDS_BIGENDIAN) && \ - (defined(__BIG_ENDIAN__) || defined(_M_PPC) || \ - (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) -#define WORDS_BIGENDIAN -#endif - -typedef enum { - kSSE2, - kSSE3, - kSlowSSSE3, // special feature for slow SSSE3 architectures - kSSE4_1, - kAVX, - kAVX2, - kNEON, - kMIPS32, - kMIPSdspR2, - kMSA -} CPUFeature; -// returns true if the CPU supports the feature. -typedef int (*VP8CPUInfo)(CPUFeature feature); -WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo; //------------------------------------------------------------------------------ // Init stub generator @@ -550,15 +332,6 @@ extern void WebPConvertARGBToUV_C(const uint32_t* argb, uint8_t* u, uint8_t* v, extern void WebPConvertRGBA32ToUV_C(const uint16_t* rgb, uint8_t* u, uint8_t* v, int width); -// utilities for accurate RGB->YUV conversion -extern uint64_t (*WebPSharpYUVUpdateY)(const uint16_t* src, const uint16_t* ref, - uint16_t* dst, int len); -extern void (*WebPSharpYUVUpdateRGB)(const int16_t* src, const int16_t* ref, - int16_t* dst, int len); -extern void (*WebPSharpYUVFilterRow)(const int16_t* A, const int16_t* B, - int len, - const uint16_t* best_y, uint16_t* out); - // Must be called before using the above. void WebPInitConvertARGBToYUV(void); diff --git a/thirdparty/libwebp/src/dsp/lossless.h b/thirdparty/libwebp/src/dsp/lossless.h index c26c6bca07..de60d95d0b 100644 --- a/thirdparty/libwebp/src/dsp/lossless.h +++ b/thirdparty/libwebp/src/dsp/lossless.h @@ -182,9 +182,9 @@ extern VP8LPredictorAddSubFunc VP8LPredictorsSub_C[16]; // ----------------------------------------------------------------------------- // Huffman-cost related functions. -typedef double (*VP8LCostFunc)(const uint32_t* population, int length); -typedef double (*VP8LCostCombinedFunc)(const uint32_t* X, const uint32_t* Y, - int length); +typedef float (*VP8LCostFunc)(const uint32_t* population, int length); +typedef float (*VP8LCostCombinedFunc)(const uint32_t* X, const uint32_t* Y, + int length); typedef float (*VP8LCombinedShannonEntropyFunc)(const int X[256], const int Y[256]); @@ -198,7 +198,7 @@ typedef struct { // small struct to hold counters } VP8LStreaks; typedef struct { // small struct to hold bit entropy results - double entropy; // entropy + float entropy; // entropy uint32_t sum; // sum of the population int nonzeros; // number of non-zero elements in the population uint32_t max_val; // maximum value in the population diff --git a/thirdparty/libwebp/src/dsp/lossless_enc.c b/thirdparty/libwebp/src/dsp/lossless_enc.c index 1580631e38..de6c4ace5f 100644 --- a/thirdparty/libwebp/src/dsp/lossless_enc.c +++ b/thirdparty/libwebp/src/dsp/lossless_enc.c @@ -402,7 +402,7 @@ static float FastLog2Slow_C(uint32_t v) { // Compute the combined Shanon's entropy for distribution {X} and {X+Y} static float CombinedShannonEntropy_C(const int X[256], const int Y[256]) { int i; - double retval = 0.; + float retval = 0.f; int sumX = 0, sumXY = 0; for (i = 0; i < 256; ++i) { const int x = X[i]; @@ -418,7 +418,7 @@ static float CombinedShannonEntropy_C(const int X[256], const int Y[256]) { } } retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY); - return (float)retval; + return retval; } void VP8LBitEntropyInit(VP8LBitEntropy* const entropy) { @@ -636,17 +636,17 @@ void VP8LBundleColorMap_C(const uint8_t* const row, int width, int xbits, //------------------------------------------------------------------------------ -static double ExtraCost_C(const uint32_t* population, int length) { +static float ExtraCost_C(const uint32_t* population, int length) { int i; - double cost = 0.; + float cost = 0.f; for (i = 2; i < length - 2; ++i) cost += (i >> 1) * population[i + 2]; return cost; } -static double ExtraCostCombined_C(const uint32_t* X, const uint32_t* Y, +static float ExtraCostCombined_C(const uint32_t* X, const uint32_t* Y, int length) { int i; - double cost = 0.; + float cost = 0.f; for (i = 2; i < length - 2; ++i) { const int xy = X[i + 2] + Y[i + 2]; cost += (i >> 1) * xy; diff --git a/thirdparty/libwebp/src/dsp/lossless_enc_mips32.c b/thirdparty/libwebp/src/dsp/lossless_enc_mips32.c index 0412a093cf..639f786631 100644 --- a/thirdparty/libwebp/src/dsp/lossless_enc_mips32.c +++ b/thirdparty/libwebp/src/dsp/lossless_enc_mips32.c @@ -103,8 +103,8 @@ static float FastLog2Slow_MIPS32(uint32_t v) { // cost += i * *(pop + 1); // pop += 2; // } -// return (double)cost; -static double ExtraCost_MIPS32(const uint32_t* const population, int length) { +// return (float)cost; +static float ExtraCost_MIPS32(const uint32_t* const population, int length) { int i, temp0, temp1; const uint32_t* pop = &population[4]; const uint32_t* const LoopEnd = &population[length]; @@ -130,7 +130,7 @@ static double ExtraCost_MIPS32(const uint32_t* const population, int length) { : "memory", "hi", "lo" ); - return (double)((int64_t)temp0 << 32 | temp1); + return (float)((int64_t)temp0 << 32 | temp1); } // C version of this function: @@ -148,9 +148,9 @@ static double ExtraCost_MIPS32(const uint32_t* const population, int length) { // pX += 2; // pY += 2; // } -// return (double)cost; -static double ExtraCostCombined_MIPS32(const uint32_t* const X, - const uint32_t* const Y, int length) { +// return (float)cost; +static float ExtraCostCombined_MIPS32(const uint32_t* const X, + const uint32_t* const Y, int length) { int i, temp0, temp1, temp2, temp3; const uint32_t* pX = &X[4]; const uint32_t* pY = &Y[4]; @@ -183,7 +183,7 @@ static double ExtraCostCombined_MIPS32(const uint32_t* const X, : "memory", "hi", "lo" ); - return (double)((int64_t)temp0 << 32 | temp1); + return (float)((int64_t)temp0 << 32 | temp1); } #define HUFFMAN_COST_PASS \ @@ -347,24 +347,24 @@ static void GetCombinedEntropyUnrefined_MIPS32(const uint32_t X[], static void AddVector_MIPS32(const uint32_t* pa, const uint32_t* pb, uint32_t* pout, int size) { uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - const uint32_t end = ((size) / 4) * 4; + const int end = ((size) / 4) * 4; const uint32_t* const LoopEnd = pa + end; int i; ASM_START ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout) ASM_END_0 - for (i = end; i < size; ++i) pout[i] = pa[i] + pb[i]; + for (i = 0; i < size - end; ++i) pout[i] = pa[i] + pb[i]; } static void AddVectorEq_MIPS32(const uint32_t* pa, uint32_t* pout, int size) { uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - const uint32_t end = ((size) / 4) * 4; + const int end = ((size) / 4) * 4; const uint32_t* const LoopEnd = pa + end; int i; ASM_START ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout) ASM_END_1 - for (i = end; i < size; ++i) pout[i] += pa[i]; + for (i = 0; i < size - end; ++i) pout[i] += pa[i]; } #undef ASM_END_1 diff --git a/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c b/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c index b2f83b871c..948001a3d5 100644 --- a/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c +++ b/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c @@ -239,7 +239,7 @@ static void AddVectorEq_SSE2(const uint32_t* a, uint32_t* out, int size) { static float CombinedShannonEntropy_SSE2(const int X[256], const int Y[256]) { int i; - double retval = 0.; + float retval = 0.f; int sumX = 0, sumXY = 0; const __m128i zero = _mm_setzero_si128(); @@ -273,7 +273,7 @@ static float CombinedShannonEntropy_SSE2(const int X[256], const int Y[256]) { } } retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY); - return (float)retval; + return retval; } #else diff --git a/thirdparty/libwebp/src/dsp/yuv.c b/thirdparty/libwebp/src/dsp/yuv.c index 48466f8b11..d16c13d3ca 100644 --- a/thirdparty/libwebp/src/dsp/yuv.c +++ b/thirdparty/libwebp/src/dsp/yuv.c @@ -194,50 +194,6 @@ void WebPConvertRGBA32ToUV_C(const uint16_t* rgb, //----------------------------------------------------------------------------- -#if !WEBP_NEON_OMIT_C_CODE -#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic -static uint16_t clip_y(int v) { - return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v; -} - -static uint64_t SharpYUVUpdateY_C(const uint16_t* ref, const uint16_t* src, - uint16_t* dst, int len) { - uint64_t diff = 0; - int i; - for (i = 0; i < len; ++i) { - const int diff_y = ref[i] - src[i]; - const int new_y = (int)dst[i] + diff_y; - dst[i] = clip_y(new_y); - diff += (uint64_t)abs(diff_y); - } - return diff; -} - -static void SharpYUVUpdateRGB_C(const int16_t* ref, const int16_t* src, - int16_t* dst, int len) { - int i; - for (i = 0; i < len; ++i) { - const int diff_uv = ref[i] - src[i]; - dst[i] += diff_uv; - } -} - -static void SharpYUVFilterRow_C(const int16_t* A, const int16_t* B, int len, - const uint16_t* best_y, uint16_t* out) { - int i; - for (i = 0; i < len; ++i, ++A, ++B) { - const int v0 = (A[0] * 9 + A[1] * 3 + B[0] * 3 + B[1] + 8) >> 4; - const int v1 = (A[1] * 9 + A[0] * 3 + B[1] * 3 + B[0] + 8) >> 4; - out[2 * i + 0] = clip_y(best_y[2 * i + 0] + v0); - out[2 * i + 1] = clip_y(best_y[2 * i + 1] + v1); - } -} -#endif // !WEBP_NEON_OMIT_C_CODE - -#undef MAX_Y - -//----------------------------------------------------------------------------- - void (*WebPConvertRGB24ToY)(const uint8_t* rgb, uint8_t* y, int width); void (*WebPConvertBGR24ToY)(const uint8_t* bgr, uint8_t* y, int width); void (*WebPConvertRGBA32ToUV)(const uint16_t* rgb, @@ -247,18 +203,9 @@ void (*WebPConvertARGBToY)(const uint32_t* argb, uint8_t* y, int width); void (*WebPConvertARGBToUV)(const uint32_t* argb, uint8_t* u, uint8_t* v, int src_width, int do_store); -uint64_t (*WebPSharpYUVUpdateY)(const uint16_t* ref, const uint16_t* src, - uint16_t* dst, int len); -void (*WebPSharpYUVUpdateRGB)(const int16_t* ref, const int16_t* src, - int16_t* dst, int len); -void (*WebPSharpYUVFilterRow)(const int16_t* A, const int16_t* B, int len, - const uint16_t* best_y, uint16_t* out); - extern void WebPInitConvertARGBToYUVSSE2(void); extern void WebPInitConvertARGBToYUVSSE41(void); extern void WebPInitConvertARGBToYUVNEON(void); -extern void WebPInitSharpYUVSSE2(void); -extern void WebPInitSharpYUVNEON(void); WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) { WebPConvertARGBToY = ConvertARGBToY_C; @@ -269,17 +216,10 @@ WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) { WebPConvertRGBA32ToUV = WebPConvertRGBA32ToUV_C; -#if !WEBP_NEON_OMIT_C_CODE - WebPSharpYUVUpdateY = SharpYUVUpdateY_C; - WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_C; - WebPSharpYUVFilterRow = SharpYUVFilterRow_C; -#endif - if (VP8GetCPUInfo != NULL) { #if defined(WEBP_HAVE_SSE2) if (VP8GetCPUInfo(kSSE2)) { WebPInitConvertARGBToYUVSSE2(); - WebPInitSharpYUVSSE2(); } #endif // WEBP_HAVE_SSE2 #if defined(WEBP_HAVE_SSE41) @@ -293,7 +233,6 @@ WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) { if (WEBP_NEON_OMIT_C_CODE || (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) { WebPInitConvertARGBToYUVNEON(); - WebPInitSharpYUVNEON(); } #endif // WEBP_HAVE_NEON @@ -302,7 +241,4 @@ WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) { assert(WebPConvertRGB24ToY != NULL); assert(WebPConvertBGR24ToY != NULL); assert(WebPConvertRGBA32ToUV != NULL); - assert(WebPSharpYUVUpdateY != NULL); - assert(WebPSharpYUVUpdateRGB != NULL); - assert(WebPSharpYUVFilterRow != NULL); } diff --git a/thirdparty/libwebp/src/dsp/yuv_neon.c b/thirdparty/libwebp/src/dsp/yuv_neon.c index a34d60248f..ff77b00980 100644 --- a/thirdparty/libwebp/src/dsp/yuv_neon.c +++ b/thirdparty/libwebp/src/dsp/yuv_neon.c @@ -173,116 +173,8 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVNEON(void) { WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_NEON; } -//------------------------------------------------------------------------------ - -#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic -static uint16_t clip_y_NEON(int v) { - return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v; -} - -static uint64_t SharpYUVUpdateY_NEON(const uint16_t* ref, const uint16_t* src, - uint16_t* dst, int len) { - int i; - const int16x8_t zero = vdupq_n_s16(0); - const int16x8_t max = vdupq_n_s16(MAX_Y); - uint64x2_t sum = vdupq_n_u64(0); - uint64_t diff; - - for (i = 0; i + 8 <= len; i += 8) { - const int16x8_t A = vreinterpretq_s16_u16(vld1q_u16(ref + i)); - const int16x8_t B = vreinterpretq_s16_u16(vld1q_u16(src + i)); - const int16x8_t C = vreinterpretq_s16_u16(vld1q_u16(dst + i)); - const int16x8_t D = vsubq_s16(A, B); // diff_y - const int16x8_t F = vaddq_s16(C, D); // new_y - const uint16x8_t H = - vreinterpretq_u16_s16(vmaxq_s16(vminq_s16(F, max), zero)); - const int16x8_t I = vabsq_s16(D); // abs(diff_y) - vst1q_u16(dst + i, H); - sum = vpadalq_u32(sum, vpaddlq_u16(vreinterpretq_u16_s16(I))); - } - diff = vgetq_lane_u64(sum, 0) + vgetq_lane_u64(sum, 1); - for (; i < len; ++i) { - const int diff_y = ref[i] - src[i]; - const int new_y = (int)(dst[i]) + diff_y; - dst[i] = clip_y_NEON(new_y); - diff += (uint64_t)(abs(diff_y)); - } - return diff; -} - -static void SharpYUVUpdateRGB_NEON(const int16_t* ref, const int16_t* src, - int16_t* dst, int len) { - int i; - for (i = 0; i + 8 <= len; i += 8) { - const int16x8_t A = vld1q_s16(ref + i); - const int16x8_t B = vld1q_s16(src + i); - const int16x8_t C = vld1q_s16(dst + i); - const int16x8_t D = vsubq_s16(A, B); // diff_uv - const int16x8_t E = vaddq_s16(C, D); // new_uv - vst1q_s16(dst + i, E); - } - for (; i < len; ++i) { - const int diff_uv = ref[i] - src[i]; - dst[i] += diff_uv; - } -} - -static void SharpYUVFilterRow_NEON(const int16_t* A, const int16_t* B, int len, - const uint16_t* best_y, uint16_t* out) { - int i; - const int16x8_t max = vdupq_n_s16(MAX_Y); - const int16x8_t zero = vdupq_n_s16(0); - for (i = 0; i + 8 <= len; i += 8) { - const int16x8_t a0 = vld1q_s16(A + i + 0); - const int16x8_t a1 = vld1q_s16(A + i + 1); - const int16x8_t b0 = vld1q_s16(B + i + 0); - const int16x8_t b1 = vld1q_s16(B + i + 1); - const int16x8_t a0b1 = vaddq_s16(a0, b1); - const int16x8_t a1b0 = vaddq_s16(a1, b0); - const int16x8_t a0a1b0b1 = vaddq_s16(a0b1, a1b0); // A0+A1+B0+B1 - const int16x8_t a0b1_2 = vaddq_s16(a0b1, a0b1); // 2*(A0+B1) - const int16x8_t a1b0_2 = vaddq_s16(a1b0, a1b0); // 2*(A1+B0) - const int16x8_t c0 = vshrq_n_s16(vaddq_s16(a0b1_2, a0a1b0b1), 3); - const int16x8_t c1 = vshrq_n_s16(vaddq_s16(a1b0_2, a0a1b0b1), 3); - const int16x8_t d0 = vaddq_s16(c1, a0); - const int16x8_t d1 = vaddq_s16(c0, a1); - const int16x8_t e0 = vrshrq_n_s16(d0, 1); - const int16x8_t e1 = vrshrq_n_s16(d1, 1); - const int16x8x2_t f = vzipq_s16(e0, e1); - const int16x8_t g0 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 0)); - const int16x8_t g1 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 8)); - const int16x8_t h0 = vaddq_s16(g0, f.val[0]); - const int16x8_t h1 = vaddq_s16(g1, f.val[1]); - const int16x8_t i0 = vmaxq_s16(vminq_s16(h0, max), zero); - const int16x8_t i1 = vmaxq_s16(vminq_s16(h1, max), zero); - vst1q_u16(out + 2 * i + 0, vreinterpretq_u16_s16(i0)); - vst1q_u16(out + 2 * i + 8, vreinterpretq_u16_s16(i1)); - } - for (; i < len; ++i) { - const int a0b1 = A[i + 0] + B[i + 1]; - const int a1b0 = A[i + 1] + B[i + 0]; - const int a0a1b0b1 = a0b1 + a1b0 + 8; - const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4; - const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4; - out[2 * i + 0] = clip_y_NEON(best_y[2 * i + 0] + v0); - out[2 * i + 1] = clip_y_NEON(best_y[2 * i + 1] + v1); - } -} -#undef MAX_Y - -//------------------------------------------------------------------------------ - -extern void WebPInitSharpYUVNEON(void); - -WEBP_TSAN_IGNORE_FUNCTION void WebPInitSharpYUVNEON(void) { - WebPSharpYUVUpdateY = SharpYUVUpdateY_NEON; - WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_NEON; - WebPSharpYUVFilterRow = SharpYUVFilterRow_NEON; -} - #else // !WEBP_USE_NEON WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVNEON) -WEBP_DSP_INIT_STUB(WebPInitSharpYUVNEON) #endif // WEBP_USE_NEON diff --git a/thirdparty/libwebp/src/dsp/yuv_sse2.c b/thirdparty/libwebp/src/dsp/yuv_sse2.c index baa48d5371..970bbb7884 100644 --- a/thirdparty/libwebp/src/dsp/yuv_sse2.c +++ b/thirdparty/libwebp/src/dsp/yuv_sse2.c @@ -747,128 +747,9 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVSSE2(void) { WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_SSE2; } -//------------------------------------------------------------------------------ - -#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic -static uint16_t clip_y(int v) { - return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v; -} - -static uint64_t SharpYUVUpdateY_SSE2(const uint16_t* ref, const uint16_t* src, - uint16_t* dst, int len) { - uint64_t diff = 0; - uint32_t tmp[4]; - int i; - const __m128i zero = _mm_setzero_si128(); - const __m128i max = _mm_set1_epi16(MAX_Y); - const __m128i one = _mm_set1_epi16(1); - __m128i sum = zero; - - for (i = 0; i + 8 <= len; i += 8) { - const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i)); - const __m128i B = _mm_loadu_si128((const __m128i*)(src + i)); - const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i)); - const __m128i D = _mm_sub_epi16(A, B); // diff_y - const __m128i E = _mm_cmpgt_epi16(zero, D); // sign (-1 or 0) - const __m128i F = _mm_add_epi16(C, D); // new_y - const __m128i G = _mm_or_si128(E, one); // -1 or 1 - const __m128i H = _mm_max_epi16(_mm_min_epi16(F, max), zero); - const __m128i I = _mm_madd_epi16(D, G); // sum(abs(...)) - _mm_storeu_si128((__m128i*)(dst + i), H); - sum = _mm_add_epi32(sum, I); - } - _mm_storeu_si128((__m128i*)tmp, sum); - diff = tmp[3] + tmp[2] + tmp[1] + tmp[0]; - for (; i < len; ++i) { - const int diff_y = ref[i] - src[i]; - const int new_y = (int)dst[i] + diff_y; - dst[i] = clip_y(new_y); - diff += (uint64_t)abs(diff_y); - } - return diff; -} - -static void SharpYUVUpdateRGB_SSE2(const int16_t* ref, const int16_t* src, - int16_t* dst, int len) { - int i = 0; - for (i = 0; i + 8 <= len; i += 8) { - const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i)); - const __m128i B = _mm_loadu_si128((const __m128i*)(src + i)); - const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i)); - const __m128i D = _mm_sub_epi16(A, B); // diff_uv - const __m128i E = _mm_add_epi16(C, D); // new_uv - _mm_storeu_si128((__m128i*)(dst + i), E); - } - for (; i < len; ++i) { - const int diff_uv = ref[i] - src[i]; - dst[i] += diff_uv; - } -} - -static void SharpYUVFilterRow_SSE2(const int16_t* A, const int16_t* B, int len, - const uint16_t* best_y, uint16_t* out) { - int i; - const __m128i kCst8 = _mm_set1_epi16(8); - const __m128i max = _mm_set1_epi16(MAX_Y); - const __m128i zero = _mm_setzero_si128(); - for (i = 0; i + 8 <= len; i += 8) { - const __m128i a0 = _mm_loadu_si128((const __m128i*)(A + i + 0)); - const __m128i a1 = _mm_loadu_si128((const __m128i*)(A + i + 1)); - const __m128i b0 = _mm_loadu_si128((const __m128i*)(B + i + 0)); - const __m128i b1 = _mm_loadu_si128((const __m128i*)(B + i + 1)); - const __m128i a0b1 = _mm_add_epi16(a0, b1); - const __m128i a1b0 = _mm_add_epi16(a1, b0); - const __m128i a0a1b0b1 = _mm_add_epi16(a0b1, a1b0); // A0+A1+B0+B1 - const __m128i a0a1b0b1_8 = _mm_add_epi16(a0a1b0b1, kCst8); - const __m128i a0b1_2 = _mm_add_epi16(a0b1, a0b1); // 2*(A0+B1) - const __m128i a1b0_2 = _mm_add_epi16(a1b0, a1b0); // 2*(A1+B0) - const __m128i c0 = _mm_srai_epi16(_mm_add_epi16(a0b1_2, a0a1b0b1_8), 3); - const __m128i c1 = _mm_srai_epi16(_mm_add_epi16(a1b0_2, a0a1b0b1_8), 3); - const __m128i d0 = _mm_add_epi16(c1, a0); - const __m128i d1 = _mm_add_epi16(c0, a1); - const __m128i e0 = _mm_srai_epi16(d0, 1); - const __m128i e1 = _mm_srai_epi16(d1, 1); - const __m128i f0 = _mm_unpacklo_epi16(e0, e1); - const __m128i f1 = _mm_unpackhi_epi16(e0, e1); - const __m128i g0 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0)); - const __m128i g1 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 8)); - const __m128i h0 = _mm_add_epi16(g0, f0); - const __m128i h1 = _mm_add_epi16(g1, f1); - const __m128i i0 = _mm_max_epi16(_mm_min_epi16(h0, max), zero); - const __m128i i1 = _mm_max_epi16(_mm_min_epi16(h1, max), zero); - _mm_storeu_si128((__m128i*)(out + 2 * i + 0), i0); - _mm_storeu_si128((__m128i*)(out + 2 * i + 8), i1); - } - for (; i < len; ++i) { - // (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 = - // = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4 - // We reuse the common sub-expressions. - const int a0b1 = A[i + 0] + B[i + 1]; - const int a1b0 = A[i + 1] + B[i + 0]; - const int a0a1b0b1 = a0b1 + a1b0 + 8; - const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4; - const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4; - out[2 * i + 0] = clip_y(best_y[2 * i + 0] + v0); - out[2 * i + 1] = clip_y(best_y[2 * i + 1] + v1); - } -} - -#undef MAX_Y - -//------------------------------------------------------------------------------ - -extern void WebPInitSharpYUVSSE2(void); - -WEBP_TSAN_IGNORE_FUNCTION void WebPInitSharpYUVSSE2(void) { - WebPSharpYUVUpdateY = SharpYUVUpdateY_SSE2; - WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_SSE2; - WebPSharpYUVFilterRow = SharpYUVFilterRow_SSE2; -} - #else // !WEBP_USE_SSE2 WEBP_DSP_INIT_STUB(WebPInitSamplersSSE2) WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVSSE2) -WEBP_DSP_INIT_STUB(WebPInitSharpYUVSSE2) #endif // WEBP_USE_SSE2 diff --git a/thirdparty/libwebp/src/enc/alpha_enc.c b/thirdparty/libwebp/src/enc/alpha_enc.c index 0b54f3e6ec..f7c02690e3 100644 --- a/thirdparty/libwebp/src/enc/alpha_enc.c +++ b/thirdparty/libwebp/src/enc/alpha_enc.c @@ -86,7 +86,7 @@ static int EncodeLossless(const uint8_t* const data, int width, int height, // a decoder bug related to alpha with color cache. // See: https://code.google.com/p/webp/issues/detail?id=239 // Need to re-enable this later. - ok = (VP8LEncodeStream(&config, &picture, bw, 0 /*use_cache*/) == VP8_ENC_OK); + ok = VP8LEncodeStream(&config, &picture, bw, /*use_cache=*/0); WebPPictureFree(&picture); ok = ok && !bw->error_; if (!ok) { diff --git a/thirdparty/libwebp/src/enc/backward_references_cost_enc.c b/thirdparty/libwebp/src/enc/backward_references_cost_enc.c index 516abd73eb..6968ef3c9f 100644 --- a/thirdparty/libwebp/src/enc/backward_references_cost_enc.c +++ b/thirdparty/libwebp/src/enc/backward_references_cost_enc.c @@ -15,10 +15,11 @@ // #include <assert.h> +#include <float.h> +#include "src/dsp/lossless_common.h" #include "src/enc/backward_references_enc.h" #include "src/enc/histogram_enc.h" -#include "src/dsp/lossless_common.h" #include "src/utils/color_cache_utils.h" #include "src/utils/utils.h" @@ -30,15 +31,15 @@ extern void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs, const PixOrCopy v); typedef struct { - double alpha_[VALUES_IN_BYTE]; - double red_[VALUES_IN_BYTE]; - double blue_[VALUES_IN_BYTE]; - double distance_[NUM_DISTANCE_CODES]; - double* literal_; + float alpha_[VALUES_IN_BYTE]; + float red_[VALUES_IN_BYTE]; + float blue_[VALUES_IN_BYTE]; + float distance_[NUM_DISTANCE_CODES]; + float* literal_; } CostModel; static void ConvertPopulationCountTableToBitEstimates( - int num_symbols, const uint32_t population_counts[], double output[]) { + int num_symbols, const uint32_t population_counts[], float output[]) { uint32_t sum = 0; int nonzeros = 0; int i; @@ -51,7 +52,7 @@ static void ConvertPopulationCountTableToBitEstimates( if (nonzeros <= 1) { memset(output, 0, num_symbols * sizeof(*output)); } else { - const double logsum = VP8LFastLog2(sum); + const float logsum = VP8LFastLog2(sum); for (i = 0; i < num_symbols; ++i) { output[i] = logsum - VP8LFastLog2(population_counts[i]); } @@ -75,8 +76,8 @@ static int CostModelBuild(CostModel* const m, int xsize, int cache_bits, } ConvertPopulationCountTableToBitEstimates( - VP8LHistogramNumCodes(histo->palette_code_bits_), - histo->literal_, m->literal_); + VP8LHistogramNumCodes(histo->palette_code_bits_), histo->literal_, + m->literal_); ConvertPopulationCountTableToBitEstimates( VALUES_IN_BYTE, histo->red_, m->red_); ConvertPopulationCountTableToBitEstimates( @@ -92,27 +93,27 @@ static int CostModelBuild(CostModel* const m, int xsize, int cache_bits, return ok; } -static WEBP_INLINE double GetLiteralCost(const CostModel* const m, uint32_t v) { +static WEBP_INLINE float GetLiteralCost(const CostModel* const m, uint32_t v) { return m->alpha_[v >> 24] + m->red_[(v >> 16) & 0xff] + m->literal_[(v >> 8) & 0xff] + m->blue_[v & 0xff]; } -static WEBP_INLINE double GetCacheCost(const CostModel* const m, uint32_t idx) { +static WEBP_INLINE float GetCacheCost(const CostModel* const m, uint32_t idx) { const int literal_idx = VALUES_IN_BYTE + NUM_LENGTH_CODES + idx; return m->literal_[literal_idx]; } -static WEBP_INLINE double GetLengthCost(const CostModel* const m, - uint32_t length) { +static WEBP_INLINE float GetLengthCost(const CostModel* const m, + uint32_t length) { int code, extra_bits; VP8LPrefixEncodeBits(length, &code, &extra_bits); return m->literal_[VALUES_IN_BYTE + code] + extra_bits; } -static WEBP_INLINE double GetDistanceCost(const CostModel* const m, - uint32_t distance) { +static WEBP_INLINE float GetDistanceCost(const CostModel* const m, + uint32_t distance) { int code, extra_bits; VP8LPrefixEncodeBits(distance, &code, &extra_bits); return m->distance_[code] + extra_bits; @@ -122,20 +123,20 @@ static WEBP_INLINE void AddSingleLiteralWithCostModel( const uint32_t* const argb, VP8LColorCache* const hashers, const CostModel* const cost_model, int idx, int use_color_cache, float prev_cost, float* const cost, uint16_t* const dist_array) { - double cost_val = prev_cost; + float cost_val = prev_cost; const uint32_t color = argb[idx]; const int ix = use_color_cache ? VP8LColorCacheContains(hashers, color) : -1; if (ix >= 0) { // use_color_cache is true and hashers contains color - const double mul0 = 0.68; + const float mul0 = 0.68f; cost_val += GetCacheCost(cost_model, ix) * mul0; } else { - const double mul1 = 0.82; + const float mul1 = 0.82f; if (use_color_cache) VP8LColorCacheInsert(hashers, color); cost_val += GetLiteralCost(cost_model, color) * mul1; } if (cost[idx] > cost_val) { - cost[idx] = (float)cost_val; + cost[idx] = cost_val; dist_array[idx] = 1; // only one is inserted. } } @@ -172,7 +173,7 @@ struct CostInterval { // The GetLengthCost(cost_model, k) are cached in a CostCacheInterval. typedef struct { - double cost_; + float cost_; int start_; int end_; // Exclusive. } CostCacheInterval; @@ -187,7 +188,7 @@ typedef struct { int count_; // The number of stored intervals. CostCacheInterval* cache_intervals_; size_t cache_intervals_size_; - double cost_cache_[MAX_LENGTH]; // Contains the GetLengthCost(cost_model, k). + float cost_cache_[MAX_LENGTH]; // Contains the GetLengthCost(cost_model, k). float* costs_; uint16_t* dist_array_; // Most of the time, we only need few intervals -> use a free-list, to avoid @@ -262,10 +263,13 @@ static int CostManagerInit(CostManager* const manager, CostManagerInitFreeList(manager); // Fill in the cost_cache_. + // Has to be done in two passes due to a GCC bug on i686 + // related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 + for (i = 0; i < cost_cache_size; ++i) { + manager->cost_cache_[i] = GetLengthCost(cost_model, i); + } manager->cache_intervals_size_ = 1; - manager->cost_cache_[0] = GetLengthCost(cost_model, 0); for (i = 1; i < cost_cache_size; ++i) { - manager->cost_cache_[i] = GetLengthCost(cost_model, i); // Get the number of bound intervals. if (manager->cost_cache_[i] != manager->cost_cache_[i - 1]) { ++manager->cache_intervals_size_; @@ -294,7 +298,7 @@ static int CostManagerInit(CostManager* const manager, cur->end_ = 1; cur->cost_ = manager->cost_cache_[0]; for (i = 1; i < cost_cache_size; ++i) { - const double cost_val = manager->cost_cache_[i]; + const float cost_val = manager->cost_cache_[i]; if (cost_val != cur->cost_) { ++cur; // Initialize an interval. @@ -303,6 +307,8 @@ static int CostManagerInit(CostManager* const manager, } cur->end_ = i + 1; } + assert((size_t)(cur - manager->cache_intervals_) + 1 == + manager->cache_intervals_size_); } manager->costs_ = (float*)WebPSafeMalloc(pix_count, sizeof(*manager->costs_)); @@ -311,7 +317,7 @@ static int CostManagerInit(CostManager* const manager, return 0; } // Set the initial costs_ high for every pixel as we will keep the minimum. - for (i = 0; i < pix_count; ++i) manager->costs_[i] = 1e38f; + for (i = 0; i < pix_count; ++i) manager->costs_[i] = FLT_MAX; return 1; } @@ -457,7 +463,7 @@ static WEBP_INLINE void InsertInterval(CostManager* const manager, // If handling the interval or one of its subintervals becomes to heavy, its // contribution is added to the costs right away. static WEBP_INLINE void PushInterval(CostManager* const manager, - double distance_cost, int position, + float distance_cost, int position, int len) { size_t i; CostInterval* interval = manager->head_; @@ -474,7 +480,7 @@ static WEBP_INLINE void PushInterval(CostManager* const manager, const int k = j - position; float cost_tmp; assert(k >= 0 && k < MAX_LENGTH); - cost_tmp = (float)(distance_cost + manager->cost_cache_[k]); + cost_tmp = distance_cost + manager->cost_cache_[k]; if (manager->costs_[j] > cost_tmp) { manager->costs_[j] = cost_tmp; @@ -492,7 +498,7 @@ static WEBP_INLINE void PushInterval(CostManager* const manager, const int end = position + (cost_cache_intervals[i].end_ > len ? len : cost_cache_intervals[i].end_); - const float cost = (float)(distance_cost + cost_cache_intervals[i].cost_); + const float cost = distance_cost + cost_cache_intervals[i].cost_; for (; interval != NULL && interval->start_ < end; interval = interval_next) { @@ -570,22 +576,21 @@ static int BackwardReferencesHashChainDistanceOnly( const int pix_count = xsize * ysize; const int use_color_cache = (cache_bits > 0); const size_t literal_array_size = - sizeof(double) * (NUM_LITERAL_CODES + NUM_LENGTH_CODES + - ((cache_bits > 0) ? (1 << cache_bits) : 0)); + sizeof(float) * (VP8LHistogramNumCodes(cache_bits)); const size_t cost_model_size = sizeof(CostModel) + literal_array_size; CostModel* const cost_model = (CostModel*)WebPSafeCalloc(1ULL, cost_model_size); VP8LColorCache hashers; CostManager* cost_manager = - (CostManager*)WebPSafeMalloc(1ULL, sizeof(*cost_manager)); + (CostManager*)WebPSafeCalloc(1ULL, sizeof(*cost_manager)); int offset_prev = -1, len_prev = -1; - double offset_cost = -1; + float offset_cost = -1.f; int first_offset_is_constant = -1; // initialized with 'impossible' value int reach = 0; if (cost_model == NULL || cost_manager == NULL) goto Error; - cost_model->literal_ = (double*)(cost_model + 1); + cost_model->literal_ = (float*)(cost_model + 1); if (use_color_cache) { cc_init = VP8LColorCacheInit(&hashers, cache_bits); if (!cc_init) goto Error; @@ -675,7 +680,7 @@ static int BackwardReferencesHashChainDistanceOnly( } ok = !refs->error_; -Error: + Error: if (cc_init) VP8LColorCacheClear(&hashers); CostManagerClear(cost_manager); WebPSafeFree(cost_model); diff --git a/thirdparty/libwebp/src/enc/backward_references_enc.c b/thirdparty/libwebp/src/enc/backward_references_enc.c index 519b36a091..49a0fac034 100644 --- a/thirdparty/libwebp/src/enc/backward_references_enc.c +++ b/thirdparty/libwebp/src/enc/backward_references_enc.c @@ -10,6 +10,8 @@ // Author: Jyrki Alakuijala (jyrki@google.com) // +#include "src/enc/backward_references_enc.h" + #include <assert.h> #include <float.h> #include <math.h> @@ -17,10 +19,11 @@ #include "src/dsp/dsp.h" #include "src/dsp/lossless.h" #include "src/dsp/lossless_common.h" -#include "src/enc/backward_references_enc.h" #include "src/enc/histogram_enc.h" +#include "src/enc/vp8i_enc.h" #include "src/utils/color_cache_utils.h" #include "src/utils/utils.h" +#include "src/webp/encode.h" #define MIN_BLOCK_SIZE 256 // minimum block size for backward references @@ -255,10 +258,13 @@ static WEBP_INLINE int MaxFindCopyLength(int len) { int VP8LHashChainFill(VP8LHashChain* const p, int quality, const uint32_t* const argb, int xsize, int ysize, - int low_effort) { + int low_effort, const WebPPicture* const pic, + int percent_range, int* const percent) { const int size = xsize * ysize; const int iter_max = GetMaxItersForQuality(quality); const uint32_t window_size = GetWindowSizeForHashChain(quality, xsize); + int remaining_percent = percent_range; + int percent_start = *percent; int pos; int argb_comp; uint32_t base_position; @@ -276,7 +282,13 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality, hash_to_first_index = (int32_t*)WebPSafeMalloc(HASH_SIZE, sizeof(*hash_to_first_index)); - if (hash_to_first_index == NULL) return 0; + if (hash_to_first_index == NULL) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + return 0; + } + + percent_range = remaining_percent / 2; + remaining_percent -= percent_range; // Set the int32_t array to -1. memset(hash_to_first_index, 0xff, HASH_SIZE * sizeof(*hash_to_first_index)); @@ -323,12 +335,22 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality, hash_to_first_index[hash_code] = pos++; argb_comp = argb_comp_next; } + + if (!WebPReportProgress( + pic, percent_start + percent_range * pos / (size - 2), percent)) { + WebPSafeFree(hash_to_first_index); + return 0; + } } // Process the penultimate pixel. chain[pos] = hash_to_first_index[GetPixPairHash64(argb + pos)]; WebPSafeFree(hash_to_first_index); + percent_start += percent_range; + if (!WebPReportProgress(pic, percent_start, percent)) return 0; + percent_range = remaining_percent; + // Find the best match interval at each pixel, defined by an offset to the // pixel and a length. The right-most pixel cannot match anything to the right // (hence a best length of 0) and the left-most pixel nothing to the left @@ -417,8 +439,17 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality, max_base_position = base_position; } } + + if (!WebPReportProgress(pic, + percent_start + percent_range * + (size - 2 - base_position) / + (size - 2), + percent)) { + return 0; + } } - return 1; + + return WebPReportProgress(pic, percent_start + percent_range, percent); } static WEBP_INLINE void AddSingleLiteral(uint32_t pixel, int use_color_cache, @@ -728,7 +759,7 @@ static int CalculateBestCacheSize(const uint32_t* argb, int quality, int* const best_cache_bits) { int i; const int cache_bits_max = (quality <= 25) ? 0 : *best_cache_bits; - double entropy_min = MAX_ENTROPY; + float entropy_min = MAX_ENTROPY; int cc_init[MAX_COLOR_CACHE_BITS + 1] = { 0 }; VP8LColorCache hashers[MAX_COLOR_CACHE_BITS + 1]; VP8LRefsCursor c = VP8LRefsCursorInit(refs); @@ -813,14 +844,14 @@ static int CalculateBestCacheSize(const uint32_t* argb, int quality, } for (i = 0; i <= cache_bits_max; ++i) { - const double entropy = VP8LHistogramEstimateBits(histos[i]); + const float entropy = VP8LHistogramEstimateBits(histos[i]); if (i == 0 || entropy < entropy_min) { entropy_min = entropy; *best_cache_bits = i; } } ok = 1; -Error: + Error: for (i = 0; i <= cache_bits_max; ++i) { if (cc_init[i]) VP8LColorCacheClear(&hashers[i]); VP8LFreeHistogram(histos[i]); @@ -890,7 +921,7 @@ static int GetBackwardReferences(int width, int height, int i, lz77_type; // Index 0 is for a color cache, index 1 for no cache (if needed). int lz77_types_best[2] = {0, 0}; - double bit_costs_best[2] = {DBL_MAX, DBL_MAX}; + float bit_costs_best[2] = {FLT_MAX, FLT_MAX}; VP8LHashChain hash_chain_box; VP8LBackwardRefs* const refs_tmp = &refs[do_no_cache ? 2 : 1]; int status = 0; @@ -902,7 +933,7 @@ static int GetBackwardReferences(int width, int height, for (lz77_type = 1; lz77_types_to_try; lz77_types_to_try &= ~lz77_type, lz77_type <<= 1) { int res = 0; - double bit_cost = 0.; + float bit_cost = 0.f; if ((lz77_types_to_try & lz77_type) == 0) continue; switch (lz77_type) { case kLZ77RLE: @@ -976,15 +1007,16 @@ static int GetBackwardReferences(int width, int height, const VP8LHashChain* const hash_chain_tmp = (lz77_types_best[i] == kLZ77Standard) ? hash_chain : &hash_chain_box; const int cache_bits = (i == 1) ? 0 : *cache_bits_best; - if (VP8LBackwardReferencesTraceBackwards(width, height, argb, cache_bits, - hash_chain_tmp, &refs[i], - refs_tmp)) { - double bit_cost_trace; - VP8LHistogramCreate(histo, refs_tmp, cache_bits); - bit_cost_trace = VP8LHistogramEstimateBits(histo); - if (bit_cost_trace < bit_costs_best[i]) { - BackwardRefsSwap(refs_tmp, &refs[i]); - } + float bit_cost_trace; + if (!VP8LBackwardReferencesTraceBackwards(width, height, argb, cache_bits, + hash_chain_tmp, &refs[i], + refs_tmp)) { + goto Error; + } + VP8LHistogramCreate(histo, refs_tmp, cache_bits); + bit_cost_trace = VP8LHistogramEstimateBits(histo); + if (bit_cost_trace < bit_costs_best[i]) { + BackwardRefsSwap(refs_tmp, &refs[i]); } } @@ -1000,31 +1032,37 @@ static int GetBackwardReferences(int width, int height, } status = 1; -Error: + Error: VP8LHashChainClear(&hash_chain_box); VP8LFreeHistogram(histo); return status; } -WebPEncodingError VP8LGetBackwardReferences( +int VP8LGetBackwardReferences( int width, int height, const uint32_t* const argb, int quality, int low_effort, int lz77_types_to_try, int cache_bits_max, int do_no_cache, const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs, - int* const cache_bits_best) { + int* const cache_bits_best, const WebPPicture* const pic, int percent_range, + int* const percent) { if (low_effort) { VP8LBackwardRefs* refs_best; *cache_bits_best = cache_bits_max; refs_best = GetBackwardReferencesLowEffort( width, height, argb, cache_bits_best, hash_chain, refs); - if (refs_best == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY; + if (refs_best == NULL) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + return 0; + } // Set it in first position. BackwardRefsSwap(refs_best, &refs[0]); } else { if (!GetBackwardReferences(width, height, argb, quality, lz77_types_to_try, cache_bits_max, do_no_cache, hash_chain, refs, cache_bits_best)) { - return VP8_ENC_ERROR_OUT_OF_MEMORY; + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + return 0; } } - return VP8_ENC_OK; + + return WebPReportProgress(pic, *percent + percent_range, percent); } diff --git a/thirdparty/libwebp/src/enc/backward_references_enc.h b/thirdparty/libwebp/src/enc/backward_references_enc.h index 4c0267b41e..4dff1c27b5 100644 --- a/thirdparty/libwebp/src/enc/backward_references_enc.h +++ b/thirdparty/libwebp/src/enc/backward_references_enc.h @@ -134,10 +134,11 @@ struct VP8LHashChain { // Must be called first, to set size. int VP8LHashChainInit(VP8LHashChain* const p, int size); -// Pre-compute the best matches for argb. +// Pre-compute the best matches for argb. pic and percent are for progress. int VP8LHashChainFill(VP8LHashChain* const p, int quality, const uint32_t* const argb, int xsize, int ysize, - int low_effort); + int low_effort, const WebPPicture* const pic, + int percent_range, int* const percent); void VP8LHashChainClear(VP8LHashChain* const p); // release memory static WEBP_INLINE int VP8LHashChainFindOffset(const VP8LHashChain* const p, @@ -227,11 +228,14 @@ enum VP8LLZ77Type { // VP8LBackwardRefs is put in the first element, the best value with no-cache in // the second element. // In both cases, the last element is used as temporary internally. -WebPEncodingError VP8LGetBackwardReferences( +// pic and percent are for progress. +// Returns false in case of error (stored in pic->error_code). +int VP8LGetBackwardReferences( int width, int height, const uint32_t* const argb, int quality, int low_effort, int lz77_types_to_try, int cache_bits_max, int do_no_cache, const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs, - int* const cache_bits_best); + int* const cache_bits_best, const WebPPicture* const pic, int percent_range, + int* const percent); #ifdef __cplusplus } diff --git a/thirdparty/libwebp/src/enc/histogram_enc.c b/thirdparty/libwebp/src/enc/histogram_enc.c index 38a0cebcab..8418def2e1 100644 --- a/thirdparty/libwebp/src/enc/histogram_enc.c +++ b/thirdparty/libwebp/src/enc/histogram_enc.c @@ -13,15 +13,17 @@ #include "src/webp/config.h" #endif +#include <float.h> #include <math.h> -#include "src/enc/backward_references_enc.h" -#include "src/enc/histogram_enc.h" #include "src/dsp/lossless.h" #include "src/dsp/lossless_common.h" +#include "src/enc/backward_references_enc.h" +#include "src/enc/histogram_enc.h" +#include "src/enc/vp8i_enc.h" #include "src/utils/utils.h" -#define MAX_COST 1.e38 +#define MAX_BIT_COST FLT_MAX // Number of partitions for the three dominant (literal, red and blue) symbol // costs. @@ -228,8 +230,8 @@ void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo, // ----------------------------------------------------------------------------- // Entropy-related functions. -static WEBP_INLINE double BitsEntropyRefine(const VP8LBitEntropy* entropy) { - double mix; +static WEBP_INLINE float BitsEntropyRefine(const VP8LBitEntropy* entropy) { + float mix; if (entropy->nonzeros < 5) { if (entropy->nonzeros <= 1) { return 0; @@ -238,67 +240,67 @@ static WEBP_INLINE double BitsEntropyRefine(const VP8LBitEntropy* entropy) { // Let's mix in a bit of entropy to favor good clustering when // distributions of these are combined. if (entropy->nonzeros == 2) { - return 0.99 * entropy->sum + 0.01 * entropy->entropy; + return 0.99f * entropy->sum + 0.01f * entropy->entropy; } // No matter what the entropy says, we cannot be better than min_limit // with Huffman coding. I am mixing a bit of entropy into the // min_limit since it produces much better (~0.5 %) compression results // perhaps because of better entropy clustering. if (entropy->nonzeros == 3) { - mix = 0.95; + mix = 0.95f; } else { - mix = 0.7; // nonzeros == 4. + mix = 0.7f; // nonzeros == 4. } } else { - mix = 0.627; + mix = 0.627f; } { - double min_limit = 2 * entropy->sum - entropy->max_val; - min_limit = mix * min_limit + (1.0 - mix) * entropy->entropy; + float min_limit = 2.f * entropy->sum - entropy->max_val; + min_limit = mix * min_limit + (1.f - mix) * entropy->entropy; return (entropy->entropy < min_limit) ? min_limit : entropy->entropy; } } -double VP8LBitsEntropy(const uint32_t* const array, int n) { +float VP8LBitsEntropy(const uint32_t* const array, int n) { VP8LBitEntropy entropy; VP8LBitsEntropyUnrefined(array, n, &entropy); return BitsEntropyRefine(&entropy); } -static double InitialHuffmanCost(void) { +static float InitialHuffmanCost(void) { // Small bias because Huffman code length is typically not stored in // full length. static const int kHuffmanCodeOfHuffmanCodeSize = CODE_LENGTH_CODES * 3; - static const double kSmallBias = 9.1; + static const float kSmallBias = 9.1f; return kHuffmanCodeOfHuffmanCodeSize - kSmallBias; } // Finalize the Huffman cost based on streak numbers and length type (<3 or >=3) -static double FinalHuffmanCost(const VP8LStreaks* const stats) { +static float FinalHuffmanCost(const VP8LStreaks* const stats) { // The constants in this function are experimental and got rounded from // their original values in 1/8 when switched to 1/1024. - double retval = InitialHuffmanCost(); + float retval = InitialHuffmanCost(); // Second coefficient: Many zeros in the histogram are covered efficiently // by a run-length encode. Originally 2/8. - retval += stats->counts[0] * 1.5625 + 0.234375 * stats->streaks[0][1]; + retval += stats->counts[0] * 1.5625f + 0.234375f * stats->streaks[0][1]; // Second coefficient: Constant values are encoded less efficiently, but still // RLE'ed. Originally 6/8. - retval += stats->counts[1] * 2.578125 + 0.703125 * stats->streaks[1][1]; + retval += stats->counts[1] * 2.578125f + 0.703125f * stats->streaks[1][1]; // 0s are usually encoded more efficiently than non-0s. // Originally 15/8. - retval += 1.796875 * stats->streaks[0][0]; + retval += 1.796875f * stats->streaks[0][0]; // Originally 26/8. - retval += 3.28125 * stats->streaks[1][0]; + retval += 3.28125f * stats->streaks[1][0]; return retval; } // Get the symbol entropy for the distribution 'population'. // Set 'trivial_sym', if there's only one symbol present in the distribution. -static double PopulationCost(const uint32_t* const population, int length, - uint32_t* const trivial_sym, - uint8_t* const is_used) { +static float PopulationCost(const uint32_t* const population, int length, + uint32_t* const trivial_sym, + uint8_t* const is_used) { VP8LBitEntropy bit_entropy; VP8LStreaks stats; VP8LGetEntropyUnrefined(population, length, &bit_entropy, &stats); @@ -314,11 +316,10 @@ static double PopulationCost(const uint32_t* const population, int length, // trivial_at_end is 1 if the two histograms only have one element that is // non-zero: both the zero-th one, or both the last one. -static WEBP_INLINE double GetCombinedEntropy(const uint32_t* const X, - const uint32_t* const Y, - int length, int is_X_used, - int is_Y_used, - int trivial_at_end) { +static WEBP_INLINE float GetCombinedEntropy(const uint32_t* const X, + const uint32_t* const Y, int length, + int is_X_used, int is_Y_used, + int trivial_at_end) { VP8LStreaks stats; if (trivial_at_end) { // This configuration is due to palettization that transforms an indexed @@ -356,7 +357,7 @@ static WEBP_INLINE double GetCombinedEntropy(const uint32_t* const X, } // Estimates the Entropy + Huffman + other block overhead size cost. -double VP8LHistogramEstimateBits(VP8LHistogram* const p) { +float VP8LHistogramEstimateBits(VP8LHistogram* const p) { return PopulationCost(p->literal_, VP8LHistogramNumCodes(p->palette_code_bits_), NULL, &p->is_used_[0]) @@ -373,8 +374,7 @@ double VP8LHistogramEstimateBits(VP8LHistogram* const p) { static int GetCombinedHistogramEntropy(const VP8LHistogram* const a, const VP8LHistogram* const b, - double cost_threshold, - double* cost) { + float cost_threshold, float* cost) { const int palette_code_bits = a->palette_code_bits_; int trivial_at_end = 0; assert(a->palette_code_bits_ == b->palette_code_bits_); @@ -439,12 +439,11 @@ static WEBP_INLINE void HistogramAdd(const VP8LHistogram* const a, // Since the previous score passed is 'cost_threshold', we only need to compare // the partial cost against 'cost_threshold + C(a) + C(b)' to possibly bail-out // early. -static double HistogramAddEval(const VP8LHistogram* const a, - const VP8LHistogram* const b, - VP8LHistogram* const out, - double cost_threshold) { - double cost = 0; - const double sum_cost = a->bit_cost_ + b->bit_cost_; +static float HistogramAddEval(const VP8LHistogram* const a, + const VP8LHistogram* const b, + VP8LHistogram* const out, float cost_threshold) { + float cost = 0; + const float sum_cost = a->bit_cost_ + b->bit_cost_; cost_threshold += sum_cost; if (GetCombinedHistogramEntropy(a, b, cost_threshold, &cost)) { @@ -459,10 +458,10 @@ static double HistogramAddEval(const VP8LHistogram* const a, // Same as HistogramAddEval(), except that the resulting histogram // is not stored. Only the cost C(a+b) - C(a) is evaluated. We omit // the term C(b) which is constant over all the evaluations. -static double HistogramAddThresh(const VP8LHistogram* const a, - const VP8LHistogram* const b, - double cost_threshold) { - double cost; +static float HistogramAddThresh(const VP8LHistogram* const a, + const VP8LHistogram* const b, + float cost_threshold) { + float cost; assert(a != NULL && b != NULL); cost = -a->bit_cost_; GetCombinedHistogramEntropy(a, b, cost_threshold, &cost); @@ -473,24 +472,22 @@ static double HistogramAddThresh(const VP8LHistogram* const a, // The structure to keep track of cost range for the three dominant entropy // symbols. -// TODO(skal): Evaluate if float can be used here instead of double for -// representing the entropy costs. typedef struct { - double literal_max_; - double literal_min_; - double red_max_; - double red_min_; - double blue_max_; - double blue_min_; + float literal_max_; + float literal_min_; + float red_max_; + float red_min_; + float blue_max_; + float blue_min_; } DominantCostRange; static void DominantCostRangeInit(DominantCostRange* const c) { c->literal_max_ = 0.; - c->literal_min_ = MAX_COST; + c->literal_min_ = MAX_BIT_COST; c->red_max_ = 0.; - c->red_min_ = MAX_COST; + c->red_min_ = MAX_BIT_COST; c->blue_max_ = 0.; - c->blue_min_ = MAX_COST; + c->blue_min_ = MAX_BIT_COST; } static void UpdateDominantCostRange( @@ -505,10 +502,9 @@ static void UpdateDominantCostRange( static void UpdateHistogramCost(VP8LHistogram* const h) { uint32_t alpha_sym, red_sym, blue_sym; - const double alpha_cost = - PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym, - &h->is_used_[3]); - const double distance_cost = + const float alpha_cost = + PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym, &h->is_used_[3]); + const float distance_cost = PopulationCost(h->distance_, NUM_DISTANCE_CODES, NULL, &h->is_used_[4]) + VP8LExtraCost(h->distance_, NUM_DISTANCE_CODES); const int num_codes = VP8LHistogramNumCodes(h->palette_code_bits_); @@ -529,10 +525,10 @@ static void UpdateHistogramCost(VP8LHistogram* const h) { } } -static int GetBinIdForEntropy(double min, double max, double val) { - const double range = max - min; +static int GetBinIdForEntropy(float min, float max, float val) { + const float range = max - min; if (range > 0.) { - const double delta = val - min; + const float delta = val - min; return (int)((NUM_PARTITIONS - 1e-6) * delta / range); } else { return 0; @@ -641,15 +637,11 @@ static void HistogramAnalyzeEntropyBin(VP8LHistogramSet* const image_histo, // Merges some histograms with same bin_id together if it's advantageous. // Sets the remaining histograms to NULL. -static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo, - int* num_used, - const uint16_t* const clusters, - uint16_t* const cluster_mappings, - VP8LHistogram* cur_combo, - const uint16_t* const bin_map, - int num_bins, - double combine_cost_factor, - int low_effort) { +static void HistogramCombineEntropyBin( + VP8LHistogramSet* const image_histo, int* num_used, + const uint16_t* const clusters, uint16_t* const cluster_mappings, + VP8LHistogram* cur_combo, const uint16_t* const bin_map, int num_bins, + float combine_cost_factor, int low_effort) { VP8LHistogram** const histograms = image_histo->histograms; int idx; struct { @@ -679,11 +671,10 @@ static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo, cluster_mappings[clusters[idx]] = clusters[first]; } else { // try to merge #idx into #first (both share the same bin_id) - const double bit_cost = histograms[idx]->bit_cost_; - const double bit_cost_thresh = -bit_cost * combine_cost_factor; - const double curr_cost_diff = - HistogramAddEval(histograms[first], histograms[idx], - cur_combo, bit_cost_thresh); + const float bit_cost = histograms[idx]->bit_cost_; + const float bit_cost_thresh = -bit_cost * combine_cost_factor; + const float curr_cost_diff = HistogramAddEval( + histograms[first], histograms[idx], cur_combo, bit_cost_thresh); if (curr_cost_diff < bit_cost_thresh) { // Try to merge two histograms only if the combo is a trivial one or // the two candidate histograms are already non-trivial. @@ -731,8 +722,8 @@ static uint32_t MyRand(uint32_t* const seed) { typedef struct { int idx1; int idx2; - double cost_diff; - double cost_combo; + float cost_diff; + float cost_combo; } HistogramPair; typedef struct { @@ -787,10 +778,9 @@ static void HistoQueueUpdateHead(HistoQueue* const histo_queue, // Update the cost diff and combo of a pair of histograms. This needs to be // called when the the histograms have been merged with a third one. static void HistoQueueUpdatePair(const VP8LHistogram* const h1, - const VP8LHistogram* const h2, - double threshold, + const VP8LHistogram* const h2, float threshold, HistogramPair* const pair) { - const double sum_cost = h1->bit_cost_ + h2->bit_cost_; + const float sum_cost = h1->bit_cost_ + h2->bit_cost_; pair->cost_combo = 0.; GetCombinedHistogramEntropy(h1, h2, sum_cost + threshold, &pair->cost_combo); pair->cost_diff = pair->cost_combo - sum_cost; @@ -799,9 +789,9 @@ static void HistoQueueUpdatePair(const VP8LHistogram* const h1, // Create a pair from indices "idx1" and "idx2" provided its cost // is inferior to "threshold", a negative entropy. // It returns the cost of the pair, or 0. if it superior to threshold. -static double HistoQueuePush(HistoQueue* const histo_queue, - VP8LHistogram** const histograms, int idx1, - int idx2, double threshold) { +static float HistoQueuePush(HistoQueue* const histo_queue, + VP8LHistogram** const histograms, int idx1, + int idx2, float threshold) { const VP8LHistogram* h1; const VP8LHistogram* h2; HistogramPair pair; @@ -945,8 +935,8 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo, ++tries_with_no_success < num_tries_no_success; ++iter) { int* mapping_index; - double best_cost = - (histo_queue.size == 0) ? 0. : histo_queue.queue[0].cost_diff; + float best_cost = + (histo_queue.size == 0) ? 0.f : histo_queue.queue[0].cost_diff; int best_idx1 = -1, best_idx2 = 1; const uint32_t rand_range = (*num_used - 1) * (*num_used); // (*num_used) / 2 was chosen empirically. Less means faster but worse @@ -955,7 +945,7 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo, // Pick random samples. for (j = 0; *num_used >= 2 && j < num_tries; ++j) { - double curr_cost; + float curr_cost; // Choose two different histograms at random and try to combine them. const uint32_t tmp = MyRand(&seed) % rand_range; uint32_t idx1 = tmp / (*num_used - 1); @@ -1034,7 +1024,7 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo, *do_greedy = (*num_used <= min_cluster_size); ok = 1; -End: + End: HistoQueueClear(&histo_queue); WebPSafeFree(mappings); return ok; @@ -1057,7 +1047,7 @@ static void HistogramRemap(const VP8LHistogramSet* const in, if (out_size > 1) { for (i = 0; i < in_size; ++i) { int best_out = 0; - double best_bits = MAX_COST; + float best_bits = MAX_BIT_COST; int k; if (in_histo[i] == NULL) { // Arbitrarily set to the previous value if unused to help future LZ77. @@ -1065,7 +1055,7 @@ static void HistogramRemap(const VP8LHistogramSet* const in, continue; } for (k = 0; k < out_size; ++k) { - double cur_bits; + float cur_bits; cur_bits = HistogramAddThresh(out_histo[k], in_histo[i], best_bits); if (k == 0 || cur_bits < best_bits) { best_bits = cur_bits; @@ -1093,13 +1083,13 @@ static void HistogramRemap(const VP8LHistogramSet* const in, } } -static double GetCombineCostFactor(int histo_size, int quality) { - double combine_cost_factor = 0.16; +static float GetCombineCostFactor(int histo_size, int quality) { + float combine_cost_factor = 0.16f; if (quality < 90) { - if (histo_size > 256) combine_cost_factor /= 2.; - if (histo_size > 512) combine_cost_factor /= 2.; - if (histo_size > 1024) combine_cost_factor /= 2.; - if (quality <= 50) combine_cost_factor /= 2.; + if (histo_size > 256) combine_cost_factor /= 2.f; + if (histo_size > 512) combine_cost_factor /= 2.f; + if (histo_size > 1024) combine_cost_factor /= 2.f; + if (quality <= 50) combine_cost_factor /= 2.f; } return combine_cost_factor; } @@ -1169,13 +1159,13 @@ static void RemoveEmptyHistograms(VP8LHistogramSet* const image_histo) { } int VP8LGetHistoImageSymbols(int xsize, int ysize, - const VP8LBackwardRefs* const refs, - int quality, int low_effort, - int histogram_bits, int cache_bits, + const VP8LBackwardRefs* const refs, int quality, + int low_effort, int histogram_bits, int cache_bits, VP8LHistogramSet* const image_histo, VP8LHistogram* const tmp_histo, - uint16_t* const histogram_symbols) { - int ok = 0; + uint16_t* const histogram_symbols, + const WebPPicture* const pic, int percent_range, + int* const percent) { const int histo_xsize = histogram_bits ? VP8LSubSampleSize(xsize, histogram_bits) : 1; const int histo_ysize = @@ -1192,7 +1182,10 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize, WebPSafeMalloc(2 * image_histo_raw_size, sizeof(map_tmp)); uint16_t* const cluster_mappings = map_tmp + image_histo_raw_size; int num_used = image_histo_raw_size; - if (orig_histo == NULL || map_tmp == NULL) goto Error; + if (orig_histo == NULL || map_tmp == NULL) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } // Construct the histograms from backward references. HistogramBuild(xsize, histogram_bits, refs, orig_histo); @@ -1206,16 +1199,15 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize, if (entropy_combine) { uint16_t* const bin_map = map_tmp; - const double combine_cost_factor = + const float combine_cost_factor = GetCombineCostFactor(image_histo_raw_size, quality); const uint32_t num_clusters = num_used; HistogramAnalyzeEntropyBin(image_histo, bin_map, low_effort); // Collapse histograms with similar entropy. - HistogramCombineEntropyBin(image_histo, &num_used, histogram_symbols, - cluster_mappings, tmp_histo, bin_map, - entropy_combine_num_bins, combine_cost_factor, - low_effort); + HistogramCombineEntropyBin( + image_histo, &num_used, histogram_symbols, cluster_mappings, tmp_histo, + bin_map, entropy_combine_num_bins, combine_cost_factor, low_effort); OptimizeHistogramSymbols(image_histo, cluster_mappings, num_clusters, map_tmp, histogram_symbols); } @@ -1229,11 +1221,13 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize, int do_greedy; if (!HistogramCombineStochastic(image_histo, &num_used, threshold_size, &do_greedy)) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } if (do_greedy) { RemoveEmptyHistograms(image_histo); if (!HistogramCombineGreedy(image_histo, &num_used)) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } } @@ -1243,10 +1237,12 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize, RemoveEmptyHistograms(image_histo); HistogramRemap(orig_histo, image_histo, histogram_symbols); - ok = 1; + if (!WebPReportProgress(pic, *percent + percent_range, percent)) { + goto Error; + } Error: VP8LFreeHistogramSet(orig_histo); WebPSafeFree(map_tmp); - return ok; + return (pic->error_code == VP8_ENC_OK); } diff --git a/thirdparty/libwebp/src/enc/histogram_enc.h b/thirdparty/libwebp/src/enc/histogram_enc.h index c3428b5d55..4c0bb97464 100644 --- a/thirdparty/libwebp/src/enc/histogram_enc.h +++ b/thirdparty/libwebp/src/enc/histogram_enc.h @@ -40,10 +40,10 @@ typedef struct { int palette_code_bits_; uint32_t trivial_symbol_; // True, if histograms for Red, Blue & Alpha // literal symbols are single valued. - double bit_cost_; // cached value of bit cost. - double literal_cost_; // Cached values of dominant entropy costs: - double red_cost_; // literal, red & blue. - double blue_cost_; + float bit_cost_; // cached value of bit cost. + float literal_cost_; // Cached values of dominant entropy costs: + float red_cost_; // literal, red & blue. + float blue_cost_; uint8_t is_used_[5]; // 5 for literal, red, blue, alpha, distance } VP8LHistogram; @@ -105,21 +105,23 @@ static WEBP_INLINE int VP8LHistogramNumCodes(int palette_code_bits) { ((palette_code_bits > 0) ? (1 << palette_code_bits) : 0); } -// Builds the histogram image. +// Builds the histogram image. pic and percent are for progress. +// Returns false in case of error (stored in pic->error_code). int VP8LGetHistoImageSymbols(int xsize, int ysize, - const VP8LBackwardRefs* const refs, - int quality, int low_effort, - int histogram_bits, int cache_bits, + const VP8LBackwardRefs* const refs, int quality, + int low_effort, int histogram_bits, int cache_bits, VP8LHistogramSet* const image_histo, VP8LHistogram* const tmp_histo, - uint16_t* const histogram_symbols); + uint16_t* const histogram_symbols, + const WebPPicture* const pic, int percent_range, + int* const percent); // Returns the entropy for the symbols in the input array. -double VP8LBitsEntropy(const uint32_t* const array, int n); +float VP8LBitsEntropy(const uint32_t* const array, int n); // Estimate how many bits the combined entropy of literals and distance // approximately maps to. -double VP8LHistogramEstimateBits(VP8LHistogram* const p); +float VP8LHistogramEstimateBits(VP8LHistogram* const p); #ifdef __cplusplus } diff --git a/thirdparty/libwebp/src/enc/picture_csp_enc.c b/thirdparty/libwebp/src/enc/picture_csp_enc.c index 35eede9635..fabebcf202 100644 --- a/thirdparty/libwebp/src/enc/picture_csp_enc.c +++ b/thirdparty/libwebp/src/enc/picture_csp_enc.c @@ -15,12 +15,19 @@ #include <stdlib.h> #include <math.h> +#include "sharpyuv/sharpyuv.h" +#include "sharpyuv/sharpyuv_csp.h" #include "src/enc/vp8i_enc.h" #include "src/utils/random_utils.h" #include "src/utils/utils.h" #include "src/dsp/dsp.h" #include "src/dsp/lossless.h" #include "src/dsp/yuv.h" +#include "src/dsp/cpu.h" + +#if defined(WEBP_USE_THREAD) && !defined(_WIN32) +#include <pthread.h> +#endif // Uncomment to disable gamma-compression during RGB->U/V averaging #define USE_GAMMA_COMPRESSION @@ -76,16 +83,16 @@ int WebPPictureHasTransparency(const WebPPicture* picture) { #if defined(USE_GAMMA_COMPRESSION) -// gamma-compensates loss of resolution during chroma subsampling -#define kGamma 0.80 // for now we use a different gamma value than kGammaF -#define kGammaFix 12 // fixed-point precision for linear values -#define kGammaScale ((1 << kGammaFix) - 1) -#define kGammaTabFix 7 // fixed-point fractional bits precision -#define kGammaTabScale (1 << kGammaTabFix) -#define kGammaTabRounder (kGammaTabScale >> 1) -#define kGammaTabSize (1 << (kGammaFix - kGammaTabFix)) +// Gamma correction compensates loss of resolution during chroma subsampling. +#define GAMMA_FIX 12 // fixed-point precision for linear values +#define GAMMA_TAB_FIX 7 // fixed-point fractional bits precision +#define GAMMA_TAB_SIZE (1 << (GAMMA_FIX - GAMMA_TAB_FIX)) +static const double kGamma = 0.80; +static const int kGammaScale = ((1 << GAMMA_FIX) - 1); +static const int kGammaTabScale = (1 << GAMMA_TAB_FIX); +static const int kGammaTabRounder = (1 << GAMMA_TAB_FIX >> 1); -static int kLinearToGammaTab[kGammaTabSize + 1]; +static int kLinearToGammaTab[GAMMA_TAB_SIZE + 1]; static uint16_t kGammaToLinearTab[256]; static volatile int kGammaTablesOk = 0; static void InitGammaTables(void); @@ -93,13 +100,13 @@ static void InitGammaTables(void); WEBP_DSP_INIT_FUNC(InitGammaTables) { if (!kGammaTablesOk) { int v; - const double scale = (double)(1 << kGammaTabFix) / kGammaScale; + const double scale = (double)(1 << GAMMA_TAB_FIX) / kGammaScale; const double norm = 1. / 255.; for (v = 0; v <= 255; ++v) { kGammaToLinearTab[v] = (uint16_t)(pow(norm * v, kGamma) * kGammaScale + .5); } - for (v = 0; v <= kGammaTabSize; ++v) { + for (v = 0; v <= GAMMA_TAB_SIZE; ++v) { kLinearToGammaTab[v] = (int)(255. * pow(scale * v, 1. / kGamma) + .5); } kGammaTablesOk = 1; @@ -111,12 +118,12 @@ static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) { } static WEBP_INLINE int Interpolate(int v) { - const int tab_pos = v >> (kGammaTabFix + 2); // integer part + const int tab_pos = v >> (GAMMA_TAB_FIX + 2); // integer part const int x = v & ((kGammaTabScale << 2) - 1); // fractional part const int v0 = kLinearToGammaTab[tab_pos]; const int v1 = kLinearToGammaTab[tab_pos + 1]; const int y = v1 * x + v0 * ((kGammaTabScale << 2) - x); // interpolate - assert(tab_pos + 1 < kGammaTabSize + 1); + assert(tab_pos + 1 < GAMMA_TAB_SIZE + 1); return y; } @@ -124,7 +131,7 @@ static WEBP_INLINE int Interpolate(int v) { // U/V value, suitable for RGBToU/V calls. static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) { const int y = Interpolate(base_value << shift); // final uplifted value - return (y + kGammaTabRounder) >> kGammaTabFix; // descale + return (y + kGammaTabRounder) >> GAMMA_TAB_FIX; // descale } #else @@ -158,415 +165,41 @@ static int RGBToV(int r, int g, int b, VP8Random* const rg) { //------------------------------------------------------------------------------ // Sharp RGB->YUV conversion -static const int kNumIterations = 4; static const int kMinDimensionIterativeConversion = 4; -// We could use SFIX=0 and only uint8_t for fixed_y_t, but it produces some -// banding sometimes. Better use extra precision. -#define SFIX 2 // fixed-point precision of RGB and Y/W -typedef int16_t fixed_t; // signed type with extra SFIX precision for UV -typedef uint16_t fixed_y_t; // unsigned type with extra SFIX precision for W - -#define SHALF (1 << SFIX >> 1) -#define MAX_Y_T ((256 << SFIX) - 1) -#define SROUNDER (1 << (YUV_FIX + SFIX - 1)) - -#if defined(USE_GAMMA_COMPRESSION) - -// We use tables of different size and precision for the Rec709 / BT2020 -// transfer function. -#define kGammaF (1./0.45) -static uint32_t kLinearToGammaTabS[kGammaTabSize + 2]; -#define GAMMA_TO_LINEAR_BITS 14 -static uint32_t kGammaToLinearTabS[MAX_Y_T + 1]; // size scales with Y_FIX -static volatile int kGammaTablesSOk = 0; -static void InitGammaTablesS(void); - -WEBP_DSP_INIT_FUNC(InitGammaTablesS) { - assert(2 * GAMMA_TO_LINEAR_BITS < 32); // we use uint32_t intermediate values - if (!kGammaTablesSOk) { - int v; - const double norm = 1. / MAX_Y_T; - const double scale = 1. / kGammaTabSize; - const double a = 0.09929682680944; - const double thresh = 0.018053968510807; - const double final_scale = 1 << GAMMA_TO_LINEAR_BITS; - for (v = 0; v <= MAX_Y_T; ++v) { - const double g = norm * v; - double value; - if (g <= thresh * 4.5) { - value = g / 4.5; - } else { - const double a_rec = 1. / (1. + a); - value = pow(a_rec * (g + a), kGammaF); - } - kGammaToLinearTabS[v] = (uint32_t)(value * final_scale + .5); - } - for (v = 0; v <= kGammaTabSize; ++v) { - const double g = scale * v; - double value; - if (g <= thresh) { - value = 4.5 * g; - } else { - value = (1. + a) * pow(g, 1. / kGammaF) - a; - } - // we already incorporate the 1/2 rounding constant here - kLinearToGammaTabS[v] = - (uint32_t)(MAX_Y_T * value) + (1 << GAMMA_TO_LINEAR_BITS >> 1); - } - // to prevent small rounding errors to cause read-overflow: - kLinearToGammaTabS[kGammaTabSize + 1] = kLinearToGammaTabS[kGammaTabSize]; - kGammaTablesSOk = 1; - } -} - -// return value has a fixed-point precision of GAMMA_TO_LINEAR_BITS -static WEBP_INLINE uint32_t GammaToLinearS(int v) { - return kGammaToLinearTabS[v]; -} - -static WEBP_INLINE uint32_t LinearToGammaS(uint32_t value) { - // 'value' is in GAMMA_TO_LINEAR_BITS fractional precision - const uint32_t v = value * kGammaTabSize; - const uint32_t tab_pos = v >> GAMMA_TO_LINEAR_BITS; - // fractional part, in GAMMA_TO_LINEAR_BITS fixed-point precision - const uint32_t x = v - (tab_pos << GAMMA_TO_LINEAR_BITS); // fractional part - // v0 / v1 are in GAMMA_TO_LINEAR_BITS fixed-point precision (range [0..1]) - const uint32_t v0 = kLinearToGammaTabS[tab_pos + 0]; - const uint32_t v1 = kLinearToGammaTabS[tab_pos + 1]; - // Final interpolation. Note that rounding is already included. - const uint32_t v2 = (v1 - v0) * x; // note: v1 >= v0. - const uint32_t result = v0 + (v2 >> GAMMA_TO_LINEAR_BITS); - return result; -} - -#else - -static void InitGammaTablesS(void) {} -static WEBP_INLINE uint32_t GammaToLinearS(int v) { - return (v << GAMMA_TO_LINEAR_BITS) / MAX_Y_T; -} -static WEBP_INLINE uint32_t LinearToGammaS(uint32_t value) { - return (MAX_Y_T * value) >> GAMMA_TO_LINEAR_BITS; -} - -#endif // USE_GAMMA_COMPRESSION - -//------------------------------------------------------------------------------ - -static uint8_t clip_8b(fixed_t v) { - return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u; -} - -static fixed_y_t clip_y(int y) { - return (!(y & ~MAX_Y_T)) ? (fixed_y_t)y : (y < 0) ? 0 : MAX_Y_T; -} - -//------------------------------------------------------------------------------ - -static int RGBToGray(int r, int g, int b) { - const int luma = 13933 * r + 46871 * g + 4732 * b + YUV_HALF; - return (luma >> YUV_FIX); -} - -static uint32_t ScaleDown(int a, int b, int c, int d) { - const uint32_t A = GammaToLinearS(a); - const uint32_t B = GammaToLinearS(b); - const uint32_t C = GammaToLinearS(c); - const uint32_t D = GammaToLinearS(d); - return LinearToGammaS((A + B + C + D + 2) >> 2); -} - -static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w) { - int i; - for (i = 0; i < w; ++i) { - const uint32_t R = GammaToLinearS(src[0 * w + i]); - const uint32_t G = GammaToLinearS(src[1 * w + i]); - const uint32_t B = GammaToLinearS(src[2 * w + i]); - const uint32_t Y = RGBToGray(R, G, B); - dst[i] = (fixed_y_t)LinearToGammaS(Y); - } -} - -static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2, - fixed_t* dst, int uv_w) { - int i; - for (i = 0; i < uv_w; ++i) { - const int r = ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1], - src2[0 * uv_w + 0], src2[0 * uv_w + 1]); - const int g = ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1], - src2[2 * uv_w + 0], src2[2 * uv_w + 1]); - const int b = ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1], - src2[4 * uv_w + 0], src2[4 * uv_w + 1]); - const int W = RGBToGray(r, g, b); - dst[0 * uv_w] = (fixed_t)(r - W); - dst[1 * uv_w] = (fixed_t)(g - W); - dst[2 * uv_w] = (fixed_t)(b - W); - dst += 1; - src1 += 2; - src2 += 2; - } -} - -static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) { - int i; - for (i = 0; i < w; ++i) { - y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]); - } -} - -//------------------------------------------------------------------------------ - -static WEBP_INLINE fixed_y_t Filter2(int A, int B, int W0) { - const int v0 = (A * 3 + B + 2) >> 2; - return clip_y(v0 + W0); -} - //------------------------------------------------------------------------------ +// Main function -static WEBP_INLINE fixed_y_t UpLift(uint8_t a) { // 8bit -> SFIX - return ((fixed_y_t)a << SFIX) | SHALF; -} - -static void ImportOneRow(const uint8_t* const r_ptr, - const uint8_t* const g_ptr, - const uint8_t* const b_ptr, - int step, - int pic_width, - fixed_y_t* const dst) { - int i; - const int w = (pic_width + 1) & ~1; - for (i = 0; i < pic_width; ++i) { - const int off = i * step; - dst[i + 0 * w] = UpLift(r_ptr[off]); - dst[i + 1 * w] = UpLift(g_ptr[off]); - dst[i + 2 * w] = UpLift(b_ptr[off]); - } - if (pic_width & 1) { // replicate rightmost pixel - dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1]; - dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1]; - dst[pic_width + 2 * w] = dst[pic_width + 2 * w - 1]; - } -} - -static void InterpolateTwoRows(const fixed_y_t* const best_y, - const fixed_t* prev_uv, - const fixed_t* cur_uv, - const fixed_t* next_uv, - int w, - fixed_y_t* out1, - fixed_y_t* out2) { - const int uv_w = w >> 1; - const int len = (w - 1) >> 1; // length to filter - int k = 3; - while (k-- > 0) { // process each R/G/B segments in turn - // special boundary case for i==0 - out1[0] = Filter2(cur_uv[0], prev_uv[0], best_y[0]); - out2[0] = Filter2(cur_uv[0], next_uv[0], best_y[w]); - - WebPSharpYUVFilterRow(cur_uv, prev_uv, len, best_y + 0 + 1, out1 + 1); - WebPSharpYUVFilterRow(cur_uv, next_uv, len, best_y + w + 1, out2 + 1); - - // special boundary case for i == w - 1 when w is even - if (!(w & 1)) { - out1[w - 1] = Filter2(cur_uv[uv_w - 1], prev_uv[uv_w - 1], - best_y[w - 1 + 0]); - out2[w - 1] = Filter2(cur_uv[uv_w - 1], next_uv[uv_w - 1], - best_y[w - 1 + w]); - } - out1 += w; - out2 += w; - prev_uv += uv_w; - cur_uv += uv_w; - next_uv += uv_w; - } -} - -static WEBP_INLINE uint8_t ConvertRGBToY(int r, int g, int b) { - const int luma = 16839 * r + 33059 * g + 6420 * b + SROUNDER; - return clip_8b(16 + (luma >> (YUV_FIX + SFIX))); -} +extern void SharpYuvInit(VP8CPUInfo cpu_info_func); -static WEBP_INLINE uint8_t ConvertRGBToU(int r, int g, int b) { - const int u = -9719 * r - 19081 * g + 28800 * b + SROUNDER; - return clip_8b(128 + (u >> (YUV_FIX + SFIX))); -} +static void SafeInitSharpYuv(void) { +#if defined(WEBP_USE_THREAD) && !defined(_WIN32) + static pthread_mutex_t initsharpyuv_lock = PTHREAD_MUTEX_INITIALIZER; + if (pthread_mutex_lock(&initsharpyuv_lock)) return; +#endif -static WEBP_INLINE uint8_t ConvertRGBToV(int r, int g, int b) { - const int v = +28800 * r - 24116 * g - 4684 * b + SROUNDER; - return clip_8b(128 + (v >> (YUV_FIX + SFIX))); -} + SharpYuvInit(VP8GetCPUInfo); -static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv, - WebPPicture* const picture) { - int i, j; - uint8_t* dst_y = picture->y; - uint8_t* dst_u = picture->u; - uint8_t* dst_v = picture->v; - const fixed_t* const best_uv_base = best_uv; - const int w = (picture->width + 1) & ~1; - const int h = (picture->height + 1) & ~1; - const int uv_w = w >> 1; - const int uv_h = h >> 1; - for (best_uv = best_uv_base, j = 0; j < picture->height; ++j) { - for (i = 0; i < picture->width; ++i) { - const int off = (i >> 1); - const int W = best_y[i]; - const int r = best_uv[off + 0 * uv_w] + W; - const int g = best_uv[off + 1 * uv_w] + W; - const int b = best_uv[off + 2 * uv_w] + W; - dst_y[i] = ConvertRGBToY(r, g, b); - } - best_y += w; - best_uv += (j & 1) * 3 * uv_w; - dst_y += picture->y_stride; - } - for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) { - for (i = 0; i < uv_w; ++i) { - const int off = i; - const int r = best_uv[off + 0 * uv_w]; - const int g = best_uv[off + 1 * uv_w]; - const int b = best_uv[off + 2 * uv_w]; - dst_u[i] = ConvertRGBToU(r, g, b); - dst_v[i] = ConvertRGBToV(r, g, b); - } - best_uv += 3 * uv_w; - dst_u += picture->uv_stride; - dst_v += picture->uv_stride; - } - return 1; +#if defined(WEBP_USE_THREAD) && !defined(_WIN32) + (void)pthread_mutex_unlock(&initsharpyuv_lock); +#endif } -//------------------------------------------------------------------------------ -// Main function - -#define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((W) * (H), sizeof(T))) - static int PreprocessARGB(const uint8_t* r_ptr, const uint8_t* g_ptr, const uint8_t* b_ptr, int step, int rgb_stride, WebPPicture* const picture) { - // we expand the right/bottom border if needed - const int w = (picture->width + 1) & ~1; - const int h = (picture->height + 1) & ~1; - const int uv_w = w >> 1; - const int uv_h = h >> 1; - uint64_t prev_diff_y_sum = ~0; - int j, iter; - - // TODO(skal): allocate one big memory chunk. But for now, it's easier - // for valgrind debugging to have several chunks. - fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch - fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t); - fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t); - fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t); - fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); - fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); - fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t); - fixed_y_t* best_y = best_y_base; - fixed_y_t* target_y = target_y_base; - fixed_t* best_uv = best_uv_base; - fixed_t* target_uv = target_uv_base; - const uint64_t diff_y_threshold = (uint64_t)(3.0 * w * h); - int ok; - - if (best_y_base == NULL || best_uv_base == NULL || - target_y_base == NULL || target_uv_base == NULL || - best_rgb_y == NULL || best_rgb_uv == NULL || - tmp_buffer == NULL) { - ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto End; - } - assert(picture->width >= kMinDimensionIterativeConversion); - assert(picture->height >= kMinDimensionIterativeConversion); - - WebPInitConvertARGBToYUV(); - - // Import RGB samples to W/RGB representation. - for (j = 0; j < picture->height; j += 2) { - const int is_last_row = (j == picture->height - 1); - fixed_y_t* const src1 = tmp_buffer + 0 * w; - fixed_y_t* const src2 = tmp_buffer + 3 * w; - - // prepare two rows of input - ImportOneRow(r_ptr, g_ptr, b_ptr, step, picture->width, src1); - if (!is_last_row) { - ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride, - step, picture->width, src2); - } else { - memcpy(src2, src1, 3 * w * sizeof(*src2)); - } - StoreGray(src1, best_y + 0, w); - StoreGray(src2, best_y + w, w); - - UpdateW(src1, target_y, w); - UpdateW(src2, target_y + w, w); - UpdateChroma(src1, src2, target_uv, uv_w); - memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv)); - best_y += 2 * w; - best_uv += 3 * uv_w; - target_y += 2 * w; - target_uv += 3 * uv_w; - r_ptr += 2 * rgb_stride; - g_ptr += 2 * rgb_stride; - b_ptr += 2 * rgb_stride; - } - - // Iterate and resolve clipping conflicts. - for (iter = 0; iter < kNumIterations; ++iter) { - const fixed_t* cur_uv = best_uv_base; - const fixed_t* prev_uv = best_uv_base; - uint64_t diff_y_sum = 0; - - best_y = best_y_base; - best_uv = best_uv_base; - target_y = target_y_base; - target_uv = target_uv_base; - for (j = 0; j < h; j += 2) { - fixed_y_t* const src1 = tmp_buffer + 0 * w; - fixed_y_t* const src2 = tmp_buffer + 3 * w; - { - const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0); - InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w, src1, src2); - prev_uv = cur_uv; - cur_uv = next_uv; - } - - UpdateW(src1, best_rgb_y + 0 * w, w); - UpdateW(src2, best_rgb_y + 1 * w, w); - UpdateChroma(src1, src2, best_rgb_uv, uv_w); - - // update two rows of Y and one row of RGB - diff_y_sum += WebPSharpYUVUpdateY(target_y, best_rgb_y, best_y, 2 * w); - WebPSharpYUVUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w); - - best_y += 2 * w; - best_uv += 3 * uv_w; - target_y += 2 * w; - target_uv += 3 * uv_w; - } - // test exit condition - if (iter > 0) { - if (diff_y_sum < diff_y_threshold) break; - if (diff_y_sum > prev_diff_y_sum) break; - } - prev_diff_y_sum = diff_y_sum; + const int ok = SharpYuvConvert( + r_ptr, g_ptr, b_ptr, step, rgb_stride, /*rgb_bit_depth=*/8, + picture->y, picture->y_stride, picture->u, picture->uv_stride, picture->v, + picture->uv_stride, /*yuv_bit_depth=*/8, picture->width, + picture->height, SharpYuvGetConversionMatrix(kSharpYuvMatrixWebp)); + if (!ok) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); } - // final reconstruction - ok = ConvertWRGBToYUV(best_y_base, best_uv_base, picture); - - End: - WebPSafeFree(best_y_base); - WebPSafeFree(best_uv_base); - WebPSafeFree(target_y_base); - WebPSafeFree(target_uv_base); - WebPSafeFree(best_rgb_y); - WebPSafeFree(best_rgb_uv); - WebPSafeFree(tmp_buffer); return ok; } -#undef SAFE_ALLOC //------------------------------------------------------------------------------ // "Fast" regular RGB->YUV @@ -591,8 +224,8 @@ static const int kAlphaFix = 19; // and constant are adjusted very tightly to fit 32b arithmetic. // In particular, they use the fact that the operands for 'v / a' are actually // derived as v = (a0.p0 + a1.p1 + a2.p2 + a3.p3) and a = a0 + a1 + a2 + a3 -// with ai in [0..255] and pi in [0..1<<kGammaFix). The constraint to avoid -// overflow is: kGammaFix + kAlphaFix <= 31. +// with ai in [0..255] and pi in [0..1<<GAMMA_FIX). The constraint to avoid +// overflow is: GAMMA_FIX + kAlphaFix <= 31. static const uint32_t kInvAlpha[4 * 0xff + 1] = { 0, /* alpha = 0 */ 524288, 262144, 174762, 131072, 104857, 87381, 74898, 65536, @@ -818,11 +451,20 @@ static WEBP_INLINE void AccumulateRGB(const uint8_t* const r_ptr, dst[0] = SUM4(r_ptr + j, step); dst[1] = SUM4(g_ptr + j, step); dst[2] = SUM4(b_ptr + j, step); + // MemorySanitizer may raise false positives with data that passes through + // RGBA32PackedToPlanar_16b_SSE41() due to incorrect modeling of shuffles. + // See https://crbug.com/webp/573. +#ifdef WEBP_MSAN + dst[3] = 0; +#endif } if (width & 1) { dst[0] = SUM2(r_ptr + j); dst[1] = SUM2(g_ptr + j); dst[2] = SUM2(b_ptr + j); +#ifdef WEBP_MSAN + dst[3] = 0; +#endif } } @@ -863,18 +505,18 @@ static int ImportYUVAFromRGBA(const uint8_t* r_ptr, use_iterative_conversion = 0; } - if (!WebPPictureAllocYUVA(picture, width, height)) { + if (!WebPPictureAllocYUVA(picture)) { return 0; } if (has_alpha) { assert(step == 4); #if defined(USE_GAMMA_COMPRESSION) && defined(USE_INVERSE_ALPHA_TABLE) - assert(kAlphaFix + kGammaFix <= 31); + assert(kAlphaFix + GAMMA_FIX <= 31); #endif } if (use_iterative_conversion) { - InitGammaTablesS(); + SafeInitSharpYuv(); if (!PreprocessARGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, picture)) { return 0; } @@ -1044,7 +686,7 @@ int WebPPictureYUVAToARGB(WebPPicture* picture) { return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION); } // Allocate a new argb buffer (discarding the previous one). - if (!WebPPictureAllocARGB(picture, picture->width, picture->height)) return 0; + if (!WebPPictureAllocARGB(picture)) return 0; picture->use_argb = 1; // Convert @@ -1106,6 +748,8 @@ static int Import(WebPPicture* const picture, const int width = picture->width; const int height = picture->height; + if (abs(rgb_stride) < (import_alpha ? 4 : 3) * width) return 0; + if (!picture->use_argb) { const uint8_t* a_ptr = import_alpha ? rgb + 3 : NULL; return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride, @@ -1163,24 +807,24 @@ static int Import(WebPPicture* const picture, #if !defined(WEBP_REDUCE_CSP) int WebPPictureImportBGR(WebPPicture* picture, - const uint8_t* rgb, int rgb_stride) { - return (picture != NULL && rgb != NULL) - ? Import(picture, rgb, rgb_stride, 3, 1, 0) + const uint8_t* bgr, int bgr_stride) { + return (picture != NULL && bgr != NULL) + ? Import(picture, bgr, bgr_stride, 3, 1, 0) : 0; } int WebPPictureImportBGRA(WebPPicture* picture, - const uint8_t* rgba, int rgba_stride) { - return (picture != NULL && rgba != NULL) - ? Import(picture, rgba, rgba_stride, 4, 1, 1) + const uint8_t* bgra, int bgra_stride) { + return (picture != NULL && bgra != NULL) + ? Import(picture, bgra, bgra_stride, 4, 1, 1) : 0; } int WebPPictureImportBGRX(WebPPicture* picture, - const uint8_t* rgba, int rgba_stride) { - return (picture != NULL && rgba != NULL) - ? Import(picture, rgba, rgba_stride, 4, 1, 0) + const uint8_t* bgrx, int bgrx_stride) { + return (picture != NULL && bgrx != NULL) + ? Import(picture, bgrx, bgrx_stride, 4, 1, 0) : 0; } @@ -1201,9 +845,9 @@ int WebPPictureImportRGBA(WebPPicture* picture, } int WebPPictureImportRGBX(WebPPicture* picture, - const uint8_t* rgba, int rgba_stride) { - return (picture != NULL && rgba != NULL) - ? Import(picture, rgba, rgba_stride, 4, 0, 0) + const uint8_t* rgbx, int rgbx_stride) { + return (picture != NULL && rgbx != NULL) + ? Import(picture, rgbx, rgbx_stride, 4, 0, 0) : 0; } diff --git a/thirdparty/libwebp/src/enc/picture_enc.c b/thirdparty/libwebp/src/enc/picture_enc.c index c691622d03..3af6383d38 100644 --- a/thirdparty/libwebp/src/enc/picture_enc.c +++ b/thirdparty/libwebp/src/enc/picture_enc.c @@ -45,6 +45,22 @@ int WebPPictureInitInternal(WebPPicture* picture, int version) { //------------------------------------------------------------------------------ +int WebPValidatePicture(const WebPPicture* const picture) { + if (picture == NULL) return 0; + if (picture->width <= 0 || picture->height <= 0) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); + } + if (picture->width <= 0 || picture->width / 4 > INT_MAX / 4 || + picture->height <= 0 || picture->height / 4 > INT_MAX / 4) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); + } + if (picture->colorspace != WEBP_YUV420 && + picture->colorspace != WEBP_YUV420A) { + return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION); + } + return 1; +} + static void WebPPictureResetBufferARGB(WebPPicture* const picture) { picture->memory_argb_ = NULL; picture->argb = NULL; @@ -63,18 +79,17 @@ void WebPPictureResetBuffers(WebPPicture* const picture) { WebPPictureResetBufferYUVA(picture); } -int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height) { +int WebPPictureAllocARGB(WebPPicture* const picture) { void* memory; + const int width = picture->width; + const int height = picture->height; const uint64_t argb_size = (uint64_t)width * height; - assert(picture != NULL); + if (!WebPValidatePicture(picture)) return 0; WebPSafeFree(picture->memory_argb_); WebPPictureResetBufferARGB(picture); - if (width <= 0 || height <= 0) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); - } // allocate a new buffer. memory = WebPSafeMalloc(argb_size + WEBP_ALIGN_CST, sizeof(*picture->argb)); if (memory == NULL) { @@ -86,10 +101,10 @@ int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height) { return 1; } -int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height) { - const WebPEncCSP uv_csp = - (WebPEncCSP)((int)picture->colorspace & WEBP_CSP_UV_MASK); +int WebPPictureAllocYUVA(WebPPicture* const picture) { const int has_alpha = (int)picture->colorspace & WEBP_CSP_ALPHA_BIT; + const int width = picture->width; + const int height = picture->height; const int y_stride = width; const int uv_width = (int)(((int64_t)width + 1) >> 1); const int uv_height = (int)(((int64_t)height + 1) >> 1); @@ -98,15 +113,11 @@ int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height) { uint64_t y_size, uv_size, a_size, total_size; uint8_t* mem; - assert(picture != NULL); + if (!WebPValidatePicture(picture)) return 0; WebPSafeFree(picture->memory_); WebPPictureResetBufferYUVA(picture); - if (uv_csp != WEBP_YUV420) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION); - } - // alpha a_width = has_alpha ? width : 0; a_stride = a_width; @@ -152,15 +163,12 @@ int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height) { int WebPPictureAlloc(WebPPicture* picture) { if (picture != NULL) { - const int width = picture->width; - const int height = picture->height; - WebPPictureFree(picture); // erase previous buffer if (!picture->use_argb) { - return WebPPictureAllocYUVA(picture, width, height); + return WebPPictureAllocYUVA(picture); } else { - return WebPPictureAllocARGB(picture, width, height); + return WebPPictureAllocARGB(picture); } } return 1; diff --git a/thirdparty/libwebp/src/enc/picture_rescale_enc.c b/thirdparty/libwebp/src/enc/picture_rescale_enc.c index a75f5d9c06..839f91cacc 100644 --- a/thirdparty/libwebp/src/enc/picture_rescale_enc.c +++ b/thirdparty/libwebp/src/enc/picture_rescale_enc.c @@ -13,14 +13,15 @@ #include "src/webp/encode.h" -#if !defined(WEBP_REDUCE_SIZE) - #include <assert.h> #include <stdlib.h> #include "src/enc/vp8i_enc.h" + +#if !defined(WEBP_REDUCE_SIZE) #include "src/utils/rescaler_utils.h" #include "src/utils/utils.h" +#endif // !defined(WEBP_REDUCE_SIZE) #define HALVE(x) (((x) + 1) >> 1) @@ -56,6 +57,7 @@ static int AdjustAndCheckRectangle(const WebPPicture* const pic, return 1; } +#if !defined(WEBP_REDUCE_SIZE) int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) { if (src == NULL || dst == NULL) return 0; if (src == dst) return 1; @@ -81,6 +83,7 @@ int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) { } return 1; } +#endif // !defined(WEBP_REDUCE_SIZE) int WebPPictureIsView(const WebPPicture* picture) { if (picture == NULL) return 0; @@ -120,6 +123,7 @@ int WebPPictureView(const WebPPicture* src, return 1; } +#if !defined(WEBP_REDUCE_SIZE) //------------------------------------------------------------------------------ // Picture cropping @@ -198,34 +202,34 @@ static void AlphaMultiplyY(WebPPicture* const pic, int inverse) { } } -int WebPPictureRescale(WebPPicture* pic, int width, int height) { +int WebPPictureRescale(WebPPicture* picture, int width, int height) { WebPPicture tmp; int prev_width, prev_height; rescaler_t* work; - if (pic == NULL) return 0; - prev_width = pic->width; - prev_height = pic->height; + if (picture == NULL) return 0; + prev_width = picture->width; + prev_height = picture->height; if (!WebPRescalerGetScaledDimensions( prev_width, prev_height, &width, &height)) { return 0; } - PictureGrabSpecs(pic, &tmp); + PictureGrabSpecs(picture, &tmp); tmp.width = width; tmp.height = height; if (!WebPPictureAlloc(&tmp)) return 0; - if (!pic->use_argb) { + if (!picture->use_argb) { work = (rescaler_t*)WebPSafeMalloc(2ULL * width, sizeof(*work)); if (work == NULL) { WebPPictureFree(&tmp); return 0; } // If present, we need to rescale alpha first (for AlphaMultiplyY). - if (pic->a != NULL) { + if (picture->a != NULL) { WebPInitAlphaProcessing(); - if (!RescalePlane(pic->a, prev_width, prev_height, pic->a_stride, + if (!RescalePlane(picture->a, prev_width, prev_height, picture->a_stride, tmp.a, width, height, tmp.a_stride, work, 1)) { return 0; } @@ -233,17 +237,15 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) { // We take transparency into account on the luma plane only. That's not // totally exact blending, but still is a good approximation. - AlphaMultiplyY(pic, 0); - if (!RescalePlane(pic->y, prev_width, prev_height, pic->y_stride, + AlphaMultiplyY(picture, 0); + if (!RescalePlane(picture->y, prev_width, prev_height, picture->y_stride, tmp.y, width, height, tmp.y_stride, work, 1) || - !RescalePlane(pic->u, - HALVE(prev_width), HALVE(prev_height), pic->uv_stride, - tmp.u, - HALVE(width), HALVE(height), tmp.uv_stride, work, 1) || - !RescalePlane(pic->v, - HALVE(prev_width), HALVE(prev_height), pic->uv_stride, - tmp.v, - HALVE(width), HALVE(height), tmp.uv_stride, work, 1)) { + !RescalePlane(picture->u, HALVE(prev_width), HALVE(prev_height), + picture->uv_stride, tmp.u, HALVE(width), HALVE(height), + tmp.uv_stride, work, 1) || + !RescalePlane(picture->v, HALVE(prev_width), HALVE(prev_height), + picture->uv_stride, tmp.v, HALVE(width), HALVE(height), + tmp.uv_stride, work, 1)) { return 0; } AlphaMultiplyY(&tmp, 1); @@ -257,18 +259,17 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) { // weighting first (black-matting), scale the RGB values, and remove // the premultiplication afterward (while preserving the alpha channel). WebPInitAlphaProcessing(); - AlphaMultiplyARGB(pic, 0); - if (!RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height, - pic->argb_stride * 4, - (uint8_t*)tmp.argb, width, height, - tmp.argb_stride * 4, work, 4)) { + AlphaMultiplyARGB(picture, 0); + if (!RescalePlane((const uint8_t*)picture->argb, prev_width, prev_height, + picture->argb_stride * 4, (uint8_t*)tmp.argb, width, + height, tmp.argb_stride * 4, work, 4)) { return 0; } AlphaMultiplyARGB(&tmp, 1); } - WebPPictureFree(pic); + WebPPictureFree(picture); WebPSafeFree(work); - *pic = tmp; + *picture = tmp; return 1; } @@ -280,23 +281,6 @@ int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) { return 0; } -int WebPPictureIsView(const WebPPicture* picture) { - (void)picture; - return 0; -} - -int WebPPictureView(const WebPPicture* src, - int left, int top, int width, int height, - WebPPicture* dst) { - (void)src; - (void)left; - (void)top; - (void)width; - (void)height; - (void)dst; - return 0; -} - int WebPPictureCrop(WebPPicture* pic, int left, int top, int width, int height) { (void)pic; diff --git a/thirdparty/libwebp/src/enc/picture_tools_enc.c b/thirdparty/libwebp/src/enc/picture_tools_enc.c index 38cb01534a..147cc18608 100644 --- a/thirdparty/libwebp/src/enc/picture_tools_enc.c +++ b/thirdparty/libwebp/src/enc/picture_tools_enc.c @@ -190,27 +190,28 @@ static WEBP_INLINE uint32_t MakeARGB32(int r, int g, int b) { return (0xff000000u | (r << 16) | (g << 8) | b); } -void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) { +void WebPBlendAlpha(WebPPicture* picture, uint32_t background_rgb) { const int red = (background_rgb >> 16) & 0xff; const int green = (background_rgb >> 8) & 0xff; const int blue = (background_rgb >> 0) & 0xff; int x, y; - if (pic == NULL) return; - if (!pic->use_argb) { - const int uv_width = (pic->width >> 1); // omit last pixel during u/v loop + if (picture == NULL) return; + if (!picture->use_argb) { + // omit last pixel during u/v loop + const int uv_width = (picture->width >> 1); const int Y0 = VP8RGBToY(red, green, blue, YUV_HALF); // VP8RGBToU/V expects the u/v values summed over four pixels const int U0 = VP8RGBToU(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF); const int V0 = VP8RGBToV(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF); - const int has_alpha = pic->colorspace & WEBP_CSP_ALPHA_BIT; - uint8_t* y_ptr = pic->y; - uint8_t* u_ptr = pic->u; - uint8_t* v_ptr = pic->v; - uint8_t* a_ptr = pic->a; + const int has_alpha = picture->colorspace & WEBP_CSP_ALPHA_BIT; + uint8_t* y_ptr = picture->y; + uint8_t* u_ptr = picture->u; + uint8_t* v_ptr = picture->v; + uint8_t* a_ptr = picture->a; if (!has_alpha || a_ptr == NULL) return; // nothing to do - for (y = 0; y < pic->height; ++y) { + for (y = 0; y < picture->height; ++y) { // Luma blending - for (x = 0; x < pic->width; ++x) { + for (x = 0; x < picture->width; ++x) { const uint8_t alpha = a_ptr[x]; if (alpha < 0xff) { y_ptr[x] = BLEND(Y0, y_ptr[x], alpha); @@ -219,7 +220,7 @@ void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) { // Chroma blending every even line if ((y & 1) == 0) { uint8_t* const a_ptr2 = - (y + 1 == pic->height) ? a_ptr : a_ptr + pic->a_stride; + (y + 1 == picture->height) ? a_ptr : a_ptr + picture->a_stride; for (x = 0; x < uv_width; ++x) { // Average four alpha values into a single blending weight. // TODO(skal): might lead to visible contouring. Can we do better? @@ -229,24 +230,24 @@ void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) { u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha); v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha); } - if (pic->width & 1) { // rightmost pixel + if (picture->width & 1) { // rightmost pixel const uint32_t alpha = 2 * (a_ptr[2 * x + 0] + a_ptr2[2 * x + 0]); u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha); v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha); } } else { - u_ptr += pic->uv_stride; - v_ptr += pic->uv_stride; + u_ptr += picture->uv_stride; + v_ptr += picture->uv_stride; } - memset(a_ptr, 0xff, pic->width); // reset alpha value to opaque - a_ptr += pic->a_stride; - y_ptr += pic->y_stride; + memset(a_ptr, 0xff, picture->width); // reset alpha value to opaque + a_ptr += picture->a_stride; + y_ptr += picture->y_stride; } } else { - uint32_t* argb = pic->argb; + uint32_t* argb = picture->argb; const uint32_t background = MakeARGB32(red, green, blue); - for (y = 0; y < pic->height; ++y) { - for (x = 0; x < pic->width; ++x) { + for (y = 0; y < picture->height; ++y) { + for (x = 0; x < picture->width; ++x) { const int alpha = (argb[x] >> 24) & 0xff; if (alpha != 0xff) { if (alpha > 0) { @@ -262,7 +263,7 @@ void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) { } } } - argb += pic->argb_stride; + argb += picture->argb_stride; } } } diff --git a/thirdparty/libwebp/src/enc/predictor_enc.c b/thirdparty/libwebp/src/enc/predictor_enc.c index 2b5c767280..b3d44b59d5 100644 --- a/thirdparty/libwebp/src/enc/predictor_enc.c +++ b/thirdparty/libwebp/src/enc/predictor_enc.c @@ -16,6 +16,7 @@ #include "src/dsp/lossless.h" #include "src/dsp/lossless_common.h" +#include "src/enc/vp8i_enc.h" #include "src/enc/vp8li_enc.h" #define MAX_DIFF_COST (1e30f) @@ -31,10 +32,10 @@ static WEBP_INLINE int GetMin(int a, int b) { return (a > b) ? b : a; } // Methods to calculate Entropy (Shannon). static float PredictionCostSpatial(const int counts[256], int weight_0, - double exp_val) { + float exp_val) { const int significant_symbols = 256 >> 4; - const double exp_decay_factor = 0.6; - double bits = weight_0 * counts[0]; + const float exp_decay_factor = 0.6f; + float bits = (float)weight_0 * counts[0]; int i; for (i = 1; i < significant_symbols; ++i) { bits += exp_val * (counts[i] + counts[256 - i]); @@ -46,9 +47,9 @@ static float PredictionCostSpatial(const int counts[256], int weight_0, static float PredictionCostSpatialHistogram(const int accumulated[4][256], const int tile[4][256]) { int i; - double retval = 0; + float retval = 0.f; for (i = 0; i < 4; ++i) { - const double kExpValue = 0.94; + const float kExpValue = 0.94f; retval += PredictionCostSpatial(tile[i], 1, kExpValue); retval += VP8LCombinedShannonEntropy(tile[i], accumulated[i]); } @@ -472,12 +473,15 @@ static void CopyImageWithPrediction(int width, int height, // with respect to predictions. If near_lossless_quality < 100, applies // near lossless processing, shaving off more bits of residuals for lower // qualities. -void VP8LResidualImage(int width, int height, int bits, int low_effort, - uint32_t* const argb, uint32_t* const argb_scratch, - uint32_t* const image, int near_lossless_quality, - int exact, int used_subtract_green) { +int VP8LResidualImage(int width, int height, int bits, int low_effort, + uint32_t* const argb, uint32_t* const argb_scratch, + uint32_t* const image, int near_lossless_quality, + int exact, int used_subtract_green, + const WebPPicture* const pic, int percent_range, + int* const percent) { const int tiles_per_row = VP8LSubSampleSize(width, bits); const int tiles_per_col = VP8LSubSampleSize(height, bits); + int percent_start = *percent; int tile_y; int histo[4][256]; const int max_quantization = 1 << VP8LNearLosslessBits(near_lossless_quality); @@ -491,17 +495,24 @@ void VP8LResidualImage(int width, int height, int bits, int low_effort, for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) { int tile_x; for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) { - const int pred = GetBestPredictorForTile(width, height, tile_x, tile_y, - bits, histo, argb_scratch, argb, max_quantization, exact, - used_subtract_green, image); + const int pred = GetBestPredictorForTile( + width, height, tile_x, tile_y, bits, histo, argb_scratch, argb, + max_quantization, exact, used_subtract_green, image); image[tile_y * tiles_per_row + tile_x] = ARGB_BLACK | (pred << 8); } + + if (!WebPReportProgress( + pic, percent_start + percent_range * tile_y / tiles_per_col, + percent)) { + return 0; + } } } CopyImageWithPrediction(width, height, bits, image, argb_scratch, argb, low_effort, max_quantization, exact, used_subtract_green); + return WebPReportProgress(pic, percent_start + percent_range, percent); } //------------------------------------------------------------------------------ @@ -532,7 +543,7 @@ static float PredictionCostCrossColor(const int accumulated[256], const int counts[256]) { // Favor low entropy, locally and globally. // Favor small absolute values for PredictionCostSpatial - static const double kExpValue = 2.4; + static const float kExpValue = 2.4f; return VP8LCombinedShannonEntropy(counts, accumulated) + PredictionCostSpatial(counts, 3, kExpValue); } @@ -714,11 +725,14 @@ static void CopyTileWithColorTransform(int xsize, int ysize, } } -void VP8LColorSpaceTransform(int width, int height, int bits, int quality, - uint32_t* const argb, uint32_t* image) { +int VP8LColorSpaceTransform(int width, int height, int bits, int quality, + uint32_t* const argb, uint32_t* image, + const WebPPicture* const pic, int percent_range, + int* const percent) { const int max_tile_size = 1 << bits; const int tile_xsize = VP8LSubSampleSize(width, bits); const int tile_ysize = VP8LSubSampleSize(height, bits); + int percent_start = *percent; int accumulated_red_histo[256] = { 0 }; int accumulated_blue_histo[256] = { 0 }; int tile_x, tile_y; @@ -768,5 +782,11 @@ void VP8LColorSpaceTransform(int width, int height, int bits, int quality, } } } + if (!WebPReportProgress( + pic, percent_start + percent_range * tile_y / tile_ysize, + percent)) { + return 0; + } } + return 1; } diff --git a/thirdparty/libwebp/src/enc/quant_enc.c b/thirdparty/libwebp/src/enc/quant_enc.c index 6cede28ab4..6d8202d277 100644 --- a/thirdparty/libwebp/src/enc/quant_enc.c +++ b/thirdparty/libwebp/src/enc/quant_enc.c @@ -533,7 +533,8 @@ static void InitScore(VP8ModeScore* const rd) { rd->score = MAX_COST; } -static void CopyScore(VP8ModeScore* const dst, const VP8ModeScore* const src) { +static void CopyScore(VP8ModeScore* WEBP_RESTRICT const dst, + const VP8ModeScore* WEBP_RESTRICT const src) { dst->D = src->D; dst->SD = src->SD; dst->R = src->R; @@ -542,7 +543,8 @@ static void CopyScore(VP8ModeScore* const dst, const VP8ModeScore* const src) { dst->score = src->score; } -static void AddScore(VP8ModeScore* const dst, const VP8ModeScore* const src) { +static void AddScore(VP8ModeScore* WEBP_RESTRICT const dst, + const VP8ModeScore* WEBP_RESTRICT const src) { dst->D += src->D; dst->SD += src->SD; dst->R += src->R; @@ -588,10 +590,10 @@ static WEBP_INLINE score_t RDScoreTrellis(int lambda, score_t rate, // Coefficient type. enum { TYPE_I16_AC = 0, TYPE_I16_DC = 1, TYPE_CHROMA_A = 2, TYPE_I4_AC = 3 }; -static int TrellisQuantizeBlock(const VP8Encoder* const enc, +static int TrellisQuantizeBlock(const VP8Encoder* WEBP_RESTRICT const enc, int16_t in[16], int16_t out[16], int ctx0, int coeff_type, - const VP8Matrix* const mtx, + const VP8Matrix* WEBP_RESTRICT const mtx, int lambda) { const ProbaArray* const probas = enc->proba_.coeffs_[coeff_type]; CostArrayPtr const costs = @@ -767,9 +769,9 @@ static int TrellisQuantizeBlock(const VP8Encoder* const enc, // all at once. Output is the reconstructed block in *yuv_out, and the // quantized levels in *levels. -static int ReconstructIntra16(VP8EncIterator* const it, - VP8ModeScore* const rd, - uint8_t* const yuv_out, +static int ReconstructIntra16(VP8EncIterator* WEBP_RESTRICT const it, + VP8ModeScore* WEBP_RESTRICT const rd, + uint8_t* WEBP_RESTRICT const yuv_out, int mode) { const VP8Encoder* const enc = it->enc_; const uint8_t* const ref = it->yuv_p_ + VP8I16ModeOffsets[mode]; @@ -819,10 +821,10 @@ static int ReconstructIntra16(VP8EncIterator* const it, return nz; } -static int ReconstructIntra4(VP8EncIterator* const it, +static int ReconstructIntra4(VP8EncIterator* WEBP_RESTRICT const it, int16_t levels[16], - const uint8_t* const src, - uint8_t* const yuv_out, + const uint8_t* WEBP_RESTRICT const src, + uint8_t* WEBP_RESTRICT const yuv_out, int mode) { const VP8Encoder* const enc = it->enc_; const uint8_t* const ref = it->yuv_p_ + VP8I4ModeOffsets[mode]; @@ -855,7 +857,8 @@ static int ReconstructIntra4(VP8EncIterator* const it, // Quantize as usual, but also compute and return the quantization error. // Error is already divided by DSHIFT. -static int QuantizeSingle(int16_t* const v, const VP8Matrix* const mtx) { +static int QuantizeSingle(int16_t* WEBP_RESTRICT const v, + const VP8Matrix* WEBP_RESTRICT const mtx) { int V = *v; const int sign = (V < 0); if (sign) V = -V; @@ -869,9 +872,10 @@ static int QuantizeSingle(int16_t* const v, const VP8Matrix* const mtx) { return (sign ? -V : V) >> DSCALE; } -static void CorrectDCValues(const VP8EncIterator* const it, - const VP8Matrix* const mtx, - int16_t tmp[][16], VP8ModeScore* const rd) { +static void CorrectDCValues(const VP8EncIterator* WEBP_RESTRICT const it, + const VP8Matrix* WEBP_RESTRICT const mtx, + int16_t tmp[][16], + VP8ModeScore* WEBP_RESTRICT const rd) { // | top[0] | top[1] // --------+--------+--------- // left[0] | tmp[0] tmp[1] <-> err0 err1 @@ -902,8 +906,8 @@ static void CorrectDCValues(const VP8EncIterator* const it, } } -static void StoreDiffusionErrors(VP8EncIterator* const it, - const VP8ModeScore* const rd) { +static void StoreDiffusionErrors(VP8EncIterator* WEBP_RESTRICT const it, + const VP8ModeScore* WEBP_RESTRICT const rd) { int ch; for (ch = 0; ch <= 1; ++ch) { int8_t* const top = it->top_derr_[it->x_][ch]; @@ -922,8 +926,9 @@ static void StoreDiffusionErrors(VP8EncIterator* const it, //------------------------------------------------------------------------------ -static int ReconstructUV(VP8EncIterator* const it, VP8ModeScore* const rd, - uint8_t* const yuv_out, int mode) { +static int ReconstructUV(VP8EncIterator* WEBP_RESTRICT const it, + VP8ModeScore* WEBP_RESTRICT const rd, + uint8_t* WEBP_RESTRICT const yuv_out, int mode) { const VP8Encoder* const enc = it->enc_; const uint8_t* const ref = it->yuv_p_ + VP8UVModeOffsets[mode]; const uint8_t* const src = it->yuv_in_ + U_OFF_ENC; @@ -994,7 +999,8 @@ static void SwapOut(VP8EncIterator* const it) { SwapPtr(&it->yuv_out_, &it->yuv_out2_); } -static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* rd) { +static void PickBestIntra16(VP8EncIterator* WEBP_RESTRICT const it, + VP8ModeScore* WEBP_RESTRICT rd) { const int kNumBlocks = 16; VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_]; const int lambda = dqm->lambda_i16_; @@ -1054,7 +1060,7 @@ static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* rd) { //------------------------------------------------------------------------------ // return the cost array corresponding to the surrounding prediction modes. -static const uint16_t* GetCostModeI4(VP8EncIterator* const it, +static const uint16_t* GetCostModeI4(VP8EncIterator* WEBP_RESTRICT const it, const uint8_t modes[16]) { const int preds_w = it->enc_->preds_w_; const int x = (it->i4_ & 3), y = it->i4_ >> 2; @@ -1063,7 +1069,8 @@ static const uint16_t* GetCostModeI4(VP8EncIterator* const it, return VP8FixedCostsI4[top][left]; } -static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) { +static int PickBestIntra4(VP8EncIterator* WEBP_RESTRICT const it, + VP8ModeScore* WEBP_RESTRICT const rd) { const VP8Encoder* const enc = it->enc_; const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; const int lambda = dqm->lambda_i4_; @@ -1159,7 +1166,8 @@ static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) { //------------------------------------------------------------------------------ -static void PickBestUV(VP8EncIterator* const it, VP8ModeScore* const rd) { +static void PickBestUV(VP8EncIterator* WEBP_RESTRICT const it, + VP8ModeScore* WEBP_RESTRICT const rd) { const int kNumBlocks = 8; const VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_]; const int lambda = dqm->lambda_uv_; @@ -1211,7 +1219,8 @@ static void PickBestUV(VP8EncIterator* const it, VP8ModeScore* const rd) { //------------------------------------------------------------------------------ // Final reconstruction and quantization. -static void SimpleQuantize(VP8EncIterator* const it, VP8ModeScore* const rd) { +static void SimpleQuantize(VP8EncIterator* WEBP_RESTRICT const it, + VP8ModeScore* WEBP_RESTRICT const rd) { const VP8Encoder* const enc = it->enc_; const int is_i16 = (it->mb_->type_ == 1); int nz = 0; @@ -1236,9 +1245,9 @@ static void SimpleQuantize(VP8EncIterator* const it, VP8ModeScore* const rd) { } // Refine intra16/intra4 sub-modes based on distortion only (not rate). -static void RefineUsingDistortion(VP8EncIterator* const it, +static void RefineUsingDistortion(VP8EncIterator* WEBP_RESTRICT const it, int try_both_modes, int refine_uv_mode, - VP8ModeScore* const rd) { + VP8ModeScore* WEBP_RESTRICT const rd) { score_t best_score = MAX_COST; int nz = 0; int mode; @@ -1352,7 +1361,8 @@ static void RefineUsingDistortion(VP8EncIterator* const it, //------------------------------------------------------------------------------ // Entry point -int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd, +int VP8Decimate(VP8EncIterator* WEBP_RESTRICT const it, + VP8ModeScore* WEBP_RESTRICT const rd, VP8RDLevel rd_opt) { int is_skipped; const int method = it->enc_->method_; diff --git a/thirdparty/libwebp/src/enc/vp8i_enc.h b/thirdparty/libwebp/src/enc/vp8i_enc.h index b4bba08f27..71f76702ae 100644 --- a/thirdparty/libwebp/src/enc/vp8i_enc.h +++ b/thirdparty/libwebp/src/enc/vp8i_enc.h @@ -32,7 +32,7 @@ extern "C" { // version numbers #define ENC_MAJ_VERSION 1 #define ENC_MIN_VERSION 2 -#define ENC_REV_VERSION 2 +#define ENC_REV_VERSION 4 enum { MAX_LF_LEVELS = 64, // Maximum loop filter level MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost @@ -470,7 +470,8 @@ int VP8EncAnalyze(VP8Encoder* const enc); // Sets up segment's quantization values, base_quant_ and filter strengths. void VP8SetSegmentParams(VP8Encoder* const enc, float quality); // Pick best modes and fills the levels. Returns true if skipped. -int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd, +int VP8Decimate(VP8EncIterator* WEBP_RESTRICT const it, + VP8ModeScore* WEBP_RESTRICT const rd, VP8RDLevel rd_opt); // in alpha.c @@ -490,19 +491,24 @@ int VP8FilterStrengthFromDelta(int sharpness, int delta); // misc utils for picture_*.c: +// Returns true if 'picture' is non-NULL and dimensions/colorspace are within +// their valid ranges. If returning false, the 'error_code' in 'picture' is +// updated. +int WebPValidatePicture(const WebPPicture* const picture); + // Remove reference to the ARGB/YUVA buffer (doesn't free anything). void WebPPictureResetBuffers(WebPPicture* const picture); -// Allocates ARGB buffer of given dimension (previous one is always free'd). -// Preserves the YUV(A) buffer. Returns false in case of error (invalid param, -// out-of-memory). -int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height); +// Allocates ARGB buffer according to set width/height (previous one is +// always free'd). Preserves the YUV(A) buffer. Returns false in case of error +// (invalid param, out-of-memory). +int WebPPictureAllocARGB(WebPPicture* const picture); -// Allocates YUVA buffer of given dimension (previous one is always free'd). -// Uses picture->csp to determine whether an alpha buffer is needed. +// Allocates YUVA buffer according to set width/height (previous one is always +// free'd). Uses picture->csp to determine whether an alpha buffer is needed. // Preserves the ARGB buffer. // Returns false in case of error (invalid param, out-of-memory). -int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height); +int WebPPictureAllocYUVA(WebPPicture* const picture); // Replace samples that are fully transparent by 'color' to help compressibility // (no guarantee, though). Assumes pic->use_argb is true. diff --git a/thirdparty/libwebp/src/enc/vp8l_enc.c b/thirdparty/libwebp/src/enc/vp8l_enc.c index e330e716f1..2b345df610 100644 --- a/thirdparty/libwebp/src/enc/vp8l_enc.c +++ b/thirdparty/libwebp/src/enc/vp8l_enc.c @@ -15,15 +15,16 @@ #include <assert.h> #include <stdlib.h> +#include "src/dsp/lossless.h" +#include "src/dsp/lossless_common.h" #include "src/enc/backward_references_enc.h" #include "src/enc/histogram_enc.h" #include "src/enc/vp8i_enc.h" #include "src/enc/vp8li_enc.h" -#include "src/dsp/lossless.h" -#include "src/dsp/lossless_common.h" #include "src/utils/bit_writer_utils.h" #include "src/utils/huffman_encode_utils.h" #include "src/utils/utils.h" +#include "src/webp/encode.h" #include "src/webp/format_constants.h" // Maximum number of histogram images (sub-blocks). @@ -183,10 +184,9 @@ static void CoOccurrenceFindMax(const uint32_t* const cooccurrence, } // Builds the cooccurrence matrix -static WebPEncodingError CoOccurrenceBuild(const WebPPicture* const pic, - const uint32_t* const palette, - uint32_t num_colors, - uint32_t* cooccurrence) { +static int CoOccurrenceBuild(const WebPPicture* const pic, + const uint32_t* const palette, uint32_t num_colors, + uint32_t* cooccurrence) { uint32_t *lines, *line_top, *line_current, *line_tmp; int x, y; const uint32_t* src = pic->argb; @@ -195,7 +195,10 @@ static WebPEncodingError CoOccurrenceBuild(const WebPPicture* const pic, uint32_t idx_map[MAX_PALETTE_SIZE] = {0}; uint32_t palette_sorted[MAX_PALETTE_SIZE]; lines = (uint32_t*)WebPSafeMalloc(2 * pic->width, sizeof(*lines)); - if (lines == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY; + if (lines == NULL) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + return 0; + } line_top = &lines[0]; line_current = &lines[pic->width]; PrepareMapToPalette(palette, num_colors, palette_sorted, idx_map); @@ -226,7 +229,7 @@ static WebPEncodingError CoOccurrenceBuild(const WebPPicture* const pic, src += pic->argb_stride; } WebPSafeFree(lines); - return VP8_ENC_OK; + return 1; } struct Sum { @@ -237,7 +240,7 @@ struct Sum { // Implements the modified Zeng method from "A Survey on Palette Reordering // Methods for Improving the Compression of Color-Indexed Images" by Armando J. // Pinho and Antonio J. R. Neves. -static WebPEncodingError PaletteSortModifiedZeng( +static int PaletteSortModifiedZeng( const WebPPicture* const pic, const uint32_t* const palette_sorted, uint32_t num_colors, uint32_t* const palette) { uint32_t i, j, ind; @@ -247,15 +250,16 @@ static WebPEncodingError PaletteSortModifiedZeng( uint32_t first, last; uint32_t num_sums; // TODO(vrabaud) check whether one color images should use palette or not. - if (num_colors <= 1) return VP8_ENC_OK; + if (num_colors <= 1) return 1; // Build the co-occurrence matrix. cooccurrence = (uint32_t*)WebPSafeCalloc(num_colors * num_colors, sizeof(*cooccurrence)); - if (cooccurrence == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY; - if (CoOccurrenceBuild(pic, palette_sorted, num_colors, cooccurrence) != - VP8_ENC_OK) { - WebPSafeFree(cooccurrence); - return VP8_ENC_ERROR_OUT_OF_MEMORY; + if (cooccurrence == NULL) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + return 0; + } + if (!CoOccurrenceBuild(pic, palette_sorted, num_colors, cooccurrence)) { + return 0; } // Initialize the mapping list with the two best indices. @@ -316,7 +320,7 @@ static WebPEncodingError PaletteSortModifiedZeng( for (i = 0; i < num_colors; ++i) { palette[i] = palette_sorted[remapping[(first + i) % num_colors]]; } - return VP8_ENC_OK; + return 1; } // ----------------------------------------------------------------------------- @@ -434,8 +438,8 @@ static int AnalyzeEntropy(const uint32_t* argb, curr_row += argb_stride; } { - double entropy_comp[kHistoTotal]; - double entropy[kNumEntropyIx]; + float entropy_comp[kHistoTotal]; + float entropy[kNumEntropyIx]; int k; int last_mode_to_analyze = use_palette ? kPalette : kSpatialSubGreen; int j; @@ -949,11 +953,11 @@ static WEBP_INLINE void WriteHuffmanCodeWithExtraBits( VP8LPutBits(bw, (bits << depth) | symbol, depth + n_bits); } -static WebPEncodingError StoreImageToBitMask( +static int StoreImageToBitMask( VP8LBitWriter* const bw, int width, int histo_bits, const VP8LBackwardRefs* const refs, const uint16_t* histogram_symbols, - const HuffmanTreeCode* const huffman_codes) { + const HuffmanTreeCode* const huffman_codes, const WebPPicture* const pic) { const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1; const int tile_mask = (histo_bits == 0) ? 0 : -(1 << histo_bits); // x and y trace the position in the image. @@ -1006,44 +1010,53 @@ static WebPEncodingError StoreImageToBitMask( } VP8LRefsCursorNext(&c); } - return bw->error_ ? VP8_ENC_ERROR_OUT_OF_MEMORY : VP8_ENC_OK; + if (bw->error_) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + return 0; + } + return 1; } -// Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31 -static WebPEncodingError EncodeImageNoHuffman( - VP8LBitWriter* const bw, const uint32_t* const argb, - VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs_array, - int width, int height, int quality, int low_effort) { +// Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31. +// pic and percent are for progress. +static int EncodeImageNoHuffman(VP8LBitWriter* const bw, + const uint32_t* const argb, + VP8LHashChain* const hash_chain, + VP8LBackwardRefs* const refs_array, int width, + int height, int quality, int low_effort, + const WebPPicture* const pic, int percent_range, + int* const percent) { int i; int max_tokens = 0; - WebPEncodingError err = VP8_ENC_OK; VP8LBackwardRefs* refs; HuffmanTreeToken* tokens = NULL; - HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } }; - const uint16_t histogram_symbols[1] = { 0 }; // only one tree, one symbol + HuffmanTreeCode huffman_codes[5] = {{0, NULL, NULL}}; + const uint16_t histogram_symbols[1] = {0}; // only one tree, one symbol int cache_bits = 0; VP8LHistogramSet* histogram_image = NULL; HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc( - 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree)); + 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree)); if (huff_tree == NULL) { - err = VP8_ENC_ERROR_OUT_OF_MEMORY; + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } // Calculate backward references from ARGB image. - if (!VP8LHashChainFill(hash_chain, quality, argb, width, height, - low_effort)) { - err = VP8_ENC_ERROR_OUT_OF_MEMORY; + if (!VP8LHashChainFill(hash_chain, quality, argb, width, height, low_effort, + pic, percent_range / 2, percent)) { + goto Error; + } + if (!VP8LGetBackwardReferences(width, height, argb, quality, /*low_effort=*/0, + kLZ77Standard | kLZ77RLE, cache_bits, + /*do_no_cache=*/0, hash_chain, refs_array, + &cache_bits, pic, + percent_range - percent_range / 2, percent)) { goto Error; } - err = VP8LGetBackwardReferences( - width, height, argb, quality, /*low_effort=*/0, kLZ77Standard | kLZ77RLE, - cache_bits, /*do_no_cache=*/0, hash_chain, refs_array, &cache_bits); - if (err != VP8_ENC_OK) goto Error; refs = &refs_array[0]; histogram_image = VP8LAllocateHistogramSet(1, cache_bits); if (histogram_image == NULL) { - err = VP8_ENC_ERROR_OUT_OF_MEMORY; + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } VP8LHistogramSetClear(histogram_image); @@ -1054,7 +1067,7 @@ static WebPEncodingError EncodeImageNoHuffman( // Create Huffman bit lengths and codes for each histogram image. assert(histogram_image->size == 1); if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) { - err = VP8_ENC_ERROR_OUT_OF_MEMORY; + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } @@ -1071,7 +1084,7 @@ static WebPEncodingError EncodeImageNoHuffman( tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens)); if (tokens == NULL) { - err = VP8_ENC_ERROR_OUT_OF_MEMORY; + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } @@ -1083,27 +1096,32 @@ static WebPEncodingError EncodeImageNoHuffman( } // Store actual literals. - err = StoreImageToBitMask(bw, width, 0, refs, histogram_symbols, - huffman_codes); + if (!StoreImageToBitMask(bw, width, 0, refs, histogram_symbols, huffman_codes, + pic)) { + goto Error; + } Error: WebPSafeFree(tokens); WebPSafeFree(huff_tree); VP8LFreeHistogramSet(histogram_image); WebPSafeFree(huffman_codes[0].codes); - return err; + return (pic->error_code == VP8_ENC_OK); } -static WebPEncodingError EncodeImageInternal( +// pic and percent are for progress. +static int EncodeImageInternal( VP8LBitWriter* const bw, const uint32_t* const argb, VP8LHashChain* const hash_chain, VP8LBackwardRefs refs_array[4], int width, int height, int quality, int low_effort, int use_cache, const CrunchConfig* const config, int* cache_bits, int histogram_bits, - size_t init_byte_position, int* const hdr_size, int* const data_size) { - WebPEncodingError err = VP8_ENC_ERROR_OUT_OF_MEMORY; + size_t init_byte_position, int* const hdr_size, int* const data_size, + const WebPPicture* const pic, int percent_range, int* const percent) { const uint32_t histogram_image_xysize = VP8LSubSampleSize(width, histogram_bits) * VP8LSubSampleSize(height, histogram_bits); + int remaining_percent = percent_range; + int percent_start = *percent; VP8LHistogramSet* histogram_image = NULL; VP8LHistogram* tmp_histo = NULL; int histogram_image_size = 0; @@ -1112,9 +1130,8 @@ static WebPEncodingError EncodeImageInternal( 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree)); HuffmanTreeToken* tokens = NULL; HuffmanTreeCode* huffman_codes = NULL; - uint16_t* const histogram_symbols = - (uint16_t*)WebPSafeMalloc(histogram_image_xysize, - sizeof(*histogram_symbols)); + uint16_t* const histogram_symbols = (uint16_t*)WebPSafeMalloc( + histogram_image_xysize, sizeof(*histogram_symbols)); int sub_configs_idx; int cache_bits_init, write_histogram_image; VP8LBitWriter bw_init = *bw, bw_best; @@ -1126,14 +1143,27 @@ static WebPEncodingError EncodeImageInternal( assert(hdr_size != NULL); assert(data_size != NULL); - // Make sure we can allocate the different objects. memset(&hash_chain_histogram, 0, sizeof(hash_chain_histogram)); + if (!VP8LBitWriterInit(&bw_best, 0)) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + + // Make sure we can allocate the different objects. if (huff_tree == NULL || histogram_symbols == NULL || - !VP8LHashChainInit(&hash_chain_histogram, histogram_image_xysize) || - !VP8LHashChainFill(hash_chain, quality, argb, width, height, - low_effort)) { + !VP8LHashChainInit(&hash_chain_histogram, histogram_image_xysize)) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + + percent_range = remaining_percent / 5; + if (!VP8LHashChainFill(hash_chain, quality, argb, width, height, + low_effort, pic, percent_range, percent)) { goto Error; } + percent_start += percent_range; + remaining_percent -= percent_range; + if (use_cache) { // If the value is different from zero, it has been set during the // palette analysis. @@ -1142,22 +1172,27 @@ static WebPEncodingError EncodeImageInternal( cache_bits_init = 0; } // If several iterations will happen, clone into bw_best. - if (!VP8LBitWriterInit(&bw_best, 0) || - ((config->sub_configs_size_ > 1 || - config->sub_configs_[0].do_no_cache_) && - !VP8LBitWriterClone(bw, &bw_best))) { + if ((config->sub_configs_size_ > 1 || config->sub_configs_[0].do_no_cache_) && + !VP8LBitWriterClone(bw, &bw_best)) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } + for (sub_configs_idx = 0; sub_configs_idx < config->sub_configs_size_; ++sub_configs_idx) { const CrunchSubConfig* const sub_config = &config->sub_configs_[sub_configs_idx]; int cache_bits_best, i_cache; - err = VP8LGetBackwardReferences(width, height, argb, quality, low_effort, - sub_config->lz77_, cache_bits_init, - sub_config->do_no_cache_, hash_chain, - &refs_array[0], &cache_bits_best); - if (err != VP8_ENC_OK) goto Error; + int i_remaining_percent = remaining_percent / config->sub_configs_size_; + int i_percent_range = i_remaining_percent / 4; + i_remaining_percent -= i_percent_range; + + if (!VP8LGetBackwardReferences( + width, height, argb, quality, low_effort, sub_config->lz77_, + cache_bits_init, sub_config->do_no_cache_, hash_chain, + &refs_array[0], &cache_bits_best, pic, i_percent_range, percent)) { + goto Error; + } for (i_cache = 0; i_cache < (sub_config->do_no_cache_ ? 2 : 1); ++i_cache) { const int cache_bits_tmp = (i_cache == 0) ? cache_bits_best : 0; @@ -1172,11 +1207,17 @@ static WebPEncodingError EncodeImageInternal( histogram_image = VP8LAllocateHistogramSet(histogram_image_xysize, cache_bits_tmp); tmp_histo = VP8LAllocateHistogram(cache_bits_tmp); - if (histogram_image == NULL || tmp_histo == NULL || - !VP8LGetHistoImageSymbols(width, height, &refs_array[i_cache], - quality, low_effort, histogram_bits, - cache_bits_tmp, histogram_image, tmp_histo, - histogram_symbols)) { + if (histogram_image == NULL || tmp_histo == NULL) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } + + i_percent_range = i_remaining_percent / 3; + i_remaining_percent -= i_percent_range; + if (!VP8LGetHistoImageSymbols( + width, height, &refs_array[i_cache], quality, low_effort, + histogram_bits, cache_bits_tmp, histogram_image, tmp_histo, + histogram_symbols, pic, i_percent_range, percent)) { goto Error; } // Create Huffman bit lengths and codes for each histogram image. @@ -1189,6 +1230,7 @@ static WebPEncodingError EncodeImageInternal( // GetHuffBitLengthsAndCodes(). if (huffman_codes == NULL || !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } // Free combined histograms. @@ -1211,12 +1253,14 @@ static WebPEncodingError EncodeImageInternal( write_histogram_image = (histogram_image_size > 1); VP8LPutBits(bw, write_histogram_image, 1); if (write_histogram_image) { - uint32_t* const histogram_argb = - (uint32_t*)WebPSafeMalloc(histogram_image_xysize, - sizeof(*histogram_argb)); + uint32_t* const histogram_argb = (uint32_t*)WebPSafeMalloc( + histogram_image_xysize, sizeof(*histogram_argb)); int max_index = 0; uint32_t i; - if (histogram_argb == NULL) goto Error; + if (histogram_argb == NULL) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + goto Error; + } for (i = 0; i < histogram_image_xysize; ++i) { const int symbol_index = histogram_symbols[i] & 0xffff; histogram_argb[i] = (symbol_index << 8); @@ -1227,12 +1271,17 @@ static WebPEncodingError EncodeImageInternal( histogram_image_size = max_index; VP8LPutBits(bw, histogram_bits - 2, 3); - err = EncodeImageNoHuffman( - bw, histogram_argb, &hash_chain_histogram, &refs_array[2], - VP8LSubSampleSize(width, histogram_bits), - VP8LSubSampleSize(height, histogram_bits), quality, low_effort); + i_percent_range = i_remaining_percent / 2; + i_remaining_percent -= i_percent_range; + if (!EncodeImageNoHuffman( + bw, histogram_argb, &hash_chain_histogram, &refs_array[2], + VP8LSubSampleSize(width, histogram_bits), + VP8LSubSampleSize(height, histogram_bits), quality, low_effort, + pic, i_percent_range, percent)) { + WebPSafeFree(histogram_argb); + goto Error; + } WebPSafeFree(histogram_argb); - if (err != VP8_ENC_OK) goto Error; } // Store Huffman codes. @@ -1256,9 +1305,10 @@ static WebPEncodingError EncodeImageInternal( } // Store actual literals. hdr_size_tmp = (int)(VP8LBitWriterNumBytes(bw) - init_byte_position); - err = StoreImageToBitMask(bw, width, histogram_bits, &refs_array[i_cache], - histogram_symbols, huffman_codes); - if (err != VP8_ENC_OK) goto Error; + if (!StoreImageToBitMask(bw, width, histogram_bits, &refs_array[i_cache], + histogram_symbols, huffman_codes, pic)) { + goto Error; + } // Keep track of the smallest image so far. if (VP8LBitWriterNumBytes(bw) < bw_size_best) { bw_size_best = VP8LBitWriterNumBytes(bw); @@ -1278,7 +1328,10 @@ static WebPEncodingError EncodeImageInternal( } } VP8LBitWriterSwap(bw, &bw_best); - err = VP8_ENC_OK; + + if (!WebPReportProgress(pic, percent_start + remaining_percent, percent)) { + goto Error; + } Error: WebPSafeFree(tokens); @@ -1292,7 +1345,7 @@ static WebPEncodingError EncodeImageInternal( } WebPSafeFree(histogram_symbols); VP8LBitWriterWipeOut(&bw_best); - return err; + return (pic->error_code == VP8_ENC_OK); } // ----------------------------------------------------------------------------- @@ -1305,22 +1358,23 @@ static void ApplySubtractGreen(VP8LEncoder* const enc, int width, int height, VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height); } -static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc, - int width, int height, - int quality, int low_effort, - int used_subtract_green, - VP8LBitWriter* const bw) { +static int ApplyPredictFilter(const VP8LEncoder* const enc, int width, + int height, int quality, int low_effort, + int used_subtract_green, VP8LBitWriter* const bw, + int percent_range, int* const percent) { const int pred_bits = enc->transform_bits_; const int transform_width = VP8LSubSampleSize(width, pred_bits); const int transform_height = VP8LSubSampleSize(height, pred_bits); // we disable near-lossless quantization if palette is used. - const int near_lossless_strength = enc->use_palette_ ? 100 - : enc->config_->near_lossless; + const int near_lossless_strength = + enc->use_palette_ ? 100 : enc->config_->near_lossless; - VP8LResidualImage(width, height, pred_bits, low_effort, enc->argb_, - enc->argb_scratch_, enc->transform_data_, - near_lossless_strength, enc->config_->exact, - used_subtract_green); + if (!VP8LResidualImage( + width, height, pred_bits, low_effort, enc->argb_, enc->argb_scratch_, + enc->transform_data_, near_lossless_strength, enc->config_->exact, + used_subtract_green, enc->pic_, percent_range / 2, percent)) { + return 0; + } VP8LPutBits(bw, TRANSFORM_PRESENT, 1); VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2); assert(pred_bits >= 2); @@ -1328,19 +1382,23 @@ static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc, return EncodeImageNoHuffman( bw, enc->transform_data_, (VP8LHashChain*)&enc->hash_chain_, (VP8LBackwardRefs*)&enc->refs_[0], transform_width, transform_height, - quality, low_effort); + quality, low_effort, enc->pic_, percent_range - percent_range / 2, + percent); } -static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc, - int width, int height, - int quality, int low_effort, - VP8LBitWriter* const bw) { +static int ApplyCrossColorFilter(const VP8LEncoder* const enc, int width, + int height, int quality, int low_effort, + VP8LBitWriter* const bw, int percent_range, + int* const percent) { const int ccolor_transform_bits = enc->transform_bits_; const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits); const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits); - VP8LColorSpaceTransform(width, height, ccolor_transform_bits, quality, - enc->argb_, enc->transform_data_); + if (!VP8LColorSpaceTransform(width, height, ccolor_transform_bits, quality, + enc->argb_, enc->transform_data_, enc->pic_, + percent_range / 2, percent)) { + return 0; + } VP8LPutBits(bw, TRANSFORM_PRESENT, 1); VP8LPutBits(bw, CROSS_COLOR_TRANSFORM, 2); assert(ccolor_transform_bits >= 2); @@ -1348,23 +1406,21 @@ static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc, return EncodeImageNoHuffman( bw, enc->transform_data_, (VP8LHashChain*)&enc->hash_chain_, (VP8LBackwardRefs*)&enc->refs_[0], transform_width, transform_height, - quality, low_effort); + quality, low_effort, enc->pic_, percent_range - percent_range / 2, + percent); } // ----------------------------------------------------------------------------- -static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic, - size_t riff_size, size_t vp8l_size) { +static int WriteRiffHeader(const WebPPicture* const pic, size_t riff_size, + size_t vp8l_size) { uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = { 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P', 'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE, }; PutLE32(riff + TAG_SIZE, (uint32_t)riff_size); PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size); - if (!pic->writer(riff, sizeof(riff), pic)) { - return VP8_ENC_ERROR_BAD_WRITE; - } - return VP8_ENC_OK; + return pic->writer(riff, sizeof(riff), pic); } static int WriteImageSize(const WebPPicture* const pic, @@ -1384,36 +1440,29 @@ static int WriteRealAlphaAndVersion(VP8LBitWriter* const bw, int has_alpha) { return !bw->error_; } -static WebPEncodingError WriteImage(const WebPPicture* const pic, - VP8LBitWriter* const bw, - size_t* const coded_size) { - WebPEncodingError err = VP8_ENC_OK; +static int WriteImage(const WebPPicture* const pic, VP8LBitWriter* const bw, + size_t* const coded_size) { const uint8_t* const webpll_data = VP8LBitWriterFinish(bw); const size_t webpll_size = VP8LBitWriterNumBytes(bw); const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size; const size_t pad = vp8l_size & 1; const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad; - err = WriteRiffHeader(pic, riff_size, vp8l_size); - if (err != VP8_ENC_OK) goto Error; - - if (!pic->writer(webpll_data, webpll_size, pic)) { - err = VP8_ENC_ERROR_BAD_WRITE; - goto Error; + if (!WriteRiffHeader(pic, riff_size, vp8l_size) || + !pic->writer(webpll_data, webpll_size, pic)) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE); + return 0; } if (pad) { const uint8_t pad_byte[1] = { 0 }; if (!pic->writer(pad_byte, 1, pic)) { - err = VP8_ENC_ERROR_BAD_WRITE; - goto Error; + WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE); + return 0; } } *coded_size = CHUNK_HEADER_SIZE + riff_size; - return VP8_ENC_OK; - - Error: - return err; + return 1; } // ----------------------------------------------------------------------------- @@ -1429,18 +1478,16 @@ static void ClearTransformBuffer(VP8LEncoder* const enc) { // Flags influencing the memory allocated: // enc->transform_bits_ // enc->use_predict_, enc->use_cross_color_ -static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc, - int width, int height) { - WebPEncodingError err = VP8_ENC_OK; +static int AllocateTransformBuffer(VP8LEncoder* const enc, int width, + int height) { const uint64_t image_size = width * height; // VP8LResidualImage needs room for 2 scanlines of uint32 pixels with an extra // pixel in each, plus 2 regular scanlines of bytes. // TODO(skal): Clean up by using arithmetic in bytes instead of words. const uint64_t argb_scratch_size = - enc->use_predict_ - ? (width + 1) * 2 + - (width * 2 + sizeof(uint32_t) - 1) / sizeof(uint32_t) - : 0; + enc->use_predict_ ? (width + 1) * 2 + (width * 2 + sizeof(uint32_t) - 1) / + sizeof(uint32_t) + : 0; const uint64_t transform_data_size = (enc->use_predict_ || enc->use_cross_color_) ? VP8LSubSampleSize(width, enc->transform_bits_) * @@ -1448,17 +1495,16 @@ static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc, : 0; const uint64_t max_alignment_in_words = (WEBP_ALIGN_CST + sizeof(uint32_t) - 1) / sizeof(uint32_t); - const uint64_t mem_size = - image_size + max_alignment_in_words + - argb_scratch_size + max_alignment_in_words + - transform_data_size; + const uint64_t mem_size = image_size + max_alignment_in_words + + argb_scratch_size + max_alignment_in_words + + transform_data_size; uint32_t* mem = enc->transform_mem_; if (mem == NULL || mem_size > enc->transform_mem_size_) { ClearTransformBuffer(enc); mem = (uint32_t*)WebPSafeMalloc(mem_size, sizeof(*mem)); if (mem == NULL) { - err = VP8_ENC_ERROR_OUT_OF_MEMORY; - goto Error; + WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); + return 0; } enc->transform_mem_ = mem; enc->transform_mem_size_ = (size_t)mem_size; @@ -1471,19 +1517,16 @@ static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc, enc->transform_data_ = mem; enc->current_width_ = width; - Error: - return err; + return 1; } -static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) { - WebPEncodingError err = VP8_ENC_OK; +static int MakeInputImageCopy(VP8LEncoder* const enc) { const WebPPicture* const picture = enc->pic_; const int width = picture->width; const int height = picture->height; - err = AllocateTransformBuffer(enc, width, height); - if (err != VP8_ENC_OK) return err; - if (enc->argb_content_ == kEncoderARGB) return VP8_ENC_OK; + if (!AllocateTransformBuffer(enc, width, height)) return 0; + if (enc->argb_content_ == kEncoderARGB) return 1; { uint32_t* dst = enc->argb_; @@ -1497,7 +1540,7 @@ static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) { } enc->argb_content_ = kEncoderARGB; assert(enc->current_width_ == width); - return VP8_ENC_OK; + return 1; } // ----------------------------------------------------------------------------- @@ -1559,16 +1602,19 @@ static WEBP_INLINE uint32_t ApplyPaletteHash2(uint32_t color) { // using 'row' as a temporary buffer of size 'width'. // We assume that all src[] values have a corresponding entry in the palette. // Note: src[] can be the same as dst[] -static WebPEncodingError ApplyPalette(const uint32_t* src, uint32_t src_stride, - uint32_t* dst, uint32_t dst_stride, - const uint32_t* palette, int palette_size, - int width, int height, int xbits) { +static int ApplyPalette(const uint32_t* src, uint32_t src_stride, uint32_t* dst, + uint32_t dst_stride, const uint32_t* palette, + int palette_size, int width, int height, int xbits, + const WebPPicture* const pic) { // TODO(skal): this tmp buffer is not needed if VP8LBundleColorMap() can be // made to work in-place. uint8_t* const tmp_row = (uint8_t*)WebPSafeMalloc(width, sizeof(*tmp_row)); int x, y; - if (tmp_row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY; + if (tmp_row == NULL) { + WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); + return 0; + } if (palette_size < APPLY_PALETTE_GREEDY_MAX) { APPLY_PALETTE_FOR(SearchColorGreedy(palette, palette_size, pix)); @@ -1613,7 +1659,7 @@ static WebPEncodingError ApplyPalette(const uint32_t* src, uint32_t src_stride, } } WebPSafeFree(tmp_row); - return VP8_ENC_OK; + return 1; } #undef APPLY_PALETTE_FOR #undef PALETTE_INV_SIZE_BITS @@ -1621,9 +1667,7 @@ static WebPEncodingError ApplyPalette(const uint32_t* src, uint32_t src_stride, #undef APPLY_PALETTE_GREEDY_MAX // Note: Expects "enc->palette_" to be set properly. -static WebPEncodingError MapImageFromPalette(VP8LEncoder* const enc, - int in_place) { - WebPEncodingError err = VP8_ENC_OK; +static int MapImageFromPalette(VP8LEncoder* const enc, int in_place) { const WebPPicture* const pic = enc->pic_; const int width = pic->width; const int height = pic->height; @@ -1641,19 +1685,22 @@ static WebPEncodingError MapImageFromPalette(VP8LEncoder* const enc, xbits = (palette_size <= 16) ? 1 : 0; } - err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height); - if (err != VP8_ENC_OK) return err; - - err = ApplyPalette(src, src_stride, + if (!AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height)) { + return 0; + } + if (!ApplyPalette(src, src_stride, enc->argb_, enc->current_width_, - palette, palette_size, width, height, xbits); + palette, palette_size, width, height, xbits, pic)) { + return 0; + } enc->argb_content_ = kEncoderPalette; - return err; + return 1; } // Save palette_[] to bitstream. static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, int low_effort, - VP8LEncoder* const enc) { + VP8LEncoder* const enc, + int percent_range, int* const percent) { int i; uint32_t tmp_palette[MAX_PALETTE_SIZE]; const int palette_size = enc->palette_size_; @@ -1668,7 +1715,7 @@ static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, int low_effort, tmp_palette[0] = palette[0]; return EncodeImageNoHuffman(bw, tmp_palette, &enc->hash_chain_, &enc->refs_[0], palette_size, 1, /*quality=*/20, - low_effort); + low_effort, enc->pic_, percent_range, percent); } // ----------------------------------------------------------------------------- @@ -1712,7 +1759,6 @@ typedef struct { CrunchConfig crunch_configs_[CRUNCH_CONFIGS_MAX]; int num_crunch_configs_; int red_and_blue_always_zero_; - WebPEncodingError err_; WebPAuxStats* stats_; } StreamEncodeContext; @@ -1729,7 +1775,6 @@ static int EncodeStreamHook(void* input, void* data2) { #if !defined(WEBP_DISABLE_STATS) WebPAuxStats* const stats = params->stats_; #endif - WebPEncodingError err = VP8_ENC_OK; const int quality = (int)config->quality; const int low_effort = (config->method == 0); #if (WEBP_NEAR_LOSSLESS == 1) @@ -1737,6 +1782,7 @@ static int EncodeStreamHook(void* input, void* data2) { #endif const int height = picture->height; const size_t byte_position = VP8LBitWriterNumBytes(bw); + int percent = 2; // for WebPProgressHook #if (WEBP_NEAR_LOSSLESS == 1) int use_near_lossless = 0; #endif @@ -1750,12 +1796,13 @@ static int EncodeStreamHook(void* input, void* data2) { if (!VP8LBitWriterInit(&bw_best, 0) || (num_crunch_configs > 1 && !VP8LBitWriterClone(bw, &bw_best))) { - err = VP8_ENC_ERROR_OUT_OF_MEMORY; + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } for (idx = 0; idx < num_crunch_configs; ++idx) { const int entropy_idx = crunch_configs[idx].entropy_idx_; + int remaining_percent = 97 / num_crunch_configs, percent_range; enc->use_palette_ = (entropy_idx == kPalette) || (entropy_idx == kPaletteAndSpatial); enc->use_subtract_green_ = @@ -1779,11 +1826,10 @@ static int EncodeStreamHook(void* input, void* data2) { use_near_lossless = (config->near_lossless < 100) && !enc->use_palette_ && !enc->use_predict_; if (use_near_lossless) { - err = AllocateTransformBuffer(enc, width, height); - if (err != VP8_ENC_OK) goto Error; + if (!AllocateTransformBuffer(enc, width, height)) goto Error; if ((enc->argb_content_ != kEncoderNearLossless) && !VP8ApplyNearLossless(picture, config->near_lossless, enc->argb_)) { - err = VP8_ENC_ERROR_OUT_OF_MEMORY; + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } enc->argb_content_ = kEncoderNearLossless; @@ -1805,14 +1851,17 @@ static int EncodeStreamHook(void* input, void* data2) { enc->palette_); } else { assert(crunch_configs[idx].palette_sorting_type_ == kModifiedZeng); - err = PaletteSortModifiedZeng(enc->pic_, enc->palette_sorted_, - enc->palette_size_, enc->palette_); - if (err != VP8_ENC_OK) goto Error; + if (!PaletteSortModifiedZeng(enc->pic_, enc->palette_sorted_, + enc->palette_size_, enc->palette_)) { + goto Error; + } } - err = EncodePalette(bw, low_effort, enc); - if (err != VP8_ENC_OK) goto Error; - err = MapImageFromPalette(enc, use_delta_palette); - if (err != VP8_ENC_OK) goto Error; + percent_range = remaining_percent / 4; + if (!EncodePalette(bw, low_effort, enc, percent_range, &percent)) { + goto Error; + } + remaining_percent -= percent_range; + if (!MapImageFromPalette(enc, use_delta_palette)) goto Error; // If using a color cache, do not have it bigger than the number of // colors. if (use_cache && enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) { @@ -1823,8 +1872,7 @@ static int EncodeStreamHook(void* input, void* data2) { // In case image is not packed. if (enc->argb_content_ != kEncoderNearLossless && enc->argb_content_ != kEncoderPalette) { - err = MakeInputImageCopy(enc); - if (err != VP8_ENC_OK) goto Error; + if (!MakeInputImageCopy(enc)) goto Error; } // ----------------------------------------------------------------------- @@ -1835,15 +1883,22 @@ static int EncodeStreamHook(void* input, void* data2) { } if (enc->use_predict_) { - err = ApplyPredictFilter(enc, enc->current_width_, height, quality, - low_effort, enc->use_subtract_green_, bw); - if (err != VP8_ENC_OK) goto Error; + percent_range = remaining_percent / 3; + if (!ApplyPredictFilter(enc, enc->current_width_, height, quality, + low_effort, enc->use_subtract_green_, bw, + percent_range, &percent)) { + goto Error; + } + remaining_percent -= percent_range; } if (enc->use_cross_color_) { - err = ApplyCrossColorFilter(enc, enc->current_width_, height, quality, - low_effort, bw); - if (err != VP8_ENC_OK) goto Error; + percent_range = remaining_percent / 2; + if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality, + low_effort, bw, percent_range, &percent)) { + goto Error; + } + remaining_percent -= percent_range; } } @@ -1851,12 +1906,13 @@ static int EncodeStreamHook(void* input, void* data2) { // ------------------------------------------------------------------------- // Encode and write the transformed image. - err = EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_, - enc->current_width_, height, quality, low_effort, - use_cache, &crunch_configs[idx], - &enc->cache_bits_, enc->histo_bits_, - byte_position, &hdr_size, &data_size); - if (err != VP8_ENC_OK) goto Error; + if (!EncodeImageInternal( + bw, enc->argb_, &enc->hash_chain_, enc->refs_, enc->current_width_, + height, quality, low_effort, use_cache, &crunch_configs[idx], + &enc->cache_bits_, enc->histo_bits_, byte_position, &hdr_size, + &data_size, picture, remaining_percent, &percent)) { + goto Error; + } // If we are better than what we already have. if (VP8LBitWriterNumBytes(bw) < best_size) { @@ -1886,18 +1942,15 @@ static int EncodeStreamHook(void* input, void* data2) { } VP8LBitWriterSwap(&bw_best, bw); -Error: + Error: VP8LBitWriterWipeOut(&bw_best); - params->err_ = err; // The hook should return false in case of error. - return (err == VP8_ENC_OK); + return (params->picture_->error_code == VP8_ENC_OK); } -WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, - const WebPPicture* const picture, - VP8LBitWriter* const bw_main, - int use_cache) { - WebPEncodingError err = VP8_ENC_OK; +int VP8LEncodeStream(const WebPConfig* const config, + const WebPPicture* const picture, + VP8LBitWriter* const bw_main, int use_cache) { VP8LEncoder* const enc_main = VP8LEncoderNew(config, picture); VP8LEncoder* enc_side = NULL; CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX]; @@ -1909,15 +1962,24 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, // The main thread uses picture->stats, the side thread uses stats_side. WebPAuxStats stats_side; VP8LBitWriter bw_side; + WebPPicture picture_side; const WebPWorkerInterface* const worker_interface = WebPGetWorkerInterface(); int ok_main; + if (enc_main == NULL || !VP8LBitWriterInit(&bw_side, 0)) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + VP8LEncoderDelete(enc_main); + return 0; + } + + // Avoid "garbage value" error from Clang's static analysis tool. + WebPPictureInit(&picture_side); + // Analyze image (entropy, num_palettes etc) - if (enc_main == NULL || - !EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main, + if (!EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main, &red_and_blue_always_zero) || - !EncoderInit(enc_main) || !VP8LBitWriterInit(&bw_side, 0)) { - err = VP8_ENC_ERROR_OUT_OF_MEMORY; + !EncoderInit(enc_main)) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } @@ -1946,25 +2008,32 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, StreamEncodeContext* const param = (idx == 0) ? ¶ms_main : ¶ms_side; param->config_ = config; - param->picture_ = picture; param->use_cache_ = use_cache; param->red_and_blue_always_zero_ = red_and_blue_always_zero; if (idx == 0) { + param->picture_ = picture; param->stats_ = picture->stats; param->bw_ = bw_main; param->enc_ = enc_main; } else { + // Create a side picture (error_code is not thread-safe). + if (!WebPPictureView(picture, /*left=*/0, /*top=*/0, picture->width, + picture->height, &picture_side)) { + assert(0); + } + picture_side.progress_hook = NULL; // Progress hook is not thread-safe. + param->picture_ = &picture_side; // No need to free a view afterwards. param->stats_ = (picture->stats == NULL) ? NULL : &stats_side; // Create a side bit writer. if (!VP8LBitWriterClone(bw_main, &bw_side)) { - err = VP8_ENC_ERROR_OUT_OF_MEMORY; + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } param->bw_ = &bw_side; // Create a side encoder. - enc_side = VP8LEncoderNew(config, picture); + enc_side = VP8LEncoderNew(config, &picture_side); if (enc_side == NULL || !EncoderInit(enc_side)) { - err = VP8_ENC_ERROR_OUT_OF_MEMORY; + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } // Copy the values that were computed for the main encoder. @@ -1988,7 +2057,7 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, // Start the second thread if needed. if (num_crunch_configs_side != 0) { if (!worker_interface->Reset(&worker_side)) { - err = VP8_ENC_ERROR_OUT_OF_MEMORY; + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } #if !defined(WEBP_DISABLE_STATS) @@ -1998,8 +2067,6 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, memcpy(&stats_side, picture->stats, sizeof(stats_side)); } #endif - // This line is only useful to remove a Clang static analyzer warning. - params_side.err_ = VP8_ENC_OK; worker_interface->Launch(&worker_side); } // Execute the main thread. @@ -2011,7 +2078,10 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, const int ok_side = worker_interface->Sync(&worker_side); worker_interface->End(&worker_side); if (!ok_main || !ok_side) { - err = ok_main ? params_side.err_ : params_main.err_; + if (picture->error_code == VP8_ENC_OK) { + assert(picture_side.error_code != VP8_ENC_OK); + WebPEncodingSetError(picture, picture_side.error_code); + } goto Error; } if (VP8LBitWriterNumBytes(&bw_side) < VP8LBitWriterNumBytes(bw_main)) { @@ -2022,18 +2092,13 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, } #endif } - } else { - if (!ok_main) { - err = params_main.err_; - goto Error; - } } -Error: + Error: VP8LBitWriterWipeOut(&bw_side); VP8LEncoderDelete(enc_main); VP8LEncoderDelete(enc_side); - return err; + return (picture->error_code == VP8_ENC_OK); } #undef CRUNCH_CONFIGS_MAX @@ -2046,14 +2111,12 @@ int VP8LEncodeImage(const WebPConfig* const config, size_t coded_size; int percent = 0; int initial_size; - WebPEncodingError err = VP8_ENC_OK; VP8LBitWriter bw; if (picture == NULL) return 0; if (config == NULL || picture->argb == NULL) { - err = VP8_ENC_ERROR_NULL_PARAMETER; - WebPEncodingSetError(picture, err); + WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER); return 0; } @@ -2064,13 +2127,13 @@ int VP8LEncodeImage(const WebPConfig* const config, initial_size = (config->image_hint == WEBP_HINT_GRAPH) ? width * height : width * height * 2; if (!VP8LBitWriterInit(&bw, initial_size)) { - err = VP8_ENC_ERROR_OUT_OF_MEMORY; + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } if (!WebPReportProgress(picture, 1, &percent)) { UserAbort: - err = VP8_ENC_ERROR_USER_ABORT; + WebPEncodingSetError(picture, VP8_ENC_ERROR_USER_ABORT); goto Error; } // Reset stats (for pure lossless coding) @@ -2086,28 +2149,26 @@ int VP8LEncodeImage(const WebPConfig* const config, // Write image size. if (!WriteImageSize(picture, &bw)) { - err = VP8_ENC_ERROR_OUT_OF_MEMORY; + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } has_alpha = WebPPictureHasTransparency(picture); // Write the non-trivial Alpha flag and lossless version. if (!WriteRealAlphaAndVersion(&bw, has_alpha)) { - err = VP8_ENC_ERROR_OUT_OF_MEMORY; + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); goto Error; } - if (!WebPReportProgress(picture, 5, &percent)) goto UserAbort; + if (!WebPReportProgress(picture, 2, &percent)) goto UserAbort; // Encode main image stream. - err = VP8LEncodeStream(config, picture, &bw, 1 /*use_cache*/); - if (err != VP8_ENC_OK) goto Error; + if (!VP8LEncodeStream(config, picture, &bw, 1 /*use_cache*/)) goto Error; - if (!WebPReportProgress(picture, 90, &percent)) goto UserAbort; + if (!WebPReportProgress(picture, 99, &percent)) goto UserAbort; // Finish the RIFF chunk. - err = WriteImage(picture, &bw, &coded_size); - if (err != VP8_ENC_OK) goto Error; + if (!WriteImage(picture, &bw, &coded_size)) goto Error; if (!WebPReportProgress(picture, 100, &percent)) goto UserAbort; @@ -2126,13 +2187,11 @@ int VP8LEncodeImage(const WebPConfig* const config, } Error: - if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY; - VP8LBitWriterWipeOut(&bw); - if (err != VP8_ENC_OK) { - WebPEncodingSetError(picture, err); - return 0; + if (bw.error_) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); } - return 1; + VP8LBitWriterWipeOut(&bw); + return (picture->error_code == VP8_ENC_OK); } //------------------------------------------------------------------------------ diff --git a/thirdparty/libwebp/src/enc/vp8li_enc.h b/thirdparty/libwebp/src/enc/vp8li_enc.h index 00de48946c..3d35e1612d 100644 --- a/thirdparty/libwebp/src/enc/vp8li_enc.h +++ b/thirdparty/libwebp/src/enc/vp8li_enc.h @@ -89,9 +89,10 @@ int VP8LEncodeImage(const WebPConfig* const config, // Encodes the main image stream using the supplied bit writer. // If 'use_cache' is false, disables the use of color cache. -WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, - const WebPPicture* const picture, - VP8LBitWriter* const bw, int use_cache); +// Returns false in case of error (stored in picture->error_code). +int VP8LEncodeStream(const WebPConfig* const config, + const WebPPicture* const picture, VP8LBitWriter* const bw, + int use_cache); #if (WEBP_NEAR_LOSSLESS == 1) // in near_lossless.c @@ -103,13 +104,18 @@ int VP8ApplyNearLossless(const WebPPicture* const picture, int quality, //------------------------------------------------------------------------------ // Image transforms in predictor.c. -void VP8LResidualImage(int width, int height, int bits, int low_effort, - uint32_t* const argb, uint32_t* const argb_scratch, - uint32_t* const image, int near_lossless, int exact, - int used_subtract_green); - -void VP8LColorSpaceTransform(int width, int height, int bits, int quality, - uint32_t* const argb, uint32_t* image); +// pic and percent are for progress. +// Returns false in case of error (stored in pic->error_code). +int VP8LResidualImage(int width, int height, int bits, int low_effort, + uint32_t* const argb, uint32_t* const argb_scratch, + uint32_t* const image, int near_lossless, int exact, + int used_subtract_green, const WebPPicture* const pic, + int percent_range, int* const percent); + +int VP8LColorSpaceTransform(int width, int height, int bits, int quality, + uint32_t* const argb, uint32_t* image, + const WebPPicture* const pic, int percent_range, + int* const percent); //------------------------------------------------------------------------------ diff --git a/thirdparty/libwebp/src/enc/webp_enc.c b/thirdparty/libwebp/src/enc/webp_enc.c index ce2db2e94b..9620e05070 100644 --- a/thirdparty/libwebp/src/enc/webp_enc.c +++ b/thirdparty/libwebp/src/enc/webp_enc.c @@ -336,9 +336,7 @@ int WebPEncode(const WebPConfig* config, WebPPicture* pic) { if (!WebPValidateConfig(config)) { return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION); } - if (pic->width <= 0 || pic->height <= 0) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION); - } + if (!WebPValidatePicture(pic)) return 0; if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION) { return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION); } diff --git a/thirdparty/libwebp/src/mux/muxedit.c b/thirdparty/libwebp/src/mux/muxedit.c index 02c3edecd7..63e71a0aba 100644 --- a/thirdparty/libwebp/src/mux/muxedit.c +++ b/thirdparty/libwebp/src/mux/muxedit.c @@ -70,6 +70,7 @@ void WebPMuxDelete(WebPMux* mux) { err = ChunkAssignData(&chunk, data, copy_data, tag); \ if (err == WEBP_MUX_OK) { \ err = ChunkSetHead(&chunk, (LIST)); \ + if (err != WEBP_MUX_OK) ChunkRelease(&chunk); \ } \ return err; \ } diff --git a/thirdparty/libwebp/src/mux/muxi.h b/thirdparty/libwebp/src/mux/muxi.h index d9bf9b3770..0f4af1784d 100644 --- a/thirdparty/libwebp/src/mux/muxi.h +++ b/thirdparty/libwebp/src/mux/muxi.h @@ -29,7 +29,7 @@ extern "C" { #define MUX_MAJ_VERSION 1 #define MUX_MIN_VERSION 2 -#define MUX_REV_VERSION 2 +#define MUX_REV_VERSION 4 // Chunk object. typedef struct WebPChunk WebPChunk; diff --git a/thirdparty/libwebp/src/mux/muxinternal.c b/thirdparty/libwebp/src/mux/muxinternal.c index b9ee6717d3..75b6b416b9 100644 --- a/thirdparty/libwebp/src/mux/muxinternal.c +++ b/thirdparty/libwebp/src/mux/muxinternal.c @@ -155,17 +155,18 @@ WebPMuxError ChunkSetHead(WebPChunk* const chunk, WebPMuxError ChunkAppend(WebPChunk* const chunk, WebPChunk*** const chunk_list) { + WebPMuxError err; assert(chunk_list != NULL && *chunk_list != NULL); if (**chunk_list == NULL) { - ChunkSetHead(chunk, *chunk_list); + err = ChunkSetHead(chunk, *chunk_list); } else { WebPChunk* last_chunk = **chunk_list; while (last_chunk->next_ != NULL) last_chunk = last_chunk->next_; - ChunkSetHead(chunk, &last_chunk->next_); - *chunk_list = &last_chunk->next_; + err = ChunkSetHead(chunk, &last_chunk->next_); + if (err == WEBP_MUX_OK) *chunk_list = &last_chunk->next_; } - return WEBP_MUX_OK; + return err; } //------------------------------------------------------------------------------ diff --git a/thirdparty/libwebp/src/webp/encode.h b/thirdparty/libwebp/src/webp/encode.h index b4c599df87..56b68e2f10 100644 --- a/thirdparty/libwebp/src/webp/encode.h +++ b/thirdparty/libwebp/src/webp/encode.h @@ -441,7 +441,7 @@ WEBP_EXTERN int WebPPictureCrop(WebPPicture* picture, // the original dimension will be lost). Picture 'dst' need not be initialized // with WebPPictureInit() if it is different from 'src', since its content will // be overwritten. -// Returns false in case of memory allocation error or invalid parameters. +// Returns false in case of invalid parameters. WEBP_EXTERN int WebPPictureView(const WebPPicture* src, int left, int top, int width, int height, WebPPicture* dst); @@ -455,7 +455,7 @@ WEBP_EXTERN int WebPPictureIsView(const WebPPicture* picture); // dimension will be calculated preserving the aspect ratio. // No gamma correction is applied. // Returns false in case of error (invalid parameter or insufficient memory). -WEBP_EXTERN int WebPPictureRescale(WebPPicture* pic, int width, int height); +WEBP_EXTERN int WebPPictureRescale(WebPPicture* picture, int width, int height); // Colorspace conversion function to import RGB samples. // Previous buffer will be free'd, if any. @@ -526,7 +526,7 @@ WEBP_EXTERN int WebPPictureHasTransparency(const WebPPicture* picture); // Remove the transparency information (if present) by blending the color with // the background color 'background_rgb' (specified as 24bit RGB triplet). // After this call, all alpha values are reset to 0xff. -WEBP_EXTERN void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb); +WEBP_EXTERN void WebPBlendAlpha(WebPPicture* picture, uint32_t background_rgb); //------------------------------------------------------------------------------ // Main call diff --git a/thirdparty/spirv-reflect/patches/zero-calloc.patch b/thirdparty/spirv-reflect/patches/zero-calloc.patch new file mode 100644 index 0000000000..796fe1266a --- /dev/null +++ b/thirdparty/spirv-reflect/patches/zero-calloc.patch @@ -0,0 +1,28 @@ +diff --git a/thirdparty/spirv-reflect/spirv_reflect.c b/thirdparty/spirv-reflect/spirv_reflect.c +index c174ae1900..11ccbdee3a 100644 +--- a/thirdparty/spirv-reflect/spirv_reflect.c ++++ b/thirdparty/spirv-reflect/spirv_reflect.c +@@ -3322,12 +3322,18 @@ static SpvReflectResult ParseExecutionModes( + } + for (size_t entry_point_idx = 0; entry_point_idx < p_module->entry_point_count; ++entry_point_idx) { + SpvReflectEntryPoint* p_entry_point = &p_module->entry_points[entry_point_idx]; +- p_entry_point->execution_modes = +- (SpvExecutionMode*)calloc(p_entry_point->execution_mode_count, sizeof(*p_entry_point->execution_modes)); +- if (IsNull(p_entry_point->execution_modes)) { +- SafeFree(indices); +- return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; ++// -- GODOT begin -- ++ if (p_entry_point->execution_mode_count > 0) { ++// -- GODOT end -- ++ p_entry_point->execution_modes = ++ (SpvExecutionMode*)calloc(p_entry_point->execution_mode_count, sizeof(*p_entry_point->execution_modes)); ++ if (IsNull(p_entry_point->execution_modes)) { ++ SafeFree(indices); ++ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; ++ } ++// -- GODOT begin -- + } ++// -- GODOT end -- + } + + for (size_t node_idx = 0; node_idx < p_parser->node_count; ++node_idx) { diff --git a/thirdparty/spirv-reflect/spirv_reflect.c b/thirdparty/spirv-reflect/spirv_reflect.c index c174ae1900..11ccbdee3a 100644 --- a/thirdparty/spirv-reflect/spirv_reflect.c +++ b/thirdparty/spirv-reflect/spirv_reflect.c @@ -3322,12 +3322,18 @@ static SpvReflectResult ParseExecutionModes( } for (size_t entry_point_idx = 0; entry_point_idx < p_module->entry_point_count; ++entry_point_idx) { SpvReflectEntryPoint* p_entry_point = &p_module->entry_points[entry_point_idx]; - p_entry_point->execution_modes = - (SpvExecutionMode*)calloc(p_entry_point->execution_mode_count, sizeof(*p_entry_point->execution_modes)); - if (IsNull(p_entry_point->execution_modes)) { - SafeFree(indices); - return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; +// -- GODOT begin -- + if (p_entry_point->execution_mode_count > 0) { +// -- GODOT end -- + p_entry_point->execution_modes = + (SpvExecutionMode*)calloc(p_entry_point->execution_mode_count, sizeof(*p_entry_point->execution_modes)); + if (IsNull(p_entry_point->execution_modes)) { + SafeFree(indices); + return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; + } +// -- GODOT begin -- } +// -- GODOT end -- } for (size_t node_idx = 0; node_idx < p_parser->node_count; ++node_idx) { |