diff --git a/SConstruct b/SConstruct index 470830d8eb74..248b00f8b3ec 100644 --- a/SConstruct +++ b/SConstruct @@ -5,12 +5,10 @@ EnsureSConsVersion(4, 0) EnsurePythonVersion(3, 8) # System -import atexit import glob import os import pickle import sys -import time from collections import OrderedDict from importlib.util import module_from_spec, spec_from_file_location from types import ModuleType @@ -52,13 +50,14 @@ _helper_module("platform_methods", "platform_methods.py") _helper_module("version", "version.py") _helper_module("core.core_builders", "core/core_builders.py") _helper_module("main.main_builders", "main/main_builders.py") +_helper_module("misc.utility.color", "misc/utility/color.py") # Local import gles3_builders import glsl_builders import methods import scu_builders -from methods import Ansi, print_error, print_info, print_warning +from misc.utility.color import STDERR_COLOR, print_error, print_info, print_warning from platform_methods import architecture_aliases, architectures, compatibility_platform_aliases if ARGUMENTS.get("target", "editor") == "editor": @@ -74,8 +73,6 @@ platform_doc_class_path = {} platform_exporters = [] platform_apis = [] -time_at_start = time.time() - for x in sorted(glob.glob("platform/*")): if not os.path.isdir(x) or not os.path.exists(x + "/detect.py"): continue @@ -198,7 +195,7 @@ opts.Add(BoolVariable("threads", "Enable threading support", True)) opts.Add(BoolVariable("deprecated", "Enable compatibility code for deprecated and removed features", True)) opts.Add(EnumVariable("precision", "Set the floating-point precision level", "single", ("single", "double"))) opts.Add(BoolVariable("minizip", "Enable ZIP archive support using minizip", True)) -opts.Add(BoolVariable("brotli", "Enable Brotli for decompresson and WOFF2 fonts support", True)) +opts.Add(BoolVariable("brotli", "Enable Brotli for decompression and WOFF2 fonts support", True)) opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 audio driver on supported platforms", False)) opts.Add(BoolVariable("vulkan", "Enable the vulkan rendering driver", True)) opts.Add(BoolVariable("opengl3", "Enable the OpenGL/GLES3 rendering driver", True)) @@ -702,6 +699,14 @@ if env["arch"] == "x86_32": else: env.Append(CCFLAGS=["-msse2"]) +# Explicitly specify colored output. +if methods.using_gcc(env): + env.AppendUnique(CCFLAGS=["-fdiagnostics-color" if STDERR_COLOR else "-fno-diagnostics-color"]) +elif methods.using_clang(env) or methods.using_emcc(env): + env.AppendUnique(CCFLAGS=["-fcolor-diagnostics" if STDERR_COLOR else "-fno-color-diagnostics"]) + if sys.platform == "win32": + env.AppendUnique(CCFLAGS=["-fansi-escape-codes"]) + # Set optimize and debug_symbols flags. # "custom" means do nothing and let users set their own optimization flags. # Needs to happen after configure to have `env.msvc` defined. @@ -1086,30 +1091,5 @@ methods.show_progress(env) # TODO: replace this with `env.Dump(format="json")` # once we start requiring SCons 4.0 as min version. methods.dump(env) - - -def print_elapsed_time(): - elapsed_time_sec = round(time.time() - time_at_start, 2) - time_centiseconds = round((elapsed_time_sec % 1) * 100) - print( - "{}[Time elapsed: {}.{:02}]{}".format( - Ansi.GRAY, - time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)), - time_centiseconds, - Ansi.RESET, - ) - ) - - -atexit.register(print_elapsed_time) - - -def purge_flaky_files(): - paths_to_keep = [env["ninja_file"]] - for build_failure in GetBuildFailures(): - path = build_failure.node.path - if os.path.isfile(path) and path not in paths_to_keep: - os.remove(path) - - -atexit.register(purge_flaky_files) +methods.prepare_purge(env) +methods.prepare_timer() diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h index 4f21a665de7f..5bbdcc093e96 100644 --- a/core/math/delaunay_3d.h +++ b/core/math/delaunay_3d.h @@ -135,9 +135,9 @@ class Delaunay3D { R128 row3_y = v3_y - v0_y; R128 row3_z = v3_z - v0_z; - R128 sq_lenght1 = row1_x * row1_x + row1_y * row1_y + row1_z * row1_z; - R128 sq_lenght2 = row2_x * row2_x + row2_y * row2_y + row2_z * row2_z; - R128 sq_lenght3 = row3_x * row3_x + row3_y * row3_y + row3_z * row3_z; + R128 sq_length1 = row1_x * row1_x + row1_y * row1_y + row1_z * row1_z; + R128 sq_length2 = row2_x * row2_x + row2_y * row2_y + row2_z * row2_z; + R128 sq_length3 = row3_x * row3_x + row3_y * row3_y + row3_z * row3_z; // Compute the determinant of said matrix. R128 determinant = row1_x * (row2_y * row3_z - row3_y * row2_z) - row2_x * (row1_y * row3_z - row3_y * row1_z) + row3_x * (row1_y * row2_z - row2_y * row1_z); @@ -146,9 +146,9 @@ class Delaunay3D { R128 volume = determinant / R128(6.f); R128 i12volume = R128(1.f) / (volume * R128(12.f)); - R128 center_x = v0_x + i12volume * ((row2_y * row3_z - row3_y * row2_z) * sq_lenght1 - (row1_y * row3_z - row3_y * row1_z) * sq_lenght2 + (row1_y * row2_z - row2_y * row1_z) * sq_lenght3); - R128 center_y = v0_y + i12volume * (-(row2_x * row3_z - row3_x * row2_z) * sq_lenght1 + (row1_x * row3_z - row3_x * row1_z) * sq_lenght2 - (row1_x * row2_z - row2_x * row1_z) * sq_lenght3); - R128 center_z = v0_z + i12volume * ((row2_x * row3_y - row3_x * row2_y) * sq_lenght1 - (row1_x * row3_y - row3_x * row1_y) * sq_lenght2 + (row1_x * row2_y - row2_x * row1_y) * sq_lenght3); + R128 center_x = v0_x + i12volume * ((row2_y * row3_z - row3_y * row2_z) * sq_length1 - (row1_y * row3_z - row3_y * row1_z) * sq_length2 + (row1_y * row2_z - row2_y * row1_z) * sq_length3); + R128 center_y = v0_y + i12volume * (-(row2_x * row3_z - row3_x * row2_z) * sq_length1 + (row1_x * row3_z - row3_x * row1_z) * sq_length2 - (row1_x * row2_z - row2_x * row1_z) * sq_length3); + R128 center_z = v0_z + i12volume * ((row2_x * row3_y - row3_x * row2_y) * sq_length1 - (row1_x * row3_y - row3_x * row1_y) * sq_length2 + (row1_x * row2_y - row2_x * row1_y) * sq_length3); // Once we know the center, the radius is clearly the distance to any vertex. R128 rel1_x = center_x - v0_x; diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h index 3ee70a092fee..149ac0dbd9ae 100644 --- a/core/templates/rid_owner.h +++ b/core/templates/rid_owner.h @@ -417,8 +417,8 @@ class RID_Alloc : public RID_AllocBase { } } - void set_description(const char *p_descrption) { - description = p_descrption; + void set_description(const char *p_description) { + description = p_description; } RID_Alloc(uint32_t p_target_chunk_byte_size = 65536, uint32_t p_maximum_number_of_elements = 262144) { @@ -515,8 +515,8 @@ class RID_PtrOwner { alloc.fill_owned_buffer(p_rid_buffer); } - void set_description(const char *p_descrption) { - alloc.set_description(p_descrption); + void set_description(const char *p_description) { + alloc.set_description(p_description); } RID_PtrOwner(uint32_t p_target_chunk_byte_size = 65536, uint32_t p_maximum_number_of_elements = 262144) : @@ -570,8 +570,8 @@ class RID_Owner { alloc.fill_owned_buffer(p_rid_buffer); } - void set_description(const char *p_descrption) { - alloc.set_description(p_descrption); + void set_description(const char *p_description) { + alloc.set_description(p_description); } RID_Owner(uint32_t p_target_chunk_byte_size = 65536, uint32_t p_maximum_number_of_elements = 262144) : alloc(p_target_chunk_byte_size, p_maximum_number_of_elements) {} diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 147ae88f2671..f16375dbf053 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -2378,66 +2378,79 @@ Variant::Variant(const ObjectID &p_id) : Variant::Variant(const StringName &p_string) : type(STRING_NAME) { memnew_placement(_data._mem, StringName(p_string)); + static_assert(sizeof(StringName) <= sizeof(_data._mem)); } Variant::Variant(const String &p_string) : type(STRING) { memnew_placement(_data._mem, String(p_string)); + static_assert(sizeof(String) <= sizeof(_data._mem)); } Variant::Variant(const char *const p_cstring) : type(STRING) { memnew_placement(_data._mem, String((const char *)p_cstring)); + static_assert(sizeof(String) <= sizeof(_data._mem)); } Variant::Variant(const char32_t *p_wstring) : type(STRING) { memnew_placement(_data._mem, String(p_wstring)); + static_assert(sizeof(String) <= sizeof(_data._mem)); } Variant::Variant(const Vector3 &p_vector3) : type(VECTOR3) { memnew_placement(_data._mem, Vector3(p_vector3)); + static_assert(sizeof(Vector3) <= sizeof(_data._mem)); } Variant::Variant(const Vector3i &p_vector3i) : type(VECTOR3I) { memnew_placement(_data._mem, Vector3i(p_vector3i)); + static_assert(sizeof(Vector3i) <= sizeof(_data._mem)); } Variant::Variant(const Vector4 &p_vector4) : type(VECTOR4) { memnew_placement(_data._mem, Vector4(p_vector4)); + static_assert(sizeof(Vector4) <= sizeof(_data._mem)); } Variant::Variant(const Vector4i &p_vector4i) : type(VECTOR4I) { memnew_placement(_data._mem, Vector4i(p_vector4i)); + static_assert(sizeof(Vector4i) <= sizeof(_data._mem)); } Variant::Variant(const Vector2 &p_vector2) : type(VECTOR2) { memnew_placement(_data._mem, Vector2(p_vector2)); + static_assert(sizeof(Vector2) <= sizeof(_data._mem)); } Variant::Variant(const Vector2i &p_vector2i) : type(VECTOR2I) { memnew_placement(_data._mem, Vector2i(p_vector2i)); + static_assert(sizeof(Vector2i) <= sizeof(_data._mem)); } Variant::Variant(const Rect2 &p_rect2) : type(RECT2) { memnew_placement(_data._mem, Rect2(p_rect2)); + static_assert(sizeof(Rect2) <= sizeof(_data._mem)); } Variant::Variant(const Rect2i &p_rect2i) : type(RECT2I) { memnew_placement(_data._mem, Rect2i(p_rect2i)); + static_assert(sizeof(Rect2i) <= sizeof(_data._mem)); } Variant::Variant(const Plane &p_plane) : type(PLANE) { memnew_placement(_data._mem, Plane(p_plane)); + static_assert(sizeof(Plane) <= sizeof(_data._mem)); } Variant::Variant(const ::AABB &p_aabb) : @@ -2455,6 +2468,7 @@ Variant::Variant(const Basis &p_matrix) : Variant::Variant(const Quaternion &p_quaternion) : type(QUATERNION) { memnew_placement(_data._mem, Quaternion(p_quaternion)); + static_assert(sizeof(Quaternion) <= sizeof(_data._mem)); } Variant::Variant(const Transform3D &p_transform) : @@ -2478,16 +2492,19 @@ Variant::Variant(const Transform2D &p_transform) : Variant::Variant(const Color &p_color) : type(COLOR) { memnew_placement(_data._mem, Color(p_color)); + static_assert(sizeof(Color) <= sizeof(_data._mem)); } Variant::Variant(const NodePath &p_node_path) : type(NODE_PATH) { memnew_placement(_data._mem, NodePath(p_node_path)); + static_assert(sizeof(NodePath) <= sizeof(_data._mem)); } Variant::Variant(const ::RID &p_rid) : type(RID) { memnew_placement(_data._mem, ::RID(p_rid)); + static_assert(sizeof(::RID) <= sizeof(_data._mem)); } Variant::Variant(const Object *p_object) : @@ -2499,21 +2516,25 @@ Variant::Variant(const Object *p_object) : Variant::Variant(const Callable &p_callable) : type(CALLABLE) { memnew_placement(_data._mem, Callable(p_callable)); + static_assert(sizeof(Callable) <= sizeof(_data._mem)); } Variant::Variant(const Signal &p_callable) : type(SIGNAL) { memnew_placement(_data._mem, Signal(p_callable)); + static_assert(sizeof(Signal) <= sizeof(_data._mem)); } Variant::Variant(const Dictionary &p_dictionary) : type(DICTIONARY) { memnew_placement(_data._mem, Dictionary(p_dictionary)); + static_assert(sizeof(Dictionary) <= sizeof(_data._mem)); } Variant::Variant(const Array &p_array) : type(ARRAY) { memnew_placement(_data._mem, Array(p_array)); + static_assert(sizeof(Array) <= sizeof(_data._mem)); } Variant::Variant(const PackedByteArray &p_byte_array) : diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp index 21fd12d24643..a50f213bc5d3 100644 --- a/core/variant/variant_setget.cpp +++ b/core/variant/variant_setget.cpp @@ -479,7 +479,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const { } \ }; -#define INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(m_base_type, m_elem_type, m_assign_type, m_max) \ +#define INDEXED_SETGET_STRUCT_BUILTIN_NUMERIC(m_base_type, m_elem_type, m_assign_type, m_max) \ struct VariantIndexedSetGet_##m_base_type { \ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \ if (index < 0 || index >= m_max) { \ @@ -541,7 +541,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const { } \ }; -#define INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(m_base_type, m_elem_type, m_accessor, m_max) \ +#define INDEXED_SETGET_STRUCT_BUILTIN_ACCESSOR(m_base_type, m_elem_type, m_accessor, m_max) \ struct VariantIndexedSetGet_##m_base_type { \ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \ if (index < 0 || index >= m_max) { \ @@ -597,7 +597,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const { } \ }; -#define INDEXED_SETGET_STRUCT_BULTIN_FUNC(m_base_type, m_elem_type, m_set, m_get, m_max) \ +#define INDEXED_SETGET_STRUCT_BUILTIN_FUNC(m_base_type, m_elem_type, m_set, m_get, m_max) \ struct VariantIndexedSetGet_##m_base_type { \ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \ if (index < 0 || index >= m_max) { \ @@ -844,18 +844,18 @@ struct VariantIndexedSetGet_String { static uint64_t get_indexed_size(const Variant *base) { return VariantInternal::get_string(base)->length(); } }; -INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector2, double, real_t, 2) -INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector2i, int64_t, int32_t, 2) -INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector3, double, real_t, 3) -INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector3i, int64_t, int32_t, 3) -INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector4, double, real_t, 4) -INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector4i, int64_t, int32_t, 4) -INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Quaternion, double, real_t, 4) -INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Color, double, float, 4) - -INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(Transform2D, Vector2, .columns, 3) -INDEXED_SETGET_STRUCT_BULTIN_FUNC(Basis, Vector3, set_column, get_column, 3) -INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(Projection, Vector4, .columns, 4) +INDEXED_SETGET_STRUCT_BUILTIN_NUMERIC(Vector2, double, real_t, 2) +INDEXED_SETGET_STRUCT_BUILTIN_NUMERIC(Vector2i, int64_t, int32_t, 2) +INDEXED_SETGET_STRUCT_BUILTIN_NUMERIC(Vector3, double, real_t, 3) +INDEXED_SETGET_STRUCT_BUILTIN_NUMERIC(Vector3i, int64_t, int32_t, 3) +INDEXED_SETGET_STRUCT_BUILTIN_NUMERIC(Vector4, double, real_t, 4) +INDEXED_SETGET_STRUCT_BUILTIN_NUMERIC(Vector4i, int64_t, int32_t, 4) +INDEXED_SETGET_STRUCT_BUILTIN_NUMERIC(Quaternion, double, real_t, 4) +INDEXED_SETGET_STRUCT_BUILTIN_NUMERIC(Color, double, float, 4) + +INDEXED_SETGET_STRUCT_BUILTIN_ACCESSOR(Transform2D, Vector2, .columns, 3) +INDEXED_SETGET_STRUCT_BUILTIN_FUNC(Basis, Vector3, set_column, get_column, 3) +INDEXED_SETGET_STRUCT_BUILTIN_ACCESSOR(Projection, Vector4, .columns, 4) INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedByteArray, int64_t, uint8_t) INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedInt32Array, int64_t, int32_t) diff --git a/doc/Doxyfile b/doc/Doxyfile index 26d86cb1272a..bd1c940ba7b4 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1475,7 +1475,7 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml index 47fc48305b5f..e0839218064a 100644 --- a/doc/classes/Environment.xml +++ b/doc/classes/Environment.xml @@ -320,7 +320,8 @@ The tonemapping mode to use. Tonemapping is the process that "converts" HDR values to be suitable for rendering on an LDR display. (Godot doesn't support rendering on HDR displays yet.) - The white reference value for tonemapping (also called "whitepoint"). Higher values can make highlights look less blown out, and will also slightly darken the whole scene as a result. Only effective if the [member tonemap_mode] isn't set to [constant TONE_MAPPER_LINEAR]. See also [member tonemap_exposure]. + The white reference value for tonemapping (also called "whitepoint"). Higher values can make highlights look less blown out, and will also slightly darken the whole scene as a result. See also [member tonemap_exposure]. + [b]Note:[/b] [member tonemap_white] is ignored when using [constant TONE_MAPPER_LINEAR] or [constant TONE_MAPPER_AGX]. The [Color] of the volumetric fog when interacting with lights. Mist and fog have an albedo close to [code]Color(1, 1, 1, 1)[/code] while smoke has a darker albedo. @@ -425,6 +426,9 @@ Use the Academy Color Encoding System tonemapper. ACES is slightly more expensive than other options, but it handles bright lighting in a more realistic fashion by desaturating it as it becomes brighter. ACES typically has a more contrasted output compared to [constant TONE_MAPPER_REINHARDT] and [constant TONE_MAPPER_FILMIC]. [b]Note:[/b] This tonemapping operator is called "ACES Fitted" in Godot 3.x. + + Use the AgX tonemapper. AgX is slightly more expensive than other options, but it handles bright lighting in a more realistic fashion by desaturating it as it becomes brighter. AgX is less likely to darken parts of the scene compared to [constant TONE_MAPPER_ACES] and can match the overall scene brightness of [constant TONE_MAPPER_FILMIC] more closely. + Additive glow blending mode. Mostly used for particles, glows (bloom), lens flare, bright sources. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index f05f431dcf36..4cccf6470f9a 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -1280,7 +1280,7 @@ - + Sets the values to be used for ambient light rendering. See [Environment] for more details. @@ -5365,6 +5365,9 @@ Use the Academy Color Encoding System tonemapper. ACES is slightly more expensive than other options, but it handles bright lighting in a more realistic fashion by desaturating it as it becomes brighter. ACES typically has a more contrasted output compared to [constant ENV_TONE_MAPPER_REINHARD] and [constant ENV_TONE_MAPPER_FILMIC]. [b]Note:[/b] This tonemapping operator is called "ACES Fitted" in Godot 3.x. + + Use the AgX tonemapper. AgX is slightly more expensive than other options, but it handles bright lighting in a more realistic fashion by desaturating it as it becomes brighter. AgX is less likely to darken parts of the scene compared to [constant ENV_TONE_MAPPER_ACES], and can match [constant ENV_TONE_MAPPER_FILMIC] more closely. + Lowest quality of roughness filter for screen-space reflections. Rough materials will not have blurrier screen-space reflections compared to smooth (non-rough) materials. This is the fastest option. diff --git a/doc/tools/doc_status.py b/doc/tools/doc_status.py index dc52a38bddda..db2b19447b56 100755 --- a/doc/tools/doc_status.py +++ b/doc/tools/doc_status.py @@ -10,14 +10,14 @@ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../")) -from methods import COLOR_SUPPORTED, Ansi, toggle_color +from misc.utility.color import STDOUT_COLOR, Ansi, toggle_color ################################################################################ # Config # ################################################################################ flags = { - "c": COLOR_SUPPORTED, + "c": STDOUT_COLOR, "b": False, "g": False, "s": False, @@ -330,7 +330,8 @@ def generate_for_class(c: ET.Element): table_column_names.append("Docs URL") table_columns.append("url") -toggle_color(flags["c"]) +if flags["c"]: + toggle_color(True) ################################################################################ # Help # diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py index a10b5d6e7822..adb7500528bd 100755 --- a/doc/tools/make_rst.py +++ b/doc/tools/make_rst.py @@ -13,7 +13,7 @@ sys.path.insert(0, root_directory := os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../")) import version -from methods import Ansi, toggle_color +from misc.utility.color import Ansi, toggle_color # $DOCS_URL/path/to/page.html(#fragment-tag) GODOT_DOCS_PATTERN = re.compile(r"^\$DOCS_URL/(.*)\.html(#.*)?$") @@ -697,7 +697,8 @@ def main() -> None: ) args = parser.parse_args() - toggle_color(args.color) + if args.color: + toggle_color(True) # Retrieve heading translations for the given language. if not args.dry_run and args.lang != "en": diff --git a/drivers/SCsub b/drivers/SCsub index 03ad70649b2b..153298c99e9a 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -26,7 +26,9 @@ if env["xaudio2"]: print_error("Target platform '{}' does not support the XAudio2 audio driver".format(env["platform"])) Exit(255) SConscript("xaudio2/SCsub") - +# Shared Apple platform drivers +if env["platform"] in ["macos", "ios"]: + SConscript("apple/SCsub") # Midi drivers SConscript("alsamidi/SCsub") SConscript("coremidi/SCsub") diff --git a/drivers/apple/SCsub b/drivers/apple/SCsub new file mode 100644 index 000000000000..83ac27f4b610 --- /dev/null +++ b/drivers/apple/SCsub @@ -0,0 +1,7 @@ +#!/usr/bin/env python +from misc.utility.scons_hints import * + +Import("env") + +# Driver source files +env.add_source_files(env.drivers_sources, "*.mm") diff --git a/platform/ios/joypad_ios.h b/drivers/apple/joypad_apple.h similarity index 65% rename from platform/ios/joypad_ios.h rename to drivers/apple/joypad_apple.h index a61e9afafb95..909648e253dd 100644 --- a/platform/ios/joypad_ios.h +++ b/drivers/apple/joypad_apple.h @@ -1,5 +1,5 @@ /**************************************************************************/ -/* joypad_ios.h */ +/* joypad_apple.h */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,23 +28,44 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ +#include "core/input/input.h" + +#define Key _QKey #import +#undef Key -@interface JoypadIOSObserver : NSObject +@class GCController; +class RumbleContext; -- (void)startObserving; -- (void)startProcessing; -- (void)finishObserving; +struct GameController { + int joy_id; + GCController *controller; + RumbleContext *rumble_context API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) = nil; + NSInteger ff_effect_timestamp = 0; + bool force_feedback = false; -@end + GameController(int p_joy_id, GCController *p_controller); + ~GameController(); +}; -class JoypadIOS { +class JoypadApple { private: - JoypadIOSObserver *observer; + id connect_observer = nil; + id disconnect_observer = nil; + HashMap joypads; + HashMap controller_to_joy_id; + + GCControllerPlayerIndex get_free_player_index(); + + void add_joypad(GCController *p_controller); + void remove_joypad(GCController *p_controller); public: - JoypadIOS(); - ~JoypadIOS(); + JoypadApple(); + ~JoypadApple(); + + void joypad_vibration_start(GameController &p_joypad, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)); + void joypad_vibration_stop(GameController &p_joypad, uint64_t p_timestamp) API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)); - void start_processing(); + void process_joypads(); }; diff --git a/drivers/apple/joypad_apple.mm b/drivers/apple/joypad_apple.mm new file mode 100644 index 000000000000..148ec4cb2718 --- /dev/null +++ b/drivers/apple/joypad_apple.mm @@ -0,0 +1,427 @@ +/**************************************************************************/ +/* joypad_apple.mm */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#import "joypad_apple.h" + +#include +#import + +#include "core/config/project_settings.h" +#include "main/main.h" + +class API_AVAILABLE(macos(11), ios(14.0), tvos(14.0)) RumbleMotor { + CHHapticEngine *engine; + id player; + bool is_started; + + RumbleMotor(GCController *p_controller, GCHapticsLocality p_locality) { + engine = [p_controller.haptics createEngineWithLocality:p_locality]; + engine.autoShutdownEnabled = YES; + } + +public: + static RumbleMotor *create(GCController *p_controller, GCHapticsLocality p_locality) { + if ([p_controller.haptics.supportedLocalities containsObject:p_locality]) { + return memnew(RumbleMotor(p_controller, p_locality)); + } + return nullptr; + } + + _ALWAYS_INLINE_ bool has_active_player() { + return player != nil; + } + + void execute_pattern(CHHapticPattern *p_pattern) { + NSError *error; + if (!is_started) { + ERR_FAIL_COND_MSG(![engine startAndReturnError:&error], "Couldn't start controller haptic engine: " + String::utf8(error.localizedDescription.UTF8String)); + is_started = YES; + } + + player = [engine createPlayerWithPattern:p_pattern error:&error]; + ERR_FAIL_COND_MSG(error, "Couldn't create controller haptic pattern player: " + String::utf8(error.localizedDescription.UTF8String)); + ERR_FAIL_COND_MSG(![player startAtTime:CHHapticTimeImmediate error:&error], "Couldn't execute controller haptic pattern: " + String::utf8(error.localizedDescription.UTF8String)); + } + + void stop() { + id old_player = player; + player = nil; + + NSError *error; + ERR_FAIL_COND_MSG(![old_player stopAtTime:CHHapticTimeImmediate error:&error], "Couldn't stop controller haptic pattern: " + String::utf8(error.localizedDescription.UTF8String)); + } +}; + +class API_AVAILABLE(macos(11), ios(14.0), tvos(14.0)) RumbleContext { + RumbleMotor *weak_motor; + RumbleMotor *strong_motor; + +public: + RumbleContext(GCController *p_controller) { + weak_motor = RumbleMotor::create(p_controller, GCHapticsLocalityRightHandle); + strong_motor = RumbleMotor::create(p_controller, GCHapticsLocalityLeftHandle); + } + + ~RumbleContext() { + if (weak_motor) { + memdelete(weak_motor); + } + if (strong_motor) { + memdelete(strong_motor); + } + } + + _ALWAYS_INLINE_ bool has_motors() { + return weak_motor != nullptr && strong_motor != nullptr; + } + + _ALWAYS_INLINE_ bool has_active_players() { + if (!has_motors()) { + return false; + } + return (weak_motor && weak_motor->has_active_player()) || (strong_motor && strong_motor->has_active_player()); + } + + void stop() { + if (weak_motor) { + weak_motor->stop(); + } + if (strong_motor) { + strong_motor->stop(); + } + } + + void play_weak_pattern(CHHapticPattern *p_pattern) { + if (weak_motor) { + weak_motor->execute_pattern(p_pattern); + } + } + + void play_strong_pattern(CHHapticPattern *p_pattern) { + if (strong_motor) { + strong_motor->execute_pattern(p_pattern); + } + } +}; + +GameController::GameController(int p_joy_id, GCController *p_controller) : + joy_id(p_joy_id), controller(p_controller) { + force_feedback = NO; + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { + if (controller.haptics != nil) { + // Create a rumble context for the controller. + rumble_context = memnew(RumbleContext(p_controller)); + + // If the rumble motors aren't available, disable force feedback. + force_feedback = rumble_context->has_motors(); + } + } + + int l_joy_id = joy_id; + + auto BUTTON = [l_joy_id](JoyButton p_button) { + return ^(GCControllerButtonInput *button, float value, BOOL pressed) { + Input::get_singleton()->joy_button(l_joy_id, p_button, pressed); + }; + }; + + if (controller.extendedGamepad != nil) { + GCExtendedGamepad *gamepad = controller.extendedGamepad; + + gamepad.buttonA.pressedChangedHandler = BUTTON(JoyButton::A); + gamepad.buttonB.pressedChangedHandler = BUTTON(JoyButton::B); + gamepad.buttonX.pressedChangedHandler = BUTTON(JoyButton::X); + gamepad.buttonY.pressedChangedHandler = BUTTON(JoyButton::Y); + gamepad.leftShoulder.pressedChangedHandler = BUTTON(JoyButton::LEFT_SHOULDER); + gamepad.rightShoulder.pressedChangedHandler = BUTTON(JoyButton::RIGHT_SHOULDER); + gamepad.dpad.up.pressedChangedHandler = BUTTON(JoyButton::DPAD_UP); + gamepad.dpad.down.pressedChangedHandler = BUTTON(JoyButton::DPAD_DOWN); + gamepad.dpad.left.pressedChangedHandler = BUTTON(JoyButton::DPAD_LEFT); + gamepad.dpad.right.pressedChangedHandler = BUTTON(JoyButton::DPAD_RIGHT); + + gamepad.leftThumbstick.valueChangedHandler = ^(GCControllerDirectionPad *dpad, float xValue, float yValue) { + Input::get_singleton()->joy_axis(l_joy_id, JoyAxis::LEFT_X, xValue); + Input::get_singleton()->joy_axis(l_joy_id, JoyAxis::LEFT_Y, -yValue); + }; + + gamepad.rightThumbstick.valueChangedHandler = ^(GCControllerDirectionPad *dpad, float xValue, float yValue) { + Input::get_singleton()->joy_axis(l_joy_id, JoyAxis::RIGHT_X, xValue); + Input::get_singleton()->joy_axis(l_joy_id, JoyAxis::RIGHT_Y, -yValue); + }; + gamepad.leftTrigger.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + Input::get_singleton()->joy_axis(l_joy_id, JoyAxis::TRIGGER_LEFT, value); + }; + gamepad.rightTrigger.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + Input::get_singleton()->joy_axis(l_joy_id, JoyAxis::TRIGGER_RIGHT, value); + }; + + if (@available(macOS 10.14.1, iOS 12.1, tvOS 12.1, *)) { + gamepad.leftThumbstickButton.pressedChangedHandler = BUTTON(JoyButton::LEFT_STICK); + gamepad.rightThumbstickButton.pressedChangedHandler = BUTTON(JoyButton::RIGHT_STICK); + } + + if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) { + gamepad.buttonOptions.pressedChangedHandler = BUTTON(JoyButton::BACK); + gamepad.buttonMenu.pressedChangedHandler = BUTTON(JoyButton::START); + } + + if (@available(macOS 11, iOS 14.0, tvOS 14.0, *)) { + gamepad.buttonHome.pressedChangedHandler = BUTTON(JoyButton::GUIDE); + if ([gamepad isKindOfClass:[GCXboxGamepad class]]) { + GCXboxGamepad *xboxGamepad = (GCXboxGamepad *)gamepad; + xboxGamepad.paddleButton1.pressedChangedHandler = BUTTON(JoyButton::PADDLE1); + xboxGamepad.paddleButton2.pressedChangedHandler = BUTTON(JoyButton::PADDLE2); + xboxGamepad.paddleButton3.pressedChangedHandler = BUTTON(JoyButton::PADDLE3); + xboxGamepad.paddleButton4.pressedChangedHandler = BUTTON(JoyButton::PADDLE4); + } + } + + if (@available(macOS 12, iOS 15.0, tvOS 15.0, *)) { + if ([gamepad isKindOfClass:[GCXboxGamepad class]]) { + GCXboxGamepad *xboxGamepad = (GCXboxGamepad *)gamepad; + xboxGamepad.buttonShare.pressedChangedHandler = BUTTON(JoyButton::MISC1); + } + } + } else if (controller.microGamepad != nil) { + GCMicroGamepad *gamepad = controller.microGamepad; + + gamepad.buttonA.pressedChangedHandler = BUTTON(JoyButton::A); + gamepad.buttonX.pressedChangedHandler = BUTTON(JoyButton::X); + gamepad.dpad.up.pressedChangedHandler = BUTTON(JoyButton::DPAD_UP); + gamepad.dpad.down.pressedChangedHandler = BUTTON(JoyButton::DPAD_DOWN); + gamepad.dpad.left.pressedChangedHandler = BUTTON(JoyButton::DPAD_LEFT); + gamepad.dpad.right.pressedChangedHandler = BUTTON(JoyButton::DPAD_RIGHT); + } + + // TODO: Need to add support for controller.motion which gives us access to + // the orientation of the device (if supported). +} + +GameController::~GameController() { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { + if (rumble_context) { + memdelete(rumble_context); + } + } +} + +JoypadApple::JoypadApple() { + connect_observer = [NSNotificationCenter.defaultCenter + addObserverForName:GCControllerDidConnectNotification + object:nil + queue:NSOperationQueue.mainQueue + usingBlock:^(NSNotification *notification) { + GCController *controller = notification.object; + if (!controller) { + return; + } + add_joypad(controller); + }]; + + disconnect_observer = [NSNotificationCenter.defaultCenter + addObserverForName:GCControllerDidDisconnectNotification + object:nil + queue:NSOperationQueue.mainQueue + usingBlock:^(NSNotification *notification) { + GCController *controller = notification.object; + if (!controller) { + return; + } + remove_joypad(controller); + }]; + + if (@available(macOS 11.3, iOS 14.5, tvOS 14.5, *)) { + GCController.shouldMonitorBackgroundEvents = YES; + } +} + +JoypadApple::~JoypadApple() { + for (KeyValue &E : joypads) { + memdelete(E.value); + E.value = nullptr; + } + + [NSNotificationCenter.defaultCenter removeObserver:connect_observer]; + [NSNotificationCenter.defaultCenter removeObserver:disconnect_observer]; +} + +// Finds the rightmost set bit in a number, n. +// variation of https://www.geeksforgeeks.org/position-of-rightmost-set-bit/ +int rightmost_one(int n) { + return __builtin_ctz(n & -n) + 1; +} + +GCControllerPlayerIndex JoypadApple::get_free_player_index() { + // player_set will be a bitfield where each bit represents a player index. + __block uint32_t player_set = 0; + for (const KeyValue &E : controller_to_joy_id) { + player_set |= 1U << E.key.playerIndex; + } + + // invert, as we want to find the first unset player index. + int n = rightmost_one((int)(~player_set)); + if (n >= 5) { + return GCControllerPlayerIndexUnset; + } + + return (GCControllerPlayerIndex)(n - 1); +} + +void JoypadApple::add_joypad(GCController *p_controller) { + if (controller_to_joy_id.has(p_controller)) { + return; + } + + // Get a new id for our controller. + int joy_id = Input::get_singleton()->get_unused_joy_id(); + + if (joy_id == -1) { + print_verbose("Couldn't retrieve new joy ID."); + return; + } + + // Assign our player index. + if (p_controller.playerIndex == GCControllerPlayerIndexUnset) { + p_controller.playerIndex = get_free_player_index(); + } + + // Tell Godot about our new controller. + Input::get_singleton()->joy_connection_changed(joy_id, true, String::utf8(p_controller.vendorName.UTF8String)); + + // Assign our player index. + joypads.insert(joy_id, memnew(GameController(joy_id, p_controller))); + controller_to_joy_id.insert(p_controller, joy_id); +} + +void JoypadApple::remove_joypad(GCController *p_controller) { + if (!controller_to_joy_id.has(p_controller)) { + return; + } + + int joy_id = controller_to_joy_id[p_controller]; + controller_to_joy_id.erase(p_controller); + + // Tell Godot this joystick is no longer there. + Input::get_singleton()->joy_connection_changed(joy_id, false, ""); + + // And remove it from our dictionary. + GameController **old = joypads.getptr(joy_id); + memdelete(*old); + *old = nullptr; + joypads.erase(joy_id); +} + +API_AVAILABLE(macos(10.15), ios(13.0), tvos(14.0)) +CHHapticPattern *get_vibration_pattern(float p_magnitude, float p_duration) { + // Creates a vibration pattern with an intensity and duration. + NSDictionary *hapticDict = @{ + CHHapticPatternKeyPattern : @[ + @{ + CHHapticPatternKeyEvent : @{ + CHHapticPatternKeyEventType : CHHapticEventTypeHapticContinuous, + CHHapticPatternKeyTime : @(CHHapticTimeImmediate), + CHHapticPatternKeyEventDuration : [NSNumber numberWithFloat:p_duration], + + CHHapticPatternKeyEventParameters : @[ + @{ + CHHapticPatternKeyParameterID : CHHapticEventParameterIDHapticIntensity, + CHHapticPatternKeyParameterValue : [NSNumber numberWithFloat:p_magnitude] + }, + ], + }, + }, + ], + }; + NSError *error; + CHHapticPattern *pattern = [[CHHapticPattern alloc] initWithDictionary:hapticDict error:&error]; + return pattern; +} + +void JoypadApple::joypad_vibration_start(GameController &p_joypad, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) { + if (!p_joypad.force_feedback || p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) { + return; + } + + // If there is active vibration players, stop them. + if (p_joypad.rumble_context->has_active_players()) { + joypad_vibration_stop(p_joypad, p_timestamp); + } + + // Gets the default vibration pattern and creates a player for each motor. + CHHapticPattern *weak_pattern = get_vibration_pattern(p_weak_magnitude, p_duration); + CHHapticPattern *strong_pattern = get_vibration_pattern(p_strong_magnitude, p_duration); + + p_joypad.rumble_context->play_weak_pattern(weak_pattern); + p_joypad.rumble_context->play_strong_pattern(strong_pattern); + + p_joypad.ff_effect_timestamp = p_timestamp; +} + +void JoypadApple::joypad_vibration_stop(GameController &p_joypad, uint64_t p_timestamp) { + if (!p_joypad.force_feedback) { + return; + } + // If there is no active vibration players, exit. + if (!p_joypad.rumble_context->has_active_players()) { + return; + } + + p_joypad.rumble_context->stop(); + + p_joypad.ff_effect_timestamp = p_timestamp; +} + +void JoypadApple::process_joypads() { + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { + for (KeyValue &E : joypads) { + int id = E.key; + GameController &joypad = *E.value; + + if (joypad.force_feedback) { + Input *input = Input::get_singleton(); + uint64_t timestamp = input->get_joy_vibration_timestamp(id); + + if (timestamp > (unsigned)joypad.ff_effect_timestamp) { + Vector2 strength = input->get_joy_vibration_strength(id); + float duration = input->get_joy_vibration_duration(id); + if (duration == 0) { + duration = GCHapticDurationInfinite; + } + + if (strength.x == 0 && strength.y == 0) { + joypad_vibration_stop(joypad, timestamp); + } else { + joypad_vibration_start(joypad, strength.x, strength.y, duration, timestamp); + } + } + } + } + } +} diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index cd5df56fbb92..0e92d830574b 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -1660,7 +1660,7 @@ bool RenderingDeviceDriverD3D12::texture_can_make_shared_with_format(TextureID p /**** SAMPLER ****/ /*****************/ -static const D3D12_TEXTURE_ADDRESS_MODE RD_REPEAT_MODE_TO_D3D12_ADDRES_MODE[RDD::SAMPLER_REPEAT_MODE_MAX] = { +static const D3D12_TEXTURE_ADDRESS_MODE RD_REPEAT_MODE_TO_D3D12_ADDRESS_MODE[RDD::SAMPLER_REPEAT_MODE_MAX] = { D3D12_TEXTURE_ADDRESS_MODE_WRAP, D3D12_TEXTURE_ADDRESS_MODE_MIRROR, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, @@ -1715,9 +1715,9 @@ RDD::SamplerID RenderingDeviceDriverD3D12::sampler_create(const SamplerState &p_ p_state.enable_compare ? D3D12_FILTER_REDUCTION_TYPE_COMPARISON : D3D12_FILTER_REDUCTION_TYPE_STANDARD); } - sampler_desc.AddressU = RD_REPEAT_MODE_TO_D3D12_ADDRES_MODE[p_state.repeat_u]; - sampler_desc.AddressV = RD_REPEAT_MODE_TO_D3D12_ADDRES_MODE[p_state.repeat_v]; - sampler_desc.AddressW = RD_REPEAT_MODE_TO_D3D12_ADDRES_MODE[p_state.repeat_w]; + sampler_desc.AddressU = RD_REPEAT_MODE_TO_D3D12_ADDRESS_MODE[p_state.repeat_u]; + sampler_desc.AddressV = RD_REPEAT_MODE_TO_D3D12_ADDRESS_MODE[p_state.repeat_v]; + sampler_desc.AddressW = RD_REPEAT_MODE_TO_D3D12_ADDRESS_MODE[p_state.repeat_w]; for (int i = 0; i < 4; i++) { sampler_desc.BorderColor[i] = RD_TO_D3D12_SAMPLER_BORDER_COLOR[p_state.border_color][i]; @@ -3811,7 +3811,7 @@ void RenderingDeviceDriverD3D12::shader_destroy_modules(ShaderID p_shader) { /**** UNIFORM SET ****/ /*********************/ -static void _add_descriptor_count_for_uniform(RenderingDevice::UniformType p_type, uint32_t p_binding_length, bool p_dobule_srv_uav_ambiguous, uint32_t &r_num_resources, uint32_t &r_num_samplers, bool &r_srv_uav_ambiguity) { +static void _add_descriptor_count_for_uniform(RenderingDevice::UniformType p_type, uint32_t p_binding_length, bool p_double_srv_uav_ambiguous, uint32_t &r_num_resources, uint32_t &r_num_samplers, bool &r_srv_uav_ambiguity) { r_srv_uav_ambiguity = false; // Some resource types can be SRV or UAV, depending on what NIR-DXIL decided for a specific shader variant. @@ -3832,11 +3832,11 @@ static void _add_descriptor_count_for_uniform(RenderingDevice::UniformType p_typ r_num_resources += 1; } break; case RenderingDevice::UNIFORM_TYPE_STORAGE_BUFFER: { - r_num_resources += p_dobule_srv_uav_ambiguous ? 2 : 1; + r_num_resources += p_double_srv_uav_ambiguous ? 2 : 1; r_srv_uav_ambiguity = true; } break; case RenderingDevice::UNIFORM_TYPE_IMAGE: { - r_num_resources += p_binding_length * (p_dobule_srv_uav_ambiguous ? 2 : 1); + r_num_resources += p_binding_length * (p_double_srv_uav_ambiguous ? 2 : 1); r_srv_uav_ambiguity = true; } break; default: { diff --git a/drivers/gles3/shaders/tonemap_inc.glsl b/drivers/gles3/shaders/tonemap_inc.glsl index 6738bdf748cb..2219c39f753e 100644 --- a/drivers/gles3/shaders/tonemap_inc.glsl +++ b/drivers/gles3/shaders/tonemap_inc.glsl @@ -27,6 +27,14 @@ vec3 srgb_to_linear(vec3 color) { #ifdef APPLY_TONEMAPPING +// Based on Reinhard's extended formula, see equation 4 in https://doi.org/cjbgrt +vec3 tonemap_reinhard(vec3 color, float p_white) { + float white_squared = p_white * p_white; + vec3 white_squared_color = white_squared * color; + // Equivalent to color * (1 + color / white_squared) / (1 + color) + return (white_squared_color + color * color) / (white_squared_color + white_squared); +} + vec3 tonemap_filmic(vec3 color, float p_white) { // exposure bias: input scale (color *= bias, white *= bias) to make the brightness consistent with other tonemappers // also useful to scale the input to the range that the tonemapper is designed for (some require very high input values) @@ -76,18 +84,79 @@ vec3 tonemap_aces(vec3 color, float p_white) { return color_tonemapped / p_white_tonemapped; } -// Based on Reinhard's extended formula, see equation 4 in https://doi.org/cjbgrt -vec3 tonemap_reinhard(vec3 color, float p_white) { - float white_squared = p_white * p_white; - vec3 white_squared_color = white_squared * color; - // Equivalent to color * (1 + color / white_squared) / (1 + color) - return (white_squared_color + color * color) / (white_squared_color + white_squared); +// Mean error^2: 3.6705141e-06 +vec3 agx_default_contrast_approx(vec3 x) { + vec3 x2 = x * x; + vec3 x4 = x2 * x2; + + return +15.5 * x4 * x2 - 40.14 * x4 * x + 31.96 * x4 - 6.868 * x2 * x + 0.4298 * x2 + 0.1191 * x - 0.00232; +} + +const mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3( + vec3(1.6605, -0.1246, -0.0182), + vec3(-0.5876, 1.1329, -0.1006), + vec3(-0.0728, -0.0083, 1.1187)); + +const mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3( + vec3(0.6274, 0.0691, 0.0164), + vec3(0.3293, 0.9195, 0.0880), + vec3(0.0433, 0.0113, 0.8956)); + +vec3 agx(vec3 val) { + const mat3 agx_mat = mat3( + 0.856627153315983, 0.137318972929847, 0.11189821299995, + 0.0951212405381588, 0.761241990602591, 0.0767994186031903, + 0.0482516061458583, 0.101439036467562, 0.811302368396859); + + const float min_ev = -12.47393; + const float max_ev = 4.026069; + + // Do AGX in rec2020 to match Blender. + val = LINEAR_SRGB_TO_LINEAR_REC2020 * val; + val = max(val, vec3(0.0)); + + // Input transform (inset). + val = agx_mat * val; + + // Log2 space encoding. + val = max(val, 1e-10); + val = clamp(log2(val), min_ev, max_ev); + val = (val - min_ev) / (max_ev - min_ev); + + // Apply sigmoid function approximation. + val = agx_default_contrast_approx(val); + + return val; +} + +vec3 agx_eotf(vec3 val) { + const mat3 agx_mat_out = mat3( + 1.1271005818144368, -0.1413297634984383, -0.1413297634984383, + -0.1106066430966032, 1.1578237022162720, -0.1106066430966029, + -0.0164939387178346, -0.0164939387178343, 1.2519364065950405); + + val = agx_mat_out * val; + + // Convert back to linear so we can escape Rec 2020. + val = pow(val, vec3(2.4)); + + val = LINEAR_REC2020_TO_LINEAR_SRGB * val; + + return val; +} + +// Adapted from https://iolite-engine.com/blog_posts/minimal_agx_implementation +vec3 tonemap_agx(vec3 color) { + color = agx(color); + color = agx_eotf(color); + return color; } #define TONEMAPPER_LINEAR 0 #define TONEMAPPER_REINHARD 1 #define TONEMAPPER_FILMIC 2 #define TONEMAPPER_ACES 3 +#define TONEMAPPER_AGX 4 vec3 apply_tonemapping(vec3 color, float p_white) { // inputs are LINEAR // Ensure color values passed to tonemappers are positive. @@ -98,8 +167,10 @@ vec3 apply_tonemapping(vec3 color, float p_white) { // inputs are LINEAR return tonemap_reinhard(max(vec3(0.0f), color), p_white); } else if (tonemapper == TONEMAPPER_FILMIC) { return tonemap_filmic(max(vec3(0.0f), color), p_white); - } else { // TONEMAPPER_ACES + } else if (tonemapper == TONEMAPPER_ACES) { return tonemap_aces(max(vec3(0.0f), color), p_white); + } else { // TONEMAPPER_AGX + return tonemap_agx(color); } } diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h index c1d23deb4dfd..ddd1d79783d0 100644 --- a/drivers/gles3/storage/light_storage.h +++ b/drivers/gles3/storage/light_storage.h @@ -757,7 +757,7 @@ class LightStorage : public RendererLightStorage { virtual void shadow_atlas_free(RID p_atlas) override; virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override; virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override; - virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override; + virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) override; _FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_instance) { ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas); @@ -883,7 +883,7 @@ class LightStorage : public RendererLightStorage { virtual void shadow_atlas_update(RID p_atlas) override; virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override; - virtual int get_directional_light_shadow_size(RID p_light_intance) override; + virtual int get_directional_light_shadow_size(RID p_light_instance) override; virtual void set_directional_shadow_count(int p_count) override; Rect2i get_directional_shadow_rect(); diff --git a/drivers/metal/pixel_formats.h b/drivers/metal/pixel_formats.h index 167c3d560091..40189ed8a6fb 100644 --- a/drivers/metal/pixel_formats.h +++ b/drivers/metal/pixel_formats.h @@ -274,7 +274,7 @@ class API_AVAILABLE(macos(11.0), ios(14.0)) PixelFormats { MTLFormatType getFormatType(DataFormat p_format); /** Returns the format type corresponding to the specified Metal MTLPixelFormat, */ - MTLFormatType getFormatType(MTLPixelFormat p_formt); + MTLFormatType getFormatType(MTLPixelFormat p_format); /** * Returns the Metal MTLPixelFormat corresponding to the specified Godot pixel diff --git a/drivers/metal/pixel_formats.mm b/drivers/metal/pixel_formats.mm index 36edbab99aa5..97452656a08b 100644 --- a/drivers/metal/pixel_formats.mm +++ b/drivers/metal/pixel_formats.mm @@ -144,8 +144,8 @@ void clear(T *p_val, size_t p_count = 1) { return getDataFormatDesc(p_format).formatType; } -MTLFormatType PixelFormats::getFormatType(MTLPixelFormat p_formt) { - return getDataFormatDesc(p_formt).formatType; +MTLFormatType PixelFormats::getFormatType(MTLPixelFormat p_format) { + return getDataFormatDesc(p_format).formatType; } MTLPixelFormat PixelFormats::getMTLPixelFormat(DataFormat p_format) { diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp index 9c30f156267e..cad4a9752798 100644 --- a/editor/animation_track_editor_plugins.cpp +++ b/editor/animation_track_editor_plugins.cpp @@ -417,8 +417,8 @@ Rect2 AnimationTrackEditSpriteFrame::get_key_rect(int p_index, float p_pixels_se animation_path = animation_path.replace(":frame", ":animation"); int animation_track = get_animation()->find_track(animation_path, get_animation()->track_get_type(get_track())); float track_time = get_animation()->track_get_key_time(get_track(), p_index); - int animaiton_index = get_animation()->track_find_key(animation_track, track_time); - animation_name = get_animation()->track_get_key_value(animation_track, animaiton_index); + int animation_index = get_animation()->track_find_key(animation_track, track_time); + animation_name = get_animation()->track_get_key_value(animation_track, animation_index); } Ref texture = sf->get_frame_texture(animation_name, frame); @@ -509,8 +509,8 @@ void AnimationTrackEditSpriteFrame::draw_key(int p_index, float p_pixels_sec, in animation_path = animation_path.replace(":frame", ":animation"); int animation_track = get_animation()->find_track(animation_path, get_animation()->track_get_type(get_track())); float track_time = get_animation()->track_get_key_time(get_track(), p_index); - int animaiton_index = get_animation()->track_find_key(animation_track, track_time); - animation_name = get_animation()->track_get_key_value(animation_track, animaiton_index); + int animation_index = get_animation()->track_find_key(animation_track, track_time); + animation_name = get_animation()->track_get_key_value(animation_track, animation_index); } texture = sf->get_frame_texture(animation_name, frame); diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index bf9b531605b1..02babe6a068d 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -75,7 +75,7 @@ static String _translate_doc_string(const String &p_text) { return translated.indent(indent); } -// Comparator for constructors, based on `MetodDoc` operator. +// Comparator for constructors, based on `MethodDoc` operator. struct ConstructorCompare { _FORCE_INLINE_ bool operator()(const DocData::MethodDoc &p_lhs, const DocData::MethodDoc &p_rhs) const { // Must be a constructor (i.e. assume named for the class) diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index d737377012fe..641c36943618 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -332,6 +332,10 @@ void EditorSettingsDialog::_event_config_confirmed() { void EditorSettingsDialog::_update_builtin_action(const String &p_name, const Array &p_events) { Array old_input_array = EditorSettings::get_singleton()->get_builtin_action_overrides(p_name); + if (old_input_array.is_empty()) { + List> defaults = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied()[current_edited_identifier]; + old_input_array = _event_list_to_array_helper(defaults); + } EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Edit Built-in Action: %s"), p_name)); @@ -339,11 +343,11 @@ void EditorSettingsDialog::_update_builtin_action(const String &p_name, const Ar undo_redo->add_undo_method(EditorSettings::get_singleton(), "mark_setting_changed", "builtin_action_overrides"); undo_redo->add_do_method(EditorSettings::get_singleton(), "set_builtin_action_override", p_name, p_events); undo_redo->add_undo_method(EditorSettings::get_singleton(), "set_builtin_action_override", p_name, old_input_array); + undo_redo->add_do_method(this, "_update_shortcuts"); + undo_redo->add_undo_method(this, "_update_shortcuts"); undo_redo->add_do_method(this, "_settings_changed"); undo_redo->add_undo_method(this, "_settings_changed"); undo_redo->commit_action(); - - _update_shortcuts(); } void EditorSettingsDialog::_update_shortcut_events(const String &p_path, const Array &p_events) { diff --git a/editor/export/codesign.h b/editor/export/codesign.h index 9659cc1a6a54..0e0635dff897 100644 --- a/editor/export/codesign.h +++ b/editor/export/codesign.h @@ -275,7 +275,7 @@ class CodeSignCodeDirectory : public CodeSignBlob { uint32_t spare3; // Not used. uint64_t code_limit_64; // Set to 0 and ignore. // Version 0x20400 - uint64_t exec_seg_base; // Start of the signed code segmet. + uint64_t exec_seg_base; // Start of the signed code segment. uint64_t exec_seg_limit; // Code segment (__TEXT) vmsize. uint64_t exec_seg_flags; // Executable segment flags. // Version 0x20500 diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index aed3d7bb5ad2..f626891bd8ea 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -82,7 +82,7 @@ Control *FileSystemList::make_custom_tooltip(const String &p_text) const { } void FileSystemList::_line_editor_submit(const String &p_text) { - if (popup_edit_commited) { + if (popup_edit_committed) { return; // Already processed by _text_editor_popup_modal_close } @@ -90,7 +90,7 @@ void FileSystemList::_line_editor_submit(const String &p_text) { return; // ESC pressed, app focus lost, or forced close from code. } - popup_edit_commited = true; // End edit popup processing. + popup_edit_committed = true; // End edit popup processing. popup_editor->hide(); emit_signal(SNAME("item_edited")); @@ -139,7 +139,7 @@ bool FileSystemList::edit_selected() { line_editor->set_text(name); line_editor->select(0, name.rfind_char('.')); - popup_edit_commited = false; // Start edit popup processing. + popup_edit_committed = false; // Start edit popup processing. popup_editor->popup(); popup_editor->child_controls_changed(); line_editor->grab_focus(); @@ -151,7 +151,7 @@ String FileSystemList::get_edit_text() { } void FileSystemList::_text_editor_popup_modal_close() { - if (popup_edit_commited) { + if (popup_edit_committed) { return; // Already processed by _text_editor_popup_modal_close } @@ -1184,7 +1184,7 @@ HashSet FileSystemDock::_get_valid_conversions_for_file_paths(const Vect return HashSet(); } - // Get a list of all potentional conversion-to targets. + // Get a list of all potential conversion-to targets. HashSet current_valid_conversion_to_targets; for (const Ref &E : conversions) { const String what = E->converts_to(); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index b177f8a3cc62..0ed0de3d59e9 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -60,7 +60,7 @@ class FileSystemTree : public Tree { class FileSystemList : public ItemList { GDCLASS(FileSystemList, ItemList); - bool popup_edit_commited = true; + bool popup_edit_committed = true; VBoxContainer *popup_editor_vb = nullptr; Popup *popup_editor = nullptr; LineEdit *line_editor = nullptr; diff --git a/editor/gui/editor_scene_tabs.cpp b/editor/gui/editor_scene_tabs.cpp index 748903a2d466..91a7598bfbab 100644 --- a/editor/gui/editor_scene_tabs.cpp +++ b/editor/gui/editor_scene_tabs.cpp @@ -164,6 +164,11 @@ void EditorSceneTabs::_reposition_active_tab(int p_to_index) { } void EditorSceneTabs::_update_context_menu() { +#define DISABLE_LAST_OPTION_IF(m_condition) \ + if (m_condition) { \ + scene_tabs_context_menu->set_item_disabled(-1, true); \ + } + scene_tabs_context_menu->clear(); scene_tabs_context_menu->reset_size(); @@ -173,12 +178,11 @@ void EditorSceneTabs::_update_context_menu() { scene_tabs_context_menu->add_shortcut(ED_GET_SHORTCUT("editor/new_scene"), EditorNode::FILE_NEW_SCENE); if (tab_id >= 0) { scene_tabs_context_menu->add_shortcut(ED_GET_SHORTCUT("editor/save_scene"), EditorNode::FILE_SAVE_SCENE); - _disable_menu_option_if(EditorNode::FILE_SAVE_SCENE, no_root_node); + DISABLE_LAST_OPTION_IF(no_root_node); scene_tabs_context_menu->add_shortcut(ED_GET_SHORTCUT("editor/save_scene_as"), EditorNode::FILE_SAVE_AS_SCENE); - _disable_menu_option_if(EditorNode::FILE_SAVE_AS_SCENE, no_root_node); + DISABLE_LAST_OPTION_IF(no_root_node); } - scene_tabs_context_menu->add_shortcut(ED_GET_SHORTCUT("editor/save_all_scenes"), EditorNode::FILE_SAVE_ALL_SCENES); bool can_save_all_scenes = false; for (int i = 0; i < EditorNode::get_editor_data().get_edited_scene_count(); i++) { if (!EditorNode::get_editor_data().get_scene_path(i).is_empty() && EditorNode::get_editor_data().get_edited_scene_root(i)) { @@ -186,25 +190,26 @@ void EditorSceneTabs::_update_context_menu() { break; } } - _disable_menu_option_if(EditorNode::FILE_SAVE_ALL_SCENES, !can_save_all_scenes); + scene_tabs_context_menu->add_shortcut(ED_GET_SHORTCUT("editor/save_all_scenes"), EditorNode::FILE_SAVE_ALL_SCENES); + DISABLE_LAST_OPTION_IF(!can_save_all_scenes); if (tab_id >= 0) { scene_tabs_context_menu->add_separator(); scene_tabs_context_menu->add_item(TTR("Show in FileSystem"), EditorNode::FILE_SHOW_IN_FILESYSTEM); - _disable_menu_option_if(EditorNode::FILE_SHOW_IN_FILESYSTEM, !ResourceLoader::exists(EditorNode::get_editor_data().get_scene_path(tab_id))); + DISABLE_LAST_OPTION_IF(!ResourceLoader::exists(EditorNode::get_editor_data().get_scene_path(tab_id))); scene_tabs_context_menu->add_item(TTR("Play This Scene"), EditorNode::FILE_RUN_SCENE); - _disable_menu_option_if(EditorNode::FILE_RUN_SCENE, no_root_node); + DISABLE_LAST_OPTION_IF(no_root_node); scene_tabs_context_menu->add_separator(); scene_tabs_context_menu->add_shortcut(ED_GET_SHORTCUT("editor/close_scene"), EditorNode::FILE_CLOSE); - scene_tabs_context_menu->set_item_text(scene_tabs_context_menu->get_item_index(EditorNode::FILE_CLOSE), TTR("Close Tab")); + scene_tabs_context_menu->set_item_text(-1, TTR("Close Tab")); scene_tabs_context_menu->add_shortcut(ED_GET_SHORTCUT("editor/reopen_closed_scene"), EditorNode::FILE_OPEN_PREV); - scene_tabs_context_menu->set_item_text(scene_tabs_context_menu->get_item_index(EditorNode::FILE_OPEN_PREV), TTR("Undo Close Tab")); - _disable_menu_option_if(EditorNode::FILE_OPEN_PREV, !EditorNode::get_singleton()->has_previous_scenes()); + scene_tabs_context_menu->set_item_text(-1, TTR("Undo Close Tab")); + DISABLE_LAST_OPTION_IF(!EditorNode::get_singleton()->has_previous_scenes()); scene_tabs_context_menu->add_item(TTR("Close Other Tabs"), EditorNode::FILE_CLOSE_OTHERS); - _disable_menu_option_if(EditorNode::FILE_CLOSE_OTHERS, EditorNode::get_editor_data().get_edited_scene_count() <= 1); + DISABLE_LAST_OPTION_IF(EditorNode::get_editor_data().get_edited_scene_count() <= 1); scene_tabs_context_menu->add_item(TTR("Close Tabs to the Right"), EditorNode::FILE_CLOSE_RIGHT); - _disable_menu_option_if(EditorNode::FILE_CLOSE_RIGHT, EditorNode::get_editor_data().get_edited_scene_count() == tab_id + 1); + DISABLE_LAST_OPTION_IF(EditorNode::get_editor_data().get_edited_scene_count() == tab_id + 1); scene_tabs_context_menu->add_item(TTR("Close All Tabs"), EditorNode::FILE_CLOSE_ALL); const PackedStringArray paths = { EditorNode::get_editor_data().get_scene_path(tab_id) }; @@ -212,13 +217,9 @@ void EditorSceneTabs::_update_context_menu() { } else { EditorContextMenuPluginManager::get_singleton()->add_options_from_plugins(scene_tabs_context_menu, EditorContextMenuPlugin::CONTEXT_SLOT_SCENE_TABS, {}); } - last_hovered_tab = tab_id; -} +#undef DISABLE_LAST_OPTION_IF -void EditorSceneTabs::_disable_menu_option_if(int p_option, bool p_condition) { - if (p_condition) { - scene_tabs_context_menu->set_item_disabled(scene_tabs_context_menu->get_item_index(p_option), true); - } + last_hovered_tab = tab_id; } void EditorSceneTabs::_custom_menu_option(int p_option) { diff --git a/editor/gui/editor_scene_tabs.h b/editor/gui/editor_scene_tabs.h index f9b94f341024..296c7fe548ec 100644 --- a/editor/gui/editor_scene_tabs.h +++ b/editor/gui/editor_scene_tabs.h @@ -70,7 +70,6 @@ class EditorSceneTabs : public MarginContainer { void _update_tab_titles(); void _reposition_active_tab(int p_to_index); void _update_context_menu(); - void _disable_menu_option_if(int p_option, bool p_condition); void _custom_menu_option(int p_option); void _tab_preview_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Variant &p_udata); diff --git a/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp b/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp index c1e643251482..21b60743d83c 100644 --- a/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp +++ b/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp @@ -645,13 +645,13 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory // Scan descendants for mapped bones. bool found_mapped = false; - Vector decendants_to_process = src_skeleton->get_bone_children(src_idx); - while (decendants_to_process.size() > 0) { - int desc_idx = decendants_to_process[0]; - decendants_to_process.erase(desc_idx); + Vector descendants_to_process = src_skeleton->get_bone_children(src_idx); + while (descendants_to_process.size() > 0) { + int desc_idx = descendants_to_process[0]; + descendants_to_process.erase(desc_idx); Vector desc_children = src_skeleton->get_bone_children(desc_idx); for (const int &desc_child : desc_children) { - decendants_to_process.push_back(desc_child); + descendants_to_process.push_back(desc_child); } StringName desc_bone_name = is_renamed ? StringName(src_skeleton->get_bone_name(desc_idx)) : bone_map->find_profile_bone_name(src_skeleton->get_bone_name(desc_idx)); diff --git a/editor/import/3d/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp index 4b5c1011059f..4a8837ce5b0d 100644 --- a/editor/import/3d/resource_importer_scene.cpp +++ b/editor/import/3d/resource_importer_scene.cpp @@ -2363,12 +2363,12 @@ void ResourceImporterScene::get_import_options(const String &p_path, Listpush_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/root_type", PROPERTY_HINT_TYPE_STRING, "Node"), "")); r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/root_name"), "")); - List script_extentions; - ResourceLoader::get_recognized_extensions_for_type("Script", &script_extentions); + List script_extensions; + ResourceLoader::get_recognized_extensions_for_type("Script", &script_extensions); String script_ext_hint; - for (const String &E : script_extentions) { + for (const String &E : script_extensions) { if (!script_ext_hint.is_empty()) { script_ext_hint += ","; } diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp index b10c681816b1..33186bc42c24 100644 --- a/editor/import/resource_importer_layered_texture.cpp +++ b/editor/import/resource_importer_layered_texture.cpp @@ -489,7 +489,7 @@ void ResourceImporterLayeredTexture::_check_compress_ctex(const String &p_source _save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + extension, r_texture_import->compress_mode, r_texture_import->lossy, Image::COMPRESS_S3TC /* IGNORED */, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, false); return; } - // Must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc). + // Must import in all formats, in order of priority (so platform chooses the best supported one. IE, etc2 over etc). // Android, GLES 2.x const bool can_s3tc_bptc = ResourceImporterTextureSettings::should_import_s3tc_bptc(); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index b803d2e5d828..062fa01758a4 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -2072,8 +2072,8 @@ void Node3DEditorViewport::_sinput(const Ref &p_event) { } bool current_hover_handle_secondary = false; - int curreny_hover_handle = spatial_editor->get_current_hover_gizmo_handle(current_hover_handle_secondary); - if (found_gizmo != spatial_editor->get_current_hover_gizmo() || found_handle != curreny_hover_handle || found_handle_secondary != current_hover_handle_secondary) { + int current_hover_handle = spatial_editor->get_current_hover_gizmo_handle(current_hover_handle_secondary); + if (found_gizmo != spatial_editor->get_current_hover_gizmo() || found_handle != current_hover_handle || found_handle_secondary != current_hover_handle_secondary) { spatial_editor->set_current_hover_gizmo(found_gizmo); spatial_editor->set_current_hover_gizmo_handle(found_handle, found_handle_secondary); spatial_editor->get_single_selected_node()->update_gizmos(); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index c11b107ee380..8c6c02f85482 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -1277,8 +1277,8 @@ Ref